Dvě aplikace, jeden systém
TX a RX nejsou dvě poloviny jednoho obřího programu. Jsou to dvě samostatné FreeRTOS aplikace s vlastními tasky, vlastní konfigurací a přesně rozdělenou odpovědností. Spojuje je až rádiový protokol. To je důležitější než samotný výběr ESP32 nebo nRF24 — každá strana může uvnitř růst, dokud nezmění význam bajtů, na kterých se obě dohodly.
Na TX začíná řídicí cesta v tx_io. Tam vzniká stabilní snímek ADC, tlačítek a enkodéru. Supervisor na něj aplikuje kalibraci, profil, trim, limity, expo, jízdní režim a bezpečnostní pravidla. Teprve potom sestaví další paket. RF vrstva neřeší, jestli hodnota vznikla z plynové páky nebo z menu. Dostane hotovou zásilku a odešle ji.
RX jde opačně. RF přijme a zkontroluje paket, Pošťák jej zveřejní aplikaci, link a ochranné politiky rozhodnou, zda je možné jej použít, RX supervisor přeloží obecné funkce na konkrétní výstupy a rx_io je fyzicky provede. V téže cestě vznikne ACK s telemetrií a skutečným stavem auta. Nevracím tedy jen „paket dorazil“, ale také „tohle RX opravdu dělá“.
Rytmus určuje TX, ne displej
TX má nezávislý 1ms HW sampler, 5ms supervisor a samostatnou 5ms kalibraci. Rádiový task běží po 5 ms, při ručním RF PA = MAX po 10 ms. Tasky si předávají poslední úplný snapshot bez čekání na společnou fázi a zpožděné cykly nedohánějí dávkou starých paketů. Displej, web a OTA běží vedle toho v jiných taskech. Když se web na chvíli zamyslí nad JSONem, opravdu nechci, aby si kvůli tomu auto rozmyslelo plyn.
RX dnes nemá pevnou 20ms periodu řízení. RF task po každém batchi s alespoň jedním validním paketem pošle aplikaci notifikaci a ta okamžitě zpracuje poslední atomický snímek z Pošťáku. Dvacet milisekund zůstává jen jako bezpečnostní probuzení bez RF eventu a jako rytmus pomalejšího housekeepingu. Rádiová kadence, fyzické řízení a servisní práce tak mají vlastní jasné hranice.
STEER a THROTTLE na používaném S3 RX sdílejí vyhrazený MCPWM timer na 200 Hz. Pomocná analogová serva diferenciálů, převodu a navijáku zůstávají na původních 50 Hz. Opravená TX/RX dvojice prošla společným OTA a v M020 jsem prakticky ověřil start, link, běžné řízení i základní failsafe.
Rádiová vrstva běží na 250 kb/s. Dnešní paket se pohybuje kolem 2050 µs, takže v pětimilisekundovém okně zůstává rezerva i pro ACK a obsluhu kolem něj.
Osmnáct bajtů tam, třináct zpátky
Aktuální protokol v13 posílá k RX pevný 18B paket. Obsahuje stavové příznaky, pořadové číslo, čtyři šestnáctibitové osy, šestnáctibitovou masku funkcí, čtyřbajtový servisní rámec a CRC16. Z RX se vrací 13 B: teplota motoru, ESC a jádra RX, napětí baterie, servisní odpověď, skutečná maska funkcí, stavové příznaky, diagnostické bity a CRC8.
Osy a přepínače říkají, co má model udělat. TX nemusí předstírat, že už se to stalo.
RX vrací aplikované funkce. Rozdíl REQ/ACT může UI zobrazit jako čekající změnu nebo problém.
Hlavní stav chrání vlastní CRC a celý rádiový přenos ještě hardwarová kontrola nRF24.
Přesný formát paketů, servisní operace a pravidla kompatibility jsou v technické dokumentaci Ultimate RC →
Pošťák hlídá celé zásilky
Jakmile několik tasků pracuje nad stejnými daty, vznikne obyčejná, ale nepříjemná otázka: co když jeden právě přepisuje paket a druhý jej ve stejné chvíli čte? Po prvním seznámení s FreeRTOS a mutexy jsem nechtěl tento problém rozlézt po celém programu. Vznikla proto jedna čistá hranice — Pošťák.
Pro každý směr drží dva datové hrníčky. Producent zapisuje do neaktivního, dopočítá CRC a až hotový obsah atomicky zveřejní. Čtenář vždy dostane kopii posledního kompletního stavu. Nikdy směs staré první poloviny a nové druhé. Stejný mechanismus funguje na TX i RX; pouze se prohodí typ příchozí a odchozí zásilky.
Díky tomu aplikační logika nesahá přímo na rádio a RF task nemusí znát menu, profily ani failsafe. Pošťák není další „chytrá“ vrstva. Je to schválně hloupá pošta, která velmi dobře dělá jednu věc.
RX nepřemýšlí v pinech, ale ve funkcích
V prvních pokusech by šlo napsat „GPIO 8 je řízení, GPIO 7 plyn“ a hotovo. Jenže tím bych nevytvořil univerzální RX, pouze další jednorázovou desku. Aktuální konfigurace proto pracuje s logickými OUT sloty. Pinout vybere fyzické GPIO pro konkrétní desku, ale uživatel slotu přiřazuje funkci a její parametry.
Funkce sama určí, zda potřebuje servo, digitální výstup nebo PWM a jak se její hodnota počítá. Vedle řízení, plynu, obou uzávěrek a řazení jsou tu naviják, běžná i dálková světla, světelná rampa, hazard, automatické blinkry, maják, brzdové a couvací světlo nebo ventilátory motoru a ESC podle teplotní křivky. Parametry jako servo dorazy, střed, travel, PWM jas, rampa nebo rytmus majáku patří k funkci, ne do změti podmínek nad konkrétním GPIO.
Tím software odděluje dvě věci, které se při prototypování často zbytečně slepí: co výstup znamená a kde je zrovna připojený. Výměna desky pak mění pinout, ne celý způsob uvažování RX.
Profil není jen jméno auta
TX umí až deset modelových profilů. Každý má jméno, vlastní RF kanál, mapování čtyř fyzických os na řízení, plyn a dva AUX kanály a vlastní funkce tlačítek. Pro osu se ukládá inverze, trim, dual rate, spodní a horní limit i expo. Dvanáct vstupních slotů může rozlišovat držení, klik a dlouhý klik a pracovat přímo, jako toggle nebo jako chytřejší cyklická funkce.
Uvnitř jednoho profilu jsou tři jízdní režimy. Každý může mít jiné mapování os i tlačítek, takže crawl režim nemusí být jen kosmetický nápis na displeji. Může skutečně změnit citlivost řízení, expo, rozsahy i to, co dělá konkrétní ovladač. Celý režim se přepne jako jeden konzistentní balík.
Jedna drobnost je důležitá: kalibrace Hallových snímačů je globální, protože patří fyzickému TX. Profil si nese až způsob, jak jejich kalibrované hodnoty použít. To je přesně ten rozdíl mezi vlastností zařízení a vlastností modelu, který se v konfiguraci snadno poplete.
Vedle řízení běží malý potvrzovaný kanál
V té době jsem si z vlastní zvědavosti kvůli nesouladu svých znalostí s oponentem dostudoval základní principy SAE a CANopen. Potvrdil jsem si, že mi některé věci neseděly oprávněně, a zároveň mě napadlo použít v RCulti oddělený princip požadavek → potvrzení. Ne kopírovat CAN, ale vzít si z něj užitečný způsob uvažování o službách vedle rychlých provozních dat.
Service channel má v obou směrech pouze čtyři bajty, ale nese ID transakce, operaci nebo stav, úlohu, parametr a hodnotu. Aktivní je vždy jen jeden požadavek. TX jej opakuje, dokud RX nepotvrdí přesně stejné ID, úlohu a parametr. RX stejnou transakci provede jen jednou a pro duplikát vrátí uložený výsledek. To je důležité hlavně u zápisu do NVS — ztracený ACK nesmí znamenat druhý zápis do flash.
Opuštěná transakce se sama uklidí podle času i počtu rádiových cyklů. Vícebajtová hodnota se rozdělí na potvrzované fragmenty a použije až celá. Hlavní řízení, failsafe a telemetrie přitom dál používají své pevné místo v každém paketu. Servisní vrstva je záměrně pomalejší a opatrnější; nemá právo unést volant.
Dorazy obou uzávěrek a převodovky lze doladit na TX, okamžitě vyzkoušet a teprve dlouhým klikem uložit.
PWM světelné rampy, ruční světelné příspěvky, automatické blinkry a jejich střed.
Menu potvrzeně zapne jeho servo signál, posílá rychlost a při zavření nejprve potvrdí STOP, potom disarm.
Aktuální v13 umí potvrzeně vypnout ochranu nebo během kritického okna potvrdit uspání RX.
Megatransfer: osy na chvíli nejsou osy
Megatransfer nevznikl jako plánovaná velká datová vrstva. Po výměně RX jsem jen nechtěl znovu otevírat access point a ručně opisovat domácí Wi-Fi. Čtyřbajtový servisní rámec už uměl řídit potvrzenou transakci, ale celé SSID a heslo se do něj rozumně nevešlo.
V bezpečném režimu proto čtyři osy dočasně přestanou znamenat pohyb a vytvoří osmibajtový datový chunk. Service frame dál řídí BEGIN, index každého kusu, END a potvrzení. Velikost hlavního paketu se nezmění a běžný RF mechanismus se nemusí obcházet druhým rádiovým protokolem.
RX takový přenos přijme pouze s příznakem failsafe. Nejdřív vynutí hardwarový servo disarm a stav READY vrátí až ve chvíli, kdy jsou signály opravdu LOW. Wi-Fi profil se složí v RAM, ověří CRC32, zkusí se připojit a do NVS se uloží až po získání IP adresy. Při chybě se vrátí původní konfigurace. Tento happy path není jen představa ve zdrojáku; na současném TX a RX V2 je prakticky ověřený end-to-end.
Failsafe je posloupnost, ne hodnota
První failsafe uměl auto zastavit a nedělat kraviny. Dnešní ochrana je ale složená z několika stavových automatů, protože každá vrstva řeší jiný druh průšvihu. RX neuzná spojení jen proto, že mu právě přiletěl jeden paket. Sleduje čerstvost místního příjmu i LINK stav vrácený druhou stranou, tedy skutečně obousměrnou komunikaci.
Po potvrzené ztrátě linku následuje řízená rampa os do nuly, jedna sekunda držení neutrálu a teprve potom hardwarový disarm generátoru servo pulzů. Znovu je zapne až stabilní obousměrný link. Naviják má navíc vlastní armovací bránu, aby se po návratu spojení neprobudil starý stav otevřeného menu.
TX má svou bezpečnostní bránu. Po prvním navázání linku, po dlouhém výpadku nebo po nečinnosti nepustí řízení bez kontroly uživatele. Umí rozpoznat ovladač mimo neutrál a raději nabídne kontrolu nebo setup, než aby po spojení poslal nečekaný pohyb. Bezpečnost tedy není soustředěná do jednoho kouzelného if. Je rozdělená mezi obě role a každá hlídá to, co opravdu může vědět.
Stejnou cestu mohou vynutit i lokální ochrany RX. Teplotní automat sleduje jádro přijímače, rozlišuje varování a západkový trip. Battery guard pracuje s profilem článků, potvrzovacími časy a hysterezí; při kritickém napětí drží failsafe a dává krátké rozhodovací okno, ale při ztrátě linku nebo nouzovém napětí usne sám. Parametrické bateriové profily, warning, cutoff i vědomé vypnutí Battery Guardu jsou prakticky ověřené. K 8. září jsou uzavřené také timeout rozhodování, ztráta service spojení a nouzová spodní mez napětí. Otevřené zůstává fyzické vyvolání thermal tripu včetně celé bezpečnostní sekvence.
Web je dílna, TX je polní nářadí
Kompletní konfigurace patří na web. TX v setup režimu vytvoří vlastní AP a nabídne stav, kalibraci i profiler. V něm lze spravovat profily, tři jízdní režimy, osy, dvanáct tlačítek, RX výstupy, baterii, teplotní čidla a testovací režimy. RX má vlastní webové API, ale TX jej umí z prohlížeče proxyovat, takže kvůli jednomu systému nemusím přeskakovat mezi dvěma nesouvisejícími weby.
Setup se nezapne uprostřed aktivního povelu. TX nejdřív drží rádiový neutrál a teprve potom spustí Wi-Fi. RX web má vlastní lifecycle, reconnect a zotavení, aby síťová obsluha neblokovala rádio. Záloha RX profilu obsahuje identitu, logické OUT funkce, bateriovou kalibraci a teplotní nastavení, ale schválně neobsahuje hesla, API klíč, logy ani OTA stav.
Doma tedy používám velké a pohodlné rozhraní. V lese sahám po malém potvrzeném nastavení přímo v TX. Nejsou to dvě konkurenční cesty, ale dva nástroje pro dvě úplně jiné situace.
Massive prototyping znamená žádný kabel
Při množství změn v obou aplikacích se kabel rychle stal nejotravnější součástkou projektu. TX už měl displej, enkodér a setup Wi-Fi vyvolanou dlouhým klikem, takže první OTA krok byl prostý: když už jsem na internetu, podívej se, jestli tam není nový firmware.
Dnes TX načte manifest pro správnou hardwarovou roli, ověří verzi, velikost a SHA-256. RX aktualizaci dostane přes svůj webový endpoint, obraz si stáhne a ověří sám. Po instalaci není nový firmware okamžitě prohlášený za zdravý. Nejprve musí vzniknout kritické tasky a aplikace deset sekund stabilně běžet; při časném restartu zůstává bootloaderu možnost vrátit předchozí partition.
Společný TX/RX OTA průchod i rollback guard jsou prakticky ověřené. Stejně tak přechod stable/beta, vědomý downgrade a pravidla povinné dvojice. Konkrétní otevřená chyba je pozdní příchod RX do Setup Wi-Fi: nabídka se musí znovu vyhodnotit, i když TX už katalog načetl. OTA je pro mě hlavně vývojový nástroj — díky němu změnu reálně zkusím ještě dnes a ne „až někdy vytáhnu kabel“.
Blackbox uchová špínu před chybou
Běžná telemetrie dobře ukazuje, co se děje teď. Při krátkém výpadku je to přesně ten problém: než se k údajům dostanu, „teď“ už je zase v pořádku. Proto blackbox průběžně drží kruhovou historii v RAM a do flash ji uloží až při události, která stojí za zápis. Normální jízda tedy zbytečně neopotřebovává flash.
TX ukládá okolí failsafe, pádu nebo chybné service transakce včetně rádiových statistik, os, stavů bezpečnostní brány, servisního ID a času. RX má vlastní záznam okolí skutečného výpadku s příznaky obou stran, stářím paketu, výkonem rádia, IRQ statistikami, napětím a pamětí. Logy lze spravovat z webu i přes TFT kartu Setup → Logs. Společné mazání čeká nejprve na potvrzení RX. Nový RX záznam kombinuje rychlou stopu F s pomalou stopou S; ověření skutečných souborů RX_LAST.CSV při cílených výpadcích zůstává otevřeným testem.
Právě nemožnost zpětně vysvětlit krátké výpadky vedla k dedukci, že problém není v obsahu paketu, ale v napájení nRF24 zatíženém 200Hz provozem. Software neopraví špatnou filtraci. Může ale zachovat dost kontextu, abych neopravoval naslepo.
Příběh pokračuje ve vývojovém deníku
„Je to ve zdrojáku“, „prošlo to buildem“ a „jezdí to venku“ jsou tři různé stavy. V navazující kapitole proto vedu datované zápisy o nových funkcích, důvodech změn a praktickém ověření. Dole zůstává aktuální otevřená práce.
Od M020 přibylo ABS, stable/beta OTA, správa logů, ověřená obnova RX profilu a automatický návrat čidel. Současná beta přidává External světla a lokální obnovu nRF. Jejich praktické scénáře jsou uzavřené, ale nejde o nové stable vydání.