(Nízka) spotreba energie
problém spotreby energie v IoT riešeniach, o kapacite batérií a ich životnosti, riadenie spotreby energie pomocou softvéru, low power, polling, prerušenia, typy prerušení, ISR, výhody a nevýhody používania prerušení
The Problem of Power Consumption in IoT
(slide) Internet vecí so svojím príchodom priniesol niekoľko zaujímavých tém, ktoré je potrebné riešiť. Patria medzi ne témy ako je bezpečnosť, ergonómia, technológie pre komunikáciu, ale hlavne nízka spotreba zariadení. Zariadenia IoT sú totiž častokrát napájané batériou, pretože nemajú priamy prístup k napájaniu. To je častokrát spôsobené tým, že sú umiestnené na miestach, kde prístup k elektrickej sieti proste nie je možný.
(slide) Hľadanie spôsobov, ako zabezpečiť nízku spotrebu, však samozrejme so sebou neprinieslo až IoT. Už dávno predtým sme tu mali kalkulačky, diaľkové ovládače, digitálne hry, ale aj notebooky alebo mobilné telefóny. Všetky tieto zariadenia boli napájané z batérií. IoT zariadenia však predstavujú špeciálnu skupinu zariadení, kedy sa očakáva, že tieto zariadenia budú schopné vykonávať svoju činnosť bez zásahu používateľa mesiace až roky. A pred vyčerpaním batérie ešte stihnú s dostatočným predstihom upozorniť, že je potrebné batériu vymeniť. Energeticky autonómne zariadenia sú totiž základom IoT.
V prípade IoT zariadení si však nemôžeme dovoliť to isté, čo v prípade štandardných zariadení napájaných z elektrickej siete a teda - premieňať prebytok energie na teplo.
(slide) So zvyšujúcim sa množstvom prenosných zariadení vznikajú stále nové a nové technológie pre zvyšovanie kapacity batérií. Rovnako tak vznikajú aj postupy na to, ako zabezpečiť nízky odber energie. Takýchto postupov je niekoľko, ale v princípe je možné ich rozdeliť do dvoch základných skupín a síce:
- postupy pre znížovanie odberu pri navrhovaní softvéru, a
- postupy pre znížovanie odberu pri navrhovaní hardvéru.
IoT zariadenia totiž častokrát nevyžadujú pre svoju činnosť, aby boli neustále napájané. Napríklad pri meraní teploty v miestnosti nie je potrebné, aby jej odčítanie zo senzora teploty prebehlo každú sekundu. V tomto prípade si je možné vystačiť dokonca s niekoľko minútovým intervalom merania teploty. Kým tento interval neuplynie, tak zariadenie nerobí nič. Nič však môže znamenať uspatie procesu na potrebnú dobu pomocou volania funkcie
delay()
(v prípade napr. prototypovacej dosky Arduino Uno). To sa síce môže javiť tak, že mikrokontrolér nič nerobí, pretože funkciadelay()
je blokovacia, ale zariadenie bude elektrickú energiu odoberať aj naďalej. Ak sa však na potrebný čas uvedie do režimu spánku, jeho odber elektrickej energie bude minimálny.(slide) Uviesť mikrokontrolér do režimu spánku však nie je jediný spôsob, ktorým je možné znížiť odber elektrickej energie. Martin Malý vo svojej knihe Hradla, volty, jednočipy uvádza aj ďalšie postupy [@maly2017]:
- zníženie napájacieho napätia (aspoň na úroveň 3,3V)
- spomaliť prácu mikrokontroléra (napr. jeho uspaním alebo znížením jeho pracovnej frekvencie)
- používať CMOS technológiu, ktorá má v kľude veľmi nízky odber
Znížiť odber napájania je samozrejme možné aj výberom vhodných komponentov. Častokrát môže ísť o zbytočné LED diódy, ktoré síce v porovnaní s inými zdrojmi svetla majú nízky odber, ale pri neustálom svietení dokážu spoľahlivo a rýchlo vybiť zdroj napájania.
V prípade IoT zariadení sú však zaujimáve komponenty zabezpečujúce komunikáciu. Existujú totiž technológie, ktoré sú absolútne nevhodné pre tento typ komunikácie, zatiaľ čo iné boli dizajnované práve pre tento typ zariadení.
Pri navrhovaní hardvéru si je tiež dobré uvedomiť, že celkovú spotrebu ovplyvňuje spotreba jednotlivých komponentov. Niektoré náročnejšie senzory dokonca krátkodobo vyžadujú veľmi veľký prúd aj napriek tomu, že počas bežnej prevádzky, resp. pri uspaní je ich spotreba minimálna. Po zobudení alebo pri pripájaní (napr. niektoré komunikačné moduly) sú však schopné krátkodobo vyžadovať odber aj 2A. Batéria teda musí byť pripravená v závislosti od komponentov IoT zariadenia aj na takúto krátkodobú záťaž.
Battery Life
(slide) Pri vývoji nových zariadení pre internet vecí je vždy dôležitou otázkou, ako dlho vydrží zariadenie pracovať, keď je napájané z batérie. Odpoveď na túto otázku záleží od dvoch vecí:
- od kapacity batérie, a
- od spotreby zariadenia.
Battery Capacity
(slide) Kapacita batérie sa udáva v jednotke Ah (ampérhodina), resp. v nižších jednotkách mAh (miliampérhodina). Batéria má kapacitu jednej ampérhodiny, ak je schopná pri svojom nominálnom napätí dodať teoreticky do záťaže prúd 1A po dobu 1 hodiny.
Kapacita batérií rovnakého typu sa môže líšiť v závislosti od výrobcu. Prehľad kapacít najznámejších batérií na trhu je zobrazený v nasledujúcej tabuľke. Batérie sú označené podľa ANSI označenia. Podľa IEC označenia sú označené len mincové a gombíkové batérie.
Typ Označenie Kapacita Napätie mincová batéria CR2032 190 - 225 mAh 3 V gombíková batéria R44 15 - 600 mAh 3 V tužková batéria AA 600 - 3400 mAh 1.2 - 1.5 V mikrotužková batéria AAA 350 - 1250 mAh 1.25 - 1.5 V 9V batéria 9V 400 - 1200 mAh 7.2 - 9 V (slide) Pri dizajnovaní a prevádzkovaní IoT zariadení sa neodporúča uvažovať o nabíjacích batériách. Nabíjateľné batérie sú do zariadení, ktoré sa používajú denne, ako napr. MP3 prehrávače, fotoaparáty alebo klávesnice a myši. Použitie nabíjateľných batérií je v tomto prípade finančne výhodnejšie, ako dokupovať neustále nové batérie.
IoT zariadenia sú totiž zariadenia, ktoré sa nepoužívajú denne, resp. neustále. Častokrát sa takéto zariadenie len zobudí, odčíta hodnotu zo senzora, odošle ju na spracovanie a opäť zaspí. Nabíjateľné batérie totiž trpia samovoľným vybíjaním, ktoré znižuje ich výdrž. Aj bez toho, aby bola nabíjateľná batéria používaná, sa môže po pár mesiacoch sama vybiť. Použitím nenabíjateľných (teda alkalických) batérií sa je možné tomuto problému vyhnúť. Zariadenia napájané alkalickými batériami dokážu fungovať mesiace až roky bez nutnosti výmeny batérií.
Device Consumption
(slide) Určiť spotrebu zariadenia je o niečo zložitejšie. Zariadenie totiž môže počas svojej prevádzky v závislosti od ďalších pripojených komponentov (obvodov) odoberať v rozličnom čase rozličné množstvo energie.
Získať dobu životnosti batérie, resp. čas, počas ktorého je možné zariadenie napájať z batérie, je možné ako podiel kapacity batérie a veľkosti prúdu pretekajúceho záťažou. Ak by sme teda pripojili Arduino Uno, ktoré po zapojení odoberá prúd okolo 50mA k batérii, ktorá má kapacitu 1000mAh, vydrží byť Arduino napájané spolu 20h:
\[ t = \frac{BatteryCapacity}{LoadCurrent} = \frac{1000 mAh}{50 mA} = 20 h\]
Managing Energy Consumption with Software
- (slide)
Motivation in the Beginning
(slide) Predstavte si, že pracujete na niečom veľmi dôležitom. Ste totálne sústredený, keď vtom sa náhle ozve váš žalúdok a dá vám rozličnými akusticko-citlivými možnosťami najavo, že máte hlad. Neváhate, však to predsa nie je prvýkrát, keď ste vyhladli, a vytočíte svoju obľúbenú pizzeriu, objednáte si svoju obľúbenú pizzu a spojovateľka vám oznámi, že vám vašu pizzu doručia až o 60 minút. Takže ešte 60 minút budete zápasiť s hladom.
Čo teraz? Do úvahy prichádza niekoľko možností:
- nebudem robiť ďalej, pokiaľ sa nenajem - takže nasledujúcich 60 minút strávim sledovaním hodiniek
- budem ďalej robiť hladný a popri tom budem pravidelne sledovať hodinky, či už neuplynulo tých 60 minút
- nastavím si budik, aby ma po uplynutí 60 minút upozornil a ja som teda nemusel sledovať neustále hodinky, ale môžem sa plne sústrediť na prácu
Aj napriek tomu, že tento príklad z reálneho života vyznieva vzhľadom na uvedené možnosti pomerne komicky, môžeme isté paralely nájsť v mnohých našich, ale aj v rozličných existujúcich IoT riešeniach. Takže - čo robíme zle?
The Polling
(slide) Pamätáte sa na druhú časť animáku Shrek? Shrek šiel spolu s Fionou a oslíkom na návštevu k Fioniným rodičom do kráľovstva za siedmymi horami a siedmymi dolinami. A pamätáte sa na to, čo robil celý čas oslík? Celý čas sa pýtal rovnakú otázku: “Kedy tam už budeme?”
A presne rovnaký prístup častokrát volíme pri čítaní hodnôt zo senzorov - každé volanie funkcie
loop()
sa začne prečítaním hodnoty výstupu zo senzora. A to celé sa udeje niekoľkokrát za sekundu. Aby sa dopytovanie nedialo príliš často, funkciu je možné na krátky čas uspať. Tým je zabezpečené, aby sa dopytovanie na výstup z PIR senzoru vykonalo práve 2x za sekundu.Pri takomto prístupe sa správame presne tak, ako oslík v Shrekovi - neustále sa pýtame na tú istú vec. Znova a znova. Vo svete informatiky sa tento prístup nazýva slovom polling, pretože sa pýtame (z angl. poll). Jeho princíp spočíva v neustálom dopytovaní sa externého zariadenia, či na ňom nedošlo k požadovanej udalosti, resp. k zmene stavu. Polling predstavuje synchrónnu operáciu.
(slide) Polling je veľmi jednoduchý a častokrát postačuje pre riešenie väčšiny problémov. Má však aj niektoré nevýhody. Jednou z nich je vysoká pravdepodobnosť straty údajov. K tomu môže dôjsť napr. vtedy, ak externé zariadenie pošle údaje mikrokontroléru tesne potom, ako sa ich ten pokúsil prečítať. Alebo aj vtedy, ak dôjde k pohybu uprostred 500 ms prestávky a počas tých istých 500 ms sa pohyb aj skončí.
V ilustrácii na začiatku kapitoly o doručení pizze môže dôjsť k problému napr. vtedy, ak bude pizza doručená pred uplynutím 60 min intervalu. Obecne takýto prístup nepredstavuje veľmi dobrý dizajn, ak je potrebné zákazníkovi povedať, že pizza dorazí presne po 60 minútach a ak vtedy neotvorí, svoj tovar nedostane (aj napriek tomu, že zaň zaplatil).
Samozrejme existujú požiadavky, pri ktorých je takéto správanie postačujúce. Napr. merať vonkajšiu teplotu stačí v niekoľkominútových pravidelných intervaloch a prípadný výkyv teplôt medzi dvoma meraniami je možné považovať za zanedbateľný.
Vďaka neustálemu dopytovaniu sa si polling vyžaduje vyhradenie väčšieho množstva zdrojov a hlavne času mikrokontroléra. Ten teda miesto vykonávania potrebných operácií plytvá svojimi zdrojmi na neustále kontrolovanie stavu externého zariadenia. To sa priamoúmerne dokáže prejaviť na spotrebe energie, pretože čím častejšie kontrolujeme stav externého zariadenia, tým viac energie spotrebujeme.
The Interrupts
Riešenie pôvodného problému s doručením pizze je však veľmi jednoduché - keď doručovateľ s pizzou dorazí, zazvoní alebo zaklope na dvere zákazníka. Poprípade ho pred príchodom upozorní telefonátom. Ten sa teda nemusí starať o to, či uplynula doba doručenia alebo či náhodou neprišiel skôr. Môže sa venovať svojim dôležitejším povinnostiam a na vznik udalosti doručenia bude automaticky a hlavne včas upozornený.
(slide) Tento mechanizmus sa v svete informačných technológií nazýva prerušenie (z angl. interrupt). Koncept prerušení je vo svete mikrokontrolérov veľmi dôležitý.
Prerušenie je mechanizmus, ktorým dá prostredie mikrokontroléru vedieť, že sa práve stalo niečo dôležité. Vo všeobecnosti je možné povedať, že prerušenie je špeciálny signál pre mikrokontrolér, ktorý poslal softvér alebo hardvér a vyžaduje si okamžitú pozornosť.
Výhodou takéhoto prístupu je vo všeobecnosti zníženie zaťaženia mikrokontroléra, ktorý nemusí stále dookola testovať, či k udalosti došlo alebo ešte nie (viď polling). V porovnaní s polling-om má prerušenie lepší reakčný čas, pretože reaguje na udalosť okamžite.
Princíp prerušenia sa využíva aj v architektúre riadenej udalosťami (a zngl. event driven architecture) alebo v programovaní riadenom udalosťami (z angl. event driven programming). V objektovom programovaní je zasa tento prístup opísaný pomocou návrhového vzoru pozorovateľ (z angl. observer).
Podobne, ako keď donášková služba volá priamo zákazníkovi, aby ho informovala o tom, že je donáška pripravená, aj požiadavku o prerušenie dostane od zariadenia priamo mikrokontrolér Tým pádom môže prísť požiadavka o prerušenie kedykoľvek a prerušenie predstavuje asynchrónny spôsob komunikácie.
Hlavný rozdiel medzi polling-om a prerušením je v tom, či sa softvér sám opýta alebo hardvér sám oznámi, či došlo k predmetnej udalosti.
Interrupt Service Routine
(slide) Inštrukcie programu, ktorý beží v mikrokontroléri, sa (obyčajne) vykonávajú sekvenčne. To znamená, že po vykonaní jednej inštrukcie sa vykoná nasledujúca inštrukcia v poradí. Akonáhle však mikrokontrolér dostane požiadavku na prerušenie, pozastaví sa vykonávanie inštrukcií programu mikrokontroléra a ten spustí špeciálnu funkciu na spracovanie prerušenia, ktorá sa označuje ISR (z angli. Interrupt Service Routine). Po jej skončení sa obnoví vykonávanie prerušeného programu vykonaním ďalšej inštrukcie v poradí.
(slide) ISR funkcie nevracajú žiadnu hodnotu a nemajú žiadny parameter. Ak je teda potrebné vo vnútri ISR funkcie zmeniť stav správania aplikácie, je na to možné použiť globálne premenné. Je to vlastne jediný spôsob, pomocou ktorého je možné prenášať údaje medzi ISR a hlavným programom.
(slide) Pri tvorbe ISR je dobré dodržiavať niekoľko odporúčaní:
- ISR majú byť čo najkratšie a čo najrýchlejšie, aby zbytočne nebrzdili hlavný program alebo prípadne ďalšie prerušenia, ktoré môžu nastať.
- Je potrebné sa vo vnútri ISR vyhnúť použitiu funkcie
delay()
! - Nepoužívať sériovú komunikáciu!
- Ak programujete v jazyku C, tak globálne premenné, ktoré
používate na zdieľanie údajov medzi ISR a programom, označte
pomocou kvalifikátora
volatile
! Tým poviete prekladaču, že táto premenná môže byť použiteľná kdekoľvek v kóde a prekladač jej obsah vždy pri použití znovu načíta a nebude sa spoliehať na jej kópiu v registri. Zabránite tak aj prípadným optimalizáciám prekladača, vďaka ktorým by ju mohol napr. vyhodiť, pretože sa nepoužíva (v hlavnom programe). - Nevypínať ani nezapínať podporu prerušení vo vnútri ISR. V tomto prípade však existujú výnimky, ktoré budú opísané neskôr v kapitole.
V dokumentácii jazyka MicroPython nájdeme tieto odporúčania [@s7]:
- Keep the code as short and simple as possible.
- Avoid memory allocation: no appending to lists or insertion into dictionaries, no floating point.
- Consider using micropython.schedule to work around the above constraint.
- Where an ISR returns multiple bytes use a pre-allocated bytearray. If multiple integers are to be shared between an ISR and the main program consider an array (array.array).
- Where data is shared between the main program and an ISR, consider disabling interrupts prior to accessing the data in the main program and re-enabling them immediately afterwards (see Critical Sections).
- Allocate an emergency exception buffer (see below).
Reasons to use Interrupts
(slide) Existuje veľa dôvodov, prečo prerušenia používať . Niektoré z nich sú tieto:
- To detect pin changes (eg. rotary encoders, button presses)
- Watchdog timer (eg. if nothing happens after 8 seconds, interrupt me)
- Timer interrupts - used for comparing/overflowing timers
- SPI data transfers
- I2C data transfers
- USART data transfers
- ADC conversions (analog to digital)
- EEPROM ready for use
- Flash memory ready
Types of Interrupts
(slide) Pri práci s mikrokontrolérmi je možné prerušenia rozdeliť do dvoch skupín:
- hardvérové prerušenia, známe tiež ako externé prerušenia, alebo tiež pin-change prerušenia, a
- softvérové prerušenia, ktoré sú známe ako interné prerušenia alebo tiež časovače.
Ako už názov napovedá, signál prerušenia prichádza v prípade hardvérových alebo externých prerušení z externého zariadenia. Toto zariadenie je s mikrokontrolérom priamo prepojené. Keďže sú prerušenia asynchrónne, k prerušeniu môže dôjsť kedykoľvek.
Interné prerušenia zasa referujú na čokoľvek vo vnútri mikrokontroléra, čo dokáže vyvolať prerušenie. Príkladom môžu byť napríklad časovače, pomocou ktorých je možné zabezpečiť, aby k vyvolaniu prerušenia dochádzalo pravidelne napr. každú 1 sekundu.
Interrupt Vectors in ATmega328P
(slide) V jednej chvíli môžu byť naraz vyvolané viaceré žiadosti o prerušenie a mikrokontrolér sa musí rozhodnúť, ktorá z nich bude ošetrená ako prvá. Je teda potrebné, aby mikrokontrolér vedel povedať, ktoré prerušenia majú prednosť pred inými.
Mikrokontrolér obsahuje tzv. tabuľku vektorov prerušení. Táto tabuľka sa nachádza na začiatku programovej flash pamäti a obsahuje adresy ISR funkcií jednotlivých prerušení. V ich poradí je však aj priorita - čím má prerušenie nižšiu adresu, resp. vektor prerušenia má nižšie číslo, tým má vyššiu prioritu. Z tabuľky je teda možné vidieť, že najvyššiu prioritu má prerušenie od zdroja
RESET
a najnižšiu prioritu od zdrojaSPM READY
.
Ošetrovanie externých prerušení
Poďme sa teda pokúsiť vylepšiť náš kontajner tým, že vytvoríme externé prerušenie pri uzavretí kontajnera. Už v rámci predchádzajúcich analýz sme identifikovali, že zmysel má odčítavať úroveň smetí v kontajneri až pri jeho zatvorení. Zatvorenie kontajnera budeme reprezentovať tlačidlom a to konkrétne jeho uvoľnením.
Začnem tým, že vytvorím ISR funkciu pre ošetrenie vzniknutého prerušenia a nechám v nej vypísať do sériovej linky (čo samozrejme nie je odporúčaný prístup) jednoduchú správu:
def handle_closed_lid(pin): print('>> Lid was closed.')
Následne vytvoríme objekt pre pin, ku ktorému pripojíme tlačidlo:
from machine import Pin = Pin(19, Pin.IN) button
Poznámka
Každý mikrokontrolér je špecifický tým, že na zachytenie externého prerušenia z pripojeného zariadenia nie je možné použiť každý digitálny pin. Vždy je preto potrebné overiť si možnosti mikrokontroléra v jeho dokumentácii. V prípade mikrokontroléra ESP32 je možné použiť každý GPIO pin. V prípade mikrokontroléra ATmega328P, ktorý sa používa na doskách Arduino, však môžeme použiť len 2 piny.
Následne pomocou metódy
.irq()
nad objektombutton
zašpecifikujeme, pomocou ktorej funkcie ošetríme vzniknuté prerušenie a akým spôsobom sa toto prerušenie spustí. Metóda.irq()
má teda tieto parametre:trigger
- definuje spôsob spustenia prerušenia; k dispozícii sú tri režimy:falling - Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne z
HIGH
naLOW
. Tento proces sa deje napríklad pri uvoľnení stlačeného tlačidla. Režim je reprezentovaný pomocou hodnotyPin.IRQ_FALLING
.rising - Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne z
LOW
naHIGH
. Tento proces sa deje napríklad pri stlačení tlačidla. Režim je reprezentovaný pomocou hodnotyPin.IRQ_FALLING
.change - Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne pinu buď z
HIGH
naLOW
alebo zLOW
naHIGH
. Tento proces sa deje napríklad pri stláčaní prepínača. Režim je reprezentovaný hodnotou3
.
handler
- funkcia (ISR), ktorá sa zavolá na ošetrenie vzniknutého prerušenia
Princíp fungovania jednotlivých režimov prerušenia je možné vidieť na nasledujúcom obrázku:
Keďže v našom prípade chceme na pin-e, ku ktorému je pripojené tlačidlo, sledovať zmenu z úrovne
HIGH
na úroveňLOW
, režime vzniku prerušenia nastavíme naPin.IRQ_FALLING
:=Pin.IRQ_FALLING, button.irq(trigger=handle_closed_lid) handler
Ak aktuálne spustíme program, nič sa neudeje. Ak ale stlačíme tlačidlo, pri jeho uvoľnení dôjde k vzniku externého prerušenia a rovnako tak k jeho ošetreniu.
Poznámka
Na rozličných mikrokontroléroch sa je možné stretnúť s rozličnými režimami prerušení. Okrem režimov falling, rising a change sa je možné stretnúť aj s ďalšími režimami:
- low - Prerušenie je vyvolané vtedy, keď sa na pine
nachádza úroveň
LOW
. Tento proces sa deje napríklad vtedy, ak je tlačidlo pripojené k digitálnemu pinu v režimeINPUT_PULLUP
a po jeho stlačení sa na pin privedie úroveňLOW
. - high - K tomuto prerušeniu dôjde vždy vtedy, keď sa
na pine bude nachádzať úroveň
HIGH
.
- low - Prerušenie je vyvolané vtedy, keď sa na pine
nachádza úroveň
Na základe uvedených režimov prerušenia mikrokontroléra sa je možné stretnúť ešte s nasledujúcim rozdelením externých prerušení:
Level Interrupts - Prerušenie je vyvolané zakaždým, keď sa na vstupe objaví signál konkrétnej úrovne (
HIGH
aleboLOW
). Pri tomto type prerušenia je dobré dať pozor na to, že pri nezmenenom signále môže k prerušeniu dochádzať opakovane aj počas ošetrovania predchádzajúceho prerušenia.Edge Interrupts - Prerušenie je vyvolané vtedy, keď dôjde k zmene jednej úrovne signálu na druhú (napr. ak dôjde k zmene úrovne z
HIGH
naLOW
alebo zLOW
naHIGH
).
Časovače
Blink pomocou časovača
from machine import Pin, Timer
def blink(timer):
= Pin('LED', Pin.OUT)
led
led.toggle()
= Timer()
timer
timer.init(=5000, # in ms
period=Timer.PERIODIC, # can be Timer.PERIODIC or Timer.ONE_SHOT
mode=blink # function to call
callback )
môžeme mu zadefinovať aj frekvenciu:
=1, mode=Timer.PERIODIC, callback=blink) # 1x za sekundu timer.init(freq
Pros and Cons of Interrupts
Výhody:
- lepší reakčný čas v porovnaní s polling-om
- šetrenie zdrojov
Nevýhody:
- Prerušenia sa výrazne horšie ladia, pretože k prerušeniu môže dôjsť aj počas ladenia programu. A vy zrazu neviete, koľko prerušení bolo vykonaných medzi krokovaním aktuálnej časti programu.