Inspiration
Ground control stations are keyboard-and-mouse hell. A real drone operator at a flight line has one hand on an RC transmitter, eyes on the aircraft, and wind in the microphone — the last thing they can do is alt-tab through menus to plan a survey. We fly actual hexacopters and quadcopters at Stratofirma, and every field session made the same point: the missing interface for fleet operations is conversation. So we built STADO — a voice agent wired into a production ground control station, where "both drones take off to 30 meters and survey a 300 meter area" is a complete, executable mission order.
What it does
Hold push-to-talk and speak. Qwen3.5-Omni-Plus-Realtime hears the raw audio (no separate ASR stage), decides among 38 flight and mission tools — takeoff, land, orbit, goto, multi-drone survey planning with zone splitting and separation corridors, formation flight, target tracking, geofenced altitude overrides — and the GCS executes them over MAVLink against two PX4 drones. Qwen speaks the outcome, and speaks up proactively when a takeoff completes or a battery runs low. Qwen3.7-Plus handles vision: open-vocabulary target grounding ("track the red truck" seeds the onboard tracker), scene description, license-plate reads, and satellite-tile parcel detection for the survey planner. Qwen3.7-Max writes the end-of-flight mission report.
The underlying GCS is real and field-flown — it flies a physical hexacopter over a SIYI datalink and a quadcopter through a Jetson Orin DDS bridge. The public demo wraps that exact production code around two PX4 SITL drones so anyone can fly the fleet from a browser: https://stado.sfautonomy.com/.
One voice round-trip, end to end:
🎙 PTT ──► /ws/voice ──► Qwen Realtime ──► tool call (1 of 38)
│
SAFETY INTERLOCKS ◄───┘
Ready-for-Flight · max-alt ceiling · home-alt gate
│ pass
MAVLink ──► PX4 (×2 drones)
│ ack + telemetry
🔊 spoken outcome ◄── Qwen Realtime ◄── function_call_output
How we built it
- Voice — the browser streams mic PCM16@16 kHz over a WebSocket to a FastAPI backend, which bridges it to Qwen Realtime's native WebSocket API (
wss://…/api-ws/v1/realtime). Manual turn detection (turn_detection: null+ buffer commit on PTT release) maps one-to-one onto push-to-talk — the correct UX for command-and-control, because an open mic near a flying drone is a hazard. Barge-in viaresponse.cancel. Qwen's audio contract (16 kHz up / 24 kHz down) matches the browser pipeline exactly, so the frontend does zero transcoding. - One tool surface, three models — the 38 tool schemas are declared once and shared by the realtime session, the REST API, and the field system. Vision and reasoning calls go through Model Studio's OpenAI-compatible endpoint with the same
DASHSCOPE_API_KEY. One key, one cloud, the entire model surface. - The demo container — two PX4 SITL instances, each in its own Gazebo world (shared physics starves the sensor watchdog and PX4 refuses to arm — learned the hard way), plus the backend and nginx, all on one Alibaba Cloud ECS instance in Singapore with a Caddy sidecar for auto-HTTPS. One-command deploy in
alibaba/. - The trust boundary — every model-initiated action passes deterministic gates before a single MAVLink byte leaves the dispatcher. The model proposes; the gates dispose.
Challenges we ran into
- Realtime models narrate instead of acting. Qwen would sometimes say "taking off now" without emitting the tool call. Fix: a post-response auto-nudge — if the reply describes an action but no
function_callarrived, the bridge injects a system turn demanding the call. Tool-call reliability went from "usually" to "reliably". - A real-flight incident made us paranoid. During field testing, a flight command dispatched that the operator had not intended. The result is the Ready-for-Flight gate: a per-vehicle, human-armed software interlock. Voice takeoff is refused — politely, out loud — until the operator arms the pill in the UI. It was validated end-to-end in a live field test the next day.
- Altitude references lie. A barometer-drift failure mode (home/EKF altitude off by meters) produced a "stuck armed, zero climb" aircraft in the field. The GCS now runs a home-alt sanity gate and a TAKEOFF-mode-first arming sequence that survives drift — the same patch fixes a PX4 SITL edge case in the demo.
- Edge-cloud voice latency over field WiFi pushed us to keep every per-frame loop off the cloud: tracking and state estimation run on the Jetson at the edge; Qwen handles intent, orchestration, and speech.
Accomplishments we're proud of
- Sub-500 ms voice round-trip, browser to Qwen to MAVLink and back.
- Three Qwen models composed into one agent — realtime voice, vision grounding, mission reasoning — behind a single tool schema.
- The safety architecture is flight-tested, not theoretical: the Ready-for-Flight gate refused an unauthorized voice takeoff in a real field test.
- 384 backend tests, MIT-licensed, and a live demo any judge can fly right now.
What we learned
Realtime speech models drift into narration under long sessions — the engineering is in detecting and correcting it, not in the inference. And the interesting problem in edge agents isn't "put an LLM on a robot"; it's the seam: what must stay at the edge (reflexes, tracking, failsafes), what belongs in the cloud (language, orchestration, open-vocabulary perception), and the deterministic dispatcher that sits between them and trusts neither.
What's next
Hardening the Jetson DDS bridge (orbit-command relay, honest home-position acks), formation-flight polish, and pilot deployments with inspection and security operators in India and the GCC.
Built With
- alibaba-cloud
- caddy
- docker
- fastapi
- gazebo
- google-maps
- jetson
- mavlink
- opencv
- px4
- python
- qwen
- qwen-3.5-omni
- qwen-3.7-max
- qwen-3.7-plus
- qwen-omni
- qwen-realtime
- react
- ros2
- tailwindcss
- typescript
- vite
- websockets
Log in or sign up for Devpost to join the conversation.