Skip to main content
The driver base classes and data types ship in both SDKs (ados.sdk.drivers in Python, ados_sdk::drivers in Rust), and the method contracts on these pages match them. The agent does not route drivers. It never calls discover(), open() or the iterators. register_*_driver calls return not_implemented, and the sensor.*.register capabilities are refused at grant time. A driver plugin opens and runs its own device from its lifecycle hooks, as the first-party Gimbal v2 plugin does. No Mission Control panel renders driver output.
The driver layer is a set of typed base classes for hardware-driver plugins. A driver plugin is an ordinary agent plugin: same manifest, same lifecycle, same sandbox. The base classes give every device kind the same shape, so a driver written against them is easy to test with a mock backend and easy to read. Python drivers subclass the abstract base classes in ados.sdk.drivers. Rust drivers implement the matching trait in ados_sdk::drivers. The two are method-for-method equivalents. Set agent.runtime in the manifest to python or rust to pick the language.

The six driver kinds

All six share the same preamble in both languages:
The kind-specific methods carry the data. A CameraDriver yields FrameBuffers, a GpsDriver yields GpsFixes, a GimbalDriver takes attitude commands. In Python the stream methods return an AsyncIterator. In Rust they return a SampleStream (a boxed Stream), and the opaque Python *Session class becomes the Session associated type.

Running a driver from your plugin

Your plugin owns the driver from start to finish:
  1. In on_start, construct the driver with its backend (a serial port, a USB handle, a MAVLink router handle).
  2. Call discover() and pick a candidate. If there is none, report the failure and return.
  3. Call open(candidate, config). config is your plugin’s operator config, validated against config-schema.json.
  4. Consume the kind-specific stream (frame_iterator, fix_iterator, state_iterator, telemetry_iterator) in a task you start.
  5. Publish what Mission Control should see with ctx.telemetry.extend or ctx.events.publish. Your plugin’s GCS half renders it.
  6. In on_stop, cancel the task and call close(session).
The MAVLink Gimbal v2 plugin follows this pattern in agent/src/altnautica_gimbal_v2/plugin.py, and the FLIR Lepton plugin does the same in agent/src/altnautica_thermal_camera/plugin.py.

Manifest permissions

Declare only the hardware and data capabilities your driver actually uses. sensor.camera.register, sensor.depth.register, sensor.lidar.register, sensor.imu.register and sensor.payload.register are in the capability catalog, but this agent refuses to grant them (“not supported by this agent runtime”) because the host method they gate is not implemented. Declaring one buys nothing. Risk levels and the full catalog are on Permissions.

Errors

Python drivers raise from ados.sdk.drivers.errors. Rust drivers return the DriverError enum from ados_sdk::drivers (every driver method returns DriverResult<T>).
In Python, DriverError is the base. DriverDeviceNotFound means the candidate disappeared between discover and open. DriverPermissionDenied means the device exists but the plugin process cannot open it (a missing udev rule, a locked USB device, an undeclared capability). The Rust enum mirrors these. InvalidParam is returned for an unknown set_param name or an unknown actuate action, and NotSupported for an optional capability the device lacks (a rate command on a position-only gimbal, RTCM injection on a non-RTK GPS). Other carries any recoverable condition that does not fit a named kind. Raise these from your own driver code and handle them in your plugin. A plugin that raises an unhandled exception out of a lifecycle hook is handled per Lifecycle.

Next steps

Camera driver

The worked example, with the FLIR Lepton driver.

Gimbal driver

The MAVLink Gimbal v2 reference driver.

Vendor binaries

Ship a closed-source library or per-architecture binary.

Hardware testing

Mock backends, SITL and bench rigs.
Last modified on October 11, 2026