Ein Flug ist vorbei, die Drohne steht wieder am Boden — und trotzdem weiß niemand, was in den Sekunden davor wirklich passiert ist. Genau dafür schreibt der Flightcontroller mit: ArduPilot legt bei jedem Flug ein Dataflash-Log an, eine binäre Datei, in der alles steht, was der Copter gemessen und befohlen hat. Sensorwerte, Regler-Ausgänge, Moduswechsel, Textmeldungen — im Prinzip das ganze Innenleben, sauber mit Zeitstempel.
Wer Fehlersuche an einer Drohne betreibt, verbringt die meiste Zeit nicht am
Fluggerät, sondern in diesen Dateien. Dieser Artikel ist der Methodik-Teil der
Reihe: Wie ich ein .BIN-Log mit pymavlink öffne, wie ich es in Python
auswerte und wie ich aus dem Datenrauschen das eine Signal herausfinde, das die
Ursache verrät. Den Rahmen dazu liefert der
SITL-Artikel: erst simulieren,
dann fliegen — und das echte Log lesen, wenn es darauf ankommt.
Was ein Dataflash-Log ist
Ein Dataflash-Log ist eine Folge binärer Datensätze. Jeder Datensatz beginnt mit einem Kopf, der sagt, um welchen Nachrichtentyp es geht und wie lang der Rest ist. Danach kommen die eigentlichen Messwerte, typischerweise mehrmals pro Sekunde. Das Format ist selbstbeschreibend: Man muss die Feldnamen nicht raten, sie stecken im Log.
ArduPilot hat Dutzende solcher Nachrichten. Für die Fehlersuche sind eine Handvoll davon fast immer ausreichend:
| Message | Bedeutung | Interessante Felder |
|---|---|---|
ATT | Ist- und Soll-Lage | Roll, Pitch, Yaw, DesRoll, ErrRP |
RCOU | Servo-/Motorausgänge | C1–C4 (die vier Motoren) |
CTUN | Drossel und Schubschätzung | ThO (tatsächlich), ThH (Schwebe-Schätzung), ThI |
GPS | GPS-Fix | Lat, Lng, Spd, NSats, Status |
POS | Position | Lat, Lng, Alt |
MAG | Magnetometer | MagX, MagY, MagZ |
IMU | Roh-IMU | AccX/Y/Z, GyrX/Y/Z |
VIBE | Vibrationsniveau | VibeX/Y/Z |
BARO | Barometer | Alt, Press |
MODE | Moduswechsel | Mode, ModeNum |
EV | Ereignisse (Arm/Disarm/Land) | Id |
MSG | Textmeldungen des FC | Message |
PARM | Parameter-Snapshot | Name, Value |
Zwei Meldungen sind Metadaten und stehen am Anfang fast jedes Logs: PARM (die
Parameter, mit denen geflogen wurde) und MSG (Klartext, inklusive der Warntexte,
die der Copter zur Laufzeit ausgibt). Die sind oft der schnellste Einstieg.
Log mit pymavlink öffnen
mavutil.mavlink_connection() erkennt das Dataflash-Format an der Datei selbst —
kein Flag nötig. Danach liest recv_match() die Nachrichten in chronologischer
Reihenfolge aus. Ein type=[...]-Filter sorgt dafür, dass man nur das bekommt,
was man wirklich braucht:
from pymavlink import mavutil
m = mavutil.mavlink_connection("flight.BIN")
while True:
msg = m.recv_match(type=["ATT", "RCOU", "CTUN", "MODE"], blocking=False)
if msg is None: # blocking=False: None am Dateiende
break
t = msg.TimeUS / 1e6 # Zeitstempel in Sekunden
if msg.get_type() == "ATT":
print(f"{t:8.2f}s Roll={msg.Roll:+.1f} Pitch={msg.Pitch:+.1f} Yaw={msg.Yaw:+.1f}")
Die Feldnamen sind exakt die aus der Tabelle — man greift sie direkt als
Attribute ab (msg.Roll, msg.ThO, msg.C1). TimeUS ist der gemeinsame
Zeitstempel in Mikrosekunden und die Klammer, die alle Nachrichten
zusammenhält: Jede Größe wird über t auf dieselbe Achse gelegt.
Für die Weiterverarbeitung reicht ein CSV-Export, für die Optik ein Plot:
import csv
from pymavlink import mavutil
m = mavutil.mavlink_connection("flight.BIN")
with open("att.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["t", "roll", "pitch", "yaw"])
while True:
msg = m.recv_match(type="ATT", blocking=False)
if msg is None:
break
w.writerow([msg.TimeUS / 1e6, msg.Roll, msg.Pitch, msg.Yaw])
Mit matplotlib ist es dann ein Zweizeiler, jede Spalte gegen t zu zeichnen —
mehrere Größen übereinander in ein Diagramm, das ist das eigentliche Werkzeug der
Fehlersuche.
Falle
GPS.Lat/GPS.Lng: Bei pymavlink sind das Grad als Float, nicht die um1e7skalierte Ganzzahl aus MAVLink-Messages. Wer sie falsch behandelt, zieht die ganze Bahn auf 0 m zusammen und „sieht" einen stillstehenden Copter, obwohl er fliegt. Gegencheck:GPS.SpdundNSatsstehen separat im selben Log und sind plausibel.
Methodik: vom Rauschen zum Signal
Ein Log zeigt hundert Kurven. Die Kunst ist nicht, sie alle zu plotten, sondern die eine zu finden, die etwas bedeutet. Bei mir hat sich eine Reihenfolge von drei Schritten bewährt.
1. Zeitlich segmentieren. Zuerst die MODE-Timeline lesen und den Flug in
Fenster zerlegen: Start, Steigflug, Halten, Sinkflug, Landung. Greift man
Moduswechsel nicht ab, bewertet man schnell eine Handsteuer-Sequenz so, als wäre
sie ein automatischer Positions-Hold — und jagt ein Problem, das gar keines ist.
Jedes Fenster wird danach getrennt beurteilt, nie der ganze Flug am Stück.
2. Größen über die Zeit korrelieren. Die Motorausgänge (RCOU.C1–C4) gegen
die Lage (ATT.Roll, ATT.Pitch) und die Drossel (CTUN.ThO) legen. Erst im
Nebeneinander sieht man, ob eine Bewegung vom Regler gewollt war oder ob er ihr
hinterherläuft. Ein einzelner Wert ohne seinen Nachbarn ist wertlos.
3. Ausschläge und Sprünge finden. Die Differenz benachbarter Samples (oder ein gleitendes Fenster) hebt das hervor, was im Rohplot untergeht: kurze Spitzen, Phasenversatz, wachsende Schwingung. Auffälligkeiten werden danach im Kontext geprüft, nicht isoliert.
Das richtige Signal wählen ist der teuerste Teil. In einem konkreten Fall war
der erste Verdacht die Vibrationsgröße (VIBE) — und daneben eine
Geschwindigkeitsgröße. Beide waren untauglich: Sie sahen im guten wie im
schlechten Flug ähnlich aus und trennten die beiden Fälle nicht. Aussagekräftig
war erst die Oszillation der Lageregler — die Soll-/Ist-Lage (DesRoll gegen
Roll) und ihr Zusammenspiel mit den Motorausgängen. Die Frequenz und Phasenlage
dieser Schwingung unterschieden Problem- und Referenzflug deutlich.
Die Lehre ist verallgemeinerbar und schmerzhaft einfach: Eine Größe ist nur dann ein Beweis, wenn sie sich zwischen Gut und Schlecht tatsächlich ändert. Man nimmt nicht das offensichtlichste Item aus der Liste, sondern das, dessen Kurven in beiden Flügen auseinanderlaufen. Deshalb gehört zu jeder Auswertung immer ein Referenzflug — ein Log ohne das Problem. Ohne Kontrast gibt es kein Signal, nur ein Diagramm.
Praktische Helfer
Zwei Skripte nehmen einem die Handarbeit ab, ohne dass man Code für jeden Flug neu schreibt.
Logs vom FC ziehen. Ein Pull-Skript verbindet sich über USB-Serial mit dem
Flightcontroller und liest zuerst die Log-Liste über MAVLink: Die
LOG_ENTRY-Nachrichten tragen id, size und einen UTC-Zeitstempel pro Datei.
Die letzten N Logs werden dann per MAVFTP aus dem Verzeichnis /APM/LOGS/
heruntergeladen und lokal mit Zeitstempel und Log-ID benannt
(flight_<datum>_id<N>.bin). Das erhält die Zuordnung zum Flug. MAVFTP ist
langsam — je nach Log sind 30–50 KB/s realistisch, ein großes Log dauert also.
Batch-Auswertung. Ein zweites Skript läuft über alle Logs in einem Ordner und
gibt pro Flug eine Kennzeile aus: Dauer, Modus-Timeline, Arms/Disarms aus den
EV-Ereignissen (Id 10 = armed, 11 = disarmed), die Parameter aus dem
PARM-Snapshot und den Verlauf der Drossel (CTUN.ThH/ThO). Damit fällt der
Ausreißer auf, bevor man einen einzelnen Flug überhaupt von Hand öffnet — man
analysiert gezielt, statt jedes Log gleich tief zu durchlaufen.
Lessons Learned
- Das Log ist die Wahrheit, nicht die Erinnerung. „Hat komisch geruckelt" ist ein Symptom, kein Befund. Die Kurve zeigt, ob es der Regler, der Sensor oder der Pilot war.
- Eine Zahl ohne Kontext sagt nichts. Jede Größe gehört auf dieselbe Zeitachse zu den Nachbargrößen — Motoren gegen Lage gegen Drossel.
- Das richtige Signal findet man durch Kontrast. Nicht das offensichtlichste Feld greifen, sondern das, das Gut- und Schlecht-Flug unterscheidet. Referenzflug ist Pflicht.
- Erst segmentieren, dann urteilen. Moduswechsel zerlegen den Flug. Ein Positions-Hold ist nur im Positions-Hold beurteilbar.
- Einheiten und Skalierung prüfen, bevor man rechnet.
GPS.Lat/GPS.Lngsind Grad — die häufigste stille Fehlerquelle bei Flugbahn-Plots. - Die Metadaten zuerst lesen.
PARMundMSGstehen am Log-Anfang und beantworten oft schon die Frage, mit welchen Werten und welchen Warnungen geflogen wurde.
Checkliste
- Log vom FC gezogen, mit Datum und Log-ID benannt
-
PARM-Snapshot undMSG-Warnungen zuerst gelesen -
MODE-Timeline gelesen, Flug in Segmente zerlegt - Nur relevante Nachrichtentypen gefiltert, Zeitachse auf Sekunden
- Alle Größen auf dieselbe
TimeUS-Achse gelegt und gemeinsam geplottet - Referenzflug zum Vergleich herangezogen
- Das Signal gewählt, das beide Flüge unterscheidet — nicht das naheliegendste
- Auffälligkeit im Kontext geprüft, nicht isoliert
- Datenweg oder Ergebnis durch eine zweite Auswertung gegengeprüft