> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altnautica.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ESC driver

> Implement an EscDriver to read motor telemetry.

An `EscDriver` reads per-motor telemetry from electronic speed
controllers and surfaces it as a stream of `EscTelemetry` samples.
DShot-telemetry, KISS, and BLHeli32 protocols all share this
interface.

ESC drivers are read-only by design. Setpoint commands flow
through the FC over MAVLink, not through the agent.

## The interface

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from ados.sdk.drivers.esc import (
    EscDriver,
    EscCandidate,
    EscCapabilities,
    EscSession,
    EscTelemetry,
)

class MyEscDriver(EscDriver):
    async def discover(self) -> list[EscCandidate]:
        ...

    async def open(self, candidate, config) -> EscSession:
        ...

    async def close(self, session) -> None:
        ...

    def capabilities(self, session) -> EscCapabilities:
        ...

    async def telemetry_iterator(self, session):
        # async generator yielding EscTelemetry, one per motor per update
        ...
```

<Note>
  Writing the agent half in Rust? The trait equivalent is
  `ados_sdk::drivers::EscDriver` (re-exported from the `drivers`
  module of the `ados-sdk` crate). It carries the same five methods
  (`discover`, `open`, `close`, `capabilities`, `telemetry_iterator`)
  over an `async-trait`, with `EscCandidate`, `EscCapabilities`, and
  `EscTelemetry` as the matching types. The Python `EscSession` base
  class becomes a `Session` associated type the host treats as an
  opaque token. Set `runtime: rust` in the manifest and the host
  treats the driver the same way it treats the Python one.
</Note>

## Capabilities

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
EscCapabilities(
    protocol="dshot-telemetry",
    motor_count=4,
    has_rpm=True,
    has_temperature=True,
    has_voltage=True,
    has_current=False,
    update_hz=200.0,
)
```

## Telemetry samples

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
EscTelemetry(
    timestamp_ns=ns,
    motor_index=0,
    rpm=12500,
    temp_c=42.0,
    voltage_v=22.1,
    current_a=0.0,
    throttle_pct=37.5,
)
```

`current_a` is `0.0` when the protocol does not carry it. For a bank
with no thermistor, report `temp_c=0.0` and set `has_temperature=False`
in `EscCapabilities` so the GCS hides the column.

## Manifest permissions

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
agent:
  permissions:
    - id: sensor.payload.register   # ESC drivers register under the payload cap (no dedicated ESC cap in the current catalog)
    - id: mavlink.read              # for ESC telemetry carried in the MAVLink stream
    - id: hardware.uart             # for a direct serial telemetry line
```

## See also

* [Driver layer](/developers/driver-layer) for the contract.
