Android Question DJI virtual Joystick (almost -not- working)

freedom2000

Well-Known Member
Licensed User
Longtime User
Hi all,

I wanted to test virtual joysticks with my spark (waypoints not available...)
I saw this video which gives the evidence that it could work (and well !)

It's impressive how the "ground coordinate" frame could help to have nice motion of the drone.
code is available here : https://github.com/dbaldwin/Mobile-SDK-iOS/blob/master/Sample Code/SwiftSampleCode/DJISDKSwiftDemo/VirtualSticks/VirtualSticksViewController.swift

But limited to IOS swift... BTW it is almost readable even for me !
So I tried to mofiy the DJI example to introduce virtual Joysticks.

So far I have understood that you need to switch the controller to "virtualJoystick mode"
This seems to work with this code :
B4X:
Sub HardwareState_Event (MethodName As String, Args() As Object) As Object
    Dim HardwareState As JavaObject = Args(0)
    Dim c1button As JavaObject = HardwareState.RunMethod("getC1Button", Null)
    Dim IsClicked As Boolean = c1button.RunMethod("isClicked", Null)
    Log($"C1 button: ${IsClicked}"$)
    Dim pauseButton As JavaObject = HardwareState.RunMethod("getPauseButton", Null)
    Dim pauseClicked As Boolean = pauseButton.RunMethod("isClicked", Null)
    Log($"pause button: ${pauseClicked}"$)
'    Dim Lstick As JavaObject = HardwareState.RunMethod("getLeftStick", Null)
'    Dim Lhoriz As Int = Lstick.RunMethod("getHorizontalPosition", Null)
'    Log($"left stick H value: ${Lhoriz}"$)

'virtual joystick
    FlightController = aircraft
    FlightController = FlightController.RunMethod("getFlightController", Null)    'get the flight controller
    Dim flag As Boolean = True
    If IsClicked =  True Then
        flag = True
        timerVirtualSticks.enabled = True
    Else
        flag = False
        timerVirtualSticks.enabled = False
    End If
    FlightController.RunMethod("setVirtualStickModeEnabled",Array(flag, Null))    'switch on/off the virtual joysticks
    virtualStickAvailable = FlightController.RunMethod("isVirtualStickControlModeAvailable", Null)
    Log($"virtual stick available: ${virtualStickAvailable}"$)

    Return Null
End Sub

Happy with this success I tried to sendVirtualStickFlightControlData using the DJI API

Here is what I tried :
B4X:
Sub sendVirtualStickThrottle(tt As Float)
    Dim controlData As JavaObject
    Dim y, p, r As Float
    y = 0
    p = 0
    r = 0
    Try
        controlData = FlightController.RunMethod("sendVirtualStickFlightControlData",Array(Array(p,r,y,tt),Null)) 'XXXXX ----> DOES NOT WORK
    Catch
        Log(LastException)
    End Try

End Sub

Sub timerVirtualSticks_Tick
    If (virtualStickAvailable) Then sendVirtualStickThrottle(50)
End Sub

It does not work and crashes with this error :

B4X:
pause button: false

virtual stick available: true
b4xmainpage_sendvirtualstickthrottle (java line: 1019)
java.lang.RuntimeException: Method: sendVirtualStickFlightControlData not matched.
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:129)
    at fr.free.JulienGley.DjiSpark1.b4xmainpage._sendvirtualstickthrottle(b4xmainpage.java:1019)
    at fr.free.JulienGley.DjiSpark1.b4xmainpage._timervirtualsticks_tick(b4xmainpage.java:1166)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:213)
    at anywheresoftware.b4a.objects.Timer$TickTack.run(Timer.java:105)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
(RuntimeException) java.lang.RuntimeException: Method: sendVirtualStickFlightControlData not matched.
C1 button: false

Obviously I don't know how to call the method
I understand that I should first call the constructor for FlightControlData... but I don't know how !

I am not a master chief when using JavaObject... So please if a guru reads these lines, please help me
Thanks
 
Last edited:

freedom2000

Well-Known Member
Licensed User
Longtime User
I even found the java code into the DJI documentation :

B4X:
class SendVirtualStickDataTask extends TimerTask {

        @Override
        public void run() {

            if (mFlightController != null) {
                mFlightController.sendVirtualStickFlightControlData(
                        new FlightControlData(
                                mPitch, mRoll, mYaw, mThrottle
                        ), new CommonCallbacks.CompletionCallback() {
                            @Override
                            public void onResult(DJIError djiError) {

                            }
                        }
                );
            }
        }
    }

And I am totally unable to do this with javaObject :(
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
Have you tried?

B4X:
Sub sendVirtualStickThrottle(tt As Float)
 
    Dim y, p, r As Float
    y = 0
    p = 0
    r = 0
    Try
        Dim FlightControlData as JavaObject
        FlightControlData.InitializeNewInstance("dji.common.flightcontroller.virtualstick.FlightControlData", Array(p,r,y,tt) )
        FlightController.RunMethod("sendVirtualStickFlightControlData",Array( FlightControlData, Null) )
    Catch
        Log(LastException)
    End Try

End Sub
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
@JordiCP : you are a BigBoss (not to say The Boss who will forever remain Erel !)

It works perfectly. That's really funny to see the throttle climbing whenever you push the Fn button on the remote controller.

I have now to investigate a little what I can get from these virtual joysticks, but seems very promissing :)
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
yet another problem...

I wanted to change the throttle control mode from "POSITION" to "VELOCITY" following the API :
https://developer.dji.com/api-refer...ler_djivirtualstickverticalcontrolmode_inline

So I have to pass an "enum" into the method setVerticalControlMode

I tried this :

B4X:
Try
        FlightController.RunMethod("setVerticalControlMode",Array("VELOCITY", Null) ) 'XXXXX --> DOES NOT WORK
        Dim FlightControlData As JavaObject
        FlightControlData.InitializeNewInstance("dji.common.flightcontroller.virtualstick.FlightControlData", Array(p,r,y,tt) )
        FlightController.RunMethod("sendVirtualStickFlightControlData",Array( FlightControlData, Null) )
    Catch
        Log(LastException)
    End Try

It crashes with this exception
B4X:
(RuntimeException) java.lang.RuntimeException: Method: setVerticalControlMode not matched.

So how could I access an enum with javaobject ?

Thank in advance !
 
Last edited:
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
It's strange that it works with POSITION but it does not with VELOCITY.

I have never worked with this lib, but in theory you can get the permitted enum values (which should be those of the documentation) with this.

Could you check the output of this code?
B4X:
   Dim VirtualStick as JavaObject
   VirtualStick.initializeStatic("dji.common.flightcontroller.virtualstick.VerticalControlMode")
   Dim possibleEnumValues() As Object = jo.RunMethod("values", Null)
   
   ' If, in debug mode, you place a breakpoint after this line and place your mouse over possibleEnumValues, you'll see it is an array of values with name and ordinal.
   ' When we log it it is directly casted to string.
   For k=0 to possibleEnumValues.Length-1        
      Log( possibleEnumValues(k) )
   Next
   ' ...
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
you are right Jordi, it didn't work either with POSITION... My mistake sorry for the trouble (you were faster than me to correct the post !)

I check your code !
 
Last edited:
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
So it seems that the enum values are the right ones (POSITION and VELOCITY) as expected

But my call with these values crashes... line 177 and log
bug.jpg


So the bug is on my side when I call the method setVerticalControlMode
B4X:
        Try
            FlightController.RunMethod("setVerticalControlMode", Array("POSITION", Null) ) 'XXXXX --> DOES NOT WORK 
        Catch
            Log(LastException)
        End Try
        Dim VirtualStick As JavaObject
        VirtualStick.initializeStatic("dji.common.flightcontroller.virtualstick.VerticalControlMode")
        Dim possibleEnumValues() As Object = VirtualStick.RunMethod("values", Null)
 
        ' If, in debug mode, you place a breakpoint after this line and place your mouse over possibleEnumValues, you'll see it is an array of values with name and ordinal.
        ' When we log it it is directly casted to string.
        For k=0 To possibleEnumValues.Length-1
            Log( possibleEnumValues(k) )
        Next

Is it the right syntax to pass an enum ?
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
Not sure why it happens, according to other posts seems correct. Perhaps it is related to the fact that the enum is declared in another class? No idea.

Just to try, I'd check the following options
B4X:
      Try
            Dim myVelocityMode as int = 0    '<-- the ordinal for VELOCITY
            FlightController.RunMethod("setVerticalControlMode", Array(myVelocityMode, Null) ) 
        Catch
            Log(LastException)
        End Try
or
B4X:
      Try
         Dim VerticalControlMode As JavaObject
         VerticalControlMode.initializeStatic("dji.common.flightcontroller.virtualstick.VerticalControlMode")
         Dim VelocityEnum as Object = VerticalControlMode.Getfield("VELOCITY")
         FlightController.RunMethod("setVerticalControlMode", Array( VelocityEnum, Null) ) 
        Catch
            Log(LastException)
        End Try
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
Oups I probably found the bug... There is no callback for this method.

Correct syntax may be :
B4X:
Try
            FlightController.RunMethod("setVerticalControlMode", Array("POSITION") )
        Catch
            Log(LastException)
        End Try
 
Last edited:
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
OMG, you are right, totally missed that!! Sometimes the obvious things are soo obvious that we just ignore them :eek:

The good part is that I've learned a lot about enums in Java ;)
 
Upvote 0

JordiCP

Well-Known Member
Licensed User
Longtime User
I must admit that I am a complete noob with java
...I don't think so, and besides you have a DJI drone!! 😁

Having downloaded the SDK for this post, I saw that it is really impressive. I had not paid attention up to now to the related DJI threads simply because I don't own one.
When I have time (and money, don't know how much it costs), I'll look at it :)
 
Upvote 0

freedom2000

Well-Known Member
Licensed User
Longtime User
You can get a spark at rather low price. They are in the range 300g so in a "not totally good" category regarding the new regulation for drone and UAV.
They are also discontinued, so they can be found rather cheap on the second hand market.
Another good (better) option is to buy a second hand Mavic Mini. It's a really good drone which is less than 250g (the best UAV category). You can find it with all the goodies (flight more combo) for less than 300€.
And if you have more money you can buy a brand new Mavic Mini2 :)
 
Last edited:
Upvote 0
Top