Drone (ex_drone v0.2.0)

View Source

BEAM-native drone control for Elixir.

ex_drone provides a supervised, safety-first API for controlling programmable drones. It supports pluggable adapters (simulator, Tello, and more in the future), a safety pipeline that validates every command, and telemetry events for observability.

Getting Started

# Connect to the simulator (no hardware needed)
{:ok, drone} = Drone.connect(:sim, name: :test)

# Enter SDK mode (required for Tello, automatic for sim)
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)

Safety

All commands pass through a safety pipeline before reaching the drone. Safety policies can be configured at connection time:

{:ok, drone} = Drone.connect(:sim,
  name: :classroom,
  safety: [indoor: true, prop_guards: true]
)

See Drone.Safety.Policy for all safety options.

Safety warning: Drones are physical devices that can cause injury. Always test in the simulator first. Use prop guards. Do not fly near faces. Have an emergency stop ready. Understand local laws and regulations.

Summary

Types

Result of flight / control commands that go through the safety pipeline.

Registered name of a connected drone vehicle.

Functions

Connects to a drone and starts a supervised process.

Sends the SDK mode activation command.

Disconnects from the drone and stops the vehicle process.

Sends an emergency stop command.

Sends a flip command.

Sends a hover command.

Sends a land command.

Sends a movement command.

Sends a query command to the drone.

Sends a rotation command.

Sets the drone speed.

Sends a stop command (hover in place / cancel velocity).

Sends a takeoff command.

Retrieves telemetry data from the drone.

Types

command_result()

@type command_result() ::
  :ok | {:ok, term()} | {:error, :safety, term()} | {:error, term()}

Result of flight / control commands that go through the safety pipeline.

  • :ok — success with no payload
  • {:ok, term()} — success with a value (rare for flight cmds; used when the adapter returns a non-:ok reply)
  • {:error, :safety, term()} — rejected by Drone.Safety
  • {:error, term()} — adapter / connectivity failure

Examples

:ok
{:error, :safety, :max_altitude}
{:error, :not_connected}

connect_result()

@type connect_result() :: {:ok, atom()} | {:error, term()}

Result of connect/2.

  • {:ok, atom()} — connected; value is the drone name
  • {:error, :name_already_taken} — name already registered
  • {:error, term()} — adapter or supervisor failure

Examples

{:ok, :demo}
{:error, :name_already_taken}

drone()

@type drone() :: atom()

Registered name of a connected drone vehicle.

Always an atom looked up via Drone.Vehicle.Registry (pids are not accepted by the public API).

Examples

:my_drone
:tello_1
:good_advisor

Functions

connect(adapter, opts)

@spec connect(
  atom() | module(),
  keyword()
) :: connect_result()

Connects to a drone and starts a supervised process.

Accepts an adapter identifier (:sim or :tello) or a module that implements Drone.Adapter. Options are passed to the adapter and safety policy.

Parameters

  • adapter (atom() | module()) — :sim, :tello, or adapter module

  • opts (keyword()) — connection options:
    • :name (atom(), required) — unique vehicle name
    • :safety (keyword() | Drone.Safety.Policy.t()) — safety policy

    • remaining keys — forwarded to the adapter (e.g. :initial_x, :drone_ip, :battery)

Returns

connect_result/0

Examples

{:ok, drone} = Drone.connect(:sim, name: :test)
{:ok, drone} = Drone.connect(:tello, name: :tello_1, drone_ip: {192, 168, 10, 1})
{:ok, drone} = Drone.connect(:sim, name: :left, initial_x: -50, safety: [indoor: true])

connect_sdk(drone)

@spec connect_sdk(drone()) :: command_result()

Sends the SDK mode activation command.

Required for Tello drones before any other command. The simulator enters SDK mode automatically on connect but still accepts this command.

Parameters

  • drone (drone/0) — registered vehicle name

Returns

command_result/0

Example

:ok = Drone.connect_sdk(:my_drone)

disconnect(drone)

@spec disconnect(drone()) :: :ok | {:error, :not_connected}

Disconnects from the drone and stops the vehicle process.

Parameters

Returns

  • :ok
  • {:error, :not_connected}

Example

:ok = Drone.disconnect(:my_drone)

emergency(drone)

@spec emergency(drone()) :: :ok | {:error, term()}

Sends an emergency stop command.

Bypasses all safety checks and immediately stops the drone's motors. Use only in actual emergencies.

Parameters

Returns

  • :ok
  • {:error, term()}

Example

:ok = Drone.emergency(:my_drone)

flip(drone, direction)

Sends a flip command.

Parameters

  • drone (drone/0)
  • direction (Drone.Command.flip_direction()) — :left | :right | :forward | :back

Returns

command_result/0 (may include a prop-guards warning path via telemetry)

Example

:ok = Drone.flip(:my_drone, :left)

hover(drone, opts \\ [])

@spec hover(
  drone(),
  keyword()
) :: command_result()

Sends a hover command.

Parameters

  • drone (drone/0)
  • opts (keyword()) — :seconds (pos_integer(), default 1)

Returns

command_result/0

Example

:ok = Drone.hover(:my_drone, seconds: 5)

land(drone)

@spec land(drone()) :: command_result()

Sends a land command.

The drone must be flying.

Parameters

Returns

command_result/0

Example

:ok = Drone.land(:my_drone)

move(drone, direction, distance)

Sends a movement command.

Parameters

  • drone (drone/0)
  • direction (Drone.Command.direction()) — :up | :down | :left | :right | :forward | :back

  • distance (pos_integer()) — centimeters (20..500)

Returns

command_result/0

Example

:ok = Drone.move(:my_drone, :forward, 100)

query(drone, type)

@spec query(drone(), Drone.Command.query_type()) :: {:ok, term()} | {:error, term()}

Sends a query command to the drone.

Parameters

  • drone (drone/0)
  • type (Drone.Command.query_type()) — :battery, :height, :speed, :time, :wifi, :sdk_version, or :serial_number

Returns

  • {:ok, term()} — query value
  • {:error, :safety, term()}
  • {:error, term()}

Example

{:ok, percent} = Drone.query(:my_drone, :battery)

rotate(drone, direction, degrees)

Sends a rotation command.

Parameters

  • drone (drone/0)
  • direction (Drone.Command.rotation()) — :cw or :ccw
  • degrees (pos_integer()) — 1..3600

Returns

command_result/0

Example

:ok = Drone.rotate(:my_drone, :cw, 90)

set_speed(drone, speed)

@spec set_speed(drone(), pos_integer()) :: command_result()

Sets the drone speed.

Parameters

  • drone (drone/0)
  • speed (pos_integer()) — cm/s (10..100)

Returns

command_result/0

Example

:ok = Drone.set_speed(:my_drone, 50)

stop(drone)

@spec stop(drone()) :: command_result()

Sends a stop command (hover in place / cancel velocity).

Parameters

Returns

command_result/0

Example

:ok = Drone.stop(:my_drone)

takeoff(drone)

@spec takeoff(drone()) :: command_result()

Sends a takeoff command.

The drone must be in SDK mode and not already flying. Safety checks are applied (battery, altitude, geofence, etc.).

Parameters

Returns

command_result/0

Example

:ok = Drone.takeoff(:my_drone)
{:error, :safety, :low_battery} = Drone.takeoff(:low_bat)

telemetry(drone)

@spec telemetry(drone()) :: {:ok, map()} | {:error, term()}

Retrieves telemetry data from the drone.

Parameters

Returns

  • {:ok, map()} — includes :x, :y, :z, :yaw, :battery, :flying, :mode, ...
  • {:error, term()}

Example

{:ok, tel} = Drone.telemetry(:my_drone)
tel.z
#=> 30