Skip to content

Multi GCS update#14560

Open
Davidsastresas wants to merge 17 commits into
masterfrom
pr-multi-gcs-June2026
Open

Multi GCS update#14560
Davidsastresas wants to merge 17 commits into
masterfrom
pr-multi-gcs-June2026

Conversation

@Davidsastresas

@Davidsastresas Davidsastresas commented Jun 18, 2026

Copy link
Copy Markdown
Member

What this does

Brings QGC's GCS operator-control support up to the final MAV_CMD_REQUEST_OPERATOR_CONTROL / CONTROL_STATUS protocol (mavlink/mavlink#2313), succeeding the earlier work in #12410.

Long story short - Now multiple GCS can share a vehicle with one primary holding exclusive manual control; others are recognized secondaries and can send commands, missions, etc but not manual control. Adds the operator-control panel, request/release flow, takeover handshake, and a configurable secondary-GCS range.

Tested against peterbarker/ardupilot#46 in multi-GCS SITL (4× QGC + MAVProxy for routing).

Changes

Protocol / Vehicle

  • Send the requester's actual GCS sysid in param4, with an optional param4/5 range from the configured secondaries (GCS Operator control updates mavlink#2313 changed param4 from earlier implementation).
  • Parse full CONTROL_STATUS (gcs_main + gcs_secondary[10]) and expose the secondary list.
  • Gate MANUAL_CONTROL / RC override so joystick is sent only when this GCS is in control (or the vehicle is uncontrolled).
  • ACK the forwarded takeover notification (COMMAND_ACK/ACCEPTED) so the handshake completes.
  • Address the command to the system-manager component learned from CONTROL_STATUS, not assumed to be the autopilot.

UI (GCSControlIndicator)

  • Role-aware toolbar indicator: stacked aircraft / link / role glyph (solid device = primary, outlined = secondary, open/closed lock = no role) with a MAIN/SEC label; green is reserved for the control relationship.
  • Operator-control panel as a status roster (Control status, Main GCS, Secondary GCS with this GCS marked, Takeover), with request / take / change / release actions and editable settings behind a "More options" expander and a "control group" toggle.
  • "Take full control" when granted immediately (uncontrolled or takeover allowed, no countdown) vs "Request full control" otherwise.
  • Request countdown lifecycle fixed (stops on grant / release / uncontrolled; no stale restart on reopen).
  • A recognized secondary shows its role even when the vehicle is uncontrolled (gcs_main == 0).
  • Configurable secondary-GCS range, with a warning when the contiguous range would also accept unconfigured ids.

Settings

  • New persisted operatorControlSecondaryGCS (secondary sysids, comma- or space-separated).

Some screenshots, Artwork and UI by @alexdelatorre

Top toolbar Icon, depending on status:

Screenshot from 2026-06-18 20-32-57 Screenshot from 2026-06-18 20-33-18

reduced popup, after single click, depending on status:

Screenshot from 2026-06-18 20-36-12 Screenshot from 2026-06-18 20-35-58

Command request from a GCS to the main GCS:

Screenshot from 2026-06-18 20-37-40

expanded panel with aditional options:

Screenshot from 2026-06-18 20-38-10 Screenshot from 2026-06-18 20-38-17

Secondary GCS input, detail of warning for user awareness:

Screenshot from 2026-06-18 20-38-27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates QGroundControl’s multi-GCS operator-control support to align with the finalized MAV_CMD_REQUEST_OPERATOR_CONTROL / CONTROL_STATUS protocol by moving control-status handling into a dedicated manager, gating manual-control outputs, and expanding the toolbar UI and settings needed for multi-operator workflows.

Changes:

  • Introduces GCSControlManager to own CONTROL_STATUS parsing, operator-control request/release flow, and role state exposed to QML.
  • Gates joystick/RC override output in Vehicle based on operator-control ownership.
  • Refreshes the toolbar indicator/panel UI, adds a persisted “secondary GCS IDs” setting, and updates bundled indicator artwork and MAVLink dependency pin.

Reviewed changes

Copilot reviewed 11 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Vehicle/Vehicle.h Exposes gcsControlManager to QML and adds an atomic gate setter for joystick output.
src/Vehicle/Vehicle.cc Instantiates/routs control messages to GCSControlManager and gates joystick send paths.
src/Vehicle/GCSControlManager.h New QObject/QML-facing manager API and properties for operator-control state and actions.
src/Vehicle/GCSControlManager.cc Implements CONTROL_STATUS parsing, operator-control request/release, and takeover ACK handshake.
src/Vehicle/CMakeLists.txt Adds new manager sources to the build.
src/Toolbar/GCSControlIndicator.qml Reworks indicator UI for MAIN/SEC role display, roster, actions, and expanded settings UI.
src/Toolbar/CMakeLists.txt Updates toolbar resource list to the new multi-GCS indicator SVGs.
src/Settings/FlyViewSettings.h Adds operatorControlSecondaryGCS SettingFact.
src/Settings/FlyViewSettings.cc Registers operatorControlSecondaryGCS SettingFact.
src/Settings/FlyView.SettingsGroup.json Defines persisted operatorControlSecondaryGCS string setting metadata.
resources/gcscontrolIndicator/multigcs_lock_open.svg New lock-open role glyph artwork.
resources/gcscontrolIndicator/multigcs_lock_closed.svg New lock-closed role glyph artwork.
resources/gcscontrolIndicator/multigcs_line.svg New “control relationship” line artwork.
resources/gcscontrolIndicator/multigcs_device.svg New primary-role device glyph artwork.
resources/gcscontrolIndicator/multigcs_device_alt.svg New secondary-role outlined device glyph artwork.
resources/gcscontrolIndicator/multigcs_aircraft.svg New aircraft glyph artwork.
cmake/CustomOptions.cmake Updates the pinned MAVLink git tag to a commit containing the finalized protocol.

Comment thread src/Vehicle/Vehicle.cc Outdated
Comment thread src/Vehicle/GCSControlManager.cc Outdated
@Davidsastresas Davidsastresas removed the request for review from HTRamsey June 18, 2026 18:54
Davidsastresas and others added 16 commits June 18, 2026 21:04
- Send the actual GCS sysid in param4 of MAV_CMD_REQUEST_OPERATOR_CONTROL
  (spec changed from #2158 to #2313; autopilot rejects param4=0), with
  optional param4/param5 range computed from configured secondary GCS ids
- Gate MANUAL_CONTROL and RC override sends on operator control: block
  joystick output while another GCS is in control
- Parse full CONTROL_STATUS (gcs_main + gcs_secondary[10]) and expose
  secondary GCS list to QML
- Add release control support and secondary GCS range configuration UI
  to GCSControlIndicator
- New persisted setting operatorControlSecondaryGCS (comma-separated
  secondary GCS sysids)
The request countdown could keep running (or restart from a stale
value) after the request was already resolved:

- The stop check in _handleControlStatus() missed the uncontrolled
  case: when the owning GCS releases control, CONTROL_STATUS arrives
  with gcs_main=0 and takeover not allowed, so neither stop condition
  matched. Add _sysid_in_control == 0 to the check.
- The QML progress tracker only stopped on the takeover-allowed
  transition. Add watchers so it also stops when this GCS gains
  control or when the C++ side re-allows sending requests.
- requestOperatorControlRemainingMsecs was declared CONSTANT but wraps
  QTimer::remainingTime(), so reopening the popup restored the
  countdown from a stale cached value. Tie it to
  sendControlRequestAllowedChanged instead.
- releaseOperatorControl() left the request and takeover-revert timers
  running, firing stale signals after release. Stop them first.
- A pending takeover revert also kept running when control moved to
  another GCS. Stop it on control loss in _handleControlStatus().
When takeover is not allowed, the autopilot forwards
MAV_CMD_REQUEST_OPERATOR_CONTROL to the GCS in control as a
notification. QGC showed the popup but never sent COMMAND_ACK, leaving
the autopilot notification pending and the command unacknowledged at
the MAVLink level. Reply with MAV_RESULT_ACCEPTED to the sender.
…onent

The spec says a GCS should monitor for CONTROL_STATUS with the
GCS_CONTROL_STATUS_FLAGS_SYSTEM_MANAGER flag and address
MAV_CMD_REQUEST_OPERATOR_CONTROL to that component, which is not
necessarily the autopilot. Learn the component id from CONTROL_STATUS
and use it as the command target, falling back to the default
component id until the first CONTROL_STATUS is seen.
_joystickSendAllowed was read and written with memory_order_relaxed.
On weakly ordered architectures the store could in principle be
observed by the joystick thread after other effects of the
CONTROL_STATUS handling. Use release on the store and acquire on the
loads so the gate change is properly ordered with the control status
update that caused it.
The operator control request encodes secondary GCS as a contiguous
sysid range, so non-contiguous configured ids (e.g. 200, 254) silently
grant control to every id in between. Show a warning in the range
configuration panel with the number of unconfigured ids the computed
range would accept.
Replace the line/device/gcs icon set with a state-driven composition
using new artwork (aircraft, line, solid/outlined device, open/closed
lock):

- aircraft (top-left): green when any GCS controls the vehicle
- line (bottom-left): green only when this GCS has an operator role
  (its own control link)
- role glyph (right), always white: solid device = primary,
  outlined device = secondary, lock when this GCS has no role -
  open when control is acquirable now (uncontrolled or takeover
  allowed), closed when a request is required
- PRIM/SEC label shown in green when this GCS is primary/secondary

The lock open/closed condition reuses controlGrantedImmediately, so it
always agrees with the request button (Take Control / Acquire / Send
Request).

> Co-authored-by: alexdelatorre <alex.delatorre@lincesystems.com>
Replace the flat label list with a labelled status roster (Control
status / Main GCS / Secondary GCS / Takeover), mark this GCS in each
row, and move editable settings behind a More options expander with
a control group toggle. Recognize a secondary's role even when the
vehicle is uncontrolled (gcs_main == 0).
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@Davidsastresas Davidsastresas force-pushed the pr-multi-gcs-June2026 branch from 817d6ee to 47d0f04 Compare June 18, 2026 19:30
@Davidsastresas

Davidsastresas commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

Pending items after discussions in ArduPilot/ardupilot#33332 and ArduPilot/mavlink#503

  • Mechanism to detect Joysticks ( or virtual Joysticks ) moving more than a threshold to automatically take control. Expose as an independent setting, to enable/disable this behaviour on demand.
  • After accept (operator already allowed takeover): A retry replaces the "takeover reverts in Xs" countdown popup with the request popup again. The _timerRevertAllowTakeover is still running in the background so takeover remains allowed and the requesting GCS can still take control — it's not broken, just a minor UX quirk (operator sees the request again even though they already said yes). Could suppress the popup if takeover is already allowed, but that's a nice-to-have. More info in development.xml: copy MAV_COMMAND_REQUEST_OPERATOR_CONTROL from mavlink/mavlink/master ArduPilot/mavlink#503 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants