Poťouchlost Arduina – serva

Opět jsem narazil na poťouchlost, kterou nepozorným uživatelům nachystali autoři knihoven Arduina. Tentokrát se týká ovládání serv.

Pro osvěžení znalostí:
K ovládání běžných malých analogových serv se používá signál s periodou 20 ms, kde vysoká úroveň po dobu 1,5 ms znamená střední polohu serva, kratší doba výchylku na jednu stranu a delší doba výchylku na druhou stranu (obvykle se uvádí, že 1 ms je výchylka -90° a 2 ms výchylka +90°, ale jsou i serva, která to mají jinak – záleží na specifikaci od výrobce1, ale všem společný de facto standard je, že 1.5 ms je uprostřed pracovního rozsahu).
U serv upravených na stálé otáčení pak 1,5 ms znamená stop, délka kratší než 1,5 ms točení na jednu stranu a větší než 1,5 ms točení na druhou stranu.

Použití v Arduinu:
Knihovna Servo v Arduinu poskytuje rozhraní, které pro řízení nabízí dvě funkce, write a writeMicroseconds. Funkce write umožňuje nastavit servo na požadovaný úhel, takže write(0); nastaví servo na úhel 0°, write(90); na 90°, write (180); na 180° atd. Funkce writeMicroseconds nastavuje délku signálu v mikrosekundách, takže writeMicroseconds(1500); nastaví servo doprostřed, writeMicroseconds(1000); na jednu stranu a writeMicroseconds(2000); na druhou.

HA! Jenže ono to tak úplně není! Parametr předaný funkci write se totiž přepočítává2 podle rozsahu serva tak, aby 0 odpovídala dolní hodnotě pro řízení serva a 180 horní. Ten rozsah se dá nastavit při zapínání serva pomocí funkce attach, ale většina uživatelů používá tuto funkci zjednodušenou, jen s jedním parametrem určujícím pin, ke kterému je servo připojeno (např. mojeServo.attach(12);). Existuje ale ještě druhá varianta funkce attach, kdy parametrem je kromě pinu Arduina ještě minimum a maximum doby signálu v mikrosekundách. Pokud použijete první variantu, tak se ty zbylé dva parametry, minimum a maximum, nastaví na default. No a tady právě vycítil čertík příležitost, a našeptal vývojářům Arduina, aby nastavili ty defaultní hodnoty na 544 (minimum) a 2400 (maximum). Kolik je tedy uprostřed? Není to 1500, ale 1472. Ha ha.

Výsledek tedy je, že když jednou servo nastavíte do půlky příkazem writeMicroseconds(1500); a podruhé příkazem write(90);, tak to nebude totéž. Bude to o kousek vedle, tak asi 2,5°. V případě serva upraveného pro točení pak nebude oboje znamenat stop, ale jedno volání motor zastaví, zatímco druhé ho nechá pomalu točit.

Ještě je tu taková legrácka, že funkci write se taky dá místo úhlu poslat doba v mikrosekundách. Vývojáři asi usoudili, že vyjdou vstříc lenivým uživatelům, kteří si nepamatují správná jména funkcí, a naprgali to tak, že když je poslaný parametr menší než minimum, tak to je asi úhel, a když vetší nebo roven, tak to je asi doba v mikrosekundách. Mno, nejsem sice programátorský purista, ale tohle je ošklivé. A navíc se to testuje proti minimu defaultnímu, tj. 544, ne tomu, které si uživatel zadal pomocí funkce attach. To už je vyloženě zhovadilost3!

Takže taková rada na závěr: zásadně servo zapínejte s uvedením minima a maxima, např. zamerovac.attach( 12, 900, 2100 ); abyste se vyhnuli blamáži, že jste poslali míč do branky, ale slovy klasika „čo chýbalo! Milimetre! Ale bolo ich veľa.“ (a kdybyste posílali V-2, tak by jistě chýbalo ještě mnohem víc milimetrov, než jen veľa …)

No a jak mi připomenul na minulém Robodoupěti Gilhad, tak funkce map je taky poněkud poťouchlá. Má přepočítávat hodnotu z jednoho rozsahu do jiného, ale abych to řekl jemně, „za jistých okolností dává neočekávané výstupy“. Ale o tom raději jindy, protože to už by s váma mohlo šlehnout, počkám, až rozdejcháte tohle 😉


Poznámky:

  1. Hitec například pro všechna svá serva povoluje 0,9-2,1 ms, jedno konkrétní servo Hextronik zase má 0,5 ms pro 0° a 2.5 ms pro 180°.
  2. Přepočet se děje pomocí funkce map, která je tedy taky poťouchlá, ale o tom zase jindy.
  3. Původně jsem chtěl napsat zhůvěřilost, ale pak jsem si přečetl článek p. Nejedlého Co ve slovnících nenajdete: zhůvěřilost a usoudil jsem, že zhovadilost je nakonec trefnější…