MAVLink support for the STorM32 Gimbal Controller: How to make it "compatible"?


Hey Folks

I would need your advices and recommendations.

I’m in the course of reworking the MAVLink support of the STorM32 gimbal controller, mainly because I want to integrate the camera microservice messages, which requires MAVLink 2 which the STorM32 didn’t yet do, but also because MAVLink has progressed significantly and I considered it time to catch up. The general idea is to make it as “MAVLink compatible” as possible.

MAVLink 2 and several new messages are already working fine, so that’s no the issue, but unfortunately there are quite a couple of points, related to the MAVLink version negotiation and some new MAVLink features, which are unclear to me, and which I couldn’t figure out despite having deeply dived through the docs.

I would greatly appreciate if you could help clarify them.

A. MAVLink Version negotiating.

This is the major part where I’m unsure how a gimbal controller should behave.

Please note that a gimbal controller may be used as both a “system” (e.g. when connected directly to a GCS, an Arduino, and so on) and a “component” (e.g. when connected to a PixHawk flight controller).

To make the story short, I won’t attempt to describe all my thoughts; pl assume that I carefully and repeatedly read the docs and was trying to make best sense of it, but that I do see (edge) cases where it’s unclear to me how a component and the STorM32 in particular should behave. So let me describe just what it currently does:

The messages can be differentiated as “outgoing”, such as e.g. a heartbeat or mountorientation, and “incomming with a potential response”, such as a command_long or param_request_list.
It also has a configuration parameter which can be set to Mavlink1 and Mavlink2.
It currently does this:

  • Outging messages are emitted using the version specfied by the parameter. If the outgoing message is MAVLink2 but the parameter is MAVLink1 when this message is dropped and not emitted.

  • When the parameter is set to Mavlink1, then incoming MAVLink2 messages are ignored, and a required response is send also in MAVLink1.

  • When the parameter is set to Mavlink2, then both incoming MAVLink1 and MAVLink2 messages are accepted, and a required response is send in the same version as the incoming message.

Is this what you would expect the STorM32 to do? What is OK what is not OK?

B. HeartBeat, autopilot field

So far the STorM32 used its own value in the heartbeat’s autopilot field, but reading through the docs it seems to me that the proper value would be autopilot = MAV_AUTOPILOT_INVALID.

Is this what you would expect the STorM32 to use?

C. HeartBeat, type field

So far the STorM32 used it’s own value in the heartbeat’s type field. However, there is now a MAV_TYPE_GIMBAL value in the enum ( and it appears obvious that this should be used.

However, the docu also says

type: Type of the system (quadrotor, helicopter, etc.). Components use the same type as their associated system.

This would IMHO represent a real issue.

  • First, in case the STorM32 is not connected to a flight controller one would want it to show type = GIMBAL.
  • Second, this requirement would imply that a component must wait for a heartbeat from the system to arrive, which implies that the component must know which heartbeat is the one from the system !!! I can’t see how that could be achieved without additional configuration parameters, which would be most inconvenient from a usability perspective.
  • Third, I can’t see a generic way for the STorM32 to decide if its the first or the second situation, which would imply the need for further configuration parameters, which would be most inconvenient from a usability perspective.
  • Fourth, this requirement actually doesn’t make any sense to me. Why should a component not be allowed to tell what sort of a kind it is. This loss of information can also create issues, e.g. it might be useful to figure out which ID/messages are related to the gimbal, which would not be possible.

My conclusion would be that the type should be GIMBAL in all cases.

What would you expect the STorM32 to do?


I find these values in the enum

  • MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT: Autopilot supports the new param float message type.
  • MAV_PROTOCOL_CAPABILITY_PARAM_UNION: Autopilot supports the new param union message type.

Could you please explain what this means, what these are?


The docs appear to be quite inconsistent as regards this set of messages.

Here it appears very clear. However, PROTOCOL_VERSION is marked in big red letters as WIP and that it should not be used.

Later below,, there is then no talk of PROTOCOL_VERSION, but of AUTOPILOT_VERSION. However, there is no obviously related message in common.h which would allow oneto request AUTOPILOT_VERSION. Is one supposed to emit it periodically? What’s then the deal of it, since heartbeat does this already?
I note, ArduPilot in fact has added and uses a AUTOPILOT_VERSION_REQUEST in its dialect.

To make it totally confusing, there further is a MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES, but it’s totally unclear what should be send out as response. PROTOCOL_VERSION? AUTOPILOT_VERSION? ??

Currently I’ve followed the path of ArduPilot & MissionPlanner, which use ArduPilot’s AUTOPILOT_VERSION_REQUEST, and made the STorM32 to respond to it by sending a AUTOPILOT_VERSION. This works nice with MissionPlanner, but not at all with QGC.

What would you expect the STorM32 to do?

Lot’s of stuff, I know, sorry for that. Maybe you nevertheless could find time to provide some guidance.
Many thx,


Point (B) I’ve answered myself by deciding to set it to autopilot = MAV_AUTOPILOT_INVALID

However, for all the other points I still would be highly interested and would much appreciate to get some advices and/or explanations !!

:slight_smile: :slight_smile: :slight_smile:


For part A - What parameter and library are we talking about? This is really “FWIW” given that I don’t have enough context …

Assuming you’re talking about some parameter that you use to say whether you’re communicating in MAVLink 1 or 2 with a remote system - ie you have already done the negotiating versions to work out what the remote system supports then …

Outging messages are emitted using the version specfied by the parameter. If the outgoing message is MAVLink2 but the parameter is MAVLink1 when this message is dropped and not emitted.

Depends what you mean by “Outgoing message is MAVLink 2”. MAVLink 2 can send any message id and any message extension, while MAVLink 1 can send messages with id<255 only and cannot send message extensions.
So if your parameter is MAVLink 1, I’d expect you to dump any message with id > 255 and also strip off extension fields. You’d also have to use the MAVLink 1 packet format of course.

When the parameter is set to Mavlink1, then incoming MAVLink2 messages are ignored, and a required response is send also in MAVLink1.

If your system understands MAVLink 2 I’d expect it to switch to MAVLink 2 on the channel as per “Negotiating versions”.

If it only understands MAVLink 1 then it won’t get the message, because it won’t even see the magic packet marker.

When the parameter is set to Mavlink2, then both incoming MAVLink1 and MAVLink2 messages are accepted, and a required response is send in the same version as the incoming message.

Yes. If you receive MAVLink 1 though, I’d then start the negotiating versions process to see if it supports MAVLink 2, switching over if it does.


Yes, that is my interpretation


Don’t know. For MAV_PROTOCOL_CAPABILITY_PARAM_FLOAT a complete guess is that before the current parameter protocol (which encodes parameters in a float field) there was another way of doing it. This essentially indicates support for the parameter protocol.

Never seen the union - might be something used in ArduPilot?

@auturgy @JulianOes Any ideas?


Yes, docs are a mess here.

Looking at the PX4 code,

  • MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES - returns ACK response then emits AUTOPILOT_VERSION. If you want capabilities, this is what should be called.
  • PROTOCOL_VERSION - yes, we don’t have a very good cleanup process. Will seek to get the above fixed.

Does that answer “enough”?



thx so much for taking the time to respond in this detail

as regards A
I need to better think about your response before answering :slight_smile:

So it’s not just me who isn’t sure what the meaning is. Would be nice if it could be cleared up. For the moment, I guess I can take that as indication that I shouldn’t be concerned :slight_smile:

as regards E
except of the somewhat unfortunate naming that it’s called MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES and not MAV_CMD_REQUEST_AUTOPILOT_VERSION, your answer makes fully sense, and is clarifying. I will do as you listed. Thx. It would be great if the docs could be updated.

Maybe you could unambiguously confirm/disconfirm with a simple yes/no, if possible: Does it mean that PROTOCOL_VERSION is no longer WIP/DONOTUSE, but in fact official now?

I’d like to point again to that ArduPilot has an AUTOPILOT_VERSION_REQUEST message (not command, message) in it’s dialect, which is in fact used by e.g. MissionPlanner to query for AUTOPILOT_VERSION, and MissionPlanner in fact kind of requires a component to respond to this request in order to work properly. As you claryfied, it now turns out that this message is tautologous to the official MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES, but since MissionPlanner relies on it, it’s quite a breach of the standard. I guess one should bring this to the attention of the ArduPilot/MissionPlanner folks.

Also, if the behavior, that a GCS essentially requires a component to support AUTOPILOT_VERSION for proper functioning, is how it is supossed to be, then it should be said so in the specs. I mean, from the spec it should IMHO in principle be clear what messages/commands a component should minimally support for proper interaction with the common things like autopilot & GCSes.

thx again, Olli


I would! As long as you stick to INTS/Floats for PX4 and floats as ardupilot interprets them you should be fine for interacting with those two autopilots.

I’ve got a PR in place following this discussion. Needs to be reviewed and approved, and I want to confirm with both ArduPilot and PX4 the same interpretation.

No, not until the PR goes in.
But I suspect that it is “official”, just that no one has removed the wip yet. It has been around for some years now.

We don’t know that their dialect message doesn’t predate the command. But yes, in either case it would be good for us all to use the same approach. I will add it for discussion.

Yes. I need to revisit the heartbeat protocol and document some more of this. If you create a bug against the page I will certainly do so. Even if you don’t I hope to do so, but a bug report helps reduce the chance things will fall off my list.


@hamishwillee bug me on Friday arvo, I have a chunk of Mavlink stuff to work through but am time challenged at present.


MANY thx, all clear now :slight_smile: . I’ve seen the PRs. I’ve also raised an issue for the last point.

let me please come back to part A

I surely acknowledge that your response sounds very clear and compelling at first, which made me rethinking, but I think it doesn’t actually solve things. I also like to acknowledge that I simply might not yet fully understand how the hole MAVLink2 versioning is supposed to work - at least I don’t feel like fully understanding it.

I’d like to start with mentioning - and I realize that I have failed to emphasize that before - that I’m interested in establish something which is working now, and not in some ideal world which for the time being is hypothetical. Currently, different key players are not working well together, i.e., QGC cannot be used with ArduPilot (ArduCopter stable), since it doesn’t make ArduPilot to switch to MAVLink2. I need to connect with MissionPlanner once for it to work. You can see this in this video at around 6mins:

Btw, the library is what I have PRed as “light” version, but that’s irrelevant since behavior-wise it’s identical to the original library (which I actually would expect to be so fro any library).

In the context of doing the negotiation you were referring to Negotiating Versions and not to Version Handshaking. It’s not totally clear to me if this was by purpose, or just because of a desired fast response. So, I’m not sure what to answer. I’d like to answer however that IMHO the spec as outlined in MAVLink Versions is problematic in several aspects.

  1. The procedures described in Negotiating Versions are obviously at odds with the procedure described higher up in Version Handshaking. In the former chapter essentially all sorts of methods are described, except of exactly the one described in the latter chapter.

I understand (or believe to do so), that the procedures in Negotiating Versions are not “official” but for helping in the transition, and that the procedure in Version Handshaking is the “official”. However, for as long as we are in the transitioning state one obviously can’t just resort to referring to one of the procedures. The QGC-ArduPilot case I consider an example.

  1. The procedure described in Negotiating Versions is incomplete in that components are not mentioned/considered, and fails to recognize that there are two ends to a link while the handshaking protocol assumes one active and one passive side.

For the pair GCS-autopilot it is specified that the GCS should initiate the negotiation process. However, for the pair autopilot-component, who should here start the negotiation? The component? If so, when this is at least not current practice. Also, who is supposed to “win” when you connect a gimbal directly to a GCS? The autopilot? Makes sense since the autopilot is somewhat “superior” to components. But when why a difference in case of a GCS, why shouldn’t this also be negotiated by the autopilot? Both the autopilot and the component? Well, argh … So, what? I just see lots of question marks, which at best could be filled with lots of guessing (producing issues).

Your response reads as if you assume that it’s the gimbal who should have done the negotiation. So maybe you were refereeing to Negotiating Versions by purpose. So let’s see:

  1. The procedures described in Negotiating Versions cannot ensure a successful negotiation. It could if implemented on both sides with some sufficient overlap, but they can’t ensure since situations are allowed there it fails. See e.g. QGC-ArduPilot. E.g. when both sides choose automatic switching (chicken-and-egg problem). It also fails to mention/consider components. A component can’t just follow the rules given there for an ensured successfull negotiation. I came to the conclusion that the “best practice” should be somewhat different for components, but it’s not clear to me in which way exactly.

So, I somehow still feel that it’s not yet totally clear how the STorM32 should behave
(it obviously already behaves in a way which allows it to work for the “right circumstances”, see video, but this can’t be the goal, it should behave in all circumstances)

sorry for the long text, but the matter really bothers me.


Hi @olliw

A lot of this stuff predates my involvement. I am sure you have valid points, but I will not have time to address this point, possibly until next week.

On my list.


no urgency in here

and yes, it’s a somewhat involved topic with many edge (but not unrealistic) cases to be thought through, not something for the quick

many thx so far, sir :slight_smile:


actually, maybe it’s more reasonable to conclude this here.

I start to get the feeling that I am somewhat too ambitious here, and am trying to achieve something which isn’t easily achieved. I probably just should be happy with having something which is somehow working.