Close

Arduino jako klávesnice a myš

Deska Arduino Esplora

V dnešním díle se podíváme na již dříve zmiňované desky, které jsou založeny na čipu ATmega32u4. Ukážeme si, jak se může Arduino s tímto čipem vydávat za klávesnici, nebo myš. Také si podrobně popíšeme funkce Arduino Esplora.

Úvod

V prvním článku z této série jsem se zmínil o šesti Arduinech, jejichž mozkem je procesor ATmega32u4. Byly to desky Arduino Micro, Lilypad Arduino, Arduino Leonardo, Arduino Yún, Arduino Esplora a Arduino Robot. Jejich největší výhodou je to, že ke komunikaci s PC nepotřebují žádný převodník. Použitý čip má totiž serial-USB převodník přímo v sobě. Díky absenci tohoto prostředníka je daleko jednodušší naprogramovat Arduino tak, aby se vydávalo za myš či klávesnici (nebo oboje dohromady). V dnešním článku se budeme zabývat hlavně deskou Arduino Leonardo a Arduino Esplora. Popsané postupy jsou však většinou použitelné u všech desek.

Níže popsané funkce může využívat i Arduino DUE. Nemá sice procesor ATmega32u4, ale jiný, který také pracuje bez přídavného převodníku a může vystupovat jako vstupní zařízení pro PC.

Poznámka: Převodníky dalších desek jsou většinou založeny na čipu ze stejné řady, jako je ATmega32u4. Není tedy nemožné naprogramovat i jiné desky jako vstupní zařízené pro PC. Jedná se ale většinou o neoficiální postupy. Jeden z nich naleznete například zde[EN] – vše však na vlastní nebezpečí.

Arduino Leonardo

Deska Arduino Leonardo

Arduino Leonardo

 Leonardo je velmi podobné dalším deskám z hlavní řady. Jelikož má standartní rozložení konektorů, funguje s ním většina shieldů určená pro Uno a další. Co se funkčnosti týče, není oproti ostatním nijak omezeno. Navíc má velkou výhodu, a to právě v použitém procesoru. Díky němu je jeho standartní „arzenál“ funkcí rozšířen o ty, které z desky udělají myš nebo klávesnici. Pojďme si nyní představit jednotlivé funkce, které můžeme použít.

Poznámka: Může se stát, že Arduino nepůjde znovu naprogramovat. Před uploadem programu totiž musí být čip resetován. Za normálních okolností reset probíhá na dálku přes USB. Může se však stát, že čip zrovna dělá něco jiného a upload skončí chybou. Například: „Could not find Leonardo on the selected port.“ V tomto případě musíme čipu s nahráváním pomoci. Před spuštěním uploadu zmáčkneme a držíme tlačítko RESET na desce. Poté zahájíme upload. Ve stavovém řádku se objeví: „Compiling sketch…“. Jakmile tento nápis zmizí a vystřídá ho: „Uploading…“, pustíme tlačítko RESET. Poté by se měl program v pořádku nahrát.

Také si musíme uvědomit, že při používání následujících funkcí přebírá Arduino kontrolu nad PC. Může se tedy stát, že Arduino zasílá 100 stisků klávesy za sekundu, což se počítači líbit nebude. Pokud se dostaneme do této situace, odpojíme Arduino od USB. Při dalším připojení ihned zmáčkneme tlačítko RESET a poté postupujeme tak, jak bylo popsáno výše.

Mouse

První skupinou jsou funkce pro ovládání myši. Ty umožňují ovládat pohyb kurzoru, zmáčknutí tlačítek a rolování kolečka myši. První z funkcí je Mouse.begin(), která říká programu, že má očekávat práci s myší. Většinou se umisťuje do bloku setup(), ale není to podmínkou. Musí však být umístěna v těle funkce (setup, loop, nebo uživatelem vytvořené). S touto funkcí úzce souvisí Mouse.end(), která ovládání myši ukončí.

void setup() {
	Keyboard.begin();
	//příkazy myši
	Keyboard.end();
}

void loop() {}

Dalším příkazem je Mouse.press(), který odpovídá zmáčknutí a uvolnění vybraného tlačítka. Pokud do závorek neuvedeme žádný parametr, je příkaz vyhodnocen jako zmáčknutí levého tlačítka. V opačném případě může parametr nabývat těchto hodnot:

  • MOUSE_LEFT – stisk levého tlačítka myši (výchozí hodnota)
  • MOUSE_RIGHT – stisk pravého tlačítka
  • MOUSE_MIDDLE – stisk prostředního tlačítka (kolečka)

Mějme tři tlačítka (LEFT, MIDDLE, RIGHT) zapojená na piny 10, 9, 8. Tyto tlačítka budou fungovat jako ty u myši.

byte pin[3] = {8,9,10};
byte tlacitko[3] = {MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT};
byte i;

void setup() {
	Mouse.begin();
	for(i = 0; i < 3; i++){
		pinMode(pin[i], INPUT);
	}
}

void loop() {
	for(i = 0; i < 3; i++){
		if(digitalRead(pin[i]) == HIGH){
			Mouse.click(tlacitko[i]);	
		}
	}
	delay(100);
}	

Příkaz Mouse.move(x,y,kolečko) slouží k pohybu kurzoru myši po obrazovce a také k pohybu kolečka. Důležité je si uvědomit, že pohyb kurzoru pomocí tohoto příkazu není absolutní, ale relativní. Příkaz Mouse.move(10,-10,0) tedy neposune kurzor na souřadnice x = 10, y = -10, ale změní souřadnice vůči aktuální poloze kurzoru, tedy o 10 doprava a o 10 nahoru. Berme na vědomí, že osa x leží na horní hraně obrazovky, osa y na levém okraji a počátek os je v levém horním rohu. Pro pohyb kurzoru z leva doprava můžeme tedy využít předchozí zapojení a kód:

byte pin[3] = {8,9,10};
byte i;

void setup() {
	Mouse.begin();
	for(i = 0; i < 3; i++){
		pinMode(pin[i], INPUT);
	}
}

void loop() {
	if(digitalRead(pin[2]) == HIGH){
		Mouse.move(1,0,0);
	}
	else if(digitalRead(pin[0]) == HIGH){
		Mouse.move(-1,0,0);
	}
	delay(3);
}

Dalším příkazem je Mouse.press(). Ten slouží ke zmáčknutí tlačítka a jeho držení. Aby tlačítko nezůstalo zmáčknuté napořád, existuje příkaz Mouse.release(), který zmáčknuté tlačítko uvolní. Posledním příkazem je Mouse.isPressed(), který zjišťuje, jestli je nějaké tlačítko stisknuté. Parametr všech funkcí může nabývat stejných hodnot jako u Mouse.click(). Jeho výchozí hodnota je také MOUSE_LEFT.

Příklad: Myš

Využijeme již hotové zapojení, ke kterému přidáme čtyři tlačítka (každé odpovídající jednomu směru). Rolování kolečka pro zjednodušení vynecháme. Budeme potřebovat:

  1. Arduino Leonardo, nebo jiné zmíněné v úvodu
  2. Nepájivé kontaktní pole s vodiči
  3. 7 x tlačítko do kontaktního pole
  4. 7 x 10 kohm resistor

Program

byte smery[4] = {10,8,9,11}; //nahoru, dolu, doprava, doleva
byte pinyTlacitka[3] = {4,3,2}; //levé, prostřední, pravé
byte tlacitka[3] = {MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT};
byte posledniStavTlacitek[3] = {LOW,LOW,LOW};
int hodnotySmeru[4][2] = {{0,-1},{0,1},{1,0},{-1,0}};
//nahoru, dolu, doprava, doleva
byte i;
int limitPohyb = 2;
//jak často se bude pohybovat myší
long posledniPohyb = 0;
//proměnná pro uložení času posledního odeslání příkazu
 
void setup() {
    Mouse.begin();
    for(i = 0; i <= 2; i++){
        pinMode(pinyTlacitka[i], INPUT);
    }
    for(i = 0; i <= 3; i++){
        pinMode(smery[i], INPUT);
    }
}
 
void loop() {
    for(i = 0; i <= 2; i++){
        if(digitalRead(pinyTlacitka[i]) != posledniStavTlacitek[i]){
            if(digitalRead(pinyTlacitka[i]) == HIGH){
                Mouse.press(tlacitka[i]);
            }
            else{
                Mouse.release(tlacitka[i]);
            }
            posledniStavTlacitek[i] = !(posledniStavTlacitek[i]); 
        }
    }
    
    if(posledniPohyb + limitPohyb < millis()){
        for(i = 0; i <=3; i++){
            if(digitalRead(smery[i]) == HIGH){
                Mouse.move(hodnotySmeru[i][0],hodnotySmeru[i][1],0);
            }
        }	
        posledniPohyb = millis();
    }
}

Keyboard

Jak už název napovídá, druhá část funkcí slouží k odesílání příkazů ve formě úhozů kláves. Jak jistě poznáme, jsou si funkce pro Mouse a Keyboard velmi podobné. Nalezneme zde dvojici funkcí Keyboard.begin() a Keyboard.end() sloužící pro zahájení a ukončení odesílání úhozů kláves. Příkazem Keyboard.write() se odešle jeden úhoz klávesy. Parametrem je daná klávesa. Pokud chceme odeslat znak, stačí volat funkci s parametrem znaku v uvozovkách, nebo s jeho odpovídajícím číslem v ASCII tabulce. Když chceme stisknout nějakou z funkčních kláves (CTRL, F1…), můžeme využít předdefinované konstanty. Jejich seznam nalezneme v oficiální dokumentaci. Vytvořme si program, který nás po zmáčknutí tlačítka pozdraví.

byte tlacitko = 10;

void setup() {
	Keyboard.begin();
	pinMode(tlacitko, INPUT);
}

void loop() {
	if(digitalRead(tlacitko) == 1){
		Keyboard.write('A');
		Keyboard.write('h');
		Keyboard.write('o');
		Keyboard.write('j');
	}
	delay(1000);
}

Další dvojicí funkcí jsou Keyboard.print() a Keyboard.println(). Stejně jako u sériové komunikace, i zde je rozdíl v tom, že po příkazu Keyboard.println() následuje odřádkování. Parametrem obou funkcí může být znak, nebo řetězec znaků. Pokud je Keyboard.println() volána bez parametru, dojde pouze k odřádkování. Program se stejnou funkčností jako předchozí, jen s kratším zápisem může vypadat takto:

byte tlacitko = 10;

void setup() {
    Keyboard.begin();
    pinMode(tlacitko, INPUT);
}

void loop() {
    if(digitalRead(tlacitko) == 1){
        Keyboard.print("Ahoj");
    }
    delay(1000);
}

Funkce Keyboard.press() slouží k odeslání informace, že je zmáčknutý znak. Odeslaný znak je stále zmáčknutý, dokud nedojde k jeho uvolnění pomocí funkce Keyboard.release(), který uvolní právě daný znak, nebo Keyboard.releaseAll(), která uvolní všechny stisknuté znaky. Jako demonstraci si vytvořme herní konzoli pro ovládání hry Sonic. Využijeme zapojení z příkladu s myší. K ovládání hry slouží klávesy a jim odpovídající hodnoty: doleva – KEY_LEFT_ARROW, mezerník – 32 a doprava – KEY_RIGHT_ARROW.

byte pinyTlacitek[3] = {11,10,9}; //doleva, nahoru, doprava
byte posledniStavTlacitek[3] = {LOW,LOW,LOW}; 
byte tlacitka[3] = {KEY_LEFT_ARROW, 32, KEY_RIGHT_ARROW};
byte i;

void setup() {
	Keyboard.begin();
	for(i = 0; i < 3; i++){
		pinMode(pinyTlacitek[i], INPUT);
	}
}

void loop() {
	for(i = 0; i < 3; i++){
		if(digitalRead(pinyTlacitek[i]) != posledniStavTlacitek[i]){
			//abychom PC nezahltili,pošleme příkaz 
			//pouze když se změní stav tlačítka
			if(digitalRead(pinyTlacitek[i]) == HIGH){
				Keyboard.press(tlacitka[i]);        
			}
			else{
				Keyboard.release(tlacitka[i]);  
			}
			//změna stavu tlačítka v poli pomocí negace
			posledniStavTlacitek[i] = !(posledniStavTlacitek[i]);
		}
	}
}

Arduino Esplora

Deska Arduino Esplora

Arduino Esplora

Arduino Esplora se od ostatních desek velmi liší a to nejenom svým tvarem, ale i tím, že na něm najdeme spoustu přídavných periferií, jako piezo bzučák, teploměr, joystick, nebo tlačítka. Také se mírně liší ve způsobu programování. Arduino Esplora se totiž tváří stejně jako Leonardo, jen má vlastní knihovnu příkazů (balíček funkcí), které slouží k využití všech částí desky. U této verze je ještě více než u ostatních patrná snaha o zjednodušení programování a minimalizaci zapojování. Je tedy určena pro všechny, kteří se nechtějí moc zdržovat správným zapojením komponent a chtějí rovnou programovat. Abychom mohli s Esplorou pracovat, musíme na začátek programu vložit: #include <Esplora.h>. Pojďme si nyní představit funkce pro pracování s jednotlivými částmi desky.

Joystick

Joystick jistě všichni znáte z různých herních konzolí. Jedná se o zařízení, které umožňuje ovládání ve dvou osách. Joystick Arduina Esplora má navíc tlačítko, k jehož zmáčknutí dojde při stlačení joysticku směrem k desce. Pro čtení hodnot z joysticku se používají funkce Esplora.readJoystickX() a Esplora.readJoystickY(). Ty vrací hodnoty od -512 do 512. Pro osu x jsou záporné hodnoty ve směru doleva a kladné doprava. Po ose Y jsou kladné hodnoty nahoru a záporné dolů. Pokud je tedy joystick nevychýlený, jeho souřadnice jsou x=0, y=0. Pro zjišťování stavu tlačítka se používá funkce Esplora.readJoystickButton(). Pokud je tlačítko zmáčknuto, vrací hodnotu LOW. Sestavme si aplikaci, která bude pomocí joysticku ovládat kurzor myši a po jeho zmáčknutí dvakrát klikne levým tlačítkem.

#include <Esplora.h>

int x,y;

void setup(){
	Mouse.begin();
}

void loop(){
	x = map(Esplora.readJoystickX(), -512, 512, 2, -2);
	y = map(Esplora.readJoystickY(), -512, 512, -2, 2);
	Mouse.move(x,y,0);
	delay(1);
    
	if(Esplora.readJoystickButton() == LOW){
		Mouse.click();
		delay(100);
		Mouse.click();
	}    
}

Směrová tlačítka

Rozložení čtyřech velkých tlačítek přímo vybízí k jejich použití jako směrové klávesy. Nikde však není psáno, že musí být použity právě na směry. Pomocí nich mohou být vytvořeny třeba různé funkční klávesy. Ke zjištění stavu tlačítek slouží funkce Esplora.readButton(). Stejně jako u joysticku i zde vrací funkce hodnotu LOW, pokud je tlačítko stisknuté. Funkce má jeden parametr, který může nabývat čtyř hodnot, a to:

  • SWITCH_UP – nahoru
  • SWITCH_DOWN – dolů
  • SWITCH_LEFT – doleva
  • SWITCH_RIGHT – doprava

Herní konzole pro hru ovládanou šipkami tedy může vypadat takto:

#include <Esplora.h>

byte sipky[] = {SWITCH_UP, SWITCH_DOWN, SWITCH_LEFT, SWITCH_RIGHT};
byte zkratky[] = {KEY_UP_ARROW, KEY_DOWN_ARROW, KEY_LEFT_ARROW, KEY_RIGHT_ARROW};
byte posledniStav[] = {1,1,1,1};
byte i;

void setup(){
	Keyboard.begin();
	Serial.begin(9600);
}

void loop(){
	for(i = 0; i < 4; i++){
		if(Esplora.readButton(sipky[i]) != posledniStav[i]){
			if(Esplora.readButton(sipky[i]) == LOW){
				Keyboard.press(zkratky[i]);
			}
			else{
				Keyboard.release(zkratky[i]);
			}
			posledniStav[i] = !(posledniStav[i]);
		}
	} 
}

Poznámka: V oficiální dokumentaci funkce readButton() nalezneme popis dalších parametrů. Všechny však slouží k práci se čtyřmi základními tlačítky a jsou tedy shodné.

Lineární potenciometr

Lineární potenciometr, anglicky nazývaný slider, je umístěn při dolním okraji desky. Funguje stejně, jako nám dobře známé potenciometry. Liší se pouze v mechanické konstrukci. Pro čtení hodnot se používá funkce Esplora.readSlider(). Ta vrací hodnoty od 0 do 1023. Na nule je hodnota funkce, když je posuvník potenciometru vpravo. Vlevo je to 1023. Příkladem může být jednoduchá funkce odesílající hodnoty ze slideru.

#include <Esplora.h>

int hodnota;

void setup(){
    Serial.begin(9600);
}

void loop(){
    hodnota = Esplora.readSlider();
    Serial.println(hodnota);
    delay(500);
}

Mikrofon

Dalším přídavným hardwarem je standartní elektretový mikrofon. Ten zde slouží převážně k zjištění intenzity okolního hluku než k jiným audio účelům. Pro čtení hodnot slouží funkce Esplora.readMicrophone(). Ta vrací hodnoty v rozmezí 0 až 1023. Jako příklad si uveďme jednoduchou aplikaci, která bude po sériové lince vypisovat „audiovlnu“ se vzorkovací frekvencí 1 kHz (kolikrát za sekundu dojde k měření). Pokud bychom takovouto vlnu přehráli, bude velmi zdeformovaná. Pro lidské ucho se totiž doporučuje vzorkovací frekvence 40kHz a vyšší. Spousta zvukových informací se tedy při 1 kHz ztratí.

#include <Esplora.h>

int hodnota;

void setup(){
    Serial.begin(9600);
}

void loop(){
    hodnota = Esplora.readMicrophone();
    hodnota = map(hodnota, 0, 1023, 0, 50);
    for(int i = 0; i < hodnota; i++){
        Serial.print('|');
    }    
    Serial.println();
    delay(1);
}

Světelný senzor

Světelný senzor zde není nic jiného, než obyčejný fotoresistor. Ke čtení hodnot se využívá funkce Esplora.readLightSensor(), která vrací hodnoty od 0 (pro tmu) do 1023 (pro světlo). Příklad práce s měřením světla je stejný jako u mikrofonu, jen se zaměněním funkcí pro získání hodnot, čili:

hodnota = Esplora.readLightSensor();

Teploměr

Arduino Esplora má také přímo na desce teploměr. Ten měří teplotu ve stupních Celsia, nebo Fahrenheita. Připomeňme si převodní vztah, kdy °C = (°F-32)*(5/9). Ve fyzice se častěji používá Kelvinova stupnice. Její nula je definovaná jako absolutní nula (0°K = -273,15°C). Velikost jednoho stupně Kelvina odpovídá jednomu stupni Celsia, jen je celá stupnice posunuta směrem k absolutní nule. Pro získání naměřené teploty slouží funkce Esplora.readTemperature(). Funkce má jeden parametr, který nabývá dvou hodnot (podle volby požadované stupnice). Pro hodnotu DEGREES_C vrátí funkce hodnotu ve stupních Celsia (od -40 do +150 °C). Pro parametr DEGREES_F bude vrácená hodnota ve stupních Fahrenheita (od -40 do +302 °F). Níže vidíte program, který bude při zmáčknutí tlačítka každou sekundu vypisovat naměřené hodnoty přes sériovou linku.

#include <Esplora.h>

int hodnota;

void setup(){
    Serial.begin(9600);
}

void loop(){
    if(Esplora.readButton(SWITCH_UP) == LOW){
        hodnota = Esplora.readTemperature(DEGREES_C);
        Serial.print(hodnota);
        Serial.println(" C");
        delay(1000);
    }
}

Poznámka: Více o Celsiově stupnici naleznete na Wikipedii.

Akcelerometr

Akcelerometr je součástka schopná měřit zrychlení. U Arduina Esplora jej nalezneme ve verzi, která je schopná detekovat zrychlení ve třech kolmých osách (x, y, z). Nalezneme ho uprostřed desky. Na zařízení působí zrychlení, i když je v klidu. Zrychlení totiž vyvolává tíhová síla, kterou na něj působí země. Poté závisí na úhlu desky vůči zemi, jakou bude zrychlení mít velikost v jednotlivých osách. Pokud je naměřená hodnota zrychlení na nějaké ose nula, znamená to, že právě působí kolmo na danou osu. Osa X jde od středu Esplory směrem ke tlačítkům. Osa Y ze středu k USB portu a osa Z ze středu vystupuje kolmo nad desku. Pokud tedy Esplora leží na vodorovné podložce, měly by být hodnoty: x = 0, y = 0 a z přibližně 150. Ke čtení hodnot se používá funkce Esplora.readAccelerometer() s parametrem se třemi možnými hodnotami: X_AXIS, Y_AXIS a Z_AXIS. Pro demonstraci můžeme využít příklad z dokumentace. Ten nám bude posílat po sériové lince naměřené hodnoty zrychlení na jednotlivých osách.

#include <Esplora.h>

void setup(){
	Serial.begin(9600);

void loop(){
	int xAxis = Esplora.readAccelerometer(X_AXIS);
	int yAxis = Esplora.readAccelerometer(Y_AXIS);
	int zAxis = Esplora.readAccelerometer(Z_AXIS);

	Serial.print("x: ");
	Serial.print(xAxis);
	Serial.print("\ty: ");
	Serial.print(yAxis);
	Serial.print("\tz: ");
	Serial.println(zAxis);

	delay(500);
}

Piezo bzučák

Na desce také najdeme bzučák, který jsme si popsali už v minulém článku. Použití je stejné, jen ubyde parametr pro výstup, na kterém se tón generuje. Pomocí funkce Esplora.tone() se generuje tón. Funkce má jeden povinný parametr pro frekvenci a nepovinný parametr pro trvání tónu. Tón se vypne funkcí Esplora.noTone().

RGB LED

Na pravé straně slideru nalezneme tříbarevnou LED diodu. Od každé barvy je možné nastavit 256 různých sytostí (0 – 255). Máme-li tři barvy, můžeme celkově generovat až 2563 různých barev. K ovládání se nám nabízejí čtyři různé funkce. Esplora.writeRed(), Esplora.writeGreen() a Esplora.writeBlue() slouží každá ke generování jedné barvy, kdy parametrem je jejich jas v rozsahu 0 až 255. Funkce Esplora.writeRGB() je shrnutím předchozích funkcí do jedné. Má tři parametry, a to jas červené, zelené a modré (v tomto pořadí). Vyzkoušejme si mixování barev pomocí slideru a joysticku.

#include <Esplora.h>

int r,g,b;

void setup(){
} 

void loop(){
    r = map(Esplora.readJoystickX(), -512, 512, 0, 255);
    g = map(Esplora.readJoystickY(), -512, 512, 0, 255);
    b = map(Esplora.readSlider(), 0, 1023, 0, 255);
    
    Esplora.writeRGB(r,g,b);
}

Neoficiální pinout

Oficiální dokumentace se nezmiňuje o jedné věci a to o využití pinů na přední straně desky. Levá část je bohužel nepřipojená a slouží pouze k lepšímu mechanickému uchycení případných rozšíření. Pravá část však nabízí několik využitelných pinů. Velice dobře zpracovaný popis pinů desky nalezneme v tomto dokumentu. Zde nás budou zajímat hnědě vyznačené piny. Pod jejich číslem je můžeme používat pomocí standartních funkcí, jako digitalRead(), digitalWrite() a dalších. Nikoliv tedy Esplora.read…

Neoficiální popis pinů pochází z webu pighixxx.tumblr.com. Zde naleznete graficky výborně zpracované rozložení pinů a součástek většiny desek Arduino a spoustu dalších včetně doporučeného zapojení dalších přídavných komponent.

Zdroje obrázků

[Arduino Leonardo]

[Arduino Esplora]

[Esplora Pinout]

V případě jakýchkoliv dotazů či nejasností se na mě neváhejte obrátit v komentářích.

Zbyšek Voda

Napsat komentář