129 lines
7.7 KiB
Markdown
129 lines
7.7 KiB
Markdown
# WireClaw — Drone d'Inspection Thermique Autonome
|
|
|
|
## Contexte du projet
|
|
WireClaw est un système de pilotage de drone en langage naturel.
|
|
L'opérateur donne des instructions en français (texte ou voix),
|
|
un LLM les interprète et génère des commandes MAVLink vers ArduPilot.
|
|
|
|
## Architecture
|
|
- **Jetson Orin Nano 8Go** : station sol, héberge WireClaw + SITL
|
|
- **ESP32 DevKitV4** : relais WiFi↔UART (firmware PlatformIO sur Windows)
|
|
- **Pi Zero 2W** : IP 192.168.1.132 — flux vidéo H.264 UDP → Jetson (câblé, arrêté pour l'instant)
|
|
- **Matek H743** : à venir — contrôleur de vol ArduPilot réel
|
|
|
|
## Renommage du dossier (20 juillet 2026)
|
|
|
|
Ce dossier s'appelait `~/wireclaw`, renommé en `~/wireclaw-jetson` pour clarté : le repo `wireclaw-pizero` (config du drone) est maintenant aussi cloné localement sur le Jetson (voir ci-dessous), donc les deux noms de dossier doivent être distincts.
|
|
|
|
**Le dépôt distant Gitea reste `wireclaw.git`** (inchangé) — seul le nom du dossier local sur le Jetson a changé. Ne pas confondre les deux : `git remote -v` continuera d'afficher `wireclaw.git`, c'est normal.
|
|
|
|
Services systemd mis à jour en conséquence (`WorkingDirectory`/`ExecStart` pointent vers `/home/nicoboy/wireclaw-jetson`) :
|
|
- `wireclaw.service` (tests SITL ArduPilot, carte MAV+GPS)
|
|
- `receive-cam.service` (réception vidéo/YOLO/MJPEG)
|
|
|
|
## Organisation des deux repos sur le Jetson
|
|
|
|
Depuis le 20 juillet 2026, les deux dépôts du projet sont clonés localement sur le Jetson, pour permettre au script `switch_band.sh` (voir ci-dessous) de lire les deux profils de config radio sans dépendre du réseau vers un PC distant :
|
|
|
|
- `~/wireclaw-jetson/` — ce repo, code Jetson (réception vidéo, config radio ground station)
|
|
- `~/wireclaw-pizero/` — code Pi Zero (émission caméra, config radio drone). **Ce repo reste normalement édité depuis le PC habituel** — le clone Jetson sert uniquement de source pour le déploiement des profils radio, pas de zone d'édition principale. Toujours faire `git pull` avant toute édition, où que ce soit, pour éviter une divergence entre les deux clones.
|
|
|
|
## Profils radio versionnés (5GHz / 2.4GHz)
|
|
|
|
Deux profils complets et testés existent dans `config/` de chaque repo :
|
|
- `wifibroadcast_gs_5ghz.cfg` / `wifibroadcast_drone_5ghz.cfg` — canal 149, bande opérationnelle par défaut du projet
|
|
- `wifibroadcast_gs_24ghz.cfg` / `wifibroadcast_drone_24ghz.cfg` — canal 6, **usage diagnostic/comparatif uniquement** : confirmé sujet à interférence domestique sévère (freeze disparaît en mode auto Freebox, revient sur canal chevauchant — cf 20260720_wireclaw_avancement_v17.md §6)
|
|
|
|
Bascule via `scripts/switch_band.sh 5ghz` ou `scripts/switch_band.sh 2.4ghz` (voir le script pour le détail — copie directe des profils, pas de patch, backup unique `.bak_last` écrasé à chaque bascule).
|
|
|
|
## Stack logicielle
|
|
- Python 3.10, asyncio
|
|
- MAVSDK Python (udp://:14551)
|
|
- pymavlink (udpin:0.0.0.0:14552)
|
|
- Gemini 2.0 Flash API (clé dans .env, jamais en dur)
|
|
- MAVProxy en daemon (ports TCP:5760, UDP:14550/14551/14552)
|
|
- ArduPilot SITL (binaire ARM64 ~/ardupilot/build/sitl/bin/arducopter)
|
|
- PyTorch 2.8.0 + CUDA 12.6 (wheel Jetson : pypi.jetson-ai-lab.io/jp6/cu126, GPU Orin)
|
|
- ultralytics 8.4.62 (YOLOv8), numpy 1.26.4 (≥2 incompatible avec torch 2.8), cv2 4.5.4 système
|
|
|
|
## Fichiers principaux
|
|
- `wireclaw_core.py` : cerveau principal, boucle de commande
|
|
- `config.py` : configuration (lit .env via python-dotenv)
|
|
- `.env` : secrets — NE JAMAIS MODIFIER NI COMMITTER
|
|
- `start.sh` : lance ArduCopter + MAVProxy + WireClaw automatiquement
|
|
- `sitl_params.parm` : paramètres SITL (batterie désactivée)
|
|
- `receive_cam.py` : réception H.264 UDP port 5600 → inférence YOLOv8n → MJPEG annoté port 5601
|
|
|
|
## Ports réseau
|
|
- 5760 TCP : ArduCopter ↔ MAVProxy
|
|
- 14550 UDP : MAVProxy output standard + ESP32 source
|
|
- 14551 UDP : MAVSDK (WireClaw) + heartbeats ESP32
|
|
- 14552 UDP : pymavlink (WireClaw)
|
|
- 5600 UDP : flux H.264 RTP entrant depuis Pi Zero (caméra OV5647) — ouvert via `ufw allow 5600/udp` (2026-07-18, précaution). Fonctionne aujourd'hui via un relais loopback (`wfb-ng`/`wfb_rx` réinjecte le flux décodé sur `127.0.0.1:5600`), qui contourne de fait le filtrage sur l'interface externe : dépendance fragile, à surveiller si le pipeline de réception change (ex. flux direct depuis `gs-wfb` sans relais loopback)
|
|
- 5601 TCP : MJPEG annoté YOLOv8 exposé par receive_cam.py — ouvert via `ufw allow` (règle `5601/tcp`)
|
|
- 5602 UDP : sideband stats Pi Zero (résolution, fps, temp, CPU) vers receive_cam.py, via tunnel WFB-NG (`10.5.0.2` → `10.5.0.1` sur l'interface `gs-wfb`) — ouvert via `ufw allow 5602/udp` (2026-07-18). **Ce port était resté fermé par défaut (policy DROP d'ufw) alors que le code sideband existait depuis un moment** : l'overlay stats semblait "figé" ou absent car les paquets réels du Pi Zero étaient droppés par le pare-feu avant d'atteindre le socket applicatif, malgré un socket/threading fonctionnels par ailleurs (`tcpdump` voit toujours le trafic sur l'interface, quel que soit son sort côté netfilter — ne pas se fier à `tcpdump` seul pour valider qu'un flux atteint l'appli)
|
|
|
|
## Réseau local
|
|
- Jetson Ethernet : 192.168.1.84
|
|
- Jetson WiFi : 192.168.1.143 (utilisé pour ESP32)
|
|
- ESP32 WiFi : 192.168.1.122
|
|
|
|
## Règles importantes
|
|
- Ne jamais modifier `.env` ni `credentials.h` (secrets WiFi/API)
|
|
- Toujours tester via `~/wireclaw-jetson/start.sh` avant de commiter
|
|
- Les commandes MAVLink passent toutes par `execute_command()` dans wireclaw_core.py
|
|
- L'état armement est synchronisé en temps réel via `monitor_armed()` (tâche de fond)
|
|
- `MAV_CMD_DO_ORBIT` (commande 34) non supportée en SITL → fallback waypoints circulaires 16 points
|
|
- La batterie SITL est désactivée (BATT_MONITOR=0) pour éviter les failsafes en simulation
|
|
|
|
## Commandes de session
|
|
```bash
|
|
# Démarrer tout
|
|
~/wireclaw-jetson/start.sh
|
|
|
|
# Vérifier SITL actif
|
|
ps aux | grep -E "arducopter|mavproxy" | grep -v grep
|
|
|
|
# Vérifier WiFi Jetson actif
|
|
nmcli dev status | grep wifi
|
|
|
|
# Tuer Hermes si actif (occupe port 14550)
|
|
pkill -f hermes
|
|
|
|
# Lancer la réception caméra Pi Zero (quand Pi Zero actif)
|
|
python3 ~/wireclaw-jetson/receive_cam.py
|
|
|
|
# Vérifier MJPEG stream caméra
|
|
curl -s --max-time 2 http://localhost:5601/ | head -1
|
|
|
|
# Pipeline GStreamer brute (debug)
|
|
gst-launch-1.0 udpsrc port=5600 ! application/x-rtp,payload=96 ! rtph264depay ! avdec_h264 ! videoconvert ! fakesink
|
|
|
|
# Git commit + push
|
|
git add . && git commit -m "message" && git push origin master
|
|
```
|
|
|
|
## Commandes WireClaw validées
|
|
- `takeoff Xm` → décollage altitude X mètres
|
|
- `land` / `atterris` → atterrissage
|
|
- `rtl` / `rentre` → retour à la base
|
|
- `hover` → maintien de position
|
|
- `goto` → navigation vers coordonnées (calcul depuis description naturelle)
|
|
- `status` → position, altitude, batterie, mode, armement
|
|
- `orbit` → orbite native (fallback waypoints en SITL)
|
|
|
|
## Prochaines étapes
|
|
1. ~~Réception Pi Zero 2W + caméra OV5647~~ ✅ Pi Zero IP 192.168.1.132, reçu et testé
|
|
2. Câblage UART ESP32 ↔ Pi Zero (GPIO17→GPIO15, GPIO16←GPIO14, GND)
|
|
3. ~~Préparation réception flux H.264 UDP Jetson~~ ✅ receive_cam.py opérationnel, MJPEG 5601 accessible
|
|
4. ~~YOLOv8 intégré dans receive_cam.py~~ ✅ yolov8n.pt, CUDA Orin, mode synthétique actif en attendant Pi Zero
|
|
5. **Prochaine étape : Pi Zero émet GStreamer UDP H.264 vers 192.168.1.84:5600**
|
|
6. Intégrer MJPEG 5601 dans l'interface web (flux vidéo + commandes)
|
|
7. Matek H743 + ArduPilot réel (remplace SITL)
|
|
8. SkyDroid C12 (caméra thermique + gimbal 3 axes, 117g)
|
|
9. Whisper local (transcription vocale)
|
|
|
|
## Gitea
|
|
- WireClaw Python : git.syoul.fr/nicoboy/wireclaw
|
|
- Firmware ESP32 : git.syoul.fr/nicoboy/wireclaw-esp32
|