Skip to content

Comments

feat: add Cockpit Actions for changing the mode of MAVLink vehicles#2313

Merged
rafaellehmkuhl merged 6 commits intobluerobotics:masterfrom
rafaellehmkuhl:issue-2312-add-boat-actions
Jan 27, 2026
Merged

feat: add Cockpit Actions for changing the mode of MAVLink vehicles#2313
rafaellehmkuhl merged 6 commits intobluerobotics:masterfrom
rafaellehmkuhl:issue-2312-add-boat-actions

Conversation

@rafaellehmkuhl
Copy link
Member

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

  • Introduced MAVLink rover/boat mode-changing actions.
  • Updated joystick-profiles.ts to include new default button correspondences for mode changes in the Boat profile (Loiter, Manual, Auto, and Acro). Layout suggested by Tony.
  • Expanded ardurover.ts with a new custom mode: Circle.

Closes #2312

Copy link
Contributor

@ES-Alexander ES-Alexander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

@rafaellehmkuhl
Copy link
Member Author

@ES-Alexander see what you think about the new structure. If agreed I will rebase the last commit.

@rafaellehmkuhl rafaellehmkuhl force-pushed the issue-2312-add-boat-actions branch 6 times, most recently from 0872bd6 to fc31107 Compare January 7, 2026 20:35
Comment on lines 22 to 35
// 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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these not be defined in the ardurover.ts file?
Rover Actions shouldn't be presented as available for other vehicle types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It now shows only those mode changes for vehicle types tied to the joystick profile being edited.

Comment on lines 67 to 80
// 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'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All automatically defined now.

@rafaellehmkuhl
Copy link
Member Author

@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.

Copy link
Contributor

@ES-Alexander ES-Alexander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 76 to 88
{ 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 },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be loop-based, using the base roverModes variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are all being automatically generated from the original mode definition now.

Comment on lines 6 to 17
/**
* 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 }

Copy link
Contributor

@ES-Alexander ES-Alexander Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mode definitions are not duplicated anymore and the solution was made generic to all vehicle types.

@ES-Alexander ES-Alexander added the fast-track Solves an important user complaint - only block for major concerns label Jan 21, 2026
@ES-Alexander
Copy link
Contributor

ES-Alexander commented Jan 21, 2026

Blocker: non-Rover vehicles get new Actions they can't/shouldn't use.
They should ideally never be created, but if necessary could be filtered out.

The other comments are non-essential, and can be raised in an Issue and fixed later if necessary.

@rafaellehmkuhl rafaellehmkuhl force-pushed the issue-2312-add-boat-actions branch from 292dbaf to 2f72d01 Compare January 22, 2026 20:48
@rafaellehmkuhl
Copy link
Member Author

rafaellehmkuhl commented Jan 22, 2026

Blocker: non-Rover vehicles get new Actions they can't/shouldn't use. They should ideally never be created, but if necessary could be filtered out.

The other comments are non-essential, and can be raised in an Issue and fixed later if necessary.

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.

Copy link
Contributor

@ES-Alexander ES-Alexander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :-)

.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}`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

@rafaellehmkuhl rafaellehmkuhl force-pushed the issue-2312-add-boat-actions branch from be28aa6 to 5f82824 Compare January 27, 2026 18:51
@rafaellehmkuhl
Copy link
Member Author

@ES-Alexander I've implemented all the suggestions from the last review as well. Thank you!

@rafaellehmkuhl rafaellehmkuhl merged commit 83ed5e2 into bluerobotics:master Jan 27, 2026
11 checks passed
@rafaellehmkuhl rafaellehmkuhl deleted the issue-2312-add-boat-actions branch January 27, 2026 19:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fast-track Solves an important user complaint - only block for major concerns

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BlueBoat: Missing joystick actions for vehicle mode changes

2 participants