Firmware flight controllera trzeba testować warstwowo. Test funkcji filtra na komputerze nie potwierdza poprawnego transferu SPI, a udany lot nie dowodzi, że parser odrzuci uszkodzoną ramkę albo że licznik czasu przejdzie przez przepełnienie. Skuteczna strategia łączy szybkie testy czystej logiki, testy komponentów z kontrolowanym czasem, symulację SITL, stanowisko HIL oraz stopniowane próby sprzętowe. Każda warstwa odpowiada na inne pytanie i pozostawia artefakt pozwalający odtworzyć wynik.
Spis treści#
- Od wymagania do testu
- Piramida testów dla systemu wbudowanego
- Architektura podatna na testowanie
- Kontrolowany czas
- Testy matematyki i regulatorów
- Estymacja i filtry
- Sterowniki sensorów
- Parsery i protokoły
- Harmonogram i współbieżność
- Golden vectors i golden logs
- Testy własnościowe i metamorficzne
- Analiza statyczna i sanitizery
- SITL
- HIL i HITL
- Fault injection
- Zasilanie, reset i watchdog
- Continuous integration
- Pokrycie kodu
- Testy stanowiskowe i lotne
- Obsługa regresji
- Minimalna macierz testów
- Lista kontrolna
- Powiązane tematy
- Przypisy
Od wymagania do testu#
Test ma wartość wtedy, gdy wiadomo, jakie twierdzenie sprawdza. „Test IMU” jest zbyt szeroki. Lepsze wymagania mają postać:
- po odebraniu poprawnej ramki sterownik publikuje próbkę z czasem pomiaru;
- po trzech kolejnych błędach CRC zwiększa licznik, ale nie publikuje danych;
- brak nowej próbki przez 20 ms ustawia stan
stale; - regulator nigdy nie zwraca
NaNdla skończonych danych wejściowych; - po saturacji integrator nie narasta w kierunku nieosiągalnego momentu;
- parser nie odczytuje pamięci poza buforem dla dowolnej długości wejścia.
Do każdego wymagania warto przypisać:
| Pole | Znaczenie |
|---|---|
| identyfikator | trwały numer wymagania lub hazardu |
| poziom testu | unit, component, integration, SITL, HIL, bench, flight |
| bodziec | dane wejściowe i stan początkowy |
| oracle | oczekiwany wynik i tolerancja |
| negatywne przypadki | uszkodzone dane, timeout, zanik zasilania |
| artefakt | log, raport, seed losowania, wersja firmware |
Ta macierz ujawnia luki. Jeśli reakcja na brownout występuje tylko w planie lotu próbnego, błąd będzie drogi i słabo odtwarzalny. Jeśli sprawdza ją także test sterownika zasilania i HIL, lot potwierdza integrację, a nie odkrywa podstawową logikę.
Nie każde wymaganie musi mieć test na każdym poziomie. Czyste przeliczenie jednostek można wyczerpująco zbadać na hoście. Zachowanie po fizycznym zwarciu magistrali wymaga sprzętu. Ważne, aby decyzja była jawna.
Piramida testów dla systemu wbudowanego#
Praktyczny podział obejmuje:
- testy jednostkowe host — pojedyncze funkcje i klasy bez sprzętu;
- testy komponentu — moduł z atrapą zależności, np. sterownik IMU nad mockiem SPI;
- integracja host — kilka prawdziwych modułów, wirtualny czas i transport;
- test binarny target — ten sam kod skompilowany dla MCU lub płytki testowej;
- SITL — kompletny autopilot połączony z modelem pojazdu;
- HIL/HITL — fizyczny kontroler, symulowane sensory i dynamika;
- bench — prawdziwy sprzęt, bezpiecznie ograniczone aktuatory;
- flight test — stopniowane potwierdzenie zachowania całego systemu.
Dolne warstwy są szybkie i dokładnie wskazują źródło regresji. Górne obejmują więcej realnych interakcji, ale są wolniejsze, bardziej zmienne i trudniejsze w diagnozie. Duża liczba lotów nie zastępuje testów jednostkowych, tak jak pełne pokrycie funkcji matematycznych nie zastępuje próby sprzętowej.
W repozytorium należy rozdzielić zestawy według czasu i wymaganych zasobów. Programista powinien móc uruchomić szybkie testy lokalnie, a CI okresowo wykonywać symulacje długie, konfiguracje macierzowe i stanowiska sprzętowe.
Architektura podatna na testowanie#
Kod związany bezpośrednio z rejestrami, zegarem systemowym i globalnymi singletonami jest trudny do izolowania. Nie oznacza to, że firmware potrzebuje ciężkiego frameworka. Wystarczą małe interfejsy na granicach:
struct Clock {
virtual uint64_t monotonic_us() const = 0;
};
struct SpiBus {
virtual Result transfer(std::span<const uint8_t> tx,
std::span<uint8_t> rx) = 0;
};
W produkcji implementacje korzystają z timera i SPI MCU. W teście FakeClock oraz ScriptedSpi zwracają kontrolowane wartości. Logika sterownika nie musi wiedzieć, czy działa na STM32, czy w procesie testowym.
W systemach bez funkcji wirtualnych można wstrzykiwać tablicę wskaźników funkcji, szablon albo jawny obiekt HAL. Kluczowe są właściwości, nie mechanizm:
- zależności są widoczne w konstruktorze lub inicjalizacji;
- test nie podmienia losowo globalnych symboli;
- produkcyjna i testowa logika modułu jest ta sama;
- brak sprzętu nie wymaga
#ifdef TESTw każdym algorytmie; - warstwa HAL jest cienka i sama ma testy na docelowej płytce.
Stan modułu powinien dać się zresetować. Testy zależne od kolejności są źródłem fałszywych wyników. Jeśli parametry są globalne, framework scenariuszy musi zapisać ich wartości i odtworzyć je po zakończeniu, podobnie jak robią dojrzałe narzędzia AutoTest.
Kontrolowany czas#
Prawdziwe oczekiwanie sleep(20 ms) spowalnia zestaw i wprowadza losowość harmonogramu hosta. Test powinien przesuwać zegar wirtualny:
FakeClock clock;
Driver driver(clock, bus);
driver.poll();
clock.advance_us(19'999);
CHECK_FALSE(driver.is_stale());
clock.advance_us(1);
CHECK(driver.is_stale());
Trzeba rozróżnić:
- czas monotoniczny do timeoutów;
- czas pomiaru próbki;
- czas przybycia danych;
- czas UTC/GNSS używany do korelacji zewnętrznej.
Zmiana UTC nie może cofnąć deadline’u. Testy powinny wymusić skok czasu ściennego, przepełnienie licznika 32-bitowego i duży odstęp po pauzie debuggera. Typowa arytmetyka modulo dla liczników bez znaku działa poprawnie tylko wtedy, gdy porównywane okresy są krótsze niż połowa zakresu; tę granicę trzeba udokumentować i przetestować.
Wirtualny zegar pozwala odtworzyć jitter: próbki mogą przybywać w serii, z opóźnieniem lub poza kolejnością. Jest to niezbędne dla filtrów i detektorów freshness.
Testy matematyki i regulatorów#
Funkcje matematyczne są najlepszym kandydatem do dużej liczby szybkich testów. Zestaw dla regulatora PID powinien obejmować:
- zerowy błąd i zerowe wyjście;
- znany skok i analitycznie policzony pierwszy krok;
- różne
dt, w tym minimum, maksimum i wartość niepoprawną; - ograniczenie wyjścia dodatnie i ujemne;
- anti-windup w obu kierunkach;
- reset i bumpless transfer;
- zmianę nastaw w locie;
- wejścia
NaN,Infi denormalne zgodnie z przyjętą polityką; - bardzo długi czas pracy bez przepełnienia.
Porównanie floatów wymaga tolerancji wynikającej z problemu. Stałe 1e-6 nie pasuje do wszystkich wielkości. Można użyć sumy tolerancji bezwzględnej i względnej:
|actual - expected| <= atol + rtol * |expected|
Tolerancja nie może maskować niestabilności. Dla znormalizowanego kwaternionu odchyłka normy 1e-3 może być istotna, choć błąd pozycji w dużej symulacji wymaga innej skali.
Macierz i kwaternion trzeba testować pod kątem konwencji. Przykład: obrót jednostkowego wektora o 90° wokół osi ma znany wynik. Dodatkowo należy sprawdzić równoważność q i -q, normalizację po wielu iteracjach oraz zachowanie blisko osobliwości reprezentacji Eulera.
Estymacja i filtry#
Filtr komplementarny można testować sygnałami syntetycznymi: stałym położeniem, rampą, sinusoidą oraz impulsem szumu. Oczekiwaniem nie zawsze jest dokładna próbka wyjścia; częściej pasmo, opóźnienie, brak dryfu i ograniczona odpowiedź na impuls.
Dla EKF ważne są inwarianty:
- macierz kowariancji pozostaje symetryczna w tolerancji;
- wariancje diagonalne nie są ujemne;
- stan i kowariancja pozostają skończone;
- odrzucenie innowacji nie aktualizuje stanu tak jak pomiar przyjęty;
- powtarzanie predykcji z zerowym ruchem nie tworzy nieuzasadnionego ruchu;
- reset źródła pozycji zachowuje ciągłość wyjścia zgodnie z kontraktem.
Testy Monte Carlo z zapisanym seedem ujawniają przypadki graniczne. Każda porażka musi drukować seed oraz minimalny zestaw wejść, aby nie pozostała „losowa”. Wynik statystyczny, np. odsetek błędów w granicy kowariancji, wymaga liczby prób i przedziału akceptacji.
Golden log z prawdziwego lotu jest użyteczny do regresji, lecz nie jest nieomylnym wzorcem. Jeśli stara implementacja miała błąd, ślepe wymaganie identycznego wyniku go utrwala. Golden log należy powiązać z zaakceptowanymi cechami: końcowym błędem, liczbą odrzuceń, brakiem niefinitywnych stanów i czasem konwergencji.
Sterowniki sensorów#
Test sterownika z atrapą magistrali powinien sprawdzać dokładną sekwencję rejestrów. ScriptedSpi może wymagać:
write RESET
wait >= t_reset
read WHO_AM_I -> expected value
write ODR/RANGE
read back configuration
start sample transfer
Każdy krok powinien mieć wariant błędny: timeout, zły identyfikator, częściowy transfer, stale ustawiony bit resetu, zła wartość read-back oraz przerwanie w połowie inicjalizacji. Sterownik ma zwrócić rozróżnialny kod, a nie samo false.
Dane surowe testuje się wektorami obejmującymi:
- minimum i maksimum typu ze znakiem;
- właściwy endian;
- wartości blisko zera;
- współczynniki skali dla każdego zakresu;
- osie po transformacji montażowej;
- kompensację temperatury;
- status FIFO overflow i brak kompletnej ramki.
Sterownik DMA wymaga testu własności buforów: callback starego transferu po resecie nie może opublikować danych jako nowych. Pomaga numer generacji albo token transakcji.
Test na docelowej płytce powinien uzupełnić atrapę. Sprawdza elektryczny interfejs, piny, zegar magistrali, DMA, cache i zachowanie przerwań. Nie jest jednak dobrym miejscem do wyczerpującego generowania wszystkich ramek błędnych.
Parsery i protokoły#
Parser telemetrii pracuje na niezaufanym strumieniu. Minimalne przypadki to:
- poprawna ramka podana w jednym buforze;
- ta sama ramka po jednym bajcie;
- dwie ramki bez przerwy;
- śmieci przed znacznikiem początku;
- niepoprawna długość;
- zły CRC;
- ucięcie po każdym możliwym bajcie;
- maksymalna legalna długość;
- wartość długości większa od bufora;
- ponowna synchronizacja po błędzie;
- nieznany, lecz poprawnie opakowany typ wiadomości.
Fuzzer powinien wywoływać parser pod ASan/UBSan na hoście. Kryteriami są brak crasha, brak wyjścia poza bufor, ograniczony czas przetwarzania i spójny reset stanu. Corpus warto zasilić prawdziwymi ramkami MAVLink, GNSS, ESC i logów, ale fuzzer ma je mutować.
Obsługa CRC musi obejmować całą specyfikowaną ramkę i prawidłową kolejność bajtów. Test „CRC jest złe” nie wystarczy; potrzebny jest znany wektor z dokumentacji lub niezależnej implementacji.
Parser nie powinien dynamicznie alokować pamięci na podstawie długości z wejścia. Jeśli protokół dopuszcza duże pole, limit zasobów jest częścią kontraktu.
Harmonogram i współbieżność#
Testy schedulerów muszą kontrolować czas i kolejność zdarzeń. Sprawdzają:
- uruchomienie dokładnie na deadline lub po nim zgodnie z regułą;
- kilka zaległych okresów bez nieograniczonej pętli nadrabiania;
- priorytet zadań o wspólnym terminie;
- maksymalny budżet wykonania;
- przepełnienie licznika;
- pominięcie callbacku po dezaktywacji modułu;
- bezpieczną publikację snapshotu między producentem i konsumentem.
Wyścigów nie da się wiarygodnie wymuszać przez sleep. Lepsze są bariery testowe, kontrolowany executor albo model checking małego protokołu. Na hoście ThreadSanitizer może wykryć część data races, jeśli kod używa standardowych mechanizmów w sposób rozpoznawalny przez narzędzie.
Lock-free nie znaczy automatycznie poprawnie. Ring buffer powinien mieć testy przepełnienia, zawinięcia indeksu, producenta szybszego od konsumenta oraz właściwej kolejności pamięci. W systemie z DMA dochodzi ownership linii cache: test sprzętowy musi sprawdzić czyszczenie i invalidację.
Pomiar WCET na zwykłym komputerze nie jest reprezentatywny dla MCU. Test host może pilnować regresji algorytmicznej, natomiast cykle i jitter mierzy się na docelowym procesorze z właściwym cache, przerwaniami i kompilacją release.
Golden vectors i golden logs#
Golden vector to mały, ręcznie lub niezależnie wyznaczony zestaw wejście–wyjście. Jest dobry dla CRC, filtrów, transformacji współrzędnych i dekodowania rejestrów. Powinien być tekstowy lub mieć generator z udokumentowanym źródłem.
Golden log zawiera dłuższą sekwencję. Przydaje się do:
- odtwarzania estymatora;
- analizy zmiany filtra;
- regresji parsera;
- porównania decyzji failsafe;
- reprodukcji konkretnego błędu terenowego.
Plik musi mieć licencję/pochodzenie, wersję schematu, jednostki i sumę kontrolną. Dane prywatne, takie jak dokładna lokalizacja operatora lub miejsca lotu, należy anonimizować przed umieszczeniem w publicznym repozytorium.
Nie zawsze trzeba żądać identyczności bitowej. Zmiana biblioteki matematycznej może dać minimalnie inny wynik. Zamiast wielkiej tolerancji należy porównywać znaczące metryki i wskazać, które pola muszą być dokładne, np. decyzja stanu, liczba ramek i integralne identyfikatory.
Testy własnościowe i metamorficzne#
Test własnościowy generuje wiele danych i sprawdza inwariant. Przykłady:
decode(encode(x)) == xdla legalnej wiadomości;- alokator nie zwraca wartości poza ograniczeniami;
- normalizacja skończonego niezerowego kwaternionu daje normę bliską 1;
- filtr ze stałym wejściem zbiega do zakresu wokół tej wartości;
- zmiana znaku wszystkich elementów kwaternionu nie zmienia obrotu;
- parser zużywa albo zachowuje wejście zgodnie z kontraktem i zawsze robi postęp.
Test metamorficzny zna relację między wynikami, choć nie zna dokładnej odpowiedzi. Przesunięcie wszystkich timestampów o stałą nie powinno zmienić timeoutów liczonych z różnic. Obrót zarówno geometrii, jak i żądanego wektora powinien dać fizycznie równoważną alokację.
Generator musi respektować dziedzinę, ale część przypadków powinna celowo ją łamać. Narzędzie shrinkujące powinno redukować porażkę do małego przykładu. Seed i wersja generatora trafiają do raportu CI.
Analiza statyczna i sanitizery#
Kompilator powinien traktować ostrzeżenia jako błąd dla kodu projektu. Szczególnie ważne są:
- niejawne konwersje znaku i szerokości;
- przepełnienie i przesunięcia bitowe;
- użycie niezainicjalizowanej wartości;
- brakujący przypadek enum;
- shadowing zmiennej;
- format
printfniezgodny z typem; - funkcja oznaczona wynikiem wymagającym użycia.
Analizator statyczny znajduje ścieżki, których test nie uruchomił, ale generuje także false positives. Wyłączenie reguły powinno mieć lokalne uzasadnienie, nie globalne „uciszenie”.
Hostowe testy warto uruchamiać osobno z:
- AddressSanitizer — błędy pamięci i use-after-free;
- UndefinedBehaviorSanitizer — część niezdefiniowanych zachowań C/C++;
- ThreadSanitizer — wybrane wyścigi danych;
- narzędziem pomiaru wycieków, jeśli kod host używa sterty.
Nie wszystkie sanitizery dają się łączyć w jednym procesie. Kod docelowy może również zachowywać się inaczej ze względu na endian, wyrównanie, szerokość int i opcje FPU, dlatego potrzebna jest kompilacja cross oraz testy target.
SITL#
Software-in-the-loop uruchamia autopilot jako proces i łączy go z modelem dynamiki. Pozwala automatycznie badać misje, tryby, failsafe i protokoły bez ryzyka dla sprzętu. Dojrzałe projekty, takie jak PX4 i ArduPilot, włączają SITL i testy scenariuszy do procesu CI.
Scenariusz SITL powinien mieć:
- jednoznaczną konfigurację pojazdu i parametrów;
- zdefiniowany stan początkowy i seed środowiska;
- kryterium gotowości, nie stały
sleep; - sekwencję bodźców;
- asercje w trakcie, nie tylko końcową pozycję;
- timeout ścienny chroniący CI;
- zapis logu, konsoli i parametrów po porażce;
- pełne sprzątnięcie procesu i portów.
Przykład utraty GNSS nie powinien tylko oczekiwać „pojazd wylądował”. Należy sprawdzić czas detekcji, zmianę zdolności estymatora, wybraną akcję, brak oscylacji trybów i końcowy stan rozbrojenia.
Model symulacyjny ma ograniczenia. Idealny silnik nie ujawni opóźnienia ESC, a idealny GNSS nie pokaże multipath. Trzeba jawnie dodawać szum, latency, dropy i bias, lecz parametry powinny być kontrolowane i raportowane.
HIL i HITL#
Hardware-in-the-loop uruchamia rzeczywisty flight controller, a symulator dostarcza dane sensorów i odbiera wyjścia aktuatorów. Sprawdza:
- kompilację oraz konfigurację docelowej płytki;
- harmonogram, przerwania i obciążenie CPU;
- transporty UART/CAN/SPI emulowane przez interfejs stanowiska;
- kodowanie fizycznych wyjść;
- reset, boot i parametry w pamięci nieulotnej;
- zachowanie przy kontrolowanych opóźnieniach I/O.
HIL nie staje się automatycznie realistyczny. Jeśli sensory są wstrzykiwane przez specjalny, uproszczony kanał, nie testuje się rzeczywistego sterownika IMU. Stanowisko powinno dokumentować, które warstwy omija.
Synchronizacja czasu między symulatorem a kontrolerem jest częstym źródłem błędów. Należy mierzyć czas wysłania, odbioru i zastosowania próbki, a symulator nie powinien bez ograniczeń nadrabiać po pauzie.
HITL bywa używane jako termin szerszy lub zamienny. W dokumentacji projektu ważniejsze jest dokładne wskazanie elementów fizycznych i symulowanych niż sama etykieta.
Fault injection#
Wstrzykiwanie awarii powinno odbywać się na kilku granicach. Awaria „GNSS” może oznaczać:
- zatrzymanie ramek;
- stałe stare timestampy;
- błędny CRC;
- rosnącą niepewność;
- skok pozycji;
- wiarygodnie wyglądający, ale przesunięty pomiar;
- reset odbiornika;
- utratę tylko czasu lub tylko pozycji.
Macierz fault injection zawiera fazę lotu, czas wystąpienia, czas trwania, recovery i oczekiwaną reakcję. Testuje się również zbiegi: utrata RC podczas niskiej baterii albo degradacja pozycji w trakcie RTL.
Framework powinien potwierdzić, że fault rzeczywiście został wstrzyknięty. Inaczej test może przejść, bo polecenie nie zadziałało. W PX4 istnieją mechanizmy system failure injection służące do kontrolowanych testów; podobny interfejs w projekcie własnym powinien być niedostępny albo silnie ograniczony w normalnym buildzie produkcyjnym.
Wstrzyknięcie na poziomie wysokim testuje decyzję, ale omija detektor. Dlatego potrzebne są dwa scenariusze: sztuczne ustawienie stanu fault dla maszyny failsafe oraz realistyczne uszkodzenie strumienia danych dla całego toru.
Zasilanie, reset i watchdog#
Testy zasilania wymagają sprzętu oraz bezpiecznego sterowania źródłem. Obejmują:
- wolny spadek napięcia i próg brownout;
- krótki zapad o różnym czasie;
- wielokrotne odbicie zasilania;
- reset MCU bez resetu peryferiów;
- reset sensora bez resetu MCU;
- zanik w trakcie zapisu parametrów lub logu;
- restart wywołany watchdogiem w każdej fazie bootu.
Po restarcie system ma raportować przyczynę resetu, nie uzbrajać się samoczynnie i poprawnie traktować niedokończony zapis. Test powinien sprawdzić trwałość krytycznych parametrów oraz odrzucenie uszkodzonej kopii.
Watchdoga nie testuje się wyłącznie funkcją force_reset(). Należy celowo zatrzymać karmienie z powodu odpowiadającego realnemu faultowi i zmierzyć czas reakcji. Jeżeli każdy task może niezależnie karmić watchdog, zawieszenie krytycznej pętli może pozostać niewykryte; test ma to ujawnić.
Testy prądowe i brownout wykonuje się początkowo bez śmigieł. Załączenie dużego obciążenia na stanowisku musi mieć ograniczenie prądu, bezpiecznik i rejestrację napięcia w paśmie wystarczającym do zobaczenia krótkiego zapadu.
Continuous integration#
CI powinno dawać szybki sygnał i zachowywać dowody. Praktyczny podział:
- na każdy commit: format/lint, kompilacja, unit tests, szybkie parsowanie i sanitizery;
- na merge request: macierz kompilatorów/targetów, wybrane SITL, analiza statyczna;
- nocnie: długie scenariusze, fuzzing z budżetem czasu, Monte Carlo, pełna macierz pojazdów;
- okresowo lub przed wydaniem: stanowiska HIL, target tests, testy zasilania i regresja lotna.
Build musi być odtwarzalny: wersja kompilatora, zależności, opcje, submoduły i wygenerowane pliki są utrwalone. Artefakt testowany w HIL powinien być tym samym artefaktem, który przechodzi do wydania, a nie lokalną rekompilacją.
Po porażce zachowuje się:
- pełny log i stderr;
- binarium oraz identyfikator commitu;
- konfigurację parametrów;
- seed i dane wejściowe;
- wersję symulatora;
- core dump lub raport sanitizera;
- metryki czasu i zasobów.
Flaky test jest defektem. Automatyczne powtarzanie może zebrać dane diagnostyczne, ale nie powinno bez śladu zmieniać czerwonego wyniku w zielony. Należy mierzyć częstość niestabilności i wyznaczyć właściciela poprawki.
Pokrycie kodu#
Pokrycie linii pokazuje, czego na pewno nie wykonano, lecz nie dowodzi poprawności. Linia if (crc_ok) może być pokryta bez testu gałęzi błędnej. Warto mierzyć:
- line coverage;
- branch coverage;
- pokrycie stanów i przejść maszyn;
- pokrycie kombinacji faultów z analizy ryzyka;
- pokrycie wymagań, niezależne od kodu.
W systemach o wymaganiach formalnych spotyka się MC/DC, ale samo uruchomienie narzędzia nie czyni projektu certyfikowanym. Kryterium wymaga procesu, śledzenia wymagań i kwalifikacji narzędzi odpowiedniej do danego standardu.
Nie należy ustawiać jednego procentu dla całego repozytorium. Kod generatora strony, sterownik krytycznego wyjścia i eksperymentalny moduł analizy mają różne ryzyko. Sensowniejsze są progi per komponent oraz zasada, że nowa zmieniona gałąź musi mieć test.
Testy stanowiskowe i lotne#
Próby powinny rosnąć stopniowo:
- test elektroniki bez podłączonych aktuatorów;
- weryfikacja sygnałów na sztucznym obciążeniu;
- napęd bez śmigieł;
- zabezpieczone stanowisko napędowe;
- tether lub rama testowa, jeśli nie zaburza celu próby;
- krótki zawis w wydzielonej strefie;
- rozszerzanie obwiedni prędkości, masy i trybów;
- testy degradacji tylko z uprzednio zaakceptowaną analizą ryzyka.
Test lotny ma kartę z warunkami przerwania, rolami, pogodą, konfiguracją, wersją firmware i planem odzyskania. Nie zmienia się kilku istotnych zmiennych jednocześnie. Po każdej próbie log jest zabezpieczany, a konfiguracja eksportowana.
Nie wszystkie fault injection należy wykonywać w locie. Symulacja utraty silnika nie upoważnia do celowego wyłączenia go na platformie bez udowodnionej tolerancji. Najpierw sprawdza się model, HIL i stanowisko, a ryzyko lotu ocenia niezależnie.
Obsługa regresji#
Każdy naprawiony błąd powinien pozostawić najmniejszy test, który przed poprawką zawodził. Procedura:
- zabezpieczyć log i konfigurację zdarzenia;
- zredukować reprodukcję do najniższej możliwej warstwy;
- potwierdzić porażkę na starej wersji;
- dodać test z nazwą opisującą zachowanie;
- wprowadzić poprawkę;
- uruchomić pakiet lokalny, CI i odpowiedni scenariusz wyższy;
- powiązać test z numerem problemu.
Test, który przechodzi także przed poprawką, nie chroni przed regresją. Jeśli starego firmware nie da się uruchomić, należy przynajmniej wykazać przyczynę przez kontrolowaną mutację lub instrumentację.
Usunięcie testu ze względu na zmianę wymagań powinno pozostawić ślad decyzji. Cicha aktualizacja golden output do nowego wyniku może zaakceptować regresję.
Minimalna macierz testów#
| Obszar | Unit/component | SITL | HIL/target | Bench/flight |
|---|---|---|---|---|
| PID i filtry | wektory, granice, NaN | trajektorie i zakłócenia | timing target | odpowiedź fizyczna |
| IMU | rejestry, skalowanie, timeout | model szumu | prawdziwy bus/DMA | wibracje i temperatura |
| MAVLink/RC | parser, CRC, fuzz | utrata i opóźnienie linku | porty UART | zasięg tylko wg osobnej procedury |
| failsafe | tablica przejść | scenariusze złożone | reset i I/O | bezpieczne przypadki końcowe |
| alokacja | macierz, bounds, failure | dynamika pojazdu | kodowanie wyjść | mapowanie bez śmigieł, potem obwiednia |
| logowanie | ring buffer, korupcja | kompletność zdarzeń | SD/flash i reset | zapis pod obciążeniem |
| zasilanie | logika progów | model spadku | fizyczny brownout | próba bezpiecznego obciążenia |
Tabela jest początkiem. Konkretny projekt dodaje warianty płyt, typy ramek, wersje sensorów, systemy plików i konfiguracje kompilacji.
Lista kontrolna#
- [ ] Każde krytyczne wymaganie ma identyfikator i przypisany test.
- [ ] Logika biznesowa nie zależy bezpośrednio od globalnego zegara i rejestrów.
- [ ] Testy timeoutów używają kontrolowanego czasu.
- [ ] Filtry, regulatory i estymator mają testy granic oraz niefinitywnych danych.
- [ ] Parsery przechodzą testy fragmentacji, korupcji i fuzzing pod sanitizerem.
- [ ] Sterowniki sensorów mają skryptowane błędy magistrali.
- [ ] Przepełnienie liczników i buforów jest jawnie testowane.
- [ ] SITL zapisuje seed, parametry i log przy porażce.
- [ ] HIL dokumentuje warstwy rzeczywiste i symulowane.
- [ ] Fault injection potwierdza, że awaria faktycznie wystąpiła.
- [ ] Watchdog jest sprawdzany przez zatrzymanie realnej ścieżki karmienia.
- [ ] CI przechowuje dokładne binarium poddane testowi.
- [ ] Flaky tests są raportowane, nie ukrywane przez retry.
- [ ] Każda naprawiona regresja zostawia test reprodukujący.
- [ ] Próby z aktuatorami mają stopniowaną procedurę i kryteria przerwania.
Powiązane tematy#
- Symulacja SITL, HITL i HIL
- Failsafe jako maszyna stanów
- Watchdog w flight controllerze
- Sterownik IMU od zera
- Blackbox: pamięć i logowanie
- Harmonogram czasu rzeczywistego flight controllera
Przypisy#
- PX4 Guide, Testing and Continuous Integration, opis testów jednostkowych, SITL/HITL i infrastruktury CI, dostęp: 2026-08-15.
- ArduPilot Developer Wiki, The ArduPilot AutoTest Framework, architektura automatycznych testów i zarządzanie kontekstem, dostęp: 2026-08-15.
- ArduPilot Developer Wiki, Adding a new AutoTest test, praktyka tworzenia scenariuszy i asercji, dostęp: 2026-08-15.
- PX4 Guide, System Failure Injection, mechanizm kontrolowanego wstrzykiwania awarii, dostęp: 2026-08-15.
Ostatnia aktualizacja: 2026-08-15. Ostatnia weryfikacja źródeł: 2026-08-15.
Źródła z centralnego rejestru
- PX4: Platform Testing and Continuous Integration [dokumentacja projektu]
- ArduPilot: AutoTest Framework [dokumentacja projektu]
- ArduPilot: AutoTest Tests [dokumentacja projektu]
- PX4: System Failure Injection [dokumentacja projektu]
- PX4 Simulation [dokumentacja]