Topic taxonomy
Every event has a dotted topic name. The first segment is the namespace; the rest is the path inside it.| Namespace | Owner | Purpose |
|---|---|---|
telemetry.* | Host | Normalized vehicle telemetry. |
mavlink.* | Host | Raw MAVLink streams. |
vehicle.* | Host | Canonical vehicle events (mode change, arm, disarm). |
mission.* | Host | Mission lifecycle. |
fc.* | Host | Flight controller link state. |
video.* | Host | Video pipeline state and frames. |
recording.* | Host | Recording lifecycle. |
peripheral.* | Host | Peripheral hotplug. |
lifecycle.* | Host | Plugin lifecycle ticks and state changes. |
theme.*, config.*, i18n.* | Host | UI and config push. |
plg.<plugin-id>.* | Plugin | Plugin-published topics. |
permission_denied. A plugin’s own publish topics are namespaced
under plg.<id> automatically; the SDK prefixes them at publish
time.
Telemetry topics
Subscribe withtelemetry.subscribe, gated by
telemetry.subscribe.<topic>:
| Topic | Payload |
|---|---|
telemetry.battery | { pack_id, voltage_v, current_a, remaining_percent, cells_v[] } |
telemetry.gps | { lat, lon, alt_m, hdop, fix_type, sats } |
telemetry.attitude | { roll_deg, pitch_deg, yaw_deg, roll_rate_dps, pitch_rate_dps, yaw_rate_dps } |
telemetry.position | { lat, lon, alt_msl_m, alt_agl_m, ground_speed_mps, climb_mps } |
telemetry.heading | { heading_deg, source } |
telemetry.wind | { direction_deg, speed_mps } |
telemetry.rc | { rssi, link_quality, channels[] } |
telemetry.system | { cpu_percent, mem_percent, temperature_c } |
Vehicle topics
| Topic | Payload | Capability |
|---|---|---|
vehicle.mode_changed | { from, to, source } | event.subscribe |
vehicle.armed | { armed: true, by: "rc" | "gcs" | "plugin" } | event.subscribe |
vehicle.disarmed | { armed: false, reason } | event.subscribe |
vehicle.failsafe | { kind, severity, message } | event.subscribe |
vehicle.statustext | { severity, text } | event.subscribe |
Mission topics
| Topic | Payload |
|---|---|
mission.uploaded | { mission_id, item_count, hash } |
mission.started | { mission_id } |
mission.waypoint_reached | { mission_id, seq } |
mission.completed | { mission_id } |
mission.aborted | { mission_id, reason } |
Peripheral topics
| Topic | Payload |
|---|---|
peripheral.attached | { kind, vid, pid, serial, port } |
peripheral.detached | { kind, port } |
peripheral.attached to react to hotplug
without polling.
Lifecycle topics
| Topic | Payload |
|---|---|
lifecycle.tick | { uptime_ms } (1 Hz) |
lifecycle.config_changed | full new config object |
lifecycle.capabilities_changed | { added[], removed[] } |
ACL via capability tokens
Subscribing requiresevent.subscribe. Subscribing to a topic in
the telemetry.* namespace also requires the matching
telemetry.subscribe.<topic> capability. The host re-resolves the
required capability from the topic name, not from the plugin’s
say-so.
Publishing into plg.<id>.* requires event.publish. The host
prefixes your published topic with plg.<id>. automatically.
Delivery guarantees
Two grades:| Grade | Topics | Guarantee |
|---|---|---|
| At-most-once | telemetry.*, mavlink.*, video.* | Drops on slow consumer. No retry. |
| At-least-once | vehicle.*, mission.*, peripheral.*, lifecycle.*, plg.* | Buffered up to 256 messages per plugin per topic, dropped after that with a back_pressure warning. |
recording.* events and read
the recording from disk, do not try to log the live stream.
Back-pressure handling
Each plugin has a per-topic outbox of 256 messages. When the outbox fills:- The host drops the oldest pending message.
- The host emits one
back_pressurewarning per topic per minute, included as an event into the plugin’s normal stream. - The host increments a counter visible under
ados plugin info <id>.
Plugin-to-plugin
Plugins publish into their ownplg.<id>.* namespace. Other
plugins subscribe to that namespace if they declare the matching
permission and the operator approves the explicit grant.