MAVLink definiuje sposób serializacji wiadomości i zestaw mikroserwisów dla systemów autonomicznych. Nie określa medium radiowego, nie gwarantuje dostarczenia i nie jest szyfrowanym tunelem. Te same ramki mogą płynąć przez UART, USB, UDP, TCP albo modem, lecz przepustowość, opóźnienie, kolejki i model bezpieczeństwa każdej ścieżki są inne.

System, komponent i kanał#

Pole sysid identyfikuje system, zwykle pojazd, a compid komponent: autopilota, kamerę, gimbal lub komputer pokładowy. Para nie jest kryptograficzną tożsamością. Dwa urządzenia z tym samym identyfikatorem tworzą niejednoznaczność routingu, a przypadkowy nadawca może podszyć się pod numer, jeśli warstwa dostępu tego nie blokuje.

Kanał MAVLink jest stanem parsera i nadawania przypisanym do fizycznego/logicznego łącza. Numer sekwencyjny jest liczony per kanał i pomaga szacować utratę, ale nie zastępuje potwierdzenia operacji. Router musi pamiętać, na którym interfejsie widział dany system i zapobiegać pętlom forwardowania.

Ramka MAVLink 2 zawiera:

Pole Rozmiar Funkcja
magic 1 B znacznik wersji ramki
payload length 1 B długość przesyłanego payloadu
incompat/compat flags 2 B sposób obsługi rozszerzeń
sequence 1 B licznik pakietów kanału
system/component ID 2 B adresowanie źródła
message ID 3 B typ wiadomości
payload 0–255 B pola wiadomości po serializacji
checksum 2 B CRC wraz z CRC_EXTRA
signature 13 B opcjonalnie uwierzytelnienie ramki

Flaga niekompatybilna oznacza, że odbiorca nieznający funkcji powinien odrzucić ramkę; flagę kompatybilną może zignorować. MAVLink 2 rozszerza identyfikator wiadomości do 24 bitów, umożliwia pola extensions, obcina końcowe zera payloadu i może dołączać podpis.

Pola nie są układane po prostu w kolejności XML. Generator porządkuje część bazową według zasad serializacji i typu, aby ograniczyć padding. Nie wolno pisać parsera z założeniem, że struktura C skopiowana z pamięci jest ramką wire-format. Należy używać wygenerowanych bibliotek albo implementować specyfikację wraz z testami wektorów.

CRC i CRC_EXTRA#

Checksum chroni przed przypadkowym uszkodzeniem oraz pomaga odrzucić ramkę z inną definicją wiadomości. CRC_EXTRA jest wyprowadzane z nazwy i typów pól bazowej definicji. Nie zapewnia autentyczności: napastnik znający dialekt może obliczyć poprawne CRC.

Przy diagnostyce błędu CRC trzeba rozdzielić uszkodzenie transportu, zły framing, różny dialekt i błąd parsera. Jeśli tylko jeden typ wiadomości jest odrzucany, bardziej prawdopodobna jest niezgodna definicja niż losowy problem UART.

Dialekty i zgodność#

minimal.xml zawiera podstawy, common.xml szeroko używane wiadomości i mikroserwisy, a dialekty projektów dziedziczą oraz dodają własne definicje. Dwa końce muszą używać zgodnych definicji dla wysyłanych message ID.

Rozszerzenia MAVLink 2 pozwalają dopisywać pola na końcu wiadomości bez łamania starszych odbiorców. Starsza implementacja widzi część bazową; nowa traktuje brakujące końcowe pola jako zero. Zmiana typu, kolejności albo znaczenia pola bazowego nie jest zgodnym rozszerzeniem.

Własna wiadomość ma sens, gdy nie istnieje standardowy mikroserwis i semantyka jest stabilna. Nie należy kodować struktury zależnej od pamięci MCU ani tworzyć nowego message ID dla każdego polecenia, które da się wyrazić istniejącym protokołem.

Heartbeat i odkrywanie#

HEARTBEAT sygnalizuje obecność komponentu, typ systemu, autopilota i ogólny stan. Służy do odkrywania oraz timeoutu. Nie jest health checkiem wszystkich podsystemów. Pojazd może nadal emitować heartbeat przy nieważnej pozycji, błędzie sensora lub zablokowanym aktuatorze.

Odbiorca powinien prowadzić osobne timery dla heartbeat, danych krytycznych i transakcji. „Łącze żyje” oraz „pozycja jest świeża” są różnymi twierdzeniami.

Mikroserwis command#

Polecenia używają zwykle COMMAND_LONG lub COMMAND_INT i odpowiedzi COMMAND_ACK. ACK informuje o przyjęciu, odrzuceniu, braku wsparcia, trwaniu operacji lub jej wyniku. Transport może zgubić komendę albo ACK, dlatego nadawca potrzebuje timeoutu i kontrolowanej polityki ponowień.

Komenda nie zawsze jest idempotentna. Ponowienie „ustaw tryb” jest inne niż ponowienie akcji jednorazowej. Projekt komponentu powinien rozpoznawać duplikaty lub udokumentować skutki ponowienia. ACK nie dowodzi osiągnięcia stanu fizycznego; po komendzie startu misji należy obserwować stan i zdarzenia.

Parametry#

Klasyczny protocol parameters przenosi nazwy oraz wartości w formacie historycznie związanym z float. Nowszy extended parameter protocol lepiej obsługuje typy i dłuższe operacje. Synchronizacja całej listy może obciążyć wolne łącze, dlatego implementacja potrzebuje cache, wykrywania braków i retry.

Zapis parametru jest zmianą trwałej konfiguracji. Interfejs powinien pokazać rzeczywistą wartość odczytaną po zapisie, a nie tylko lokalną wartość wysłaną. Nazwa, jednostka i zakres pochodzą z metadanych komponentu, nie z samej ramki.

Mission protocol#

Misje są przesyłane transakcyjnie: inicjator ogłasza liczbę elementów, odbiorca żąda kolejnych indeksów, a całość kończy się ACK. Protokół ma obsługiwać utratę pakietów i retransmisję. Mieszanie równoległych uploadów z dwóch GCS prowadzi do konfliktu stanu, jeśli implementacja nie wiąże transakcji z partnerem.

MISSION_ITEM_INT stosuje całkowitoliczbowe współrzędne tam, gdzie to właściwe i jest preferowane względem starszej reprezentacji float. Znaczenie frame, komendy i parametrów musi być interpretowane zgodnie ze specyfikacją. Zapis współrzędnych bez układu odniesienia jest bezużyteczny.

Telemetria strumieniowa#

Wiadomości pozycji, orientacji i stanu są zwykle wysyłane bez potwierdzenia. Nowa próbka zastępuje starą, więc retransmisja historycznej orientacji nie ma sensu. Przepustowość planuje się na podstawie pełnego rozmiaru ramki, częstotliwości i narzutu transportu.

Przykład: wiadomość o 32-bajtowym payloadzie w MAVLink 2 bez podpisu zajmuje 44 B. Przy 20 Hz to 880 B/s przed narzutem UART/IP. Kilkanaście takich strumieni może nasycić modem 57 600 bit/s po uwzględnieniu framingu i ruchu zwrotnego.

Budżet powinien rozdzielać:

  • heartbeat i stan krytyczny;
  • sterowanie oraz ACK;
  • telemetrię operatora;
  • payloady i debug;
  • transfer plików/logów.

Debug nie może zagłodzić komend i heartbeat. Router powinien mieć priorytety, limity oraz obserwowalne kolejki.

Routing i pętle#

Router uczy się systemów/komponentów na interfejsach i przekazuje wiadomości zgodnie z target fields oraz polityką. Broadcast może trafić na wiele portów. Dwa bridge’e połączone równolegle mogą stworzyć pętlę i zwielokrotnić ruch.

Redundancja wymaga deduplikacji. Sequence number sam nie zawsze wystarcza, bo liczy się per kanał i może się zawinąć. Projekt powinien znać topologię, okno czasowe i skutki odrzucenia dwóch identycznych komend przychodzących różnymi drogami.

Timesync i timestampy#

MAVLink transportuje dane z różnymi rodzajami czasu: monotoniczny czas od startu, UNIX epoch albo czas próbki w zegarze źródła. Synchronizacja zegarów nie polega na nadpisaniu timestampu czasem odbioru. Mikroserwis timesync szacuje offset i opóźnienie wymiany.

Dla external vision błędny offset wygląda jak błąd fazy i psuje fuzję. Odbiorca powinien zachować czas pomiaru, monitorować wiek danych oraz odrzucać skoki zegara. NTP na companion computer nie synchronizuje automatycznie zegara boot-time autopilota.

Podpisywanie a szyfrowanie#

Message signing MAVLink 2 uwierzytelnia ramkę i pomaga chronić przed modyfikacją/replay dzięki kluczowi, link ID i timestampowi. Nie szyfruje payloadu: obserwator nadal może odczytać dane. Poufność wymaga VPN, TLS lub innej zabezpieczonej warstwy transportowej.

Klucz współdzielony przez całą flotę zwiększa promień skutków wycieku. Potrzebne są unikalne klucze, bezpieczne provisionowanie, rotacja i procedura recovery. Podpisane i niepodpisane kanały muszą mieć jawną politykę; automatyczny fallback do niezabezpieczonego sterowania niweluje mechanizm.

Wireshark i diagnostyka#

Diagnostykę zaczyna się od surowego przechwycenia na konkretnej granicy. Wireshark potrafi dekodować MAVLink, ale musi znać właściwy dialekt. Dla UART przydatny jest logic analyzer lub log bajtów przed parserem.

Kolejność kontroli:

  1. parametry elektryczne i baud rate UART;
  2. poprawny magic byte i długość;
  3. licznik sequence oraz rozkład strat;
  4. CRC i zgodność dialektu;
  5. sysid/compid oraz target fields;
  6. timeouty mikroserwisu;
  7. kolejki i budżet łącza;
  8. timestamp próbki i czas odbioru;
  9. polityka podpisu i odrzucenia replay.

Minimalny odbiorca#

Parser powinien konsumować strumień bajtów, obsługiwać resynchronizację i dopiero po pełnej walidacji przekazywać wiadomość logice aplikacji. Nie wolno wykonywać kosztownej akcji bezpośrednio w przerwaniu UART.

while (uart_read(&byte, 1) == 1) {
    if (mavlink_parse_char(channel, byte, &msg, &status)) {
        queue_validated_message(&msg, monotonic_now_us());
    }
}

Kolejka musi mieć limit i politykę przepełnienia. Dla telemetrii można zastępować starą próbkę, lecz komend i ACK nie wolno bezgłośnie porzucać.

Typowe błędy#

  • uznanie CRC za zabezpieczenie przed napastnikiem;
  • użycie tego samego sysid przez dwa pojazdy;
  • brak timeoutu transakcji misji lub parametrów;
  • wysyłanie wszystkich strumieni z maksymalną częstotliwością;
  • forwardowanie broadcastów w pętli;
  • traktowanie heartbeat jako dowodu gotowości do lotu;
  • podpisywanie bez ochrony klucza albo mylenie podpisu z szyfrowaniem;
  • użycie czasu odbioru jako czasu pomiaru;
  • własny dialekt bez zamrożonej definicji i testów zgodności.

Transport jest osobną warstwą#

MAVLink definiuje wiadomości i ramki, ale nie narzuca UART, UDP, TCP ani radia. Ten sam strumień może płynąć przez port szeregowy, datagramy lub tunel. Właściwości transportu pozostają widoczne: UART może gubić bajty, UDP datagramy, TCP wprowadzać head‑of‑line blocking.

Parser MAVLink powinien pracować na strumieniu i odzyskiwać synchronizację po błędzie. Nie może zakładać, że jedno read() zwróci jedną ramkę. W UDP pojedynczy datagram może zawierać kilka ramek. Warstwa transportowa ma własne kolejki, limity i statystyki.

Przy serialu 8N1 każdy bajt zajmuje około 10 bitów. Port 57 600 bit/s nie przenosi 57 600 bajtów/s, lecz teoretycznie około 5 760 przed narzutem i rezerwą. Budżet wiadomości musi uwzględnić długość ramki, częstotliwość oraz ruch w obu kierunkach.

Numer sekwencyjny i utrata#

Pole sequence inkrementuje się dla ramek wysyłanych przez dany kanał. Odbiorca może szacować utratę, ale musi rozróżnić wiele źródeł i restart nadajnika. Skok numeru nie dowodzi, że radio zgubiło pakiet: router mógł filtrować wiadomości, a proces się zrestartować.

Statystykę prowadzi się per łącze oraz źródło. Duplikaty mogą powstawać w sieci z kilkoma trasami. Deduplikacja oparta wyłącznie na sequence jest ryzykowna po zawinięciu licznika; używa się krótkiego okna i dodatkowych pól.

MAVLink nie zapewnia niezawodnego dostarczenia całego strumienia. Mikroserwisy wymagające potwierdzeń implementują je na poziomie wiadomości, na przykład COMMAND_ACK. Telemetria typu attitude jest świeża tylko przez moment i zwykle nie powinna być retransmitowana.

Identyfikatory systemu i komponentu#

sysid identyfikuje system w danej sieci, a compid komponent w systemie. Autopilot, kamera i gimbal mogą mieć ten sam sysid i różne compid. Kolizja dwóch pojazdów o tym samym sysid powoduje niejednoznaczne komendy i zlewanie stanu w GCS.

Adresowanie ma trzy poziomy: nagłówek wskazuje źródło, a wybrane wiadomości zawierają target_system i target_component. Brak pól celu oznacza semantykę broadcast danej wiadomości, nie dowolność routera. Komponent powinien ignorować polecenie skierowane do innego celu.

Heartbeat informuje o obecności, typie i stanie. Nie jest pełnym health reportem. Timeout heartbeat należy dobrać do częstotliwości i łącza, a ponowne pojawienie po przerwie traktować jako możliwy restart, sprawdzając boot time i stan protokołów.

Generowanie kodu z dialektu#

Definicje XML są źródłem typów wiadomości, pól, enumów i CRC extra. Generator tworzy biblioteki dla języków. Ręczne duplikowanie struktur sprzyja różnicom wyrównania oraz endian. Wersję wygenerowanych plików wiąże się z wersją dialektu.

Dialekt rozszerza common.xml lub inny zestaw. Własna wiadomość wymaga unikalnego ID w kontrolowanej przestrzeni, dokumentacji jednostek i zasad ważności. Pole „reserved” nie powinno później zmieniać semantyki. Odbiorca musi tolerować nieznane wiadomości i ignorować je po poprawnym odczytaniu długości.

MAVLink 2 pozwala na pola extension na końcu payloadu. Starszy nadawca wysyła krótszą wiadomość, a odbiorca zeruje brakujące rozszerzenia. Nie wolno dodawać pola do środka definicji, bo zmieni layout i CRC.

Semantyka wartości#

Jednostka i wartość sentinel są częścią protokołu. 0 może oznaczać prawdziwe zero, „nieobsługiwane” albo „nieznane” zależnie od pola. NaN bywa jawnie dozwolone dla nieznanej wartości float. Implementacja musi czytać opis wiadomości.

Czas występuje jako boot time, Unix epoch, usec lub msec. Nazwa pola zwykle wskazuje skalę, ale nie zawsze źródło. Mieszanie time_boot_ms z UTC tworzy błędy po restarcie i overflow. Do obliczania opóźnienia potrzebna jest synchronizacja oraz wiadomość o znanym momencie pomiaru.

Współrzędne mogą być globalne, lokalne NED, body lub offset. Ramka MAV_FRAME zmienia interpretację tych samych liczb. Polecenie pozycji bez sprawdzenia frame może skierować pojazd w nieoczekiwane miejsce.

Command protocol jako transakcja#

COMMAND_LONG i COMMAND_INT przenoszą polecenie, a COMMAND_ACK wynik. Nadawca utrzymuje stan: wysłane, oczekujące, zaakceptowane, wykonywane, zakończone albo odrzucone. Sam ACK accepted nie zawsze oznacza, że długotrwała czynność została zakończona.

Retry ma timeout, limit i idempotencję. Ponowienie komendy nieidempotentnej może powtórzyć akcję, jeśli pierwszy ACK zginął. Odbiorca powinien rozpoznawać duplikaty tam, gdzie specyfikacja tego wymaga, a klient prezentować brak odpowiedzi inaczej niż jawne denied.

Wynik TEMPORARILY_REJECTED różni się od UNSUPPORTED i DENIED. GCS zachowujące każdy błąd jako „failed” utrudnia diagnozę. Log zapisuje command ID, target, confirmation, wynik i czas.

Parametry#

Klasyczny protokół parametrów przesyła nazwę, wartość i typ oraz indeks. Synchronizacja pełnej listy jest stanem wieloetapowym: klient żąda, odbiera elementy, wykrywa braki i ewentualnie ponawia. Kolejność nie musi być semantyczna.

Zapis parametru wymaga potwierdzenia wartością odczytaną z pojazdu. Float transportujący wartości całkowite ma ograniczenia precyzji i różne historyczne tryby kodowania. Extended Parameter Protocol rozwiązuje część problemów i obsługuje dłuższe reprezentacje, lecz oba końce muszą wspierać ten sam mikroserwis.

Zmiana parametru może być przyjęta do RAM, zapisana trwale albo wymagać restartu. Interfejs powinien pokazać te różnice. Masowe zapisy na wolnym łączu wymagają kolejki i ograniczenia równoległości.

Mission protocol#

Upload misji jest dialogiem. Odbiorca przyjmuje liczbę elementów, żąda kolejnych sekwencji, a na końcu zwraca wynik. Nadawca nie powinien po prostu wysłać listy w ciemno. Timeout i retry są per etap.

MISSION_ITEM_INT z całkowitymi współrzędnymi jest preferowane dla pozycji globalnej, bo ogranicza utratę precyzji. Typ misji rozróżnia waypointy, fence i rally points. Klient musi dopasować odpowiedzi do właściwego typu.

Przerwanie transmisji pozostawia pytanie o atomowość. Implementacja autopilota określa, kiedy nowa misja zastępuje starą. Narzędzie przed startem powinno odczytać listę i porównać checksum lub elementy, zamiast ufać komunikatowi GUI.

Strumienie i negocjacja częstotliwości#

Każda wiadomość ma koszt bytes × rate. Attitude 50 Hz, raw IMU 100 Hz i logowanie mogą szybko nasycić radio. Przy nasyceniu kolejka starych danych jest gorsza niż świadome odrzucenie, bo operator ogląda przeszłość.

MAV_CMD_SET_MESSAGE_INTERVAL pozwala żądać interwału konkretnej wiadomości. Starsze mechanizmy stream rate grupują wiadomości i dają mniejszą kontrolę. Autopilot może odmówić lub ograniczyć rate z powodu zasobów. Klient powinien mierzyć faktyczny wynik.

Priorytetyzuje się heartbeat, stan uzbrojenia, failsafe, energię i potwierdzenia. Parametry diagnostyczne mają niższy rate. Obraz i duże pliki zwykle wymagają osobnego transportu; tunelowanie wszystkiego przez MAVLink utrudnia sterowanie kolejkami.

Router i topologia#

Router uczy się, które systemy i komponenty są widoczne na interfejsach, oraz przekazuje broadcasty zgodnie z polityką. Pętla między dwoma routerami może mnożyć ruch, ponieważ podstawowa ramka nie ma uniwersalnego TTL. Topologia wymaga zapobiegania cyklom albo deduplikacji.

Filtr powinien zachować mikroserwis jako całość. Przepuszczenie requestu i zablokowanie ACK tworzy pozorną awarię. NAT identyfikatorów jest ryzykowny, bo targety występują w payloadach wielu wiadomości, nie tylko w nagłówku.

Przy dwóch GCS trzeba rozstrzygnąć właściciela operacji. MAVLink sam nie daje pełnej blokady „jednego pilota”. Autoryzacja, role i arbitraż są warstwą systemową.

Podpis zawiera link ID, timestamp i skrót oparty na współdzielonym kluczu. Odbiorca może potwierdzić integralność oraz odrzucić replay poza oknem. Nie szyfruje payloadu: obserwator nadal odczyta pozycję i parametry.

Klucz należy dystrybuować poza zwykłym nieszyfrowanym łączem i chronić w GCS oraz pojeździe. Wspólny klucz całej floty zwiększa skutki wycieku. Zegar podpisu musi zachowywać monotoniczność przez restart zgodnie z implementacją, inaczej poprawne ramki mogą być odrzucone.

Polityka mixed signed/unsigned jest krytyczna. Jeżeli system podpisuje telemetrię, ale akceptuje niepodpisane komendy, cel bezpieczeństwa nie został osiągnięty. Most lub router musi zachować podpis i nie modyfikować ramki.

Poufność wymaga dodatkowej warstwy, na przykład poprawnie skonfigurowanego VPN. Szyfrowanie transportu nie naprawia błędnego uprawnienia komponentu końcowego.

Parser odporny na błędy#

Parser działa jako automat stanów z limitem długości. Po błędnym CRC wraca do szukania znacznika początku bez nieograniczonej alokacji. Nieznane ID jest dozwolone, jeśli ramka jest strukturalnie poprawna. Warto liczyć błędy CRC, resynchronizacje i przepełnienia per łącze.

Kod aplikacji nie powinien ufać poprawnej sumie jako walidacji semantyki. Sprawdza zakres enumów, finiteness floatów, target, frame, uprawnienie oraz świeżość. Pole position z CRC może nadal być fizycznie niemożliwe.

Fuzzing parsera obejmuje ucięte ramki, maksymalny payload, losowe znaczniki, nieznane incompat flags, błędny signature i serie bez przerwy. Testy mikroserwisów dodatkowo zmieniają kolejność, gubią ACK i restartują peer w środku transakcji.

Procedura diagnostyczna#

  1. Potwierdzić parametry transportu i liczbę surowych bajtów.
  2. Zidentyfikować źródła przez heartbeat, sysid i compid.
  3. Policzyć CRC errors, sequence gaps i overflow osobno.
  4. Zmierzyć faktyczny rate oraz wiek wiadomości.
  5. Dla transakcji zapisać request, target, retry i ACK.
  6. Sprawdzić topologię routerów oraz duplikaty.
  7. Zweryfikować timestampy i synchronizację.
  8. Przy podpisach sprawdzić politykę, link ID oraz okno czasu.

Wireshark i MAVLink Inspector pomagają zobaczyć ruch, lecz najlepszy raport łączy capture z logiem autopilota i routera na tej samej osi czasu.

Powiązane tematy#

Przypisy#

  1. MAVLink Guide — wersje, mikroserwisy, routing, signing i debug.
  2. MAVLink Protocol Overview — format pakietu i model systemów.
  3. MAVLink 2 — message ID, extensions, truncation i flagi.
  4. MAVLink Serialization — wire format, CRC i porządek pól.
  5. MAVLink Message Signing — uwierzytelnianie, timestamp i ograniczenia.
  6. MAVLink Routing — target fields i przekazywanie między interfejsami.

Źródła z centralnego rejestru

  1. MAVLink Protocol Overview [specyfikacja]
  2. MAVLink Packet Serialization [specyfikacja]
  3. ExpressLRS: MAVLink [dokumentacja]