Packages

BEAM-native drone control for Elixir and Erlang (Tello, Crazyflie, swarms).

Current section

Files

Jump to
ex_drone CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
## v0.3.0 (2026-08-03)
### Added
- `Drone.Adapters.Crazyflie` for single-drone Crazyradio / mock high-level flight
- CRTP encode/decode, high-level commander, supervisor, and platform packets
- CRTP logging TOC/subscribe helpers (`Logging`) for battery + `sys.canfly`
- Bitcraze SafeLink enable + header-bit framing (`SafeLink`)
- Crazyradio transport with pluggable USB backend (`USB.Unavailable` by default)
- In-process `Transport.Mock` profiles for CI (`mock://ready`, estimator/battery/unplug)
- Optional `Transport.telemetry/1` so adapters do not inspect transport structs
- Optional `Drone.Adapter.capabilities/1` and `Drone.Adapter.Capabilities`
- `Drone.capabilities/1` public API
- Mission preflight capability validation (`Mission.validate_capabilities/2`)
- Safety options `:require_estimator` and `:max_telemetry_age_ms`
- Guide: `docs/crazyflie.md`
- Shared adapter acceptance tests for Sim and Crazyflie mock
- Example: `examples/crazyflie_mock_flight.exs`
### Changed
- `Drone.Adapter.resolve/1` recognizes `:crazyflie` and rejects unloaded modules
- Sim and Tello advertise Tello-like capabilities
- Crazyflie pose uses `Drone.Geometry`; takeoff height feeds altitude safety
- Crazyflie readiness gate applies to takeoff, land, move, and rotate
- Radio URIs default `safelink=0`; `?safelink=1` enables SafeLink negotiation
- Estimator / telemetry-age safety fail closed on missing values
- `mix verify` mirrors CI (format, unused deps, credo, sobelow, dialyzer, tests, docs)
- README roadmap: Crazyflie delivered in v0.3.0 (swarms already shipped in v0.2.0)
### Notes
- Real `radio://` links require a user-supplied `usb_backend` implementing
`Drone.Adapters.Crazyflie.USB`. Connect downloads the logging TOC and
subscribes to `pm.batteryLevel` / `sys.canfly` for readiness. Optional
`?safelink=1` negotiates Bitcraze SafeLink. BLE, raw attitude, trajectories,
parameter editing, and Crazyflie swarms remain deferred — see
`docs/design/v0_3_0_deferred.md`.
## v0.2.0 (2026-07-31)
### Added
- `Drone.Swarm` coordinator for named multi-drone groups with fail-fast fan-out
- `Drone.Swarm.Supervisor` and `Drone.Swarm.Registry` for supervised, named swarms
- `Drone.Formation` pure planners: `:front`, `:column`, `:vee`, `:diamond`,
`:echelon`, `:circle`, `:shoulder_pair`, optional `:grid`
- Coordinated `connect_sdk/1`, `takeoff/1`, `land/1`, `emergency/1`, `run/2`,
`run/3`, `telemetry/1`, and `stop/1`
- `Drone.Swarm.start/1` public entry (handle-returning, like `Drone.connect/2`;
not an OTP `start_link`)
- `Swarm.run/3` passes formation options (`:side`, `:radius_cm`, `:columns`,
`:leader`, `:origin`, `:heading_deg`, etc.) through to the planner
- Plan-time separation checks (`min_separation_cm`) for formations
- Simulator initial pose opts: `initial_x`, `initial_y`, `initial_z`, `initial_yaw`
- Swarm telemetry events (`[:drone, :swarm, ...]`) including stop `reason`
- Good Advisor / Bad Advisor example (`examples/good_bad_advisor.exs`)
- Docs: `docs/swarm.md`, `docs/formations.md`, `docs/design/v0_2_0_deferred.md`
### Fixed
- `emergency/1` fans out from the caller (membership ETS), not blocked by `run/2`
- Coordinator traps exits, links members, and disconnects them on shutdown/crash
- Formation/`run` crash paths: bare `%Mission{}`, `:diamond` with ≠4 drones,
float yaw, invalid options, unknown mission-map keys, invalid custom returns
- Configurable call `:timeout` (default 60s) on swarm operations
### Notes
- Formations are one-shot geometric planners (simulator-first), not closed-loop
flocking. Deferred behaviours are listed in `docs/design/v0_2_0_deferred.md`.
## v0.1.0 (2026-06-10)
### Added
- `Drone` public API module for connecting, flying, and disconnecting drones
- `Drone.Vehicle` supervised GenServer per drone process
- `Drone.Adapter` behaviour for pluggable drone adapters
- `Drone.Adapters.Sim` simulator adapter (in-process state machine, no hardware needed)
- `Drone.Adapters.Tello` Tello UDP adapter with command encoding and response parsing
- `Drone.Adapters.Tello.Connection` UDP connection handler with centralized defaults
- `Drone.Command` struct with constructors for all Tello SDK commands
- `Drone.Error` error type helpers with `safety/1`, `adapter/1`, `invalid_command/1`
- `Drone.Geometry` shared position math module (`move_delta/3`, `rotate_yaw/3`, `flip_delta/1`)
- `Drone.Safety` pure validation module with altitude, distance, battery, geofence, and allowlist checks
- `Drone.Safety.Policy` struct with default, indoor, and unrestricted presets
- `Drone.Safety.Geofence` circle and polygon geofence support
- `Drone.Telemetry` event helpers emitting `:telemetry` events
- `Drone.Mission` DSL for scripting command sequences
- `Drone.Supervisor` dynamic supervisor for vehicle processes
- `Drone.Application` OTP application starting Registry and Supervisor
- Emergency stop command bypassing all safety checks
- Dry-run mode for validating missions without sending commands
- Command history tracking in simulator and vehicle state
- Flight time simulation in simulator (`query(:time)` returns cumulative motor-on seconds)
- Configurable battery drain simulation
- Configurable failure injection in simulator
- Position tracking (x, y, z, yaw) in simulator and vehicle state
- Command argument validation enforcing Tello SDK ranges (distance 20-500cm, degrees 1-3600, speed 10-100cm/s, hover seconds >0)
- CI/CD pipeline (lint, test matrix, coverage, sobelow, dialyzer, docs, Hex.pm release)
### Changed
- `Drone.Vehicle.child_spec` simplified: `:id` is a constant since DynamicSupervisor ignores it
- `Drone.Adapters.Tello` now references `Connection.default_*()` accessor functions instead of duplicating defaults
- `Drone.Adapters.Sim.query(:time)` returns cumulative flight seconds (not command count), matching real Tello behavior
- `@type drone` narrowed from `atom() | pid()` to `atom()` (pids not supported)
- `Drone.Error.safety/1` used throughout Safety module (was inline tuples)
- Battery stored as `number()` internally in sim, exposed as `trunc(battery)` integer
### Fixed
- Command range validation (F-01): `move/3`, `rotate/3`, `set_speed/2`, `hover/2` reject out-of-range values
- Battery always reported as integer (F-02)
- Graceful `{:error, :not_connected}` for unknown drone names (F-04)
- Tello parser handles negative numbers (F-08)
- `Policy.new(unrestricted: true)` no longer crashes (F-09/F-10)
- `Drone.Vehicle.terminate/2` emits adapter key (`:sim`/`:tello`) not raw module name
- Telemetry metadata bug: terminate/2 was emitting adapter module instead of adapter key