MAVLink Proxy
The MAVLink proxy is the agent’s core service, a native Rust router (ados-mavlink-router). It connects to the flight controller over serial UART, parses MAVLink frames, and distributes them to every other part of the system: the GCS over WebSocket, other services via the IPC socket, the cloud relay, and the terminal status page.
The proxy runs as the ados-mavlink systemd service.
Flight controller auto-detection
Whenmavlink.serial_port is empty in config (the default), the proxy scans serial ports in this order:
- Ports listed in the board profile’s
uart_paths(e.g.,/dev/ttyS0,/dev/ttyAMA0) - USB serial devices at
/dev/ttyACM*and/dev/ttyUSB*
Serial connection
What baud your drone is actually running
mavlink.baud_rate is only honoured when mavlink.serial_port names a port. With the port left empty, the configured baud is not used at all and the proxy sweeps this list in order:
mavlink.baud_rate on its own changes nothing, so pin mavlink.serial_port alongside it if you want a specific rate. And a fresh install behaves differently depending on what was plugged in at the time: the installer writes the detected port into the config when an FC is attached, which pins the link and skips the sweep, while a unit installed with no FC attached ships with an empty port and probes on every connect.
Read back what the link actually settled on with ados status, rather than reading it off the config file.
Multi-client distribution
The proxy is a one-to-many bridge. A single serial connection feeds multiple consumers:IPC sockets
Two Unix domain sockets carry data between services:/run/ados/mavlink.sock (binary): raw MAVLink frames with a 4-byte big-endian length prefix before each frame. Any service or script can connect and receive the full MAVLink stream.
/run/ados/state.sock (JSON): a parsed telemetry summary published at 10 Hz. Contains attitude, position, speed, battery, GPS, and armed state as JSON. Used by the health service, cloud relay, and TUI.
WebSocket endpoint
The proxy exposes a WebSocket endpoint at port 8765 (configurable viamavlink.endpoints). This is the primary way ADOS Mission Control and other browser-based GCS tools connect to the drone.
The credential for that endpoint is a short-lived HMAC ticket. A client asks the agent for one with POST /api/_ws/ticket, which is itself gated by the pairing key, and presents it on connect as a WebSocket subprotocol:
X-ADOS-Key header instead.
The WebSocket carries raw binary MAVLink frames, wire-compatible with the SITL bridge tool. No encoding changes, no JSON wrapping. The GCS decodes MAVLink in the browser using the same CRC and payload tables as pymavlink.
Companion heartbeat
The proxy sends a 1 Hz companion heartbeat to the flight controller withMAV_TYPE_ONBOARD_CONTROLLER. This prevents ArduPilot’s GCS failsafe from triggering when the companion computer is the only MAVLink endpoint.
Without this heartbeat, ArduPilot assumes the GCS has disconnected after 5 seconds and can trigger RTL or land depending on failsafe settings.
Stream requests
On connection, the proxy requests data streams from the FC:SYS_STATUS(battery, health)ATTITUDE(roll, pitch, yaw)GLOBAL_POSITION_INT(GPS lat/lon/alt)GPS_RAW_INT(fix type, satellites, HDOP)VFR_HUD(airspeed, groundspeed, heading)RC_CHANNELS(RC input values)HEARTBEAT(armed state, flight mode)
Reconnection
If the serial connection drops (FC power cycle, USB disconnect, cable fault), the proxy:- Closes the old connection cleanly (prevents file descriptor leaks)
- Waits 2 seconds
- Restarts auto-detection from the beginning
- Re-requests all data streams once reconnected
MAVLink signing
The agent is a transparent pipe for signed frames. The 32-byte signing key lives in the GCS browser as a non-extractable Web Crypto key. The agent exposes/api/mavlink/signing/capability, /api/mavlink/signing/enroll-fc, and a few related endpoints so the GCS can push the key to the flight controller once via SETUP_SIGNING. The agent never persists the key.
See MAVLink Signing for the full guide, enable steps, and troubleshooting.
The agent config file does not carry a signing key. Any legacy
mavlink.signing block in an old config is ignored with a deprecation warning on agent start.State IPC format
The JSON telemetry on/run/ados/state.sock looks like this (published at 10 Hz):