Autonomous drone horn-fly laser defense for cattle farms
Horn flies (Haematobia irritans) are among the costliest cattle pests, driving weight loss, reduced milk yield, and disease. Flyguard flies an autonomous patrol over a pasture, analyzes the video feed to detect and track horn flies on cattle, and neutralizes them with a gimbal-aimed laser — while treating cattle and humans as protected entities that are never targeted.
⚠️ A laser that kills a fly is a Class 3B/4 eye hazard.
python3.13 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # core + opencv + fastapi + pytest
flyguard selftest # validate config + interlock truth tables
flyguard sim # run the full closed loop (patrol -> detect -> safe-fire -> RTL)
flyguard sim --person # SAFETY DEMO: a person in frame -> firing fully inhibited
flyguard gcs # launch the Ground Control Station at http://127.0.0.1:8000Train the detector (needs pip install -e ".[ml]"):
flyguard synth --out data/synth --train 400 --val 80 # bootstrap a labeled dataset
flyguard train --data data/synth/data.yaml --epochs 50 # train YOLOv11
flyguard eval --weights runs/flyguard/train/weights/best.pt --data data/synth/data.yaml
flyguard export --weights runs/flyguard/train/weights/best.pt --format onnxThen point the detector at your model in the config:
detector: { backend: pytorch, model_path: runs/flyguard/train/weights/best.pt }| Subsystem | Module | Notes |
|---|---|---|
| Config (typed, validated, clamped) | flyguard/config.py |
safety ceilings enforced at load |
| Hardware abstraction | flyguard/hal/ |
sim + real (camera, flight, gimbal, laser) |
| Perception & targeting | flyguard/perception/ |
YOLO/mock detect, ByteTrack, no-fire mask, pixel→angle |
| Laser fire-control (safety core) | flyguard/laser/ |
default-deny interlocks, state machine, hash-chained audit |
| Flight & patrol | flyguard/flight/ |
geofence, lawnmower/perimeter, MAVSDK, failsafes |
| Orchestrator | flyguard/orchestrator/ |
top-level state machine + async engine |
| Training | flyguard/training/ |
synthesize → train → eval → export |
| Ground Control Station | flyguard/gcs/ |
FastAPI + dashboard, live feed, ARM/DISARM/E-STOP |
| Simulation | flyguard/sim/ |
synthetic pasture/flies, PX4 SITL launcher |
Firing is default-deny: every emission must pass all independent interlocks (armed + hardware key, inside geofence, no person in frame, target is a horn fly with sufficient confidence, clear of cattle head/eyes, range in NOHD-aware window, gimbal settled & beam-on-target, duty-cycle/thermal OK, fresh dead-man heartbeat, not E-STOP). Any interlock evaluation error fails safe. Every fire and refusal is written to a tamper-evident audit log.
Main drone: DJI Enterprise (e.g. Matrice 350 RTK / M30 / Mavic 3 Enterprise)
- NVIDIA Jetson Orin companion computer + a 2-axis gimbal and (gated) laser carried as a DJI Payload SDK (PSDK) payload via the aircraft's E-Port.
DJI aircraft don't speak MAVLink natively, so Flyguard's DJI integration takes one of two paths (set in config):
flight:
adapter: dji
dji_bridge_url: "udp://:14540" # a DJI->MAVLink bridge / PSDK onboard app endpoint- DJI→MAVLink bridge (recommended): a small PSDK onboard app (or open bridge) republishes DJI flight state as MAVLink; Flyguard reuses all its mission / geofence / failsafe logic unchanged against that endpoint.
- Onboard PSDK app: a Payload-SDK app on the Jetson commands DJI waypoint
missions directly (integration points in
flyguard/hal/flight.py:DjiFlight).
Video comes from the DJI payload camera (RTSP livestream / DJI Dock); set
camera.source: rtsp. PX4/Pixhawk is also supported (flight.adapter: mavsdk),
and flight.adapter: sim needs no hardware at all.
The Ground Control Station is a web app. Start it and open it in a browser:
flyguard gcs # built-in demo pasture
flyguard gcs --config config/farm.example.yaml # your farm
flyguard gcs --flies 8 --cattle 2 --person # demo the person-safety inhibitThen open http://127.0.0.1:8000 in your browser. The host/port come from the
gcs: block in your config:
gcs:
host: "127.0.0.1" # use "0.0.0.0" to reach it from another machine on the LAN
port: 8000What you get on the dashboard:
- Live annotated feed (
/video) — detections, track IDs, target crosshair, and a banner when firing is inhibited (person in frame / E-STOP). - Telemetry & patrol status, and the safety-interlock panel (all must be green to fire).
- Fire / abort log — every shot and every refusal, with the reason.
- ARM & PATROL / DISARM (RTL) / ■ E-STOP controls.
Nothing fires until you press ARM & PATROL. E-STOP latches and hard-offs the (simulated) laser from any state. If you set
host: 0.0.0.0, put it behind a trusted network — the controls are intentionally unauthenticated so the E-STOP is always one click away.
pytest # 60 tests incl. the safety-regression suiteMIT (software). The laser/aviation aspects carry separate legal obligations