{"id":51033754,"url":"https://github.com/thanos/ex_drone","last_synced_at":"2026-06-22T03:01:59.415Z","repository":{"id":363797551,"uuid":"1264353519","full_name":"thanos/ex_drone","owner":"thanos","description":"BEAM-native drone control for Elixir and Erlang. Fly, monitor, simulate, and coordinate programmable drones using supervised processes, telemetry, missions, and swarm APIs.","archived":false,"fork":false,"pushed_at":"2026-06-12T21:46:33.000Z","size":149,"stargazers_count":8,"open_issues_count":11,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T23:22:45.358Z","etag":null,"topics":["autonomous","beam","crazyflie","distributed-systems","drone","drones","elixir","erlang","mavlink","mission-planning","otp","px4","robotics","simulation","swarm-robotics","telemetry","tello","uas","uav"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thanos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-09T20:04:49.000Z","updated_at":"2026-06-19T12:47:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/thanos/ex_drone","commit_stats":null,"previous_names":["thanos/ex_drone"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thanos/ex_drone","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_drone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_drone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_drone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_drone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thanos","download_url":"https://codeload.github.com/thanos/ex_drone/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_drone/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34632723,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autonomous","beam","crazyflie","distributed-systems","drone","drones","elixir","erlang","mavlink","mission-planning","otp","px4","robotics","simulation","swarm-robotics","telemetry","tello","uas","uav"],"created_at":"2026-06-22T03:01:58.630Z","updated_at":"2026-06-22T03:01:59.406Z","avatar_url":"https://github.com/thanos.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ex_drone\n\n[![Hex version](https://img.shields.io/hexpm/v/ex_drone.svg)](https://hex.pm/packages/ex_drone)\n[![Hex docs](https://img.shields.io/badge/docs-hexdocs.pm-blue)](https://hexdocs.pm/ex_drone)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![CI](https://github.com/thanos/ex_drone/actions/workflows/ci.yml/badge.svg)](https://github.com/thanos/ex_drone/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/thanos/ex_drone/badge.svg?branch=main)](https://coveralls.io/github/thanos/ex_drone?branch=main)\n\nBEAM-native drone control for Elixir and Erlang. Fly, monitor, and simulate programmable drones using supervised processes, telemetry, and missions.\n\n## Safety Warning\n\n**Drones are physical devices that can cause injury or property damage.**\n\n- Do not fly near faces or people\n- Use prop guards at all times\n- Test in the simulator before connecting to real hardware\n- Use open indoor spaces or outdoor areas with clear lines of sight\n- Have an emergency stop ready at all times\n- Understand and follow local laws and regulations\n\n## Installation\n\nAdd `ex_drone` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ex_drone, \"~\u003e 0.1.0\"}\n  ]\nend\n```\n\n## Quick Start\n\n```elixir\n# Connect to the simulator (no hardware needed)\n{:ok, drone} = Drone.connect(:sim, name: :my_drone)\n\n# Enter SDK mode\nDrone.connect_sdk(drone)\n\n# Fly\nDrone.takeoff(drone)\nDrone.move(drone, :up, 40)\nDrone.move(drone, :forward, 100)\nDrone.rotate(drone, :cw, 90)\nDrone.land(drone)\n\n# Disconnect\nDrone.disconnect(drone)\n```\n\n## Safety Policies\n\nAll commands pass through a safety pipeline before reaching the drone:\n\n```elixir\n# Indoor flight with tight limits\n{:ok, drone} = Drone.connect(:sim, name: :classroom, safety: [indoor: true])\n\n# Custom safety limits\n{:ok, drone} = Drone.connect(:sim, name: :safe,\n  safety: [\n    max_altitude_cm: 200,\n    max_distance_cm: 500,\n    prop_guards: true\n  ]\n)\n\n# Dry-run mode (validates commands without sending)\n{:ok, drone} = Drone.connect(:sim, name: :test, safety: [dry_run: true])\n```\n\nSee `Drone.Safety.Policy` for all safety options.\n\n## Tello Connection\n\n```elixir\n{:ok, drone} = Drone.connect(:tello, name: :tello_1)\nDrone.connect_sdk(drone)\nDrone.takeoff(drone)\nDrone.land(drone)\nDrone.disconnect(drone)\n```\n\n## Mission Scripts\n\n```elixir\nmission =\n  Drone.Mission.new()\n  |\u003e Drone.Mission.sdk_mode()\n  |\u003e Drone.Mission.takeoff()\n  |\u003e Drone.Mission.move(:up, 40)\n  |\u003e Drone.Mission.rotate(:cw, 90)\n  |\u003e Drone.Mission.land()\n\n{:ok, results} = Drone.Mission.run(mission, :my_drone)\n```\n\n## Architecture\n\n- **Drone.Vehicle** -- One GenServer per drone, supervised\n- **Drone.Adapter** -- Behaviour for drone communication (Sim, Tello, future adapters)\n- **Drone.Geometry** -- Shared position math (move, rotate, flip deltas)\n- **Drone.Safety** -- Pure validation module, no side effects\n- **Drone.Telemetry** -- `:telemetry` events for observability\n- **Drone.Mission** -- Command sequence DSL\n\n## Roadmap\n\n### v0.1.0 — Tello + Simulator Foundation (current)\n\nPublic API, supervised processes, safety pipeline, simulator, Tello adapter, missions, telemetry.\n\n- [x] `Drone` public API (`connect/2`, `disconnect/1`, `takeoff/1`, `move/3`, `rotate/3`, etc.)\n- [x] `Drone.Vehicle` — one GenServer per drone, supervised\n- [x] `Drone.Adapter` behaviour — pluggable adapters\n- [x] `Drone.Adapters.Sim` — in-process simulator with position tracking, battery drain, failure injection\n- [x] `Drone.Adapters.Tello` — DJI Tello UDP adapter (command encoding, response parsing, state management)\n- [x] `Drone.Command` — struct constructors for 14 command types\n- [x] `Drone.Safety` — 8-stage validation pipeline (args, mode, allowlist, flying, altitude, distance, battery, geofence)\n- [x] `Drone.Safety.Policy` — default, indoor, unrestricted presets\n- [x] `Drone.Safety.Geofence` — circle and polygon geofencing\n- [x] `Drone.Geometry` — shared position math (heading-aware movement, rotation, flips)\n- [x] `Drone.Telemetry` — `:telemetry` events (command start/stop, safety reject, connect, disconnect)\n- [x] `Drone.Mission` — command sequence DSL with error-early semantics\n- [x] `Drone.Error` — error type helpers (`safety/1`, `adapter/1`, `invalid_command/1`)\n- [x] Command argument validation per Tello SDK ranges\n- [x] Emergency stop bypassing all safety checks\n- [x] Dry-run mode for validating missions without flying\n- [x] Flight time simulation (`query(:time)` returns cumulative motor-on seconds)\n- [x] CI/CD — lint, test matrix (1.17-1.20 / OTP 26-29), coverage (90.2%), sobelow, dialyzer, docs, Hex.pm publish\n- [x] 253 tests, 90.2% coverage, credo --strict clean, --warnings-as-errors clean\n\n### v0.2.0 — Adapters \u0026 Resilience\n\nNew hardware adapters, command retry, async missions, and reconnect.\n\n- [ ] `Drone.Adapters.Crazyflie` — Crazyflie BLE/USB adapter\n- [ ] `Drone.Adapters.MAVLink` — MAVLink-compatible drones via serial/UDP\n- [ ] Adapter registry — `Drone.Adapter.register/2` for third-party adapters\n- [ ] Common adapter test suite — shared `Drone.Adapter.Acceptance` tests\n- [ ] Command retry with configurable backoff (`safe_to_retry?/1` already in `Drone.Command`)\n- [ ] `Mission.run_async/2` — fire-and-forget mission execution with progress events\n- [ ] Reconnect on adapter failure — Vehicle auto-reconnects after network errors\n- [ ] `Drone.Adapters.Tello` — state recovery on reconnect (re-query SDK mode, battery, position)\n- [ ] Configurable command timeout per-vehicle (default 10s)\n\n### v0.3.0 — Multi-Drone Coordination\n\nSwarm primitives for coordinating multiple drones.\n\n- [ ] `Drone.Swarm` — supervised group of drones with shared mission context\n- [ ] Formation flying — grid, line, circle — via relative position commands\n- [ ] `Drone.Mission.concurrent/2` — run missions on multiple drones in parallel\n- [ ] Collision avoidance in simulator — safety policy rejects commands that would collide\n- [ ] Coordinated takeoff/land — swarm-level commands that dispatch to individual drones\n\n### v0.4.0 — Video \u0026 Sensors\n\nVideo stream handling and real-time sensor data from Tello EDU.\n\n- [ ] `Drone.Adapters.Tello.Stream` — receive H.264 video stream via UDP\n- [ ] `Drone.Adapters.Tello.State` — subscribe to real-time telemetry (100ms interval)\n- [ ] `Drone.Telemetry.stream/1` — stream telemetry events as Elixir Stream\n- [ ] Video frame extraction — decode keyframes to JPEG for snapshot API\n- [ ] `Drone.query(:wifi_signal)` — WiFi signal quality from state stream\n\n### v0.5.0 — Persistence \u0026 Analytics\n\nFlight logging, replay, and observability.\n\n- [ ] Ecto-backed persistence — mission logs, flight history, anomaly tracking\n- [ ] Mission replay — replay a recorded mission against a simulator for regression testing\n- [ ] `:telemetry` analytics dashboard — LiveDashboard plugin with real-time charts\n- [ ] Flight log query API — filter by drone, date, safety rejections, battery level\n\n### v1.0.0 — Stable API\n\nAPI freeze, production hardening, and deployment guides.\n\n- [ ] API stability guarantee — no breaking changes within 1.x\n- [ ] Fly.io deployment guide — run command relay in the cloud\n- [ ] Nerves integration guide — run on Raspberry Pi with Tello\n- [ ] Comprehensive property-based testing (`StreamData`)\n- [ ] Performance benchmarks and soak tests\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanos%2Fex_drone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthanos%2Fex_drone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanos%2Fex_drone/lists"}