Blackbox jest rejestratorem stanu systemu czasu rzeczywistego, a nie funkcją „zapisz kilka zmiennych do pliku”. Musi przejąć dane z wielu częstotliwości, nadać im jednoznaczną semantykę czasu, skompresować lub uporządkować strumień i zapisać go na nośniku o nieprzewidywalnych opóźnieniach — bez blokowania pętli sterowania. Dobry log pozwala odróżnić przyczynę od skutku: polecenie regulatora, rzeczywiście przydzielone wyjście, ruch platformy, fault sensora i reakcję failsafe.
Spis treści#
- Cele blackboxa
- Słownik sygnałów
- Architektura toru danych
- Pętla sterowania nie może czekać
- Budżet przepustowości
- Strumienie wieloczęstotliwościowe
- Timestamp i semantyka czasu
- Schemat, jednostki i ramy odniesienia
- Ramkowanie i odporne parsowanie
- Kompresja
- Format ULog
- Betaflight Blackbox
- Pamięć NOR flash
- Karta SD
- Bufory, DMA i cache
- Integralność i odporność na zanik zasilania
- Pre-trigger i zapis awaryjny
- Retencja i zapełnienie
- Co rejestrować
- Indeksowanie i pobieranie
- Prywatność i autentyczność
- Testowanie rejestratora
- Diagnostyka błędów logowania
- Lista projektowa
- Powiązane tematy
- Przypisy
Cele blackboxa#
Rejestrator może służyć kilku zadaniom, które mają różne wymagania:
- analiza stabilności i strojenie regulatora;
- diagnostyka wibracji, sensorów i estymatora;
- rekonstrukcja decyzji trybów oraz failsafe;
- ocena opóźnień pętli i deadline miss;
- kontrola zasilania, prądu i brownout;
- ustalenie sekwencji zdarzeń przed resetem lub wypadkiem;
- walidacja nowego firmware na golden logach;
- obsługa serwisowa floty.
Nie da się maksymalizować wszystkiego jednocześnie. Rejestracja surowej IMU z kilku sensorów wymaga dużego pasma, a wielogodzinny log misji potrzebuje kompresji i retencji. Rozwiązaniem są klasy strumieni i profile:
- strumień szybki do dynamiki i regulatora;
- strumień średni do estymatora, aktuatorów i linków;
- zdarzenia asynchroniczne z pełnym kontekstem;
- wolny stan systemu, parametry i health;
- mały zapis awaryjny w pamięci odpornej na nagły reset.
Profil nie powinien zmieniać znaczenia pola. Może zmieniać częstotliwość lub włączenie sygnału, ale nazwa, jednostka i frame pozostają stabilne dla danej wersji schematu.
Słownik sygnałów#
Przed projektowaniem binarnego formatu trzeba zbudować słownik. Dla każdego pola przechowuje się:
- trwałą nazwę i identyfikator;
- typ liczbowy i endian;
- jednostkę SI lub jawny brak jednostki;
- układ współrzędnych;
- skalę oraz offset, jeśli zapis jest całkowitoliczbowy;
- częstotliwość nominalną i sposób próbkowania;
- znaczenie timestampu;
- wartość nieważną lub osobny bit validity;
- wersję, w której pole dodano lub zmieniono.
Nazwy powinny opisywać etap przetwarzania. gyro_x jest niejednoznaczne: może oznaczać surowy rejestr, wartość po kalibracji, filtrze notch albo estymowaną prędkość kątową. Lepsze są np. imu0.gyro_raw, imu0.gyro_cal, rate.gyro_filtered z opisem.
W logu należy rozróżnić komendę i wynik:
torque_setpoint— czego zażądał regulator;actuator_unlimited— wynik przed ograniczeniami;actuator_applied— polecenie po limitach;torque_achieved— efekt przewidywany przez alokator;rpm_measured— odpowiedź telemetrii napędu.
Bez tego wysoki sygnał silnika można błędnie uznać za przyczynę ruchu, choć był reakcją na zewnętrzne zaburzenie.
Architektura toru danych#
Typowy tor ma postać:
producenci RT
-> snapshot / kolejki rekordów
-> ograniczony ring buffer RAM
-> encoder i ramkowanie
-> kolejka bloków I/O
-> sterownik flash/SD
-> indeks pliku / katalog sesji
Producenci działają w przerwaniach i taskach o różnych priorytetach. Nie powinni formatować tekstu ani wykonywać operacji systemu plików. Publikują mały rekord do bufora o znanym maksymalnym czasie.
Encoder może działać w tasku o niższym priorytecie. Grupuje rekordy, dodaje timestampy, kompresuje i tworzy bloki z CRC. Warstwa I/O zapisuje gotowe, wyrównane bloki. Rozdzielenie pozwala testować każdą część oraz zmienić nośnik bez ingerowania w pętlę regulatora.
Każda kolejka jest ograniczona. „Nieograniczony bufor” na systemie z małą pamięcią tylko przesuwa awarię do sterty. Polityka przepełnienia musi wskazywać, które rekordy można odrzucić i jakie liczniki pozostają w logu.
Pętla sterowania nie może czekać#
Zapis na kartę może trwać znacznie dłużej niż okres pętli. Nawet jeśli średnia szybkość jest wysoka, ogon rozkładu latency bywa długi z powodu kasowania, wear levellingu, aktualizacji metadanych systemu plików lub wewnętrznej pracy kontrolera karty.
Ścieżka czasu rzeczywistego powinna wykonywać operację o ograniczonym czasie:
if (!log_queue.try_push(record)) {
counters.dropped_fast++;
}
Nie może czekać na mutex trzymany podczas I/O. Jeśli wielu producentów używa wspólnej kolejki, potrzebny jest protokół o znanej blokadzie albo osobne bufory SPSC. Zadanie logowania może zostać pominięte, lecz regulator nie powinien przekroczyć deadline’u przez kartę SD.
Odrzucanie danych także wymaga projektu. Możliwe reguły:
- zdarzenia fault i zmiany stanu mają wyższy priorytet niż periodyczny status;
- przy przeciążeniu redukuje się częstotliwość strumienia szybkiego;
- zachowuje się co najmniej ostatnią próbkę i licznik pominiętych;
- krytyczny rekord awaryjny trafia do osobnego małego bufora;
- nie blokuje się pętli „żeby log był kompletny”.
Każda luka powinna być widoczna przez numer sekwencyjny, licznik dropów albo rekord discontinuity. Brak informacji o brakach prowadzi do fałszywych wniosków o częstotliwości sygnału.
Budżet przepustowości#
Surowy budżet można oszacować:
R = sum(f_i * payload_i) + overhead
Przykład: trójosiowy gyro i akcelerometr jako sześć int16 przy 8 kHz to 96 kB/s bez timestampów i nagłówków. Dwa IMU podwajają strumień. Floaty, osobny timestamp każdej próbki i wyrównanie mogą łatwo zwiększyć wynik kilkukrotnie.
Budżet powinien zawierać:
- nominalną i maksymalną częstotliwość każdego producenta;
- rozmiar po ramkowaniu;
- najgorszy przypadek kompresji, nie tylko średni;
- burst po odblokowaniu FIFO;
- metadane i indeks;
- margines na długie opóźnienie nośnika;
- równoczesne pobieranie logu, jeśli jest dozwolone.
Wymagany rozmiar bufora zależy od maksymalnego tolerowanego postoju nośnika:
buffer >= R_peak * t_stall + burst_margin
Jeśli log generuje 300 kB/s, a karta może zatrzymać się na 200 ms, sam bufor absorpcji potrzebuje co najmniej 60 kB plus margines. Pomiar latency konkretnego nośnika i systemu plików jest konieczny; sama klasa prędkości nie opisuje zachowania małych zapisów.
Strumienie wieloczęstotliwościowe#
Zapisywanie wszystkiego w rytmie jednej pętli marnuje pasmo i tworzy fałszywe duplikaty. IMU może działać w kHz, regulator w setkach Hz, GNSS w kilku–kilkudziesięciu Hz, a stan baterii wolniej.
Dwa podstawowe modele to:
- push on update — źródło emituje rekord po nowej próbce;
- snapshot periodic — logger pobiera spójny zestaw w określonym rytmie.
Push zachowuje naturalny czas danych, lecz miesza typy rekordów i wymaga sprawnego ramkowania. Snapshot ułatwia analizę kolumnową, ale wartość może być stara. Dlatego snapshot musi przechowywać age albo źródłowy timestamp.
Downsampling powinien być świadomy sygnału. Wybieranie co ósmej próbki bez filtra antyaliasingowego może zmienić wysokoczęstotliwościową wibrację w fałszywy wolniejszy sygnał. Dla diagnostyki drgań trzeba logować dane przed określonym filtrem lub stosować właściwe decymowanie.
Zdarzenia, takie jak zmiana trybu, reset EKF czy aktywacja failsafe, nie mogą czekać do następnego wolnego snapshotu. Otrzymują własny timestamp i payload z przyczyną.
Timestamp i semantyka czasu#
Najważniejszym czasem analizy sterowania jest czas monotoniczny systemu. Nie cofa się po korekcie UTC i umożliwia obliczanie odstępów. Log może przechowywać także mapowanie monotonic–UTC/GNSS, ale synchronizacja zewnętrzna jest osobnym zdarzeniem.
Dla próbki sensora istnieją co najmniej trzy czasy:
t_measure— chwila fizycznego pomiaru lub środek ekspozycji;t_arrival— odebranie w MCU;t_log— zakodowanie rekordu.
Do estymacji i analizy latency potrzebne są pierwsze dwa. Sam czas zapisu na kartę jest mało użyteczny i zawiera jitter loggera.
Jeśli sensor podaje licznik własny, trzeba rejestrować model synchronizacji i wykrywać reset/wrap. Nie wolno jednorazowo traktować licznika po resecie jako czasu z przeszłości. Przy każdym discontinuity powstaje rekord zmiany epoki.
Delta timestamp oszczędza miejsce, ale wymaga okresowych absolutnych punktów synchronizacji. Po utracie lub korupcji jednej ramki parser nie powinien błędnie przesunąć całej reszty sesji.
Schemat, jednostki i ramy odniesienia#
Format sam opisujący się ułatwia kompatybilność narzędzi. Na początku sesji lub przy pierwszym użyciu typu zapisuje się definicje pól. Oprócz nich potrzebne są:
- identyfikator builda/commit;
- wersja firmware i sprzętu;
- typ ramy i geometria aktuatorów;
- parametry kalibracji i konfiguracji;
- wersja schematu;
- boot reason i identyfikator sesji;
- informacja o endian i typach.
Jednostki powinny być kanoniczne. Jeśli gyro jest w rad/s, nie należy zmieniać go w kolejnej wersji na deg/s pod tą samą nazwą. Zmiana semantyki wymaga nowego pola albo wersji formatu z migracją parsera.
Układy współrzędnych są równie istotne: FRD/FLU/NED/ENU, sensor frame, body frame i earth frame muszą być oznaczone. Pole accel_x bez frame nie nadaje się do porównania z estymatorem.
Parametry warto zapisać na początku i po każdej zmianie. Sam końcowy dump nie pokaże, że operator zmienił gain w połowie próby.
Ramkowanie i odporne parsowanie#
Rekord binarny zwykle zawiera typ, długość, payload i opcjonalny CRC. Długość pozwala pominąć nieznany typ, a CRC wykrywa korupcję bloku. Format musi określać maksymalną długość i endian.
Parser traktuje log jak niezaufane dane. Kolejność walidacji:
- sprawdzić, czy dostępny jest minimalny nagłówek;
- odczytać długość bez niezdefiniowanego wyrównania;
- porównać ją z limitem formatu i pozostałym buforem;
- dopiero potem uzyskać widok payloadu;
- zweryfikować CRC i typ;
- nieznany poprawny rekord pominąć zgodnie z długością;
- raportować offset błędu oraz próbę resynchronizacji.
Znacznik magic może pomóc po korupcji, ale przypadkowy ciąg bajtów może wyglądać jak nagłówek. Resynchronizacja powinna wymagać kilku zgodnych cech: magic, legalnej długości, znanego typu lub poprawnego CRC.
Nie należy mapować obcej struktury przez rzutowanie wskaźnika C. Padding, endian i alignment różnią się między platformami. Bezpieczniej dekodować pola jawnie.
Kompresja#
Kompresja zmniejsza pasmo, ale zwiększa koszt CPU i wrażliwość na utratę. W logach czasu rzeczywistego sprawdzają się:
- delta między kolejnymi wartościami;
- zmienna długość liczb całkowitych;
- okresowe pełne klatki i klatki predykcyjne;
- bitmaski pól zmienionych;
- kwantyzacja do ustalonej rozdzielczości;
- kompresja całych bloków w tasku tła, jeśli budżet pozwala.
Najgorszy przypadek musi zmieścić się w buforze. Losowy, zaszumiony sygnał może kompresować się słabo. Encoder nie może nagle alokować większej pamięci albo blokować pętli.
Klatki zależne od poprzednich wymagają punktów resynchronizacji. Po uszkodzeniu klatki predykcyjnej parser odrzuca dane tylko do następnej pełnej klatki, a nie do końca pliku.
Kwantyzację dobiera się do celu. Rozdzielczość musi być znacznie lepsza od najmniejszej analizowanej zmiany, ale nie ma sensu zapisywać szumu jako 64-bit float. Słownik sygnałów przechowuje skalę, aby narzędzie odzyskało jednostki fizyczne.
Format ULog#
ULog jest formatem używanym w ekosystemie PX4. Oficjalna specyfikacja rozdziela nagłówek, sekcję definicji i sekcję danych. Wiadomości mają wspólny nagłówek z rozmiarem oraz typem, dzięki czemu parser może iterować po rekordach i obsługiwać rozszerzenia.
Definicje opisują formaty, informacje i parametry. Sekcja danych zawiera subskrypcje strumieni, próbki, log messages, synchronizację oraz inne rekordy. Format przewiduje także dane dołączane po zakończeniu normalnej sekcji, co jest przydatne w określonych scenariuszach zapisu awaryjnego.
Projekt własnego formatu powinien skorzystać z doświadczeń ULog:
- oddzielać metadane od rekordów szybkich;
- wersjonować definicje;
- pozwalać pominąć nieznany typ;
- ograniczać długości przed alokacją;
- zachowywać kompatybilność parsera;
- testować pliki ucięte w dowolnym miejscu.
Nie należy kopiować uproszczonego opisu zamiast korzystać z aktualnej oficjalnej specyfikacji. Szczegóły wersji i flag mogą się zmieniać; implementacja ma być związana z konkretną wersją dokumentu i test corpus.
Betaflight Blackbox#
Betaflight Blackbox jest zoptymalizowany pod szybką analizę dynamiki multirotora. Dokumentacja wewnętrzna opisuje m.in. klatki I oraz P: pełniejsze klatki odniesienia i klatki przewidywane/delta. Taki model dobrze kompresuje sygnały zmieniające się stopniowo, a okresowa klatka pełna ogranicza propagację błędu.
Dla konstruktora ważne są trzy wnioski:
- częstotliwość logowania powinna być związana z pętlą i celem analizy;
- predykcja musi być identycznie zdefiniowana w encoderze i parserze;
- utrata ramki wymaga jawnej resynchronizacji.
Nagłówki sesji zawierają informacje potrzebne do interpretacji pól. Narzędzie nie powinno zakładać jednej stałej listy kolumn dla wszystkich wersji firmware.
Format blackboxa konkretnego projektu nie jest automatycznie właściwy dla innej architektury. UAV z kilkoma IMU, kontrolą pozycji i redundantnymi lane potrzebuje szerszego modelu zdarzeń i metadanych niż typowy log wyścigowego FC.
Pamięć NOR flash#
Zewnętrzna SPI/QSPI NOR flash ma przewidywalniejszy interfejs niż karta, ale szczególną fizykę:
- programowanie zmienia bity typowo z
1na0; - powrót do
1wymaga skasowania całego sektora; - programowanie odbywa się stronami i nie powinno przekraczać granicy strony;
- kasowanie trwa znacznie dłużej niż odczyt;
- liczba cykli kasowania jest ograniczona;
- po komendzie trzeba sprawdzać status busy/error.
Logger powinien kasować sektory z wyprzedzeniem, a nie w chwili, gdy szybki bufor jest pełny. Ring log dzieli pamięć na bloki z numerem generacji i sekwencji. Po restarcie skanuje nagłówki, aby znaleźć najnowszą spójną sesję.
Minimalny blok odporny na zanik może zawierać:
magic | version | generation | sequence | payload_length | payload | crc | commit
Commit zapisuje się na końcu operacją, która zmienia wcześniej skasowane bity. Brak poprawnego commit oznacza blok niedokończony. CRC chroni przed częściowym programowaniem i korupcją.
Wear levelling nie musi być skomplikowany, ale zapis nie może ciągle kasować jednego sektora katalogowego. Rotacja nagłówków i liczników rozkłada zużycie. Parametry producenta dotyczą określonych warunków; projekt powinien liczyć przewidywaną liczbę cykli dla profilu lotów.
Karta SD#
Karta zapewnia dużą pojemność i łatwy transfer, lecz zawiera własny kontroler flash. Host nie kontroluje bezpośrednio kasowania i wear levellingu. Średnia szybkość sekwencyjna może być wysoka, a pojedynczy zapis mieć duży latency.
Praktyczne zasady:
- używać dużych, wyrównanych zapisów zamiast wielu małych;
- prealokować plik, jeśli system plików i biblioteka to umożliwiają;
- ograniczać częste aktualizacje katalogu i metadanych;
- mierzyć maksymalne opóźnienia na serii reprezentatywnych kart;
- wykrywać wyjęcie, write protect i błąd inicjalizacji;
- nie wykonywać
fsyncw pętli regulatora; - zamykać sesję poprawnie przy kontrolowanym rozbrojeniu, ale tolerować brak close.
Prealokacja zmniejsza fragmentację i częstotliwość rozszerzania pliku. Nie eliminuje wszystkich wewnętrznych pauz karty. Bufor RAM nadal jest konieczny.
System plików może pozostać spójny, a ostatni fragment pliku być ucięty. Format rekordów powinien pozwolić odzyskać wszystkie kompletne bloki przed ogonem. Narzędzie nie może odrzucać całej sesji tylko dlatego, że nie ma formalnego rekordu końca.
Hot removal wymaga unieważnienia uchwytu i kontrolowanego ponownego montowania. Automatyczne kontynuowanie zapisu do starego obiektu po ponownym włożeniu innej karty grozi korupcją.
Bufory, DMA i cache#
Double buffering pozwala jednocześnie napełniać jeden blok i przesyłać drugi przez DMA. Stany bufora powinny być jawne:
FREE -> FILLING -> READY -> IN_FLIGHT -> FREE
Callback DMA zmienia tylko bufor odpowiadający aktywnej transakcji. Numer generacji zapobiega zaakceptowaniu spóźnionego callbacku po resecie sterownika.
W MCU z data cache przed DMA transmit należy wyczyścić odpowiednie linie, a po DMA receive unieważnić je zgodnie z wymaganiami architektury. Adres i długość mogą wymagać wyrównania do linii cache. Błąd objawia się jako stare lub częściowo aktualne dane i bywa zależny od optymalizacji.
Bufor używany przez DMA nie może być na stosie funkcji, która zakończy się przed transferem. Nie może też zostać zmodyfikowany do czasu potwierdzenia ownership. Te reguły powinny być zawarte w API, nie tylko w komentarzu.
Kolejka bloków powinna raportować high-water mark. Dzięki temu można dobrać pamięć na podstawie rzeczywistych lotów i testów stall, a nie wyłącznie intuicji.
Integralność i odporność na zanik zasilania#
CRC wykrywa przypadkową korupcję, ale nie zastępuje transakcji. Dobrze zaprojektowany blok ma:
- numer sekwencyjny;
- długość ograniczoną limitem;
- CRC nagłówka/payloadu;
- znacznik commit zapisany na końcu;
- opcjonalny numer sesji i generacji.
Po uruchomieniu recovery skanuje tylko do pierwszego niedokończonego bloku w danej generacji albo szuka kolejnego wiarygodnego punktu synchronizacji. Nie interpretuje skasowanej pamięci 0xFF jako rekordu o ogromnej długości.
W systemie plików można grupować rekordy w niezależne bloki z CRC. Ucięty ostatni blok zostaje pominięty, wcześniejsze pozostają dostępne. Okresowe checkpointy indeksu przyspieszają otwieranie dużego pliku, ale ich brak nie może uniemożliwić skanu.
Parametry krytyczne i blackbox mają inne wymagania. Nie należy zapisywać trwałych parametrów w tym samym pierścieniu bez osobnej transakcji i wersjonowania. Zużycie loggera nie może zniszczyć konfiguracji startowej.
Test zaniku zasilania powinien odcinać energię w wielu offsetach operacji, a po każdym restarcie parser sprawdza wszystkie kompletne rekordy. Symulowanie wyjątku w funkcji write nie ujawnia wszystkich zachowań fizycznego flash.
Pre-trigger i zapis awaryjny#
Awaria jest wykrywana po rozpoczęciu problemu. Aby zachować kontekst sprzed zdarzenia, rejestrator może stale utrzymywać w RAM pierścień ostatnich sekund. Po triggerze zamraża część pre-trigger i kontynuuje zapis przez określony czas.
Triggerami mogą być:
- aktywacja krytycznego failsafe;
- reset estymatora;
- przekroczenie drgań;
- watchdog early warning;
- napięcie poniżej progu;
- ręczny marker operatora.
Brownout może pozostawić bardzo mało czasu. Zapis pełnego bufora na SD jest wtedy nierealny. Lepszy jest mały rekord awaryjny w wewnętrznej/backup SRAM lub przygotowanej stronie flash: przyczyna, ostatni stan, liczniki, napięcie i kilka najważniejszych timestampów.
Early warning watchdoga może zapisać kontekst, ale handler nie powinien próbować naprawiać złożonego systemu ani wykonywać nieograniczonego I/O. Dane muszą być wcześniej przygotowane w formie snapshotu, który kopiuje się w ograniczonym czasie.
Po restarcie rekord awaryjny jest dołączany do nowej sesji wraz z flagą, że pochodzi z poprzedniego bootu. Dopiero po potwierdzeniu bezpiecznego skopiowania można go wyczyścić.
Retencja i zapełnienie#
Polityka po zapełnieniu nośnika zależy od zastosowania:
- zatrzymanie logowania i wyraźny status;
- usuwanie najstarszych zamkniętych sesji;
- pierścień o stałej pojemności;
- rezerwacja miejsca wyłącznie na krytyczne zdarzenia;
- zakaz uzbrojenia, jeśli log jest wymagany procesowo.
Nie należy usuwać aktywnego pliku ani jedynej sesji oznaczonej jako chroniona. Retencja potrzebuje metadanych: czas, rozmiar, poprawne zamknięcie, priorytet i status pobrania.
Próg ostrzegawczy powinien pojawić się przed całkowitym zapełnieniem. Operator musi znać zarówno wolne miejsce, jak i przewidywany czas logowania dla aktywnego profilu.
Automatyczne kasowanie danych ma konsekwencje operacyjne i prawne. W systemie flotowym może wymagać zatwierdzonej polityki, a nie dowolnego progu w firmware.
Co rejestrować#
Minimalny praktyczny zestaw dla zaawansowanego FC:
Timing#
- monotonic timestamp i numer cyklu;
- rzeczywisty
dtpętli; - czas wykonania krytycznych tasków;
- deadline miss, overrun i high-water stosu;
- reset reason i watchdog status.
Sensory i estymacja#
- surowa oraz filtrowana IMU z identyfikatorem urządzenia;
- temperatura, clipping, FIFO overflow i age;
- GNSS z dokładnością, fix i timestampem;
- barometr, magnetometr i airspeed;
- innowacje, wariancje, test ratios i reset counters EKF;
- wybór primary lane i przyczynę przełączenia.
Sterowanie#
- setpoint orientacji/rates/pozycji;
- pomiar i błąd regulatora;
- składniki P, I, D i feedforward;
- żądany moment/ciąg;
- wyjście alokatora przed i po ograniczeniu;
- sterowanie osiągnięte i maska saturacji;
- RPM, prąd i status ESC.
Stan systemu#
- tryb, arming state i przejścia;
- aktywne fault/failsafe z przyczyną i priorytetem;
- health/freshness źródeł;
- link RC/GCS: age, RSSI/LQ, liczba błędów;
- geofence i wymagane capability;
- zmiany parametrów.
Zasilanie#
- napięcie na istotnych szynach;
- prąd, energia i minimalne napięcie;
- status regulatora power-good;
- brownout flags i reset cause;
- temperatura baterii/ESC, jeśli dostępna.
Częstotliwość każdego pola wynika z zjawiska. Napięcie mierzone raz na sekundę nie ujawni zapadu 5 ms; trzeba użyć szybkiego ADC, hardware min capture albo osobnego fault latch.
Indeksowanie i pobieranie#
Sesja powinna mieć stabilny identyfikator niezależny od nazwy pliku. Indeks może zawierać:
- boot/session UUID;
- czas monotoniczny startu i opcjonalny UTC;
- wersję firmware i sprzętu;
- długość i rozmiar;
- poprawność zamknięcia;
- liczbę dropów i błędów I/O;
- przyczynę zakończenia;
- skrót kryptograficzny po zamknięciu, jeśli potrzebny.
Pobieranie przez telemetrię konkuruje o CPU i pamięć. Najbezpieczniej udostępniać zamknięte sesje po rozbrojeniu. Jeśli odczyt w locie jest wymagany, ma limit pasma i niższy priorytet, a sterownik nośnika musi obsługiwać arbitraż bez blokowania zapisu.
Protokół pobierania powinien obsługiwać wznowienie, offsety i sumę bloków. Zerwanie linku nie powinno wymagać przesłania wielogigabajtowego pliku od początku.
Narzędzie desktopowe powinno wyświetlać ostrzeżenia o lukach, nieznanym schemacie i uszkodzonych blokach. Eksport CSV traci część typów i metadanych; plik oryginalny pozostaje źródłem.
Prywatność i autentyczność#
Log może ujawniać dokładne trasy, położenie operatora, identyfikatory urządzeń i konfigurację infrastruktury. Publiczne udostępnienie wymaga przeglądu oraz anonimizacji. Proste przesunięcie współrzędnych musi zachować relacje, jeśli log ma nadal służyć testom estymacji.
CRC nie potwierdza autentyczności, bo każdy może przeliczyć CRC po modyfikacji. Jeśli integralność dowodowa lub serwisowa jest wymaganiem, można stosować podpis sesji lub uwierzytelniony łańcuch bloków, z bezpiecznie przechowywanym kluczem.
Szyfrowanie danych w spoczynku zwiększa koszt i komplikuje odzysk po awarii. Klucze, nonce i rotacja muszą być projektowane systemowo. Nie należy tworzyć własnego algorytmu kryptograficznego.
Mechanizmy bezpieczeństwa nie mogą blokować krytycznej pętli. Podpis całego pliku można wykonać po zamknięciu; per-block authentication wymaga zmierzonego budżetu CPU.
Testowanie rejestratora#
Rejestrator wymaga testów na poziomie rekordów, plików i fizycznego nośnika.
Unit/component#
- encode/decode dla każdego typu;
- znane wektory endian i CRC;
- minimalna i maksymalna długość;
- ucięcie pliku po każdym bajcie przykładowego bloku;
- korupcja każdego pola nagłówka;
- nieznany typ oraz wersja;
- wrap indeksu ring buffera;
- przepełnienie kolejki i dokładne liczniki dropów;
- pełne oraz predykcyjne klatki po resynchronizacji;
NaN, infinities i skrajne liczby.
Fuzzing parsera#
Parser uruchamia się pod ASan/UBSan na corpusie prawdziwych logów. Warunki: brak crasha, ograniczony czas, brak nieograniczonej alokacji i postęp offsetu. Każdy znaleziony przypadek zostaje testem regresji.
Fault injection I/O#
Atrapa nośnika zwraca częściowy zapis, timeout, busy, błąd CRC, removal i ponowne zamontowanie. Test potwierdza, że pętla producenta nadal dotrzymuje budżetu, a status błędu trafia do telemetrii.
Power-cut#
Na stanowisku z programowalnym zasilaniem odcina się energię w pseudolosowych momentach zapisu. Po każdym cyklu urządzenie startuje, skanuje nośnik i udostępnia wszystkie kompletne bloki bez samoczynnego uzbrojenia. Seed/offset odcięcia zapisuje kontroler stanowiska, nie testowane urządzenie.
Performance#
Generator tworzy maksymalny profil strumienia oraz bursty. Mierzy się high-water kolejki, dropy, najdłuższy stall i wpływ na jitter pętli. Test trwa wystarczająco długo, aby karta wykonała wewnętrzne operacje zarządzania flash.
Diagnostyka błędów logowania#
| Objaw | Prawdopodobne klasy przyczyn |
|---|---|
| regularne luki co stały okres | flush/metadane FS, zbyt mały bufor, task periodyczny |
| losowe duże luki | ogon latency karty, błędy I/O, priorytet schedulera |
| uszkodzony tylko ostatni blok | normalny power loss bez commit albo zły recovery |
| stare fragmenty w nowym bloku | cache/DMA ownership lub niepełne nadpisanie bufora |
| log ma poprawne dane, zły czas | pomieszanie t_measure, arrival i log time |
| analiza drgań pokazuje fałszywe pasmo | decymacja bez filtra antyaliasingowego |
| parser zużywa ogromną pamięć | długość z pliku użyta przed walidacją |
| watchdog podczas zapisu | blokujące I/O lub zbyt długi handler filesystemu |
| znikające eventy przy przeciążeniu | wspólna kolejka bez priorytetu i licznika dropów |
| niemożliwa interpretacja po aktualizacji | brak wersjonowanego schematu/jednostek |
Diagnostyka loggera sama potrzebuje małego kanału. Liczniki bytes_written, records_dropped, max_queue_depth, io_errors, max_write_latency i last_error powinny być dostępne w telemetrii oraz zapisane na końcu sesji, jeśli to możliwe.
Pomiar wpływu na pętlę wykonuje się z loggerem włączonym i wyłączonym na tej samej konfiguracji release. Interesuje nie tylko średnie CPU, ale maksymalny jitter i deadline misses.
Lista projektowa#
- [ ] Każde pole ma nazwę, jednostkę, frame, typ i semantykę timestampu.
- [ ] Producenci RT używają operacji o ograniczonym czasie i nie wykonują I/O.
- [ ] Wszystkie kolejki mają limit, politykę przepełnienia i liczniki dropów.
- [ ] Budżet uwzględnia najgorszą kompresję oraz stall nośnika.
- [ ] Downsampling szybkich sygnałów ma filtr antyaliasingowy.
- [ ] Format ma długość, wersję, numery sekwencji i punkty resynchronizacji.
- [ ] Parser sprawdza limity przed odczytem i alokacją.
- [ ] Bloki mają CRC i jednoznaczny znacznik zakończonego zapisu.
- [ ] NOR flash kasuje sektory z wyprzedzeniem i rozkłada zużycie.
- [ ] Zapis SD jest blokowy/prealokowany i izolowany od pętli sterowania.
- [ ] DMA ma jawny ownership, wyrównanie i obsługę cache.
- [ ] Ucięty ostatni blok nie niszczy wcześniejszej sesji.
- [ ] Istnieje mały zapis awaryjny dla resetu/brownout.
- [ ] Log zawiera build ID, parametry, geometrię i przyczynę resetu.
- [ ] Testy obejmują fuzzing, częściowe zapisy i fizyczne power-cut.
- [ ] Telemetria raportuje dropy, high-water i błędy nośnika.
Powiązane tematy#
- Diagnostyka logów i wibracji
- Harmonogram czasu rzeczywistego flight controllera
- Watchdog w flight controllerze
- Brownout w UAV
- Testy jednostkowe firmware UAV
- Failsafe jako maszyna stanów
Przypisy#
- PX4 Guide, ULog File Format, oficjalna specyfikacja nagłówka, definicji i wiadomości danych, dostęp: 2026-08-15.
- Betaflight, Blackbox Internals, dokumentacja klatek, predykcji i kodowania rejestratora, dostęp: 2026-08-15.
- Betaflight, Blackbox flight data recorder, dokumentacja użytkowa konfiguracji i analizy logów, dostęp: 2026-08-15.
- ArduPilot, Onboard Logging and Analysis, dokumentacja pokładowych logów DataFlash i ich analizy, dostęp: 2026-08-15.
Ostatnia aktualizacja: 2026-08-15. Ostatnia weryfikacja źródeł: 2026-08-15.
Źródła z centralnego rejestru
- PX4: ULog File Format [specyfikacja formatu]
- Betaflight: Blackbox logging internals [dokumentacja projektu]
- Betaflight: Blackbox logging internals [dokumentacja]
- ArduPilot: Downloading and Analyzing Data Logs [dokumentacja]