feat: add Cockpit Actions for changing the mode of MAVLink vehicles#2313
Conversation
There was a problem hiding this comment.
I haven't tested yet, but would it perhaps make more sense to define and register the actions in the ArduRover file? As I understand it there isn't standardisation of modes within MAVLink (it's all firmware and vehicle-type specific), and it seems problematic that the main vehicle needs to know about all the different options...
Would also be good if the default profiles could be defined in the vehicle-type files, but that can be left for later if need be (when fully addressing #2063).
|
@ES-Alexander see what you think about the new structure. If agreed I will rebase the last commit. |
0872bd6 to
fc31107
Compare
| // Rover/Boat mode actions (MAVLink) | ||
| mavlink_rover_mode_acro = 'mavlink_rover_mode_acro', | ||
| mavlink_rover_mode_auto = 'mavlink_rover_mode_auto', | ||
| mavlink_rover_mode_circle = 'mavlink_rover_mode_circle', | ||
| mavlink_rover_mode_dock = 'mavlink_rover_mode_dock', | ||
| mavlink_rover_mode_follow = 'mavlink_rover_mode_follow', | ||
| mavlink_rover_mode_guided = 'mavlink_rover_mode_guided', | ||
| mavlink_rover_mode_hold = 'mavlink_rover_mode_hold', | ||
| mavlink_rover_mode_loiter = 'mavlink_rover_mode_loiter', | ||
| mavlink_rover_mode_manual = 'mavlink_rover_mode_manual', | ||
| mavlink_rover_mode_rtl = 'mavlink_rover_mode_rtl', | ||
| mavlink_rover_mode_simple = 'mavlink_rover_mode_simple', | ||
| mavlink_rover_mode_steering = 'mavlink_rover_mode_steering', | ||
| mavlink_rover_mode_smart_rtl = 'mavlink_rover_mode_smart_rtl', |
There was a problem hiding this comment.
Should these not be defined in the ardurover.ts file?
Rover Actions shouldn't be presented as available for other vehicle types.
There was a problem hiding this comment.
This would disallow someone from configuring a joystick layout for a Rover if a Rover is not connected. Not sure if we want to do that. We can think of a better mechanism, or a way to make it more explicit that this only works for Rovers. It's already on the name, but maybe we can do more?
There was a problem hiding this comment.
It now shows only those mode changes for vehicle types tied to the joystick profile being edited.
| // Rover/Boat mode actions (MAVLink) | ||
| [CockpitActionsFunction.mavlink_rover_mode_acro]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_acro, 'MAVLink: Rover Acro'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_auto]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_auto, 'MAVLink: Rover Auto'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_circle]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_circle, 'MAVLink: Rover Circle'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_dock]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_dock, 'MAVLink: Rover Dock'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_follow]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_follow, 'MAVLink: Rover Follow'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_guided]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_guided, 'MAVLink: Rover Guided'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_hold]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_hold, 'MAVLink: Rover Hold'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_loiter]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_loiter, 'MAVLink: Rover Loiter'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_manual]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_manual, 'MAVLink: Rover Manual'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_rtl]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_rtl, 'MAVLink: Rover RTL'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_simple]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_simple, 'MAVLink: Rover Simple'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_steering]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_steering, 'MAVLink: Rover Steering'), | ||
| [CockpitActionsFunction.mavlink_rover_mode_smart_rtl]: new CockpitAction(CockpitActionsFunction.mavlink_rover_mode_smart_rtl, 'MAVLink: Rover Smart RTL'), |
There was a problem hiding this comment.
Same for these.
It also seems like these could be defined in a loop, rather than laying them all out manually and repeating each of the names?
Also, if we're not going to provide more detailed descriptions of what those modes are, I think the current descriptions could just be determined automatically from the function name by whatever is after the "mode" part? If the idea is those descriptions will be presented to users when choosing Actions then I can try to write some relevant descriptions if you want.
There was a problem hiding this comment.
All automatically defined now.
|
@ES-Alexander please take a look at the last commit. It's the necessary to accomplish the loop-based entries. I'm honestly not a huge fan and I believe it creates an unnecessary code reading overhead and I would prefer to remove it. It also keeps basically the same number of lines changed. |
There was a problem hiding this comment.
I feel like this is moving in the right direction, but not really capturing the intent, so it then misses the main value (which I suspect is why you're not liking it).
The idea is to make it so supporting a new mode (or removing an existing one) requires only updating where modes are defined (e.g. a value in a list), rather than also needing to update everywhere that those modes are used.
If each vehicle type defines its own modes, and then the cockpit-actions file imports just the modes list that's relevant for the vehicle type of the selected profile and auto-generates the relevant mode-related Actions, then the vehicle types don't need to worry about defining Actions, and the Actions code doesn't need to worry about filtering out Actions that don't make sense to the user.
| { action: availableCockpitActions.mavlink_rover_mode_acro, mode: CustomMode.ACRO }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_auto, mode: CustomMode.AUTO }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_circle, mode: CustomMode.CIRCLE }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_dock, mode: CustomMode.DOCK }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_follow, mode: CustomMode.FOLLOW }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_guided, mode: CustomMode.GUIDED }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_hold, mode: CustomMode.HOLD }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_loiter, mode: CustomMode.LOITER }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_manual, mode: CustomMode.MANUAL }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_rtl, mode: CustomMode.RTL }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_simple, mode: CustomMode.SIMPLE }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_steering, mode: CustomMode.STEERING }, | ||
| { action: availableCockpitActions.mavlink_rover_mode_smart_rtl, mode: CustomMode.SMART_RTL }, |
There was a problem hiding this comment.
This could also be loop-based, using the base roverModes variable.
There was a problem hiding this comment.
They are all being automatically generated from the original mode definition now.
| /** | ||
| * Rover/Boat mode names - single source of truth for generating enum entries and actions | ||
| */ | ||
| const roverModes = ['acro', 'auto', 'circle', 'dock', 'follow', 'guided', 'hold', 'loiter', 'manual', 'rtl', 'simple', 'steering', 'smart_rtl'] as const | ||
| type RoverMode = typeof roverModes[number] | ||
| type RoverModeKey = `mavlink_rover_mode_${RoverMode}` | ||
|
|
||
| // Generate rover mode enum entries | ||
| const roverModeEntries = Object.fromEntries( | ||
| roverModes.map((mode) => [`mavlink_rover_mode_${mode}`, `mavlink_rover_mode_${mode}`]) | ||
| ) as { [K in RoverModeKey]: K } | ||
|
|
There was a problem hiding this comment.
I think this is in a good direction, but too specific to Rover. If every vehicle type needs to support its own set of modes then we should have a generic functionality defined here, and import just the mode names from the Profile's vehicle type (which then determines which Actions should be created).
One vehicle type should not have access to another vehicle type's Actions at all - they pollute the namespace and might cause confusion during assignment/configuration.
There was a problem hiding this comment.
Mode definitions are not duplicated anymore and the solution was made generic to all vehicle types.
|
Blocker: non-Rover vehicles get new Actions they can't/shouldn't use. The other comments are non-essential, and can be raised in an Issue and fixed later if necessary. |
292dbaf to
2f72d01
Compare
2f72d01 to
be28aa6
Compare
I ended up refactoring the PR to generically create Cockpit Actions for mode change of all modes in all ArduPilot vehicles, as was originally suggested. They are being generated automatically from the original mode definitions, so no duplications. The only mode-change-actions that are now shown are those available for the vehicle type tied to the joystick profile being edited, as discussed. |
ES-Alexander
left a comment
There was a problem hiding this comment.
Great work!
I'm sure this will prove useful for joystick support of non-Sub vehicles, and there are likely a bunch of existing BlueBoat users who would be keen to try it out! 😀
Some very minor suggestions. Main relevant one is the UX one about the order of the button function name fields for the visual joystick configuration window, but nothing blocking :-)
src/libs/vehicle/ardupilot/common.ts
Outdated
| .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) | ||
| .join(' ') | ||
| const vehicleDisplayName = vehicleType.charAt(0).toUpperCase() + vehicleType.slice(1) | ||
| return new CockpitAction(actionId, `ArduPilot ${vehicleDisplayName} Mode: ${displayName}`) |
There was a problem hiding this comment.
| return new CockpitAction(actionId, `ArduPilot ${vehicleDisplayName} Mode: ${displayName}`) | |
| return new CockpitAction(actionId, `${displayName} Mode (ArduPilot ${vehicleDisplayName})`) |
The joystick visual editor clips long names, so it probably makes sense to start with the key differentiable information to avoid all mode buttons looking the same.
This way others can consume from it without having to initialize code contained in the vehicle files.
… selected profile
be28aa6 to
5f82824
Compare
|
@ES-Alexander I've implemented all the suggestions from the last review as well. Thank you! |
Summary
This update introduces Cockpit Actions for changing the vehicle mode in MAVLink Rover vehicles, addressing a critical requirement for joystick operation. This enhancement allows users to map various boat control modes to joystick buttons, enabling seamless mode transitions during operation. The lack of those actions was reported by Tony (internal user) as a deal-breaker in BlueBoat operations.
Changes
joystick-profiles.tsto include new default button correspondences for mode changes in the Boat profile (Loiter, Manual, Auto, and Acro). Layout suggested by Tony.ardurover.tswith a new custom mode: Circle.Closes #2312