Vlákno názorů ke článku Řízení kotle Arduinem od MarSik - Arduino standardní knihovna vznikla dávno před rokem 2011,...

  • 2. 1. 2025 13:16

    MarSik

    Arduino standardní knihovna vznikla dávno před rokem 2011, takže nové best practices v C++ a nové styly API tam prostě nejsou a nebudou. A vycházela ještě ze starších projektů Processing a Wiring.

    Cílová skupina pro Arduino navíc nejsou profesionální embedded vývojáři. Primárně s ním začali umělci a akademici. Bez wifi (ESP přišlo až mnohem později). A i dnes je spousta kódu od bastířů, hardwerářů a lidí co napíšou co potřebují pro svůj problém (motto: scratch your own itch). Takže ten komentář "Dodělám později" není nic neobvyklého.

    Už jsme na to narazili v diskuzi o Fish. Lidi nemají obecně motivaci přepisovat starý kód do nového stylu, pokud to neopraví něco zásadního. A staré styly API snadno nezměníte, protože by to rozbilo veškerý starý kód (dekádu trvající přechod Python 2 vs. 3 nám buď varováním).

    Takže ano, ty vysokoúrovňové Arduino abstrakce neumí využít ten hardware naplno nebo neumožní libovolné skládání více asynchronních úloh (nebo neumí low power provoz).

    Pokud jste si nikdy nevšiml, průmyslové embedded kontroléry se snaží multitaskingu vyhnout! Superloop styl s pollingem je velice obvyklý. Nikdy jste se nezamyslel nad významem Arduino základních metod setup a loop?

    https://en.wikibooks.org/wiki/Embedded_Systems/Super_Loop_Architecture

    Mimochodem, zrovna ten ESP wifi koprocesor polling umí, jen si ho musíte zakomponovat do smyčky sám. Arduino vysokoúrovňové API je úmyslně jednoduché (viz cílová skupina).

    https://github.com/arduino/ArduinoCore-renesas/blob/main/libraries/WiFiS3/src/WiFi.cpp - je to jen práce se sériovou linkou.

    Komunita jako taková pak umí napsat i kvalitní kód, třeba EtlCPP (https://www.etlcpp.com/) je implementace STL kontejnerů a algoritmů pro prostředí bez dynamické alokace.

    Pro lidi více na profesionální straně spektra je tu pak třeba možnost použít PlatformIO (https://platformio.org/) a vyhnout se Arduino IDE úplně.

    Takže až příště budete nadávat na API a kvalitu, zamyslete se nad tím co používáte. On je totiž rozdíl mezi hobby a průmyslovým "nářadím". Arduino tudíž ani nemůže přejít na profesionální a detalní API, protože by tím odřízlo svoji cílovou skupinu (a staré projekty).

  • 2. 1. 2025 18:21

    Ondřej Novák

    V tom prvním máte určitě pravdu, že staré API se špatně opravuje a jediná schůdná cesta je pak přes nové alternativní API, které zase vede k nutnosti udržovat obě. A rozumím, není to jednoduché.

    Taky můj rozbor digitalWrite a pinMode nebyl míněn jako kritika, ale jako určité vyjádření pochopení. Já bych si představoval něco jako pinModeEx(pin, mode), která by třeba mohla nastavit pin do libovolného z výše uvedených stavů, kdy HIGH a LOW jsou také chápány jako móde. Pak by se mi líbil systém transkačních nastavení pinů, kdy nastavím víc pinů a jednorázově to commitnu, a někdo under hood zařídí operaci atomicky. Je to rozšíření API

    Namítám ale jednu věc. Arduino R4 UNO (Minima i Wifi) byly uvedeny v červnu 2023. Předpokládejme že vývoj SW probíhal rok, tedy bavíme se o programátorských standardech z roku 2022. Navíc pro překladač, který v té době už 6 let podporuje C++17. Ty programátorské styly které se tam používají byly platné před rokem 2011, to je nějaký 12 let!!!! Kritika je na místě

    Bridge mezi ESP32 a Renesas je softwarové vybavení které vzniklo přímo určené pro Arduino R4, jinde se nepoužívá . Github tohoto projektu začíná 16. května 2023

    https://github.com/arduino/uno-r4-wifi-usb-bridge/commit/9d2e7d71183d8a6e3e7e3511237dd7e0f2a7aa58

    Takže se prosím přestaňme vymlouvat na stará API a neexistenci ESP čipů. Ten kód je z brusu nový.

    Pak bych potřeboval vysvětlit ty poznámky kolem superlooup. Jestli jse z toho pochopil, že mi chybí multitasking - nic takového jsem neříkal, je rozdíl mezi "parallel a concurrency". Stejně tak když někde zmíním asynchroní přístup, nemyslím s tím multithreading. Právě asynchronní přístup umožnuje dobře navrhnout superloop. Ten jen není pevně danný, ale dynamicky provádí to, co je požadováno. Typicky mohu superloop použít pro eventové řízení. V rámci superloopu se zjistí změna stavu nějakého čidla a vygeneruje se event. Asynchronní kód pak může vypadat takto


    co_await wait_pin(1, HIGH); //čekej na až bude pin 1 na HIGH

    přitém co_await vrací řízení do superloopu. To je concurrency, to je asynchronní řízení. Pokud nemám co_await, mohu postaru použít callbacky, třeba


    on_pin(1, HIGH, [=]{... /* dělej něco */ ...});

    I to je asynchronní přístup.

    Scan network by šel realizovat


    WiFi.scanNetwork( [=] (auto result) {... zpracuj vysledek ...} );

    S tím, že lambda callback se zavolá jakmile je scan hotový a kód mezitím dělá něco jiného. Samozřejmě se callback zavolá ze superloopu když se zjistí, že operace je dokončena.

    A tím se dostávám k poolingu nad ESP. Nemáte pravdu, pooling tam nejde zapnout, nebo jen pro některé operace. Ano WiFiServer.ava­ilable() tam je, stejně jako WiFiClient.ava­ilable() ale to je všechno. Třeba WiFi.localIP je blokující s timeoutem až 10 sekund. WiFi.begin() je blokující, ale timeout si mohu nastavit (naštestí), WiFiClient.send() je blokující, pokud ESP zrovna loví signál a nemá kam data odeslat

    Aby ten bridge byl plně asynchroní, musel by ten protokol vypadat jinak. API by muselo používat callbacky nebo korutiny (C++20), Muselo by se v superloopu volat nějaké udělátko co zjišťuje, jestli ESP už dokončil činost. V protokolu by na to musel existovat nějaká krátká zpráva, která by se na serial portu neztratila. Třeba znak. Jakmile by se ten znak objevil, ze strany Renesas by se poslal command na přečtení výsledku.

    To by pak umožnilo superloopu vyvolávat asynchronní callbacky na požadované operace.

    Uvažoval jsem, že bych to samozřejmě celé přepsal, ale pro koho? Kdo to ocení? Já zřejmě žádný další projekt zatím dělat nebudu.

    (navíc bych musel asi přepsat i ten bridge, změnit protokol)

    Doufám, že si teď rozumíme.

  • 2. 1. 2025 22:32

    MarSik

    Renesas podpora sice je relativně nová, ale ten stejný kód (API) funguje pořád i na původní AVR Arduino Uno. A taky na dalších deskách s jinými cpu - MSP430, ESP, Tiva, STM, .. A ne všechny ty desky se chovají stejně nebo mají stejný přístup k nastavování GPIO. AVR třeba neumí open-drain a musí se emulovat. MSP a STM32 open drain umí atd.

    Korutiny jsem právě na mysli neměl. Měl jsem na mysli opravdu čistý polling, kde je garantováno pořadí v jakém se veškerý kód provede, a to včetně časování.

    - přečíst vstupy
    - vypočítat akce (něco jako serial buffer = "wifi connecting")
    - nastavit výstupy (serial write "get wifi status")
    - znovu nebo čekat

    Podívejte se na kód té WiFi třídy. Ta polling část se dá realizovat pomocí toho objektu modem. Jediné co to dělá je posílání a příjem dat přes sériovou linku. Takže pošlete dotaz na stav. A pollujete odpověď.

    Co se nových C++17 vlastností týče.. cílová skupina pro Arduino prostě C++ korutiny nezvládá. (Popravdě, ta [=] syntaxe je hrozná, ale to je asi o zvyku). A souhlasím, že zrovna ten wifi bridge je hrozně nečitelný. A to ani nemusím komentovat C++, ono je to nečitelné i z pohledu C.

  • 3. 1. 2025 8:27

    Ondřej Novák

    Jasně to wifi bych si přes Modem musel napsat sám a taky jsem to někde udělal, ale je to ad-hoc. Přepisovat to celý na async pooling se mi nechce, jsem už na to moc línej a nebudu to asi potřebovat

  • 3. 1. 2025 0:19

    Dreit

    Mám za to, že za standardní knihovnu existují víceméně drop-in náhrady. Před lety se řešilo že DigitalWrite sežere snad 100 strojových cyklů aby změnil stav pinu, ale možná už to trochu osekali, netuším. Rozhodně byly alternativní knihovny co to uměly pořádně zrychlit.