Skip to main content
The agent already speaks MAVLink to the flight controller and routes it to the GCS. An agent plugin extends that through these facades:
  • ctx.mavlink: subscribe to messages, send frames, register a MAVLink component.
  • ctx.vision: register as the visual-odometry source and inject pose.
  • ctx.msp: the raw MSP byte plane to Betaflight, iNav and KISS flight controllers.
  • ctx.flight: scoped guided-mode and attitude/rate setpoint senders.
mavlink.write, msp.write, flight.guided_setpoint and flight.rate_setpoint can move the aircraft. Bench-test with props off and read Safety before flying a plugin that uses them.

Capabilities

Risk levels and the install-dialog badges for each are on Permissions.

Subscribing to messages

ctx.mavlink.subscribe registers a callback for one message name. The callback receives the message name, the raw frame bytes and a timestamp. Decode the frame with your own MAVLink library:
The host reads each inbound frame once and fans it out to every subscriber; no per-plugin parser runs on the link.

Sending frames

ctx.mavlink.send writes an encoded frame to the flight controller. Pass component_id to send under a component the plugin has registered:

Registering as a component

A plugin that should appear on the MAVLink bus as a camera, gimbal, payload, peripheral or visual-odometry source registers a component id. Declare it in the manifest so the host reserves the id, and hold the matching mavlink.component.<kind> capability:
The kinds are camera, gimbal, payload, peripheral, vio and generic. The first five map to mavlink.component.<kind>. The SIYI pod extension registers camera 100 and gimbal 154; the Follow-Me and MAVLink Gimbal v2 extensions declare component 191 as generic.

Visual odometry

A visual-odometry plugin registers the vio component once, then sends pose estimates. The helpers are on ctx.vision and need the mavlink.component.vio grant:
inject_odometry(odometry) sends an ODOMETRY message (pose plus body-frame twist) under the same component. A bad pose stream feeds the flight controller’s estimator and can produce unsafe position control.

Re-publishing decoded data

A common pattern decodes one message and re-publishes a clean event, so raw MAVLink stays in one plugin. Publish on your own namespace for your own use, and declare a shared topic for other plugins:
Another plugin with event.subscribe and mavlink.read then subscribes to plugin.rangefinder.reading without touching MAVLink. Your plugin.com.example.rangefinder.* topics stay private to your plugin. See Agent event bus.

MSP flight controllers

For Betaflight, iNav and KISS flight controllers, ctx.msp moves raw MSP bytes. The host moves bytes only; build and parse frames with ados.plugins.msp. send needs msp.write and subscribe needs msp.read. MSP has no per-message topic, so the callback receives every chunk the flight controller sends:

Guided setpoints

A flight-behavior plugin commands the vehicle in guided mode through ctx.flight instead of raw MAVLink writes, so one capability gates the flight-command surface. guided_setpoint needs flight.guided_setpoint; the host encodes the matching SET_POSITION_TARGET_* message:
kind picks the frame family, coordinate_frame is a MAV_FRAME_* value and type_mask is the ignore-axis bitmask. Unset axes default to zero. The call returns {"ok": bool, ...}, or a not_available shape when the MAVLink router is unreachable. rate_setpoint sends SET_ATTITUDE_TARGET (attitude quaternion and/or body rates plus normalized thrust) and needs flight.rate_setpoint. A GCS half does not send MAVLink. It calls ctx.command.send with one of the host’s named commands (takeoff, land, rtl), gated on command.send; the operator approves each command in a dialog before it reaches the vehicle.

Next steps

Vision plugins

Frames, inference and detections on the vision engine.

Agent event bus

Publish and subscribe rules and shared topics.

Permissions

Every capability and its risk level.

Safety

Pre-flight checks before flying a plugin that commands the aircraft.
Last modified on October 11, 2026