Arduino a více serv

Typické příklady pro začátečníky, které ukazují ovládání modelářských serv Arduinem, se zabývají řízením jen jediného serva. S čím se můžeme potkat, pokud budeme muset pracovat s více servy? Podívejme se na to z hlediska programu, zapojení obvodů i dimenzování napájení serv.

Budeme předpokládat použití obvyklé knihovny „servo“, takže začneme tím, co je v každé začátečnické příručce, necháme přejíždět z jedné polohy do druhé jedno miniaturní servo řízené Arduinem UNO. Nebudeme jezdit úplně z kraje do kraje (výchylka 0 – 180°), ale omezíme se na ±60° (tj. 30 až 150º), to určitě zvládne každé servo. Stejně každý typ serva má trochu jiné výchylky a málokdy zadávaný úhel „sedí“.

#include <Servo.h>        // přičleníme knihovnu
  Servo moje_servo;       // definujeme objekt moje_servo typu servo
void setup() {
  moje_servo.attach(2);   // přiřadíme objektu moje_servo řízení pinem 2
  }
void loop() {             // stále opakujeme
  moje_servo.write(30);   // pro moje_servo nastavíme výchylku 30 stupňů
  delay(2000);            // počkáme 2 s
  moje_servo.write(150);  // pro moje_servo nastavíme výchylku 150 stupňů
  delay(2000);            // počkáme 2 s
  }

Zapojení může vypadat tak, jak je na obrázku, tedy pokud je Arduino napájené z USB. Pokud ne, musí být kladné napájení serva (červený vodič) připojený na stabilizované napětí +5V Arduina.
servo1_bbOno to nějak chodit bude a vyzkoušíme si na tom základní funkci, jenže to vždy bude chodit vlastně špatně. Napájení přes USB kabel stačí tak na samotné Arduino, na servo, i když je malé, už ne. Napájecí napětí není 5 V, ale na na konci USB kabelu s bídou něco přes 4 V, a při zatížení miniservem za pohybu dál spadne o nějakých 0,6 – 1 V, takže ve výsledku je servo (nezatížené při pohybu) napájeno tak asi 3 V.

Bez kondenzátoru (minimum je kombinace 100 nF v keramickém provedení a paralelně nejméně 100 μF elektrolyt) je velmi pravděpodobné, že se bude Arduino při pohybu serva náhodně resetovat a v koncových polohách servo zaškubávat. S kondenzátory se asi resetovat nebude, ale servo pojede znatelně pomalu a jas LED na Arduinu bude viditelně kolísat kvůli změnám napětí.

Lepší je napájet serva z jiného zdroje tvrdého napětí +5 V, odběr počítáme v prvním odhadu na jedno servo 1 A a ještě to nemusí stačit. Pak můžeme k jednomu Arduinu připojit více serv. Napájení serv teď vůbec nejde přes Arduino, oba napájecí zdroje (Arduina i pro serva) mají spojené země, ale jinak jsou nezávislé. Není žádný problém napájet serva i jiným napětím než +5 V, třeba +6 V (to má většina serv jako maximum) nebo pokud jde o HV serva určená k napájení ze dvou Li-pol článků přímo, tak až +8 V. Na obrázku je pro názornost zapojení na kontaktním poli, ve skutečnosti by takto nikdy serva být zapojena neměla, protože je vysoce překročen povolený proud spoji kontaktního pole. Propojení napájecích vodičů by mělo jít dostatečně silným drátem (lankem) o průřezu minimálně 1 mm².

3servaA jak budeme tato serva ovládat? Jednoduše musíme definovat více objektů typu servo (třeba servo1, servo2, servo3), každému z nich přiřadit jeho ovládací pin a pak s nimi hýbat podle potřeby. Rozšířit to na více serv by snad už opravdu nebyl problém.

#include <Servo.h>              // přičleníme knihovnu
Servo servo1, servo2, servo3;   // definujeme objekty tří serv

void setup() {
  servo1.attach(2);             // servo1 řízené pinem 2
  servo2.attach(3);             // servo2 řízené pinem 3
  servo3.attach(4);             // servo3 řízené pinem 4
  servo1.write(30);             // nastavíme počáteční polohu serva1
  servo2.write(30);             // nastavíme počáteční polohu serva2
  servo3.write(30);             // nastavíme počáteční polohu serva3
  delay(3000);                  // počkáme na ustálení serv
}

void loop() {                   // stále opakujeme
  servo1.write(150);            // servo1 kyv
  delay(2000);                  // počkáme 2 s
  servo1.write(30);             // .. a zpět
  delay(2000);                  // počkáme 2 s
  servo2.write(150);            // servo2 kyv
  delay(2000);                  // počkáme 2 s
  servo2.write(30);             // .. a zpět
  delay(2000);                  // počkáme 2 s
  servo3.write(150);            // servo3 kyv
  delay(2000);                  // počkáme 2 s
  servo3.write(30);             // .. a zpět
  delay(2000);                  // počkáme 2 s
}

Zcela záměrně program pohybuje vždy jen jedním servem a dává dost času na to, aby dosáhlo požadované polohy. I přes to signalizace nadproudu zdroje nastavená na 2 A při každém pohybu ukazovala překročení hodnoty. Použitá byla dvě robotická serva standardní velikosti Vigor VS-18MB a jedno slabší Hitec HS-422, vše napájené napatím 6 V. Odběry jednotlivých serv vůbec nepřekrývaly a k pokrytí špiček sloužil kondenzátor s kapacitou přes 150 mF (150 000 μF) a malým ESR.

Jaký by skutečný odběr jednoho nezatíženého robotického serva při pohybu ukazuje záznam z osciloskopu. Ke snímání proudu posloužil přesný bezindukční rezistor 0,01 Ω, který výsledek prakticky neovlivní. Přepočet je jednoduchý, jeden dílek ve svislém směru odpovídá při citlivosti 10 mV proudu 1 A.

Vigor VS-18MBPři každém pohybu odebíralo servo na začátku proud stejný, jako když je maximálně zatíženo (pracuje proti setrvačnosti a rozjíždí se), v daném případě to byly skoro 4 A (to se pak nelze divit, že zabírá proudové omezení zdroje !). Během ustálené jízdy bere servo podstatně méně, v daném případě kolem 0,75 A. To je také proud, který přibližně naměříme, když budeme měřit běžným ampérmetrem, ať už ručkovým, nebo v digitálním multimetru. Nejvyšší proud se neodebírá při rozjíždění, ale při brzdění, v našem případ to bylo něco málo přes 4 A. Tyto špičky odběru jsou při každém pohybu. Čím je pohyb menší a častější, tím je jich víc! Kromě toho se v odběru vyskytují i větší, ale velice krátké špičky, těmi má smysl se zabývat při odrušení serva, ale z hlediska dimenzování zdroje je nemusíme brát v úvahu, dobře dimenzované kondenzátory je pokryjí.


Nyní naše tři serva (dvě silnější VS-18MB a jedno HS-422) necháme pohybovat současně. Program bude téměř stejný, jeho smyčka bude vypadat takto:

void loop() {                   // stále opakujeme
  servo1.write(150);            // servo1 kyv
  servo2.write(150);            // servo2 kyv
  servo3.write(150);            // servo3 kyv
  delay(2000);                  // počkáme 2 s
  servo1.write(30);             // .. a zpět servo1
  servo2.write(30);             // .. a zpět servo2
  servo3.write(30);             // .. a zpět servo3
  delay(2000);                  // počkáme 2 s
}

Co se stane s odběrem? Celkem by se dalo očekávat, že se odběr všech serv sečte a zjistíme v pulzech něco přes 8 A, asi tak kolem 9 A (odběr HS-422 je něco kolem 1 A). Jenže ono je to trochu jinak a ve skutečnosti zjistíme odběr o něco menší. Ta tři serva (pro odběr jsou důležitá hlavně dvě silnější) totiž nejedou naprosto přesně stejně a jejich pulzy odběru se úplně nekryjí, takže součet odběru je o něco menší, dokonce nepatrně menší, než by odpovídalo těm dvěma silnějším servům. V našem konkrétním případě to vypadlo takto (jeden dílek nyní odpovídá 2 A):

Vigor 3ksOdběr se zvýšil, ale sotva 2x. Jak se pulzy nekryjí je vidět na nástupu proudové špičky při rozběhu, hrana  není strmá, ale se zubem, jako by byla složená ze dvou špiček, které přišly po sobě. Na pulzech brzdění jsou ty stupně vidět zcela jasně. Proč to takto funguje?

Náš program obsluhuje serva postupně, ale to není podstatou věci. Jednak jde obsluha velmi rychle po sobě, jednak to by nezpůsobilo posunutí špiček v řádu jednotek ms, ale mnohem menší. Když totiž Arduino generuje signál pro více serv, pak ho opakuje 50x za sekundu (tomu se říká rámec), jednotlivé pulzy pro serva nedělá současně, ale postupně. Nejdřív první, když skončí tak teprve druhý, když skončí tak třetí atd. Proto je také omezený počet serv, která lze takto obsloužit. Když bude mít signál pro všechna serva nejvyšší možnou délku, tak se do rámce vejde nejvýš 9 pulzů (obvykle se počítá 8) standardní délky 2,0 ms, kdy jsou delší, tak ještě méně. Jak vypadá signál pro 6 serv generovaný Arduinem UNO názorně ukazuje záznam z logického analyzátoru.analyzator_6servOdběr serv je do značné míry synchronizovaný s jejich ovládacími pulzy a ty jsou díky řízení Arduinem posunuté v čase, proto se pulzní odběry jednoduše nesčítají a největší špičky nepřicházejí ve stejném okamžiku.

Závěr by mohl být třeba tento: Nepodceňujte proudový odběr serv a dimenzování napájecích zdrojů. Proud, který naměříte multimetrem (proud v ustáleném chodu), je asi tak 5x menší než proud, který servo opravdu potřebuje při každém rozjezdu i brzdění. Při více servech se naštěstí pulzní odběr tak úplně nesčítá, ale přes to dosáhne zhruba 0,8 násobku součtu, takže je velký.


Výše uvedený závěr platí jen pro serva analogová, dnes víceméně překonaná, levnější a bez možností programování. Pokud použijeme současná digitální serva, pak největší rozdíl z našeho uvažovaného pohledu je v tom, že u nich není pulzní odběr proudu synchronizovaný s řídícím signálem. Je úplně jedno, jak je mikrokontrolér ovládá, pulzy odběru mají frekvenci typicky 600 – 1200 Hz a u každého serva trochu (alespoň nepatrně) jinou. Z toho plyne, že občas, ne často, ale třeba jednou za několik sekund nebo i několik minut, špičky odběru opravdu přijdou v jeden okamžik a jejich velikosti se naplno sečtou. Když se k tomu připojí, že digitální serva mívají motory se samonosnou kotvou, které si pulzně vezmou zhruba 2x větší proud (proti obdobnému servu s rotorem s kotvou), bude situace se zatížením zdroje podstatně horší a navíc záludnější, protože velká špička odběru přijde náhodně jednou za delší dobu. Když ji napájecí zdroj „neustojí“ a současně napájí i mikrokontrolér, pak často dochází k „nevysvětlitelným“ resetům a výpadkům funkce.