Beim Sprühen will man sehen, was die Kamera sieht: Sitzt die Düse über der richtigen Dachzeile, ist der Grünbelag wirklich weg, wohin fliegt das Gerät gerade? Ein Boden-Monitor mit Livebild beantwortet das schneller als jedes Log und ruhiger als ein Blick nach oben.
Die naheliegende Lösung — einfach eine zweite Kamera oder einen zweiten Encoder nur für das Livebild — ist die falsche. Ein zusätzlicher Encode frisst CPU, die auf dem Companion-Rechner für die Aufnahme gebraucht wird, und im schlimmsten Fall ruckelt dann genau das, was eigentlich zählt. Der Trick ist, den bereits kodierten Strom abzugreifen, statt einen zweiten zu erzeugen.
Der Kern: ein Strom, zwei Abnehmer
Der Flight-Recorder nimmt beim Armen automatisch Video auf: 1080p, 30 fps, H.264. Den fertig kodierten Strom schreibe ich in eine Datei — als fragmentiertes MP4, das auch nach einem harten Abbruch (Akku ab, Crash) noch abspielbar ist.
Statt für das Livebild noch einmal zu kodieren, hängt am Encoder-Ausgang ein Tee. Derselbe kodierte Frame geht an zwei Ziele:
- an die Datei — die Aufnahme, der kritische Pfad
- an den Netzwerk-Sender — das Livebild, unkritisches Beiwerk
Weil beide Abnehmer denselben bereits fertigen Strom bekommen, kostet das Livebild keinen zusätzlichen CPU-Encode. Die Kamera arbeitet ihre 30 fps für die Aufnahme; der Stream ist nur eine Kopie der fertigen Frames.
Warum der Tee nicht blockieren darf
Die entscheidende Frage war nicht „wie bekomme ich das Bild ins Netz", sondern
„wie stelle ich sicher, dass das Netz das Bild niemals kaputt macht". Der
Kamera-Encoder-Stack (hier: picamera2 mit libav) teilt sich intern einen
Thread und ein Lock — alle Ausgänge werden seriell durch dieselbe
outputframe-Funktion geschoben. Ein Ausgang, der dort blockiert, hält alle
anderen an. Ein zweiter Kamera-Output mit blockierendem Netz-I/O wäre also
genau die Falle: Bei einem WLAN-Einbruch würde die Aufnahme stehen.
Deshalb übergibt der Tee die Frames an eine kleine Warteschlange und kehrt sofort zurück. Netz-I/O und Versand laufen in eigenen Threads. Stockt der Netzwerk-Sender, füllt sich nur die Warteschlange; läuft sie über, werden für den Stream Frames verworfen und am nächsten Keyframe neu aufgesetzt. Die Aufnahme merkt davon nichts.
An das Armen gekoppelt
Es gibt nur dann ein Bild, wenn die Drohne gearmt ist. Der Grund ist banal: Aufnahme und Stream hängen am selben Encoder. Solange nicht aufgenommen wird, produziert der Encoder keine Frames — also gibt es nichts zu streamen. Vor dem Armen ist das Fenster schwarz, nach dem Disarmen bleibt das letzte Bild stehen.
Das ist Absicht, kein Fehler. Man spart sich einen Stream, der läuft, egal ob geflogen wird, und die Zustände „fliegt" und „bildet ab" sind derselbe.
Boden-Seite: Bild anzeigen
Pi und Boden-Rechner müssen im selben WLAN sein. Am Flugfeld ist das ein Handy-Hotspot: der Pi verbindet sich automatisch, den Laptop verbindet man manuell mit demselben Hotspot.
# 1. Erreichbarkeit prüfen (IP des Pi am Hotspot ablesen oder auf dem Pi: hostname -I)
ping -c 3 <PI-IP>
# 2. Livebild anzeigen — geringste Verzögerung
ffplay -fflags nobuffer -flags low_delay tcp://<PI-IP>:8554
ffplay gehört zu ffmpeg (sudo apt install ffmpeg). Vollbild mit f.
Wer eine GUI mag, nimmt VLC: Medien → Netzwerkstream öffnen →
tcp://<PI-IP>:8554.
Der Player darf vor dem Armen gestartet werden — er wartet dann einfach, bis Daten kommen. Auch ein Neustart mitten im Flug ist unkritisch: Das Bild steht nach etwa einer bis zwei Sekunden wieder, am nächsten Keyframe.
Latenz und Robustheit
TCP liefert lückenlos und in Reihenfolge — dafür retransmittiert es bei Paketverlust und kann an einer schwachen Funkstrecke in die Länge gehen. Für reines Monitoring ist ein Standbild von ein bis zwei Sekunden Verzögerung völlig ausreichend; es geht um „sitzt die Düse richtig", nicht um Video-Streaming in Studioqualität.
Weil die Aufnahme unabhängig vom Stream läuft, darf die Robustheit des Streams sogar schlechter sein als die der Aufnahme — das ist der richtige Trade-off. Reißt der WLAN-Client ab oder hängt der Player, wirft der Pi den Zuschauer raus und nimmt weiter auf. Im Bodentest lief die Aufnahme mit 30,03 fps lückenlos durch einen erzwungenen Client-Kill und WLAN-Stau hindurch.
Telemetrie läuft daneben
Video und Telemetrie sind getrennte Ströme. Die MAVLink-Telemetrie (Drohne ↔ Bodenstation, UDP) fließt parallel auf einem eigenen Port und hat mit dem Videostrom nichts zu tun. Beide bewusst nicht vermischen: Der Videokanal bekommt einen reinen Bildstrom, die Telemetrie ihren eigenen UDP-Fluss. So bleiben es zwei unabhängige Fehlerdomänen — fällt das Video aus, sieht man immer noch die Flugdaten, und umgekehrt.
Troubleshooting
Der Pi-Name wird nicht aufgelöst (mDNS zickt):
IP direkt verwenden. Auf dem Pi selbst hostname -I liefert die IPv4-Adresse.
Bekannte Einschränkung: Der Pi lauscht nur auf IPv4. Löst der Laptop
.local-Namen als IPv6 auf, schlägt der Connect ohne Fehlermeldung fehl →
immer die IPv4-Adresse als Fallback probieren.
Player verbindet, aber kein Bild:
Ist die Drohne überhaupt gearmt? Ohne Aufnahme kein Stream — das ist das
Design, nicht der Fehler. Danach die Sender-Ausgabe prüfen: Steht dort, dass der
Listener läuft? Ist der Port belegt (ss -tlnp | grep 8554), findet der Sender
keinen Platz — dann den Blockierer suchen oder den Pi neu starten.
Bild friert mitten im Flug ein: WLAN-Reichweite überschritten oder Hotspot-Aussetzer. Player neu starten, verbindet neu, Bild nach ~1 s. Die Aufnahme läuft in jedem Fall weiter.
Bild ruckelt stark / Puffer-Überlauf im Log: Die Funkstrecke kommt nicht hinterher. Näher an die Drohne, Hotspot höher halten. Für die Aufnahme kein Handlungsbedarf.
Lessons Learned
- Ein Encode für zwei Abnehmer. Wer den fertigen H.264-Strom per Tee abgreift, spart sich den zweiten Encoder und dessen CPU-Last.
- Der Stream darf nie am Schicksal der Aufnahme hängen. Der Tee muss nicht-blockierend sein — genau deshalb kann ein WLAN-Abriss die Datei nicht beschädigen.
- Stream an das Armen koppeln. Ein Bild gibt es nur, wenn aufgenommen wird. Das ist die einfachste mögliche Zustandslogik.
- Video und Telemetrie trennen. Zwei Ströme, zwei Ports, zwei Fehlerdomänen — nicht in einen Kanal multiplexen.
- Robustheit des Streams ist zweitrangig. Die kommt aus der Aufnahme, nicht aus dem Livebild. Wer das verwechselt, baut die falsche Seite stabil.
Checkliste
- Pi und Boden-Laptop im selben WLAN (am Flugfeld: Handy-Hotspot)
- ffmpeg/
ffplayinstalliert (sudo apt install ffmpeg) -
pingauf die Pi-IPv4-Adresse erfolgreich - Player auf
tcp://<PI-IP>:8554gestartet (darf vor dem Armen laufen) - Drohne armen → Bild erscheint nach ~1–2 s
- Vollbild mit
f; nach dem Disarmen schwarzes Bild = normal - Danach prüfen, dass die Aufnahme auf dem Pi geschrieben wurde