ex_drone
BEAM-native drone control for Elixir and Erlang. Fly, monitor, and simulate programmable drones using supervised processes, telemetry, and missions.
Safety Warning
Drones are physical devices that can cause injury or property damage.
- Do not fly near faces or people
- Use prop guards at all times
- Test in the simulator before connecting to real hardware
- Use open indoor spaces or outdoor areas with clear lines of sight
- Have an emergency stop ready at all times
- Understand and follow local laws and regulations
Installation
Add ex_drone to your list of dependencies in mix.exs:
def deps do
[
{:ex_drone, "~> 0.2.0"}
]
end
Quick Start
# Connect to the simulator (no hardware needed)
{:ok, drone} = Drone.connect(:sim, name: :my_drone)
# Enter SDK mode
Drone.connect_sdk(drone)
# Fly
Drone.takeoff(drone)
Drone.move(drone, :up, 40)
Drone.move(drone, :forward, 100)
Drone.rotate(drone, :cw, 90)
Drone.land(drone)
# Disconnect
Drone.disconnect(drone)
Swarms
Coordinate multiple simulated drones with Drone.Swarm:
{:ok, swarm} =
Drone.Swarm.start([
{:good, adapter: :sim, initial_x: -50},
{:bad, adapter: :sim, initial_x: 50}
])
Drone.Swarm.connect_sdk(swarm)
{:ok, _} = Drone.Swarm.takeoff(swarm)
{:ok, _} = Drone.Swarm.run(swarm, :front)
{:ok, _} = Drone.Swarm.land(swarm)
:ok = Drone.Swarm.stop(swarm)
See Swarms, Formations, and
examples/good_bad_advisor.exs.
Safety Policies
All commands pass through a safety pipeline before reaching the drone:
# Indoor flight with tight limits
{:ok, drone} = Drone.connect(:sim, name: :classroom, safety: [indoor: true])
# Custom safety limits
{:ok, drone} = Drone.connect(:sim, name: :safe,
safety: [
max_altitude_cm: 200,
max_distance_cm: 500,
prop_guards: true
]
)
# Dry-run mode (validates commands without sending)
{:ok, drone} = Drone.connect(:sim, name: :test, safety: [dry_run: true])
See Drone.Safety.Policy and the Safety guide.
Tello Connection
{:ok, drone} = Drone.connect(:tello, name: :tello_1)
Drone.connect_sdk(drone)
Drone.takeoff(drone)
Drone.land(drone)
Drone.disconnect(drone)
See the Tello guide.
Mission Scripts
mission =
Drone.Mission.new()
|> Drone.Mission.sdk_mode()
|> Drone.Mission.takeoff()
|> Drone.Mission.move(:up, 40)
|> Drone.Mission.rotate(:cw, 90)
|> Drone.Mission.land()
{:ok, results} = Drone.Mission.run(mission, :my_drone)
Architecture
- Drone.Vehicle -- One GenServer per drone, supervised
- Drone.Adapter -- Behaviour for drone communication (Sim, Tello, future adapters)
- Drone.Geometry -- Shared position math (move, rotate, flip deltas)
- Drone.Safety -- Pure validation module, no side effects
- Drone.Telemetry --
:telemetryevents for observability - Drone.Mission -- Command sequence DSL
- Drone.Swarm -- Multi-drone coordinator (
start/1, fan-out,run/2/run/3) - Drone.Formation -- One-shot geometric formation planners
See the Architecture guide.
Documentation
Guides
Design
Research
On HexDocs these pages appear under Guides, Design, and Research.
Further Reading
Short starter set; the full annotated list is in docs/further_reading.md.
- Tello:DJI Tello SDK 2.0 User Guide (PDF)
- Swarm behaviour: Reynolds, C. W. "Flocks, Herds, and Schools: A Distributed Behavioral Model." SIGGRAPH, 1987
- Formation control: Balch, T., and Arkin, R. C. "Behavior-based formation control for multirobot teams." IEEE TRA, 1998
- Swarm robotics survey: Brambilla, M. et al. "Swarm robotics: a review from the swarm engineering perspective." Swarm Intelligence, 2013
- Motion planning: LaValle, S. M. Planning Algorithms
- Safety: Leveson, N. G. Engineering a Safer World. MIT Press, 2011
- OTP:OTP Design Principles
- Other platforms:Crazyflie, MAVLink, PX4, ArduPilot, Nerves
Roadmap
v0.1.0 — Tello + Simulator Foundation
Public API, supervised processes, safety pipeline, simulator, Tello adapter, missions, telemetry.
Dronepublic API (connect/2,disconnect/1,takeoff/1,move/3,rotate/3, etc.)Drone.Vehicle— one GenServer per drone, supervisedDrone.Adapterbehaviour — pluggable adaptersDrone.Adapters.Sim— in-process simulator with position tracking, battery drain, failure injectionDrone.Adapters.Tello— DJI Tello UDP adapter (command encoding, response parsing, state management)Drone.Command— struct constructors for 14 command typesDrone.Safety— 8-stage validation pipeline (args, mode, allowlist, flying, altitude, distance, battery, geofence)Drone.Safety.Policy— default, indoor, unrestricted presetsDrone.Safety.Geofence— circle and polygon geofencingDrone.Geometry— shared position math (heading-aware movement, rotation, flips)Drone.Telemetry—:telemetryevents (command start/stop, safety reject, connect, disconnect)Drone.Mission— command sequence DSL with error-early semanticsDrone.Error— error type helpers (safety/1,adapter/1,invalid_command/1)- Command argument validation per Tello SDK ranges
- Emergency stop bypassing all safety checks
- Dry-run mode for validating missions without flying
- Flight time simulation (
query(:time)returns cumulative motor-on seconds) - CI/CD — lint, test matrix (1.17-1.20 / OTP 26-29), coverage, sobelow, dialyzer, docs, Hex.pm publish
- 291+ tests, credo --strict clean, --warnings-as-errors clean
v0.2.0 — Swarms and Mission Orchestration
Multi-drone coordination on the v0.1.0 vehicle model.
Drone.Swarm— supervised group of drones with fail-fast fan-out- Named swarm registry (
Drone.Swarm.Registry) - Coordinated takeoff / land / emergency
- Formation planners — front, column, vee, diamond, echelon, circle
Swarm.run/2/run/3— formations, per-drone missions, or custom functions- Simulator initial world offsets for multi-drone layouts
- Good Advisor / Bad Advisor example
- Deferred flocking / closed-loop catalogue (
docs/design/v0_2_0_deferred.md)
v0.3.0 — Adapters & Resilience
New hardware adapters, command retry, async missions, and reconnect.
Drone.Adapters.Crazyflie— Crazyflie BLE/USB adapterDrone.Adapters.MAVLink— MAVLink-compatible drones via serial/UDP- Adapter registry —
Drone.Adapter.register/2for third-party adapters - Common adapter test suite — shared
Drone.Adapter.Acceptancetests - Command retry with configurable backoff (
safe_to_retry?/1already inDrone.Command) Mission.run_async/2— fire-and-forget mission execution with progress events- Reconnect on adapter failure — Vehicle auto-reconnects after network errors
Drone.Adapters.Tello— state recovery on reconnect (re-query SDK mode, battery, position)- Configurable command timeout per-vehicle (default 10s)
v0.4.0 — Video & Sensors
Video stream handling and real-time sensor data from Tello EDU.
Drone.Adapters.Tello.Stream— receive H.264 video stream via UDPDrone.Adapters.Tello.State— subscribe to real-time telemetry (100ms interval)Drone.Telemetry.stream/1— stream telemetry events as Elixir Stream- Video frame extraction — decode keyframes to JPEG for snapshot API
Drone.query(:wifi_signal)— WiFi signal quality from state stream
v0.5.0 — Persistence & Analytics
Flight logging, replay, and observability.
- Ecto-backed persistence — mission logs, flight history, anomaly tracking
- Mission replay — replay a recorded mission against a simulator for regression testing
:telemetryanalytics dashboard — LiveDashboard plugin with real-time charts- Flight log query API — filter by drone, date, safety rejections, battery level
- Live flocking / neighbor-aware collision avoidance (see deferred swarm catalogue)
v1.0.0 — Stable API
API freeze, production hardening, and deployment guides.
- API stability guarantee — no breaking changes within 1.x
- Fly.io deployment guide — run command relay in the cloud
- Nerves integration guide — run on Raspberry Pi with Tello
- Comprehensive property-based testing (
StreamData) - Performance benchmarks and soak tests
License
MIT