BEAM-native drone control for Elixir and Erlang. Fly, monitor, and simulate programmable drones using supervised processes, telemetry, and missions.
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
Add ex_drone to your list of dependencies in mix.exs:
def deps do
[
{:ex_drone, "~> 0.1.0"}
]
end# 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)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 for all safety options.
{:ok, drone} = Drone.connect(:tello, name: :tello_1)
Drone.connect_sdk(drone)
Drone.takeoff(drone)
Drone.land(drone)
Drone.disconnect(drone)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)- 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
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, supervised -
Drone.Adapterbehaviour — pluggable adapters -
Drone.Adapters.Sim— in-process simulator with position tracking, battery drain, failure injection -
Drone.Adapters.Tello— DJI Tello UDP adapter (command encoding, response parsing, state management) -
Drone.Command— struct constructors for 14 command types -
Drone.Safety— 8-stage validation pipeline (args, mode, allowlist, flying, altitude, distance, battery, geofence) -
Drone.Safety.Policy— default, indoor, unrestricted presets -
Drone.Safety.Geofence— circle and polygon geofencing -
Drone.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 semantics -
Drone.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 (90.2%), sobelow, dialyzer, docs, Hex.pm publish
- 253 tests, 90.2% coverage, credo --strict clean, --warnings-as-errors clean
New hardware adapters, command retry, async missions, and reconnect.
-
Drone.Adapters.Crazyflie— Crazyflie BLE/USB adapter -
Drone.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)
Swarm primitives for coordinating multiple drones.
-
Drone.Swarm— supervised group of drones with shared mission context - Formation flying — grid, line, circle — via relative position commands
-
Drone.Mission.concurrent/2— run missions on multiple drones in parallel - Collision avoidance in simulator — safety policy rejects commands that would collide
- Coordinated takeoff/land — swarm-level commands that dispatch to individual drones
Video stream handling and real-time sensor data from Tello EDU.
-
Drone.Adapters.Tello.Stream— receive H.264 video stream via UDP -
Drone.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
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
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
MIT