mavlink icon indicating copy to clipboard operation
mavlink copied to clipboard

MANUAL_CONTROL: Redefine the use of `z` (throttle) to be independent to vehicle's thrust direction

Open junwoo091400 opened this issue 3 years ago • 13 comments

Description

Previously, the z component definition relied on having a knowledge of which direction the thrust would result in, depending on its value, which is tied to the vehicle's setup (e.g. Rover, which can take in reverse-throttle commands vs. conventional quadcopter with only positive throttle).

This is a bad practice because:

  1. With this definition, we need to tailor the MANUAL_CONTROL message for each different type of vehicle to use the 'correct' range of z. So having a GCS with a Joystick input will have to know which range of throttle would result in positive/negative thrust for each connected vehicle, which doesn't make sense.
  2. The concept of 'Manual Control' should be as simple as possible (just a Joystick command). And just how Joysticks all have min/max ranges, it would be simpler to not have the 'thrust' condition, but to just map the ranges simply to [-1, 1]

With this new definition, the MANUAL_CONTROL message will not be vehicle-specific and truly represent the Joystick / RC Transmitter's throttle position.

Alternatives

We could keep the convention as is 🤔

Discussion Points

  1. How do we make sure previous users who were sticking to this convention don't get affected? (Or is this inevitable?)

Context

This issue was discussed in a PX4 PR trying to standardize the range for throttle internally: https://github.com/PX4/PX4-Autopilot/pull/15949#discussion_r1025243016

junwoo091400 avatar Nov 19 '22 10:11 junwoo091400

As the wording is now "Positive values are positive thrust, negative values are negative thrust.". That implies that on a vehicle with only positive thrust you have to have a deadzone from the low position of the axis range to the centre. I bet that no one actually does that.

This is conceptually a breaking change from a MAVLink perspective but I think it makes sense, if we can get the wording right. I will take to the dev call this evening.

@MaEtUgR

  1. I don't like the "simpler definition". Refering to pitch, roll, yaw, throttle thrust is annoying unless that is how it maps to all vehicles. For example, pitch makes little sense in MC position mode right? That has always made our discussions of stick movements confusing. But, I'm not the boss of MAVLink and you know more than me about the practicalities of interpreting joysticks.
  2. But if you want to explore this, we are already thinking of how to iterate this message. We haven't really thought about the axis. The main concern is that currently we have a message that provides button mappings and the flight stack has to map those button mappings to functions - that's a lot of code in the flight stack, and requires that the GCS knows quite a bit about the flight stack it is taking to. What we're thinking about is removing the button array and having the ground station just send mavlink commands on button presses.

hamishwillee avatar Nov 23 '22 00:11 hamishwillee

2. But if you want to explore this, we are already thinking of how to iterate this message. We haven't really thought about the axis. The main concern is that currently we have a message that provides button mappings and the flight stack has to map those button mappings to functions - that's a lot of code in the flight stack, and requires that the GCS knows quite a bit about the flight stack it is taking to. What we're thinking about is removing the button array and having the ground station just send mavlink commands on button presses.

Oddly, I'm looking at doing the opposite in (non-Sub) ArduPilot (https://github.com/ArduPilot/ardupilot/pull/22259) - actually taking action based on the buttons field in MANUAL_CONTROL. ArduPilot has a set of pre-canned "auxiliary functions" which I'll be using to provide the button functions - we use that list for physical buttons present on the vehicle, RC switches, mission items, lua script and direct mavlink calls, so reusing that list is making sense so far.

Turns out that MissionPlanner actually already does what you're suggesting here - makes mavlink calls rather than passing through the button bits (a small impediment to my little project).

peterbarker avatar Nov 28 '22 10:11 peterbarker

Turns out that MissionPlanner actually already does what you're suggesting here - makes mavlink calls rather than passing through the button bits (a small impediment to my little project).

Sounds daft unless the functions you want don't have corresponding mavlink messages, or can't do so for some reason. I understand that in Canberra they call you "Mad Peter" :-)

Currently

  • ArduPilot has parameters that map what buttons are, and GCS has to know what those parameters are
  • PX4 hard codes specific buttons in the message to specific functions, so the GCS needs to know what functions are used for each case and send that set of values in the message.

The send-a-mavlink-message approach seems much smarter and more flexible.

  • The GCS does not need to know anything about the flight stack than it already knows - what commands are supported. (and even those can be in many cases checked without side effects). It doesn't need to know what parameters the flight stack uses to map button presses or what functions are called.
  • The flight stack doesn't have to have special code paths to process instructions it is already processing through mavlink.
  • The manual control message doesn't have to cope with the possiblity of joysticks with more buttons than we expose.

hamishwillee avatar Nov 30 '22 06:11 hamishwillee

On Tue, 29 Nov 2022, Hamish Willee wrote:

The send-a-mavlink-message approach seems much smarter and more flexible.

  • The GCS does not need to know anything about the flight stack than it already knows - what commands are supported. (and even those can be in many cases checked without side effects). It doesn't need to know what parameters the flight stack uses to map button presses or what functions are called.
  • The flight stack doesn't have to have special code paths to process instructions it is already processing through mavlink.
  • The manual control message doesn't have to cope with the possiblity of joysticks with more buttons than we expose.

That's all true, and we did note the first two when we discussed.

In this case one of our partners wanted to have fence enable/disable on a button. MissionPlanner didn't permit binding that to a button, and would need patching and updating to support the functionality. Having the function instantly available was what I was after - as soon as it was available in ArduPilot it could be configured.

I would like MissionPlanner to use our DO_AUX_FUNC list (I was mistaken in my initial assesment there; it has specialised code for each function it offers). Addition of an arbitrary-number-combo-box interface into the relevant configuration page might fix things.

Problem with that last is that now every GCS has to have this interface. The list of valid functions will be different autopilot-to-autopilot.... and while ArduPilot has a convenient list of functions that can be activated by MAVLink (I might actually generate a aux_func.xml at some stage), other autopilots may not...

There are advantages both ways for storing the configuration in the GCS and on the vehicle; one allows you to switch laptops and know the config will be the same. The other allows the interface to change between laptops based on input devices....

peterbarker avatar Nov 30 '22 07:11 peterbarker

@peterbarker There was an orthogonal discussion here https://github.com/mavlink/mavlink/pull/1848 which looks at the use case of a MAVLink joystick. This is a joystick that does not need to be connected to a GCS when used.

The idea was that a joystick would have a component metadata mechanism to configure its buttons a lot like the mavlink camera API - i.e. you'd query the joystick for its axes and buttons and get metadata back on what is supported. The buttons would have set options that map to parameter values - i.e. button 1 might have param_button_1 on the joystick with options "enable fence", "kill switch". So you connect to a GCS once, use the config API to select the things you want on each button based on the options it supplies. The joystick then sends its messages direct to the autopilot node on the network (or other component ID) and when a button is pressed sends the appropriate MAVLink command.

My point is that the sending mavlink command mechanism is more flexible here too. Component information helps with the problem of knowing what the joystick can do, and means that the autopilot doesn't need to have any extra config to work.

It's just an idea at this time.

hamishwillee avatar Nov 30 '22 23:11 hamishwillee

Anyway, appreciate that you're probably making a pragmatic decision based on what mission planner does now (and PX4). Nothing is going to change in any sort of short timeframe so you can do what you like. But if you go with sending mavlink commands that will work whatever is done in future with the MANUAL_CONTROL message.

hamishwillee avatar Nov 30 '22 23:11 hamishwillee

Discussed this in the 20250410 dev call. This was explained to me as follows (capturing so I don't have to ask this all again!)

  1. MANUAL CONTROL is defined as a mapping of x, y, z, axes (FRD) with a statement that these generally map to pitch, roll, thrust.
  2. The intent of the design was that these actually map to an acceleration in each of the axis. The x, y, z are mapped as intended (to pitch, roll, thrust) on a multicopter vehicle.
  3. However this mapping is not observed for other vehicle types - the z axis is always mapped to thrust, which on a fixed wing vehicle would be forwards. So there is an inconsistency across vehicles.
  4. PX4 and ArduPilot both do this "wrong thing". PX4 maps directly to the thrust setpoint, and ArduPilot maps this through an RC_CHANNEL_OVERRIDE (Used by ArduSub).
  5. This "works" because QGC is the only thing that sends this, so it is consistent.

Upshot I am not sure how to change the messages but if we change anything we break everything.

I'm not sure how we'd fix this - presumably a similar message where the definitions are as intended by MANUAL_CONTROL and that is then implemented "properly".

@julianoes Is that about right? Feel free to edit this if I misunderstood!

hamishwillee avatar Apr 09 '25 23:04 hamishwillee

(FRD) with a statement that these generally map to pitch, roll, thrust.

That's debatable. The naming would indicate this but the way it is described and implemented does not.

Upshot I am not sure how to change the messages but if we change anything we break everything.

They way how I read this is that @junwoo091400 does not actually want to change/break anything but merely document how it is actually used and implemented in QGC.

julianoes avatar Apr 10 '25 02:04 julianoes

Ping @Williangalvani

peterbarker avatar Apr 16 '25 02:04 peterbarker

So here's the summary of the whole landscape on MANUAL_CONTROL:

QGC

  • Sends: [0, 1000] or [-1000, 1000] (PX4: Rover + Submarine, Ardupilot: Rover) depending on vehicle type
  • Receives: [x] (Only shows it in MAVLink Inspector)

PX4

Ardupilot

Thus, it seems fairly customized per vehicle type, and the unification of the definition won't be trivial (expected range already differs per vehicle in Firmwares), and will lead breaking changes (e.g. [-1000, 1000] range will be rejected for Arducopter, PX4, etc)

So I think there isn't really a solution here, and the best we could do is just to clarify this difference of MANUAL_CONTROL.z per vehile type in the MAVLink message definition, and support this legacy implementation.

Thoughts?

p.s. It's interesting that QGC originally allowed users to choose whether RC transmitter's throttle channel is spring loaded or not, but now that logic isn's used AFAIK (assumes not spring loaded): https://github.com/mavlink/qgroundcontrol/pull/1827

Also, the Rover / Submarine control for PX4 through QGC is broken exactly due to this mismatch. So only the 'positive thrust' worked before, due to the (debatable) wrong implementation on Firmware side (not considering neative MANUAL_CONTROL.z range when Rover/Submarine)

junwoo091400 avatar Apr 21 '25 06:04 junwoo091400

I stand with @junwoo091400's latest suggestion.

Many times I thought about ways of remapping (for the sole purpose of following the spec) ArduSub to [-1000,1000], but I never got to a solution that wouldn't brake things. Given that most vehicle are using the [0,1000] range, I vote we just document it properly.

Williangalvani avatar Apr 22 '25 13:04 Williangalvani

Thanks @junwoo091400 for the implementation overview!

Thus, it seems fairly customized per vehicle type, and the unification of the definition won't be trivial

I reached the same conclusion. Usage varies due to the ambiguous definition.

Initially, I aimed for a consistent across vehicle types and with the other axes [-1000, 1000] full range in PX4, but transitioning cleanly proved infeasible. PX4 now enforces a [0, 1000] range and clamps negative values in that field (not rejecting the entire message), aligning with what QGC mostly sends and others mimic.

the best we could do is just to clarify this difference of MANUAL_CONTROL.z per vehile type in the MAVLink message definition, and support this legacy implementation

I agree and like your very specific description of how the field is used but would leave away the last part However originally, it generally corresponds to throttle high (1000) - throttle low (-1000) on a joystick. Centered throttle should result in value of 0 (center). because it generates confusion around the original user of the field who we cannot name. There's still the original superset range of the field at the beginning and people reading this at least know that most use cases have for historical interpretation reasons (https://github.com/mavlink/mavlink/commit/1567c0a9975aad4cd39b9d6615ad26c772007662) a different range.

Long-term, I plan to introduce a new message that clearly defines remote input axes without ambiguous ranges or assumptions about their use of different vehicle types and modes on the receiving end.

MaEtUgR avatar Apr 23 '25 12:04 MaEtUgR

Without having read everything, so how do you go backwards, or actively down?

julianoes avatar Apr 29 '25 00:04 julianoes