Skip to main content
The agent already speaks MAVLink to the flight controller and routes it to the GCS. A plugin extends that in three ways through the ctx.mavlink facade: subscribe to messages, send frames, and register itself as a MAVLink component.

Capabilities

mavlink.tunnel, vehicle.command, and estimator.pose.inject are all high-risk permissions, alongside mavlink.write. The vio component kind is high-risk too, since a visual-odometry source feeds the EKF. mavlink.write is a high-risk permission. Operators see a warning badge in the install dialog, because a plugin that can write raw MAVLink can arm motors, change modes, and alter parameters in flight.

Subscribing to messages

ctx.mavlink.subscribe registers a callback for a message name. The callback fires for each matching frame and receives the message name, the raw MAVLink frame bytes, and a timestamp. Decode the frame with your own MAVLink library:
Subscriptions are coalesced by the host: ten plugins subscribed to BATTERY_STATUS cause one underlying stream from the flight controller. Inbound frames are read once and fanned out to subscribers; there is no per-plugin parser running on the link.

Sending frames

ctx.mavlink.send writes a MAVLink frame to the flight controller. Build the frame with a MAVLink encoder, then send the bytes. An optional component_id tags the sender when the plugin owns a registered component:
The host serializes outbound writes per flight-controller link. Two plugins sending at the same time queue on one single-producer queue; neither blocks the other for more than a few milliseconds.

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. The capability is mavlink.component.<kind>:
Declare the component in the manifest so the host knows to claim the id:
The kinds are camera, gimbal, payload, peripheral, and vio. Each maps to the matching mavlink.component.<kind> capability. The gimbal extension registers component id 154 as a Gimbal v2 manager; the thermal-camera extension registers a camera component.

Visual odometry

A visual-odometry plugin registers the vio component, then sends pose estimates to the flight controller. The vision SDK wraps this: it registers the visual-odometry component once, then builds a VISION_POSITION_ESTIMATE from a pose (or an ODOMETRY message from a pose plus body-frame twist) and sends it under the visual-odometry component id.
That path keeps the pose stream on the normal MAVLink link. The separate estimator.pose.inject capability is for plugins that push pose samples directly into the autopilot state estimator instead of going over MAVLink. Both are high-risk: a bad pose stream feeds the EKF and can produce unsafe position commands.

Re-publishing decoded data

A common pattern is a plugin that decodes a message and re-publishes it as a clean event other plugins consume, so the raw MAVLink stays in one place:
Another plugin then subscribes to plugin.com.example.rangefinder.rangefinder.reading without touching MAVLink. Publishing and subscribing on the plugin’s own topics use the event.publish and event.subscribe capabilities.

High-level vehicle commands

For the canonical command set (arm, takeoff, RTL, land, mode change), vehicle.command routes through the agent’s command pipeline rather than raw MAVLink. It is a high-risk capability because it can arm or fly the aircraft. Use it instead of mavlink.write when the action is one of the canonical commands; reserve raw mavlink.write for messages the command pipeline does not cover.

See also