Minimalist AirSDK interaction

I have created an app using the GroundSDK, but I need to toggle a setting that is only available in the AirSDK. I do not want an AirSDK mission that manages the flight of the drone, which seems to be the focus of all of the examples.

Ultimately what I’d really want is a method on the MainGimbal in the GroundSDK that would unlock the yaw axis, so this functionality is what I want from the AirSDK and nothing else.

It seems cumbersome to add another whole project and build system just for this, but let me know if there are other options available.

Hello,

Unfortunately there exists no GroundSDK API to unlock the gimbal yaw. Only the pitch can be controlled.

I understand this is the case. I am struggling with the interaction between the GroundSDK and AirSDK as all of the examples are using Olympe. Looking at the documentation, I see Messages can be sent from the MissionManager but these include a “Service ID” which does not seem to be explained anywhere and this doesn’t seem to exist in the Olympe code.

I would appreciate either an example of this interaction or more thorough explanation of each of the constructor arguments in the documentation.

Thanks

Hi,

The service ID used in mission messages is the jenkins 16bit
hash of the protobuf package name + ".Command" (for messages to send to the drone) or ".Event" (for messages received from the drone).

You can use this function to compute the hash:

fun jenkinsHash16(src: String): Int {
    var hash = 0

    src.toByteArray(Charsets.US_ASCII).forEach {
        hash += it.toInt()
        hash += hash shl 10
        hash = hash xor (hash ushr 6)
    }

    hash += hash shl 3
    hash = hash xor (hash ushr 11)
    hash += hash shl 15

    return hash and 0xFFFF
}

For the message ID, you can freely choose an int value and increment it for each message.
The payload is the built protobuf message you want to send as byte array.

I hope that these explanations are clear enough.

Thibaut

Thanks, this is really helpful!

Now a couple more questions about the interaction.

  • If I’m sending a message that doesn’t need a payload, would I just supply an empty bytearray for that parameter or do I need to provide something?
  • When I’m receiving events from the drone, do need to send a message first to get it to send something? I have not had luck with the latestMessage from the MissionManager. For example, receiving the mean distance from the HelloDrone AirSDK sample (My other post about this)
  • Is this documented anywhere? I haven’t seen anything about the Jenkins Hash in the docs and this seems like a pretty crucial piece of the interaction between GroundSDK and AirSDK

We can keep the discussion for both this post and the other one here, since they’re both about interacting with the AirSDK

One more question. I see that the gimbal lock is controlled by a custom guidance mode, but is it possible to unlock the gimbal for existing modes? For example when I command the drone with PilotingInterfaces from the GroundSDK. In my testing I am able to rotate the gimbal when I have my gimbal unlock miission active, but once I take off it resets back to the center.

Also I see that there was a request for more python documentation back in 2022. Are there any updates on this?

  • I think you can send a message with an empty payload if you need to send only one kind of information.
  • You don’t need to send a message first, the drone can send the first one. However, you should notice that latestMessage is transient, so you have to add an observer to MissionManager to get the messages, like this:
drone.getPeripheral(MissionManager::class.java) { missionManager ->
  val message = missionManager?.latestMessage
  ...
}
  • This is not really documented yet, sorry.

Thanks, that did the trick!

Now I think all that I still need is the ability to unlock the gimbal for all missions/modes/piloting interfaces. I am able to unlock it with a custom guidance mode but once I take off it locks again.

Any update here? How can I unlock the gimbal and keep it unlocked?

It looks like I’d want to set the guidance mode for all the states in the Flying stage. I assume that the way to do this would just be to extend the default state classes and add set_guidance_mode into their enter method.

Something like this perhaps?:

import .......states.Manual
class MyManual(Manual):
  def enter(self, msg):
    super().enter(self, msg)
    set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

Where can I import the existing state classes from in order to make that change?

Hello,

This post is about to auto close and I don’t have any way of extending the time. I still have an unanswered question so could you please take a look at this?

Thanks

This topic was automatically closed after 30 days. New replies are no longer allowed.

Hi @RobbieNesmith ,

Yes, your code seems to be suitable for what you want to do.

You can try import all the states from the Flying stage :

from fsup.missions.default.flying.manual import Manual
from fsup.missions.default.flying.flightplan import FlightPlan
from fsup.missions.default.flying.lookat import LookAt
from fsup.missions.default.flying.poi import Poi
from fsup.missions.default.flying.rth import Rth

Hugo

Thanks, I’ll give that a try. Is there a list of all the state/stage python classes somewhere? Or a way to infer them from the AirSDK docs?

Hi,

You can retrieve the stages information from the class Mission which contains the mission state machine. The function states() shall return an array of all the states of the state machine.
See Flight supervisor - 7.7 for more information.

For each stage in the table, you will be able to access their dict which contains all their states dict.

Hugo

I tested this out but didn’t have any luck. I am able to move the gimbal while on the ground but when I send the take off command to the drone, the gimbal locks back to center.

I see this in the ulogcat logs, which seems to indicate that I have in fact replaced the states:

12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.relative_move' is not marked as required by any Flight Supervisor state
12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.absolute_move' is not marked as required by any Flight Supervisor state
12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.lookat_piloting' is not marked as required by any Flight Supervisor state
12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.poi_piloting' is not marked as required by any Flight Supervisor state
12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.flightplan' is not marked as required by any Flight Supervisor state
12-31 18:01:15.099 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.descent_to_position' is not marked as required by any Flight Supervisor state
12-31 18:01:15.100 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.magic_carpet' is not marked as required by any Flight Supervisor state
12-31 18:01:15.100 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.camera_rotation_move' is not marked as required by any Flight Supervisor state
12-31 18:01:15.100 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.lookat_gotofix' is not marked as required by any Flight Supervisor state
12-31 18:01:15.100 W fsup.StateMachine(fsup-418)                  : Guidance mode 'com.parrot.missions.default.poi_gotofix' is not marked as required by any Flight Supervisor state

Also, once I am in the air I am not able to move the drone. Is this because I’m using a ground guidance mode? Is there a way I can instead modify the guidance modes so they all unlock the gimbal instead of making a guidance mode and assigning it to all states?

Here is my code that I’m using. It’s a modification to the Hello airsdk mission’s fsup/flying/stage.py. I have also updated HelloGroundMode’s configure method in guidance/hello.py to unlock the yaw and pitch of the gimbal.

from fsup.missions.default.flying.stage import FLYING_STAGE as DEF_FLYING_STAGE
from fsup.missions.default.flying.manual import Manual
from fsup.missions.default.flying.flightplan import FlightPlan
from fsup.missions.default.flying.lookat import LookAt
from fsup.missions.default.flying.poi import Poi
from fsup.missions.default.flying.rth import Rth

import samples.hello.guidance.messages_pb2 as my_gdnc_mode_msgs

from ..uid import UID

MY_GUIDANCE_MODE_NAME = UID + ".ground"

class MyManual(Manual):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

class MyFlightPlan(FlightPlan):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

class MyLookAt(LookAt):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

class MyPoi(Poi):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

class MyRth(Rth):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

MY_MANUAL_STATE = {
  "name": "manual",
  "class": MyManual,
}

MY_FLIGHTPLAN_STATE = {
  "name": "flightplan",
  "class": MyFlightPlan,
}

MY_LOOKAT_STATE = {
  "name": "lookat",
  "class": MyLookAt,
}

MY_POI_STATE = {
  "name": "poi",
  "class": MyPoi,
}

MY_RTH_STATE = {
  "name": "rth",
  "class": MyRth,
}

FLYING_STAGE = {
    "name": "flying",
    "class": DEF_FLYING_STAGE["class"],
    "initial": "manual",
    "children": [MY_MANUAL_STATE, MY_FLIGHTPLAN_STATE, MY_LOOKAT_STATE, MY_POI_STATE, MY_RTH_STATE],
}

Hello,

Can you try adding the following in your code ?

from fsup.genstate import State, guidance_modes
from fsup.missions.default.uid import UID

...

@guidance_modes(UID + ".manual")
class MyManual(Manual):
  def enter(self, msg):
    super().enter(msg)
    self.set_guidance_mode(MY_GUIDANCE_MODE_NAME, my_gdnc_mode_msgs.Config())

Thanks,
Hugo