Under active development. Breaking changes expected. APIs, installers, and UI may shift between releases.
Extend the drone, not the core.
CAPABILITIES
One manifest, twenty-nine doors.
Every capability is declared up front. The host enforces each one at the IPC boundary, so a plugin can only do what the operator has approved.
Hardware
Talk to anything on the bus
UART, I2C, SPI, GPIO, USB serial, USB UVC video, and CSI camera access. Each interface is its own capability, so a plugin that needs UART does not get GPIO for free.
MAVLink
Register as a real component
A plugin can read and write MAVLink and register as a camera, gimbal, payload, or peripheral. The flight controller talks to it like any vendor box.
Telemetry
Read it, extend it, publish it
Subscribe to the live telemetry bus, attach derived streams, and publish custom events that other plugins or the ground station consume. No polling, no log scraping.
Sensors
Plug in the strange ones
Register cameras, depth sensors, LiDAR, or any payload at runtime. The driver stays in the plugin; the agent exposes one stable contract to the rest of the stack.
Missions
Read, write, record
Read the active mission, write new waypoints, and record full session data with video, telemetry, and events. Useful for custom autonomy and audit trails.
Network
Reach out, but on a leash
Outbound HTTPS to a domain allowlist declared in the manifest. No raw sockets, no surprise traffic. The operator sees the full destination list before approval.
RUNTIME
A plugin lives in its own process.
Each plugin runs as a subprocess under the supervisor with cgroup limits on memory, CPU, and process count. A crash, a leak, or an infinite loop stays inside the plugin.
The host owns the flight-critical path: MAVLink, the FC link, the telemetry bus, the cloud relay. The supervisor owns every plugin process and restarts it with backoff on failure. Five failures in a minute trip a circuit breaker and the plugin is auto-disabled until an operator looks at it.
Communication between plugin and host is a small msgpack RPC over a Unix domain socket. Each request carries a capability token minted at install time, and the host checks it against the granted set on every call. There is no shared memory, no shared file descriptor, no shared anything.
A plugin that crashes never affects flight. The FC keeps flying, the supervisor logs the crash and restarts if the breaker is closed, and the event surfaces to Mission Control.
ados-supervisor
├── ados-agent (flight-critical)
├── ados-mavlink (FC link)
├── ados-cloud (relay)
└── ados-plugins.slice
├── battery-health subprocess + cgroup
├── thermal-cam subprocess + cgroup
└── mavlink-inspector subprocess + cgroupcgroup limits per plugin: memory cap, CPU share, max PIDs. The supervisor restarts on exit; the circuit breaker opens after five failures in sixty seconds.
TRUST
Signed, scoped, and consented to.
Signing
- ✓Plugin archives ship as signed .adosplug files
- ✓Ed25519 signature verified at install
- ✓Revocation list checked on every boot
- ✓Unsigned plugins load only in developer mode
- ✓First-party publishers carry an allowlist marker
Permissions
- ✓The manifest declares every capability the extension needs
- ✓Two-stage install: summary, then permission grant
- ✓Sensitive capabilities are flagged in the permission list
- ✓Sensitive permissions require an explicit re-confirm
- ✓Every permission is revocable from Mission Control
Every capability the extension requests is listed at install. The ones that touch sensitive surfaces (vehicle command, MAVLink or mission write, host filesystem, network egress) are flagged so you grant them deliberately, and every one is revocable afterward.
CODE
A plugin in thirty lines.
One YAML manifest, one Python entrypoint. This example watches battery cell voltages and publishes an alert when the spread crosses a threshold.
name: cell-balance-monitor
version: 0.1.0
agent:
entry: cell_balance:run
capabilities:
- telemetry.read
- event.publishfrom ados_sdk import PluginContext
def run(ctx: PluginContext) -> None:
@ctx.events.on("telemetry.battery")
def watch(msg):
cells = msg["cell_voltages_v"]
spread = max(cells) - min(cells)
if spread > 0.15:
ctx.events.publish(
"alert.cell_imbalance",
{"spread_v": spread, "cells": cells},
)The host injects the plugin context at startup with tokens for the granted permissions only. The plugin code never sees other plugins, the FC link, or the cloud relay directly.
REFERENCE EXTENSIONS
Read the real ones.
First-party extensions live in the public ADOSExtensions repository. Read the code, fork it, build your own.
Hybrid
Thermal Camera (FLIR Lepton USB UVC)
The agent half opens a thermal camera over USB UVC, decodes 16-bit radiometric frames, applies the temperature transform, and registers a MAVLink camera component. A second H.264 stream feeds the ground-station overlay.
- ·USB UVC capability plus USB serial for control
- ·MAVLink camera component registration
- ·Raw counts to Celsius at frame rate
- ·Configurable palette and isotherm output
Hybrid
MAVLink Gimbal v2 Controller
The agent half registers a gimbal device, decodes the standard attitude commands, and streams attitude status back at thirty hertz. A bridge is included for non-MAVLink gimbals over UART or USB.
- ·Attitude set-and-report handlers
- ·Attitude status publisher at 30 Hz
- ·Optional bridge for serial gimbals
- ·SITL verification path
Browse every extension in the open-source registry.
CLI
Install, enable, inspect, remove.
Every plugin operation has a command on the agent. Mission Control wraps the same calls in a UI.
$ ados plugin install ./thermal-cam.adosplug
verifying signature ok
checking compatibility ok
permissions requested:
high usb.uvc
medium sensor.camera.register
high mavlink.write
low telemetry.read
grant permissions? [y/N] y
plugin installed: [email protected]
$ ados plugin enable thermal-cam
$ ados plugin list
NAME VERSION STATE PROCESS
geofence 0.2.1 enabled pid 4123
telemetry-logger 0.1.0 enabled pid 4124
thermal-cam 0.1.0 enabled pid 4131installVerify the signature, validate the manifest, prompt for permissions, lay down filesenable / disableStart or stop the plugin process without removing itremoveStop the process, clear cgroup state, delete files and tokenslist / infoShow installed plugins, granted permissions, and process statepermsInspect or revoke permissions on an installed pluginlogsTail the plugin's structured log streamtestRun the plugin against the bundled test runner without enabling it
SHIP STATE
What works today.
- ✓Local install of signed .adosplug archives
- ✓Capability enforcement on every IPC call
- ✓Three built-in plugins: geofence, telemetry-logger, mavlink-inspector
- ✓The full ados plugin CLI
- ✓A bundled test runner for offline validation
- ✓Two-stage install dialog with a permission review
- →The ados-sdk package for plugin authors
- →A project scaffolder for new plugins
- →Install straight from a git URL
- →A shared driver layer for cameras, gimbals, and LiDAR
- →A hosted registry with browse and search
- →A developers section on the docs site
Build an extension for ADOS.
The reference extensions are open source. Read them, fork them, ship your own.
View ADOSExtensions