CRSF jest dwukierunkowym protokołem szeregowym łączącym odbiornik RC, flight controller i inne urządzenia ekosystemu. Przenosi nie tylko kanały sterowania, lecz także statystyki łącza, dane telemetryczne, identyfikację urządzeń, parametry i komendy. W praktyce jest używany przez systemy TBS Crossfire oraz ExpressLRS, ale nie jest ich warstwą radiową: pakiet LoRa/FLRC/FSK nadawany w eterze i ramka CRSF na przewodach UART mają inne formaty oraz inne mechanizmy integralności.

W odróżnieniu od klasycznego SBUS CRSF zwykle wymaga pełnej pary UART. Odbiornik wysyła kanały i statystyki do flight controllera, a FC odsyła telemetrię. Standardowa konfiguracja spotykana w otwartym firmware to nieodwrócone poziomy 3,0–3,3 V, 8N1 i szybkość w okolicy 416666/420000 bit/s; dokładna wartość jest przedmiotem kompatybilności implementacji i aktualnej konfiguracji. Projekt musi opierać się na dokumentacji oraz kodzie obu końców, nie na założeniu, że „każde CRSF jest 420k”.

Spis treści#

CRSF a łącze radiowe#

CRSF opisuje strumień pomiędzy urządzeniami. ExpressLRS może przesyłać po radiu kanały w zoptymalizowanym formacie OTA, a odbiornik rekonstruuje z nich ramkę CRSF dla FC. Zmiana packet rate radia nie zmienia automatycznie formatu każdej ramki UART, choć wpływa na częstotliwość ich powstawania i wymagane pasmo portu.

nadajnik RC
   │ wewnętrzny CRSF między radiem a modułem, zależnie od systemu
   ▼
moduł TX ═══ zoptymalizowane łącze RF ═══ odbiornik RX
                                             │ TX: kanały, link stats
                                             │ RX: telemetria/parametry
                                             ▼
                                      pełny UART flight controllera

Nie można wnioskować o jakości RF z samego braku błędów CRC na przewodzie. CRC CRSF sprawdza ramkę między odbiornikiem a FC. Radio ma własną kontrolę pakietów i odbiornik może nie wygenerować nowej ramki kanałów, jeśli pakiet OTA zaginął. Dlatego potrzebne są statystyki łącza oraz timestamp świeżości kanałów.

Podobnie zmiana CRSF na SBUS w WebUI odbiornika nie zmienia modulacji radiowej. Zmienia tylko protokół wyjściowy. Można przez to zachować sterowanie, ale utracić dwukierunkową telemetrię i część informacji o linku.

Topologia#

Najprostsza topologia ma dwa urządzenia i cztery połączenia funkcjonalne:

RX receiver TX ─────────> FC UART RX   kanały + link statistics
RX receiver RX <───────── FC UART TX   telemetria + odpowiedzi
GND          ──────────── GND          referencja
power        <──────────── regulator    zasilanie odbiornika

Nazwy TX i RX zawsze czyta się z perspektywy urządzenia. TX odbiornika łączy się z RX flight controllera. Pomylone przewody dają całkowity brak danych, a połączenie tylko jednego kierunku może pozwolić sterować bez telemetrii. To utrudnia diagnozę, bo kanały działają, lecz skrypty nadajnika nie widzą sensorów lub parametrów.

CRSF zawiera adresy urządzeń i ramki rozszerzone, więc logiczna topologia może obejmować odbiornik, moduł radiowy, handset, FC i inne urządzenia. Fizyczny UART nadal ma ograniczone pasmo i nie jest ogólnym Ethernetem. Parser powinien rozróżniać ramki skierowane do FC, broadcast i ruch routowany.

Niektóre odbiorniki mają dodatkowy UART albo możliwość wyboru protokołu każdego wyjścia. Konfiguracja zapisana w WebUI/Lua jest częścią manifestu platformy. Po aktualizacji firmware odbiornika trzeba sprawdzić, czy protokół, baud i kierunek portu pozostały zgodne.

Warstwa elektryczna i UART#

Typowa konfiguracja CRSF receiver–FC:

parametr typowa wartość
tryb full-duplex
bity danych 8
parzystość brak
bity stopu 1
inwersja wyłączona
poziom około 3,0–3,3 V
przepływność implementacyjnie 416666 lub 420000 bit/s, możliwe negocjowane warianty

ExpressLRS zaleca pełną, nieodwróconą parę UART i w typowej konfiguracji Betaflight ustawia serialrx_inverted = off oraz serialrx_halfduplex = off. Wyjątkiem są świadomie wybrane tryby Inverted CRSF dla sprzętu, gdzie dostępny jest tylko inwertowany pad. Nazwa padu SBUS nie gwarantuje, że można do niego podłączyć zwykły CRSF bez zmiany polaryzacji.

Poziom zasilania odbiornika i poziom sygnału to różne parametry. Moduł może być zasilany z 5 V, a UART pracować przy 3,3 V. Podanie 5 V na nietolerantny pin MCU może go uszkodzić. Schemat odbiornika i flight controllera rozstrzyga zgodność.

Przy 420 kbit/s czas jednego bitu wynosi około 2,38 µs. Zbocza, pojemność przewodu i błąd zegara mają mniejszy margines niż w SBUS 100 kbit/s. Przewody powinny być krótkie, prowadzone z masą i oddalone od węzłów przełączających.

416666 a 420000 bit/s#

Kod Betaflight jawnie rozróżnia wartość 416666 bit/s wynikającą z nowszej oficjalnej dokumentacji CRSF oraz historycznie stosowane 420000 bit/s dla kompatybilności, z ostrzeżeniem dotyczącym części odbiorników ExpressLRS. To dobry przykład, dlaczego numer baud nie powinien być „poprawiany” bez testu całego ekosystemu.

Różnica wynosi około 0,8%. UART często toleruje taki błąd dla krótkich ramek, ale tolerancja zależy od zegarów obu stron, oversamplingu i temperatury. Jeśli jedno urządzenie ma własny dodatkowy błąd w tym samym kierunku, margines maleje.

Zasady integracji:

  • używać wartości domyślnej oficjalnie wspieranej przez wersję firmware obu końców;
  • nie mieszać ręcznie stałych z różnych forków;
  • mierzyć czas bitu i błędy framing/CRC w temperaturze;
  • przy wysokich packet rates sprawdzić, czy port negocjuje/obsługuje wyższy baud;
  • wersjonować ustawienie odbiornika razem z firmware FC.

Automatyczne wykrywanie może próbować ograniczonej listy prędkości, ale nie może bez końca przełączać UART podczas lotu. Po ustaleniu trybu parser monitoruje jakość i przechodzi do bezpiecznego stanu, jeśli strumień zanika.

Budowa ramki#

Podstawowa ramka ma postać:

+---------+--------+------+-------------------+-------+
| address | length | type | payload           | CRC-8 |
+---------+--------+------+-------------------+-------+
  1 byte   1 byte  1 byte  zmienna długość     1 byte

Pole długości nie obejmuje pierwszego bajtu adresu ani samego pola długości. Obejmuje typ, payload i CRC. Zatem całkowita liczba bajtów na przewodzie jest typowo:

frame_bytes = length + 2

To miejsce częstego błędu off-by-two. Parser powinien mieć jedną funkcję obliczającą oczekiwany koniec i testy dla minimalnych oraz maksymalnych ramek. W kodzie Betaflight maksymalny rozmiar ramki jest ograniczony do 64 bajtów; długość spoza zaakceptowanego zakresu odrzuca się natychmiast.

CRC jest ostatnim bajtem. Dla podstawowej ramki liczy się od pola type przez payload, bez address i length. Ramki rozszerzone mają dodatkowe pola docelowego i źródłowego adresu jako część danych chronionych odpowiednim CRC. Implementacja musi korzystać z definicji konkretnego typu.

Pole adresu#

Pierwszy bajt identyfikuje odbiorcę na fizycznym odcinku. W implementacjach występują adresy m.in. flight controllera, nadajnika radiowego, odbiornika, handsetu oraz broadcast. Wartość 0xC8 jest powszechnie używana jako adres/sync flight controllera, lecz traktowanie każdego 0xC8 jako jedynego możliwego początku ogranicza routing i może odrzucać poprawne ramki innych urządzeń.

Parser portu FC powinien mieć politykę:

  • przyjmować ramki do FC;
  • przyjmować dozwolone broadcasty;
  • przekazywać wybrane ramki rozszerzone do routera urządzeń;
  • odrzucać nieobsługiwane adresy bez interpretacji payloadu;
  • zliczać nieznane adresy diagnostycznie z ograniczeniem logowania.

Adres nie jest mechanizmem kryptograficznym. Każde urządzenie elektrycznie podłączone do UART może wygenerować bajt wybranego adresu. Nie należy na tej podstawie autoryzować niebezpiecznej zmiany parametrów.

Długość i granice#

Po odebraniu address i length parser wie, ile dalszych bajtów zebrać. Zanim zarezerwuje bufor albo czeka, waliduje:

minimum <= length <= protocol_max
length + 2 <= local_buffer_size

Wartość zero, jeden lub liczba większa od limitu nie może sterować indeksem poza buforem. Jest to ważne również w systemie zamkniętym: zakłócenie jednego bajtu length bez wcześniejszej walidacji może spowodować przepełnienie lub długi lock parsera.

Parser ma deadline ramki obliczony z baud i maksymalnej długości. Przy 420 kbit/s, 8N1 jeden bajt zajmuje około 23,8 µs, a 64 bajty około 1,52 ms. Przerwa znacznie większa może oznaczać zerwaną ramkę. Należy jednak uwzględnić FIFO i sposób dostarczania bajtów przez driver.

Po pełnej ramce najpierw sprawdza się CRC, dopiero potem rzutuje payload na strukturę. Każdy typ ma minimalną i oczekiwaną długość. Poprawne CRC nie oznacza, że stary parser zna nowy wariant typu; nieznany typ można bezpiecznie pominąć.

Typ wiadomości#

Pole type definiuje semantykę. Ważne przykłady z otwartych implementacji:

type funkcja
0x02 GPS
0x08 bateria
0x14 statystyki łącza
0x16 16 kanałów RC pakowanych po 11 bitów
0x17 podzbiór kanałów z konfigurowalną rozdzielczością
0x1E attitude
0x21 tryb lotu
0x28 device ping
0x29 device info
0x2B–0x2D parametry urządzeń
0x32 command
0x7A–0x7C transport MSP

Lista rozwija się wraz z implementacjami. Kod powinien używać nazwanych stałych z aktualnego modułu protokołu, a nie duplikować liczby w wielu plikach. Odbiór nieznanego typu nie jest błędem framingu; parser potwierdza CRC, pomija payload i zwiększa licznik unsupported_type.

Nie każda implementacja obsługuje wszystkie typy. Betaflight i ArduPilot mają różne cele telemetryczne. Interoperacyjność testuje się dla konkretnego zestawu wersji i wymaganych ramek.

CRC-8#

CRSF używa CRC-8 z wielomianem 0xD5 dla ramki. Typowa implementacja zaczyna od zera i przetwarza type + payload. CRC chroni przed wieloma błędami transmisji, ale nie uwierzytelnia nadawcy i nie chroni przed świadomą modyfikacją.

Szkic obliczenia bitowego:

static uint8_t crc8_d5(const uint8_t *data, size_t len)
{
    uint8_t crc = 0;
    while (len-- > 0) {
        crc ^= *data++;
        for (unsigned bit = 0; bit < 8; ++bit) {
            crc = (crc & 0x80U) ? (uint8_t)((crc << 1) ^ 0xD5U)
                                : (uint8_t)(crc << 1);
        }
    }
    return crc;
}

Wersja tabelowa jest szybsza, ale jej testy muszą porównywać wynik z implementacją referencyjną dla zestawu wektorów. Najczęstsze różnice to kierunek bitów, wartość początkowa, zakres danych i dołączenie samego CRC.

Ramkę z błędnym CRC odrzuca się w całości. Nie wolno publikować kanałów „bo payload wygląda sensownie”. Licznik CRC wraz z framing/overrun pomaga odróżnić EMI od błędu protokołu.

Kanały RC 0x16#

Typ RC_CHANNELS_PACKED przenosi 16 kanałów po 11 bitów, czyli 22 bajty payloadu. Układ bitów jest analogicznie ciasny jak w SBUS, lecz znajduje się w ramce z długością i CRC. Typowe surowe wartości spotykane w kodzie CRSF to około 172 dla minimum, 992 dla środka i 1811 dla maksimum.

Pełna podstawowa ramka kanałów ma:

address  1
length   1  (type + 22 payload + CRC = 24)
type     1  (0x16)
channels 22
CRC      1
----------------
razem   26 bajtów

Przy 420 kbit/s transmisja 26 bajtów 8N1 zajmuje około:

26 · 10 / 420000 ≈ 619 µs

Parser rozpakowuje kanały dopiero po CRC. Podobnie jak w SBUS, bitfieldy C nie są przenośnym formatem przewodowym. Należy użyć jawnych przesunięć albo dobrze przetestowanej funkcji z kodu projektu.

Wartości wszystkich kanałów muszą być opublikowane atomowo z jednym timestampem. Jeśli pętla sterowania działa szybciej niż przychodzą ramki, może używać ostatniej poprawnej ramki do momentu deadline, ale jej wiek jest jawny w logu.

Subset RC channels 0x17#

Typ SUBSET_RC_CHANNELS_PACKED pozwala przesłać podzbiór kanałów i kodować je z wybraną rozdzielczością, spotykaną jako 10–13 bitów. Nagłówek payloadu określa kanał początkowy, rozdzielczość i elementy konfiguracji, a pozostałe bity niosą kolejne wartości.

Obsługa wymaga więcej niż zmiany maski z 11 na 13 bitów:

  • zwalidować minimalną długość payloadu;
  • odczytać start channel i liczbę bitów;
  • obliczyć, ile pełnych wartości mieści się w pozostałych bajtach;
  • nie wyjść poza maksymalną liczbę kanałów;
  • przeskalować zakres zgodnie z rozdzielczością;
  • atomowo zaktualizować tylko przeniesiony podzbiór;
  • określić freshness kanałów nieobecnych w tej ramce.

Ostatni punkt jest krytyczny. Jeśli różne subset frames aktualizują różne grupy, każdy kanał lub grupa potrzebuje wieku albo ramki składającej kompletny stan. Nie można oznaczyć wszystkich 16 kanałów jako świeże po odebraniu tylko czterech.

Starsze odbiorniki/FC mogą nie obsługiwać 0x17. Negocjacja i kompatybilność wersji mają pierwszeństwo przed maksymalną rozdzielczością. Dla wielu drążków 11 bitów i tak przekracza użyteczną dokładność mechaniki.

Skalowanie kanałów#

CRSF przenosi wartości w domenie protokołu. Flight controller mapuje je do mikrosekundowej konwencji RC albo wartości znormalizowanej. Liniowa relacja powinna używać jawnych stałych i saturacji:

u = (raw - 992) / (1811 - 992)  dla raw >= 992
u = (raw - 992) / (992 - 172)   dla raw < 992

To daje okolice [-1, 1] dla typowego zakresu, ale rzeczywista kalibracja nadajnika może być nieco inna. FC przechowuje min/trim/max per kanał. Wartość surowa pozostaje w logu, aby odróżnić błąd radia od mapowania.

Kanał gazu może być jednokierunkowy i mieć inne sprawdzenia pre-arm. Przełączniki trójpozycyjne wymagają progów z histerezą. Nie należy porównywać surowej wartości dokładnie do jednej liczby, bo jitter wejścia może wielokrotnie przełączać stan.

Wartość poza fizycznie oczekiwanym zakresem, ale mieszcząca się w bitach, jest sygnałem diagnostycznym. Można ją ograniczyć dla regulatora, równocześnie ustawiając flagę anomalnego wejścia.

CRSF ma osobne ramki statystyk łącza. W otwartych implementacjach obejmują między innymi RSSI anten/torów, LQ, SNR, aktywną antenę, tryb RF, moc nadajnika i parametry downlinku. Dokładne pola zależą od typu oraz wersji.

Statystyki służą do:

  • ostrzeżeń operatora;
  • logowania marginesu i jakości;
  • analizy anteny oraz instalacji RF;
  • wykrywania trendu przed failsafe;
  • porównania trybów packet rate/mocy;
  • rozróżnienia problemu radiowego od UART.

Nie powinny bezpośrednio sterować pojedynczą agresywną decyzją na podstawie jednej próbki. RSSI i SNR zmieniają się z orientacją, wielodrogowością i ruchem. LQ ma okno oraz definicję zależną od systemu. Progi ostrzeżeń muszą wynikać z dokumentacji i pomiarów konkretnego radia.

Flight controller zapisuje timestamp każdej ramki statystyk. Stara wartość LQ nie może wyglądać jak aktualna. Interfejs użytkownika powinien pokazać brak/age osobno od liczby zero.

LQ, RSSI i SNR#

RSSI opisuje moc odebranego sygnału, zwykle w dBm. Bardziej ujemna liczba oznacza słabszy sygnał. SNR porównuje sygnał z szumem i przy modulacjach rozpraszających może być użyteczny nawet przy wartościach ujemnych. LQ opisuje udział lub jakość poprawnie odebranych pakietów w określonym oknie.

Te miary nie są zamienne:

  • wysokie RSSI z niskim LQ może oznaczać interferencję, przesterowanie albo problem dekodowania;
  • niskie RSSI z dobrym LQ może być poprawne przy odpornym trybie modulacji, ale margines maleje;
  • SNR zależy od pasma i estymacji odbiornika;
  • LQ może spadać skokowo wraz ze zmianą trybu lub utratą pakietów.

Wartość RF mode jest potrzebna do interpretacji. Ten sam RSSI przy szybkim i wolnym trybie nie musi oznaczać tego samego marginesu. Nadajnik może też dynamicznie zmieniać moc.

Dashboard nie powinien sprowadzać jakości do jednego „procentu zasięgu”. Do analizy technicznej zapisuje się surowe pola, tryb, moc, packet rate i pozycję/orientację platformy.

Telemetria#

Kierunek FC → odbiornik może przenosić baterię, GPS, barometr, attitude, tryb lotu, komunikaty i inne dane. Odbiornik przesyła wybrane ramki przez radio do nadajnika, gdzie handset lub skrypt je prezentuje.

Nie wszystkie sensory wymagają tej samej częstotliwości:

dane charakter
napięcie/prąd kilka–kilkanaście Hz zwykle wystarcza
GPS zależnie od zastosowania, zwykle wolniej niż attitude
tryb lotu event + okresowe odświeżenie
tekst statusowy kolejka, niski priorytet
attitude wyższa częstotliwość, ale ograniczona wartość na małym ekranie
parametry na żądanie, z kontrolą transakcji

Pasmo downlinku radiowego bywa mniejsze od UART. Zalanie portu telemetrycznego nie zwiększa ilości danych docierających do operatora; tworzy kolejki i opóźnia informacje ważniejsze. Scheduler powinien ustalać priorytety, limity i freshness.

Betaflight publikuje listę wspieranych ramek telemetrycznych, a ArduPilot ma własny moduł CRSF telemetry. Zestaw trzeba sprawdzać dla wersji firmware, zamiast zakładać identyczne pola.

Ramki rozszerzone i routing#

Extended frames dodają adres destination i origin, umożliwiając komunikację między urządzeniami w logicznej magistrali. Pole pierwszego address nadal dotyczy odbiorcy na bieżącym odcinku, a wewnętrzne adresy służą routingowi.

Router powinien:

  • walidować CRC przed odczytem adresów wewnętrznych;
  • mieć ograniczoną tabelę tras/portów;
  • zapobiegać pętli przez TTL, reguły topologii lub brak odbicia na źródło;
  • ograniczać szybkość broadcastów i zapytań discovery;
  • zachować nieznane, poprawne typy jako ruch do pominięcia, nie wyjątek;
  • nie blokować kanałów RC długą obsługą urządzeń.

CRSF nie zapewnia ogólnej gwarancji dostarczenia. Aplikacja parametrów lub komend potrzebuje identyfikatorów transakcji, timeoutu i możliwości ponowienia zgodnej z typem wiadomości. Nie wolno zakładać, że odpowiedź zawsze nadejdzie po jednej ramce.

Urządzenia i parametry#

Device ping i device info pozwalają wykryć urządzenia oraz wersje. Ramki parametrów umożliwiają przeglądanie i zmianę ustawień odbiornika/modułu przez handset. Wygoda tworzy wymagania bezpieczeństwa i spójności.

Model parametru powinien uwzględniać:

  • identyfikator urządzenia i parametru;
  • typ danych, zakres i jednostkę;
  • wersję opisu;
  • odczyt przed zapisem;
  • potwierdzenie wartości po zapisie;
  • timeout i ponowienie;
  • stan wymagający restartu;
  • zakaz części zmian podczas armed.

Zmiana protocol output, baud, regulatory domain albo model match może natychmiast przerwać łącze. Interfejs powinien ostrzegać i wykonywać takie operacje tylko na ziemi. FC nie może automatycznie uznać każdej poprawnej ramki parameter write za autoryzowaną tylko dlatego, że ma CRC.

W środowisku przemysłowym parametry krytyczne najlepiej blokować w profilu produkcyjnym, podpisywać konfigurację poza CRSF albo wymagać fizycznego trybu serwisowego.

Parser strumieniowy#

CRSF jest protokołem długościowym. Automat może wyglądać tak:

WAIT_ADDRESS
   ↓ accepted address
READ_LENGTH
   ↓ sane length
READ_BODY(length bytes)
   ↓ complete
VERIFY_CRC → DISPATCH
   │ fail
   └────────> RESYNC

Adres nie zawsze jest jednym stałym sync byte, więc parser ma listę dozwolonych adresów dla portu. Po length wyznacza całkowitą liczbę bajtów i deadline. Bufor ma stały maksymalny rozmiar; nie wykonuje się dynamicznej alokacji w ścieżce czasu rzeczywistego.

Po CRC dispatcher sprawdza typ i dokładną długość payloadu. Dane kanałów trafiają do osobnego szybkiego konsumenta, statystyki do telemetry state, a ramki urządzeń do kolejki o niższym priorytecie. Nieznany typ jest pomijany.

Publikacja kanałów ma wyższy priorytet niż generowanie odpowiedzi na parametry. Parser przerwania/DMA powinien jedynie składać ramki i umieszczać zdarzenia w bounded queue. Złożone formatowanie tekstu nie może działać w ISR.

Resynchronizacja po błędzie#

Błędne CRC może wynikać z utraty, dodania lub zmiany bajtu. Ponieważ address może pojawić się w payloadzie, proste wyrzucenie do następnego 0xC8 nie gwarantuje synchronizacji. Strategia przesuwanego okna:

  1. po błędzie zachować wszystkie bajty oprócz pierwszego;
  2. znaleźć kolejny dozwolony address;
  3. sprawdzić, czy następny bajt daje sensowną długość;
  4. jeśli jest komplet danych, zweryfikować CRC;
  5. jeśli nie, czekać tylko do deadline;
  6. po poprawnej ramce wrócić do normalnego trybu.

Alternatywnie przerwa na linii może wyznaczać nową granicę, ale CRSF może przesyłać ramki blisko siebie. Nie należy polegać wyłącznie na idle gap.

Licznik kolejnych błędów uruchamia kontrolowany reset DMA/UART, a nie pełny restart FC. Jeśli błędy trwają, system przechodzi do failsafe i zapisuje snapshot rejestrów portu.

Overrun oznacza, że software nie odebrał danych w terminie. Zwiększenie bufora maskuje symptom, ale przyczyną może być priorytet przerwań albo długa sekcja krytyczna. Wysoki packet rate i telemetria w obu kierunkach muszą być testem obciążeniowym.

Deadline i failsafe#

CRSF nie potrzebuje osobnego bitu failsafe w każdej ramce kanałów, aby FC wykrył utratę. Najważniejszy jest czas od ostatniej poprawnej, świeżej ramki RC oraz stan przekazany przez implementację odbiornika. CRC błędna ramka nie odnawia deadline.

Maszyna może rozróżniać:

HEALTHY
  ├─ pojedynczy brak / pogorszenie LQ → DEGRADED
  ├─ age RC > warning threshold       → DEGRADED
  └─ age RC > control deadline        → FAILSAFE

DEGRADED
  ├─ stabilne poprawne ramki → HEALTHY po histerezie
  └─ deadline               → FAILSAFE

FAILSAFE
  └─ odzyskanie + warunki recovery → kontrolowany powrót

Link statistics nie zastępuje ramek RC. Można odbierać telemetrię/urządzenia, gdy kanały nie są świeże. Deadline kanałów jest osobny. Z drugiej strony chwilowy brak ramki stats nie powinien unieważnić świeżych kanałów.

Wartość ostatnich drążków nie jest bezpiecznym domyślnym stanem na czas nieograniczony. Czas utrzymania musi być krótki, jawny i wynikać z analizy dynamiki. Po jego przekroczeniu autopilot wykonuje właściwą procedurę: stabilizację, hold, powrót lub lądowanie zależnie od platformy i dostępnych sensorów.

Budżet przepływności#

Surowe pasmo 420 kbit/s przy 8N1 daje około 42 000 bajtów/s przed narzutem ramek. To wspólna pojemność kierunku, ale każdy kierunek full-duplex ma własną linię. Rzeczywisty budżet uwzględnia adres, długość, typ, CRC i luki/harmonogram.

Dla ramki kanałów 26 bajtów:

częstość bajty/s udział 42 kB/s
50 Hz 1 300 3,1%
150 Hz 3 900 9,3%
250 Hz 6 500 15,5%
500 Hz 13 000 31,0%
1000 Hz 26 000 61,9%

To szacunek samych ramek 0x16. Dochodzą statystyki i inne wiadomości. Przy wysokim packet rate 420 kbit/s może stać się ograniczeniem; współczesne wersje systemów mogą negocjować wyższe szybkości. Projekt nie powinien zakładać 1000 pełnych ramek/s bez pomiaru wersji, formatu i UART.

W kierunku telemetrii ograniczeniem może być radio, nie UART. Scheduler musi znać budżet przydzielony przez system i nie tworzyć nieskończonej kolejki. Stare dane telemetryczne wyrzuca się lub nadpisuje najnowszą próbką zamiast przesyłać historię z dużym opóźnieniem.

Harmonogram i priorytety#

Priorytety przykładowe:

  1. odbiór i publikacja kanałów RC;
  2. obsługa deadline/failsafe;
  3. statystyki linku;
  4. krytyczne ostrzeżenia baterii/systemu;
  5. okresowa telemetria podstawowa;
  6. device discovery i parametry;
  7. teksty oraz dane diagnostyczne o niskim priorytecie.

Kanały nie powinny czekać za długą ramką parameter response w tej samej kolejce software. Full-duplex zmniejsza konflikt kierunków, ale CPU, DMA i parser nadal są wspólne. Bounded queues i drop policy muszą być jawne.

Każdy typ telemetryczny ma okres minimalny, maksymalny wiek i regułę koalescencji. Napięcie można zastąpić najnowszą wartością. Tekst statusowy może wymagać FIFO, ale z limitem i priorytetem severity.

Znacznik czasu powinien pochodzić z monotonicznego zegara FC. Timestamp odbioru końca ramki i timestamp źródła sensora to różne wielkości. Dla analizy latency warto zachować oba, jeśli protokół typu je niesie.

Integracja z ExpressLRS#

Odbiornik UART ExpressLRS domyślnie komunikuje się z FC przez CRSF. Procedura sprzętowa:

  1. potwierdzić model odbiornika, wersję firmware i napięcie;
  2. połączyć TX RX-a z RX FC oraz RX RX-a z TX FC;
  3. połączyć masy i właściwe zasilanie;
  4. wybrać port jako Serial RX/RC input;
  5. wybrać provider CRSF;
  6. wyłączyć inwersję i half-duplex dla zwykłego portu;
  7. włączyć telemetrię, jeśli firmware tego wymaga;
  8. sprawdzić kanały, link stats i telemetry return;
  9. zamknąć program konfiguracyjny zajmujący port przed passthrough/update.

ExpressLRS oferuje też Inverted CRSF do połączenia z inwertowanym wejściem oraz możliwość wyjścia SBUS. Należy zapisać wybraną opcję. Po aktualizacji odbiornika sprawdza się, czy serial protocol i baud nie wróciły do domyślnych.

Packet rate, telemetry ratio i moc radia są parametrami warstwy RF. Wpływają na latency i przepływność, ale nie zmieniają wymagań elektrycznych UART. Test końcowy obejmuje wszystkie tryby RF dopuszczone operacyjnie.

Model match, binding phrase i regulatory domain mają znaczenie operacyjne, lecz nie są mechanizmem zabezpieczenia ramek CRSF na przewodzie. Fizyczny dostęp do portu nadal wymaga ochrony.

cecha SBUS CRSF MAVLink
główny cel kanały RC RC + telemetria urządzeń telemetria/komendy UAS
kierunek głównie jeden full-duplex full-duplex/logicznie sieciowy
ramka stałe 25 bajtów zmienna długość, typ, CRC v1/v2 z msgid, checksum, opcjonalnym podpisem
kanały 16×11 + 2 digital typowo 16×11, subset variants RC_CHANNELS/override jako wiadomości
link stats flagi lost/failsafe bogate osobne ramki RADIO_STATUS zależnie od linku
parametry urządzeń RC nie w wejściu klasycznym tak parametry autopilota/komponentów
uwierzytelnienie brak brak kryptograficznego MAVLink 2 może podpisywać
typowe pasmo 100k 8E2 ~420k lub wyżej od wolnego UART do sieci IP

CRSF jest efektywny dla kanałów i telemetrii nadajnika. MAVLink jest bogatszym protokołem UAS/GCS i nie powinien być bez potrzeby tunelowany przez mały downlink. ExpressLRS oferuje również tryb natywnego MAVLink w określonych zastosowaniach; to inny wybór architektoniczny niż CRSF telemetry.

SBUS wymaga jednego kierunku i bywa szerzej zgodny ze starszym sprzętem. Jeśli potrzebne są tylko kanały, może wystarczyć. Konwersja CRSF→SBUS usuwa CRC ramki CRSF, statystyki i return telemetry z punktu widzenia FC.

Bezpieczeństwo danych#

CRC wykrywa przypadkowe uszkodzenie, nie atak. CRSF nie zapewnia poufności ani kryptograficznego uwierzytelnienia ramek na lokalnym przewodzie. Urządzenie podłączone do UART może próbować wysyłać kanały, komendy lub parameter writes.

Zasady redukcji ryzyka:

  • port odbiornika nie jest współdzielony z nieufnym companionem;
  • parametry krytyczne są blokowane podczas armed;
  • komendy mają allowlistę i walidację stanu;
  • routing nie przekazuje dowolnych ramek między portami;
  • firmware urządzeń i konfiguracja są wersjonowane;
  • dostęp fizyczny do wiązki/USB jest kontrolowany;
  • parser jest odporny na długości, flood i nieznane typy;
  • telemetria tekstowa jest kodowana bez wstrzyknięcia sterowania terminalem/UI.

Radio ma własne mechanizmy wiązania i transmisji, ale ich analiza jest oddzielna. Bezpieczny link RF nie naprawia podatnego parsera UART, a poprawny parser nie zabezpiecza eteru.

Implementacja parsera#

Szkielet pokazuje kolejność walidacji:

#define CRSF_MAX_FRAME 64U

typedef struct {
    uint8_t data[CRSF_MAX_FRAME];
    uint8_t used;
    uint8_t expected;
    uint32_t started_us;
} crsf_parser_t;

parse_result_t crsf_push(crsf_parser_t *p, uint8_t byte, uint32_t now_us)
{
    if (p->used == 0U) {
        if (!accepted_address(byte)) return PARSE_WAITING;
        p->data[p->used++] = byte;
        p->started_us = now_us;
        return PARSE_COLLECTING;
    }

    if (frame_deadline_expired(p, now_us)) {
        parser_reset(p);
        return PARSE_TIMEOUT;
    }

    if (p->used == 1U) {
        if (byte < 2U || byte > CRSF_MAX_FRAME - 2U) {
            parser_resync_with_candidate(p, byte, now_us);
            return PARSE_BAD_LENGTH;
        }
        p->expected = (uint8_t)(byte + 2U);
    }

    p->data[p->used++] = byte;
    if (p->used < p->expected) return PARSE_COLLECTING;

    const uint8_t calc = crc8_d5(&p->data[2], p->expected - 3U);
    const uint8_t got = p->data[p->expected - 1U];
    if (calc != got) {
        parser_resync_buffer(p, now_us);
        return PARSE_BAD_CRC;
    }

    dispatch_valid_frame(p->data, p->expected, now_us);
    parser_reset(p);
    return PARSE_FRAME;
}

To wzorzec edukacyjny. Produkcyjny parser musi poprawnie zachować kandydatów przy resync, rozróżniać formaty extended, obsługiwać błędy UART i nie dopuścić do zapisu poza bufor. Funkcja dispatch_valid_frame waliduje długość konkretnego typu przed odczytem pól.

Kanały 0x16 dekoduje się do lokalnej struktury, nadaje jeden timestamp/sequence i dopiero atomowo publikuje. Link stats i telemetry mają osobne snapshoty oraz age.

Generowanie ramek stosuje tę samą bibliotekę CRC i length. Test round-trip nie wystarcza, bo wspólny błąd encoder/decoder może się ukryć; potrzebne są wektory z niezależnej implementacji.

Diagnostyka#

Najbardziej użyteczny panel portu pokazuje:

  • skonfigurowany i zmierzony baud;
  • liczniki bytes, valid frames i frames per type;
  • CRC, bad length, unknown address/type;
  • UART parity/framing/noise/overrun;
  • wiek ostatniej ramki RC, stats i telemetry;
  • częstotliwość kanałów oraz jitter interwału;
  • RSSI/LQ/SNR/RF mode/power z timestampem;
  • zajętość i dropy kolejki telemetrycznej;
  • ostatni reset/renegocjację prędkości.

Oscyloskop odpowiada na pytania o poziom, polaryzację, baud i ringing. Analizator logiczny dekoduje długi strumień. Log FC łączy ramki z armingiem, failsafe i zachowaniem platformy.

Przy braku kanałów, ale działającej telemetrii, prawdopodobne są pomylone kierunki logiczne, zły provider lub filtr typów. Przy kanałach bez telemetrii zwykle brakuje przewodu FC TX→RX receiver, telemetria jest wyłączona albo radio ma zerowy/niski przydział downlinku.

CRC errors tylko przy uruchomionych silnikach wskazują EMC, masę albo zasilanie. Overrun bez CRC przy dużym rate sugeruje scheduler/DMA. Stabilne CRC, lecz duży age_rc może oznaczać ograniczenie packet rate lub problem po stronie radia.

Plan testów#

Parser i format#

  • minimalna i maksymalna dozwolona długość;
  • zero, jeden i length ponad bufor;
  • poprawne/niepoprawne CRC dla każdego wspieranego typu;
  • adres FC, broadcast i nieobsługiwany adres;
  • pełna ramka 0x16 z wektorami wszystkich 16 kanałów;
  • ramki 0x17 dla każdej rozdzielczości i podzbioru;
  • nieznany typ z poprawnym CRC;
  • utrata, duplikacja i wstawienie bajtu;
  • dwie ramki bez przerwy i fragmenty w dowolnych chunkach DMA.

Timing i obciążenie#

  • wszystkie dopuszczone packet rates;
  • maksymalna telemetria w przeciwnym kierunku;
  • obciążenie CPU, logowania, OSD i sensorów;
  • histogram interwału/latency kanałów;
  • overrun i zajętość kolejek;
  • 416666, 420000 oraz tryby negocjowane zgodne z urządzeniami;
  • temperatura i tolerancja zegarów.

Failsafe#

  • utrata pakietów RF przy działającym UART;
  • wyłączenie nadajnika;
  • odłączenie TX odbiornika;
  • uszkodzenie CRC przy ciągłym strumieniu;
  • zatrzymanie wyłącznie ramek RC przy obecnych stats;
  • reset odbiornika i FC;
  • powrót linku z drążkami poza neutralnym stanem;
  • niezależny watchdog wyjść wykonawczych.

Telemetria i urządzenia#

  • każdy wymagany typ i zakres pola;
  • ograniczenie częstotliwości i drop policy;
  • discovery wielu urządzeń;
  • odczyt/zapis parametru, timeout i potwierdzenie;
  • odmowa krytycznej zmiany podczas armed;
  • nieznane nowe typy bez destabilizacji;
  • różne wersje FC, odbiornika i handsetu z macierzy wsparcia.

Hardware/EMC#

  • poziomy przy minimalnym/maksymalnym zasilaniu;
  • długi przewód docelowy, temperatura i wibracje;
  • pełna moc napędu, VTX i przetwornic;
  • niezależne cykle zasilania obu urządzeń;
  • ESD zgodnie z wymaganiami platformy;
  • błędne połączenie jednego kierunku jako test negatywny.

Typowe błędy#

objaw prawdopodobna przyczyna pomiar
brak kanałów i telemetrii TX/RX pomylone, zły UART/provider lub zasilanie oscyloskop na obu liniach
kanały są, telemetrii brak brak FC TX→RX receiver, telemetria off, brak downlinku ruch bajtów w obu kierunkach
ciągłe CRC errors baud/polaryzacja/EMI lub błędny zakres CRC bit time + raw frame
błędy tylko przy wysokim rate ograniczenie baud, overrun/DMA port counters i zajętość CPU
po zmianie 416666/420000 link znika niezgodność implementacji wersje firmware i zmierzony baud
LQ jest stare, lecz wygląda poprawnie brak age/timeout stats timestamp ramki 0x14
FC nie wchodzi w failsafe telemetry frames odnawiają wspólny timeout osobny age_rc
parametry działają, sterowanie laguje zły priorytet routera/kolejki latency per frame type
losowe kanały po poprawnym CRC błąd unpack/bitfield/endian niezależne wektory 0x16
tylko część kanałów jest świeża błędna obsługa 0x17 subset freshness per subset/channel
działa na stole, nie w locie EMI, masa lub brownout RX CRC/overrun + napięcie
po update odbiornika brak linku zmieniony protocol output/baud WebUI i manifest konfiguracji

Kryteria odbioru#

obszar przykładowe kryterium
elektryka pełny nieodwrócony UART i właściwe poziomy z marginesem
baud zgodność obu końców we wszystkich wspieranych wersjach
framing length, limit i CRC sprawdzane przed interpretacją
kanały 0x16 i wymagane warianty 0x17 przechodzą niezależne wektory
atomowość komplet kanałów otrzymuje spójny timestamp i sequence
freshness osobne age dla RC, stats i telemetrii
failsafe brak świeżych RC uruchamia zdefiniowaną reakcję w terminie
throughput brak overrun i kontrolowane dropy przy najgorszym rate
priorytety telemetry/parametry nie opóźniają kanałów poza budżet
routing adresy i nieznane typy nie tworzą pętli ani floodu
konfiguracja wersje, protocol output i baud są w manifeście platformy
EMC CRC/overrun mieszczą się w limitach przy pełnym napędzie i RF
obserwowalność port publikuje liczniki, częstotliwości, age i link stats

CRSF daje flight controllerowi znacznie więcej kontekstu niż jednokierunkowy strumień kanałów, ale tylko wtedy, gdy implementacja zachowuje granice semantyczne. CRC portu nie jest jakością RF, telemetria nie jest świeżością sterowania, address nie jest uwierzytelnieniem, a wysoki packet rate nie jest gwarancją niskiego latency. Każda z tych wielkości wymaga osobnego pomiaru i deadline.

Powiązane tematy#

Przypisy#

  1. ExpressLRS, Receiver Serial Protocols, https://www.expresslrs.org/software/serial-protocols/ (dostęp: 15 sierpnia 2026).
  2. ExpressLRS, Configuring FC, https://www.expresslrs.org/quick-start/receivers/configuring-fc/ (dostęp: 15 sierpnia 2026).
  3. ExpressLRS, High Performance Open Source Radio Control Link — source repository, https://github.com/ExpressLRS/ExpressLRS (dostęp: 15 sierpnia 2026).
  4. Betaflight, CRSF protocol definitions, https://github.com/betaflight/betaflight/blob/master/src/main/rx/crsf_protocol.h (dostęp: 15 sierpnia 2026).
  5. Betaflight, CRSF receiver implementation, https://github.com/betaflight/betaflight/blob/master/src/main/rx/crsf.c (dostęp: 15 sierpnia 2026).
  6. Betaflight, Telemetry, https://betaflight.com/docs/wiki/guides/current/Telemetry (dostęp: 15 sierpnia 2026).
  7. ArduPilot, AP_CRSF_Telem implementation, https://github.com/ArduPilot/ardupilot/blob/master/libraries/AP_RCTelemetry/AP_CRSF_Telem.cpp (dostęp: 15 sierpnia 2026).
  8. ArduPilot, Radio Control Systems, https://ardupilot.org/copter/docs/common-rc-systems.html (dostęp: 15 sierpnia 2026).

Źródła z centralnego rejestru

  1. ExpressLRS: Receiver Serial Protocols [dokumentacja projektu]
  2. ExpressLRS: Configuring a flight controller for CRSF [dokumentacja projektu]
  3. ExpressLRS — high-performance open-source radio link [repozytorium open source]
  4. Betaflight: CRSF protocol definitions [repozytorium open source]
  5. Betaflight: CRSF receiver implementation [repozytorium open source]
  6. Betaflight: Telemetry over CRSF [dokumentacja projektu]
  7. ArduPilot: CRSF telemetry implementation [repozytorium open source]
  8. ArduPilot: Radio Control Systems and receiver protocols [dokumentacja projektu]