K. Isom f8bb23e409 Package as 'autohover' with uv run / uvx entry points
Add main.py and a flat-layout hatchling build with a console script (autohover = mission_client:main), replacing tool.uv package=false, so the app runs via 'uv run main.py' and installs via uvx / uv tool install -- matching the sibling Crazyflie projects.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 14:35:00 -07:00

Crazyflie Mission Client

A small DearPyGui cockpit for flying a Bitcraze Crazyflie with a Flow v2 deck (same GUI binding as the test-stand app). Arm it and the drone lifts off to 1 m above the ground and holds position; disarm to land gently; emergency-stop to cut the motors instantly.

┌──────────────────────────────────────────────┐
│ Connection                                     │
│ [ radio://0/80/2M/E7E7E7E7E7 ▾ ] [Scan][Connect]│
│ ──────────────────────────────────────────────│
│ Status                                         │
│ Hovering at 1.40 m            ← colour-coded    │
│ Battery: 3.92 V     Height: 1.41 m             │
│ Flow v2 deck: attached                         │
│ Supervisor: armed, flying                      │
│ ──────────────────────────────────────────────│
│ Estimator state                                │
│ Pos (m):  x +0.02  y -0.01  z +1.00            │
│ Yaw:  +1.4 deg                                 │
│ Flow counts:  dx +5  dy -3                     │
│ ──────────────────────────────────────────────│
│ Flight                                         │
│ Hover height  [====●========] 1.40 m           │
│ [ LAUNCH (to 1.40 m) ]   ← ARM→LAUNCH→LAND      │
│ [ Disarm ]               ← only while ARMED     │
│ [ EMERGENCY STOP (SPACE) ]                     │
│ ──────────────────────────────────────────────│
│ Console                              [Clear]   │
│ 12:00:01 I controller: [READY] …               │
│ 12:00:03 I controller: [ARMED] ready to LAUNCH │
│ 12:00:08 I controller: [FLYING] Hovering 1.40 m│
│ 12:00:09 I crazyflie.console: ...fw output...  │
└──────────────────────────────────────────────┘

Flight is a two-step flow with one context button:

State Button Colour Action
Ready ARM green reset estimator + arm; drone idles armed on the ground
Armed LAUNCH (to N m) blue take off to the hover height and hold
Flying LAND yellow gentle descent + disarm

While ARMED on the ground a separate Disarm button backs out without launching (the firmware also auto-disarms after ~30 s if you never launch). The Hover height slider (0.22.0 m) can be adjusted right up until LAUNCH (it latches there) and locks once airborne. Below everything, a console log of roughly the same height shows mission events, cflib messages, and firmware console output (auto-scrolls while at the bottom; Clear empties it). Use Scan to discover URIs, or type/select one in the combo before connecting.

Hardware

  • Crazyflie 2.x with up-to-date firmware (protocol v7+ recommended for the supervisor arming system; older firmware falls back to the thrust-unlock path).
  • Flow v2 deck mounted underneath (provides optical-flow XY + laser Z hold).
  • Crazyradio PA / 2.0 plugged into the host.
  • Charged battery, propellers in good shape, and clear space above the drone.

Install

This project uses uv. From autover/:

uv sync

That creates .venv/ and installs cflib and dearpygui (a self-contained wheel with its own GL/windowing backend — no system GUI packages needed).

On Linux you also need udev permissions for the Crazyradio (see the cflib USB docs).

requirements.txt is kept for non-uv (pip install -r requirements.txt) setups; pyproject.toml is the source of truth for uv.

Run

uv run mission_client.py
# Use a non-default radio URI:
CFLIB_URI=radio://0/80/2M/E7E7E7E7E7 uv run mission_client.py

Flying

  1. Connect — opens the radio link, starts telemetry, and probes for the Flow deck. (Optionally Scan first and pick a URI from the combo.)
  2. ARM — runs pre-flight checks (Flow deck present, battery ≥ 3.10 V, not tumbled/locked), resets and waits for the Kalman estimator to converge, and arms the motors. The drone then idles armed on the ground (props at idle) in the ARMED state; the button turns blue and reads LAUNCH. (Back out any time with Disarm; the firmware also auto-disarms after ~30 s if idle.)
  3. Set the hover height with the slider (0.22.0 m, default 1 m) — adjustable until launch — then LAUNCH: takes off to the chosen height (climb timed for a gentle ~0.35 m/s) and hovers. The button turns yellow and reads LAND.
  4. LAND — descends gently, stops the commander, and disarms.
  5. EMERGENCY STOP (button or SPACE) — cuts the motors immediately. On protocol-v7 firmware this latches the supervisor, so you must reboot the drone before it will fly again.

Closing the window (or Ctrl-C) lands the drone first (if airborne) before disconnecting.

Drift inspection

The Estimator state panel streams the estimator pose and raw optical-flow counts (stateEstimate.x/y + stateEstimate.z, stabilizer.yaw, motion.deltaX/deltaY) so you can diagnose a small circular/looping drift ("toilet-bowl effect"):

  • Yaw creeping steadily while hovering → heading-estimate drift; the position hold corrects in a rotated frame and orbits. Power-cycle for a clean gyro start.
  • x/y tracing a circle rather than jittering around zero → same orbiting hold.
  • Flow counts near zero or erratic while the drone is clearly moving → poor surface/lighting for the deck (try a textured, matte, well-lit floor at ~0.71 m).

Safety notes

  • Place the drone on a flat, level surface before arming — the estimator and supervisor expect it level and stationary.
  • The Flow deck needs a textured floor and reasonable light to hold position; over a blank/reflective surface it can drift.
  • This client commands a stationary hover at the configured height (0.22.0 m) with no horizontal movement. Keep a hand near the emergency stop (spacebar) the first few flights.

Layout

File Responsibility
controller.py All flight logic + cflib link on one worker thread.
mission_client.py DearPyGui front-end; polls controller.snapshot() per frame.
requirements.txt Python dependencies.

controller.py has no UI dependencies, so the flight logic can be reviewed and driven independently of the GUI. The UI reads state through the thread-safe snapshot() each frame and issues commands (connect/arm/disarm/ emergency_stop) that the worker thread executes.

Description
No description provided
Readme 122 KiB
Languages
Python 100%