Arduino

Zo stránky Robotický krúžok
Verzia z 20:20, 20. december 2016, ktorú vytvoril Palo (diskusia | príspevky)
Skočit na navigaci Skočit na vyhledávání

Slovo Arduino označuje niekoľko vecí:

  • je to počítač (malá doska plošného spoja osadená väčšinou jednočipovým mikropočítačom Atmel AVR ATMega328)
  • je to programovací jazyk v ktorom sa tento počítač dá programovať
  • je to program - programovacie vývojové prostredie, pomocou ktorého sa program zapisuje a zároveň cez USB kábel prenáša a spúšťa na Arduine
  • sú to všetky tieto veci dokopy.

Arduino sa vyrába v rozličných verziách.

Arduino Uno
Arduino Uno - najrozšírenejší model Arduina

Arduino Nano
Arduino Nano - funguje rovnako ako Uno, ale je oveľa menšie - takéto budeme používať aj my

Robot Acrob
Robot Acrob - používa dosku, ktorá sa podobá na Arduino, ale funguje rovnako, mali sme ich požičané od združenia Robotika.SK na krúžku

ATMega328
Jednočipový mikropočítač ATMega328, ktorý je základom Arduina

ATMega328 pinout
Funkcie jednotlivých vývodov jednočipového mikropočítača ATMega328

Podrobné informácie o jednočipovom mikropočítači ATMega328 sa dajú nájsť v jeho datasheete.

Každý počítač sa skladá z týchto základných častí:

základná schéma počítača

Pamäť uchováva všetky údaje (obrázky, zvuky, texty, čísla, a podobne) a programy, ktoré sa vykonávajú príkaz za príkazom v procesore. Pamäť s procesorom sú navzájom prepojené zbernicou, ktorá medzi nimi prenáša údaje. Aby s počítač mohol komunikovať so svojím okolím - napr. s človekom, alebo s vonkajšími pamäťami, na ktorých ukladá rozsiahle údaje (pevné disky, DVD, Internet), tak sú na zbernici pripojené aj vstupné a výstupné zariadenia.

To znamená, programy pozostávajú z postupnosti príkazov:

príkaz1
príkaz2
...
príkazN

V každom okamihu procesor naraz vykonáva iba jeden príkaz, postupne od začiatku programu do konca. V programoch sa môžu vyskytovať cykly:

príkaz
príkaz
...
opakuj:
  príkaz
  príkaz
koniec cyklu
príkaz
príkaz
...

- ak treba nejakú skupinu príkazov niekoľkokrát zopakovať, alebo podmienky, ktoré dovoľujú vykonať rozličné skupiny príkazov, podľa toho, ktorá z nich je práve vhodná (väčšinou na základe otestovania nejakej podmienky):

príkaz
príkaz
...
platí podmienka?
ak áno, vykonaj túto skupinu príkazov:
  príkaz
  ...
  príkaz
ak nie, vykonaj inú skupinu príkazov
  príkaz
  ...
  príkaz
a potom pokračuj v každom prípade ďalej:
príkaz
príkaz
...

Arduino je teda počítač, ktorý má svoju pamäť, procesor a nahrávame do neho cez kábel program, ktorý najskôr naprogramujeme pomocou prostredia Arduino:

program zapisovaný v prostredí Arduino.

Nato, aby sme mohli pracovať s prostredím Arduino si ho potrebujeme downloadnut a nainštalovať zo stránky arduino.cc - nainštalujte si "Windows Installer" - to by malo nainštalovať aj ovládače (drivers).

Program sa do Arduina nahráva cez prevodník USB-Serial (ktorý je v bežných arduinach už zabudovaný - ale Acroby ich potrebujú):

prevodník USB-Serial

Arduinové výstupy sú označené D0-D13 a A0-A5. Napájanie sa privádza na piny VCC a AVCC (+5V) a GND (zem, 0V). RXD, TXD označujú sériový port na komunikáciu s inými počítačmi alebo zariadeniami (napr. s PC), motory sa väčšinou pripájajú na piny D9 a D10.

Na väčšine Arduin je pin D13 pripojený na zabudovanú svietivú diódu (LED). Prvý program, ktorý napíšeme túto LEDku rozbliká.

Každý arduinový program obsahuje aspoň tieto dve funkcie:

void setup() {
 // put your setup code here, to run once:
 //...
}

void loop() {
 // put your main code here, to run repeatedly:
 //...
}

Funkcia setup() sa spustí vždy po zapnutí počítača - hneď po spustení programu. Jej úlohou je ponastavovať všetky zariadenia, ktoré sú k Arduinu pripojené. Funkcia loop() sa spustí, keď setup() skončí a ak loop() skončí (čo nemusí...), tak sa spúšťa znovu a znovu, stále dookola.

Pre rozblikanie LED musíme najskôr počítaču nastaviť pin D13 ako výstupný. Každý digitálny pin sa dá používať buď ako vstupný (vtedy Arduino z nožičky integrovaného obvodu vie prečítať, či tam je logická 0 (nulové napätie), alebo logická 1 (napätie 5V). Pin nemôže byť naraz aj vstupný aj výstupný, musíme sa rozhodnúť ako ho chceme používať a podľa toho ho vo fukcii setup() nastaviť. Robí sa to príkazom:

pinMode(číslo_pinu, režim) - pričom režim je buď INPUT, alebo OUTPUT (je možná aj tretia možnosť, ale o tom až niekedy neskôr)

Keď je pin nastavený ako výstupný, tak vo funkcii loop() môžeme LED kedykoľvek zasvietiť zapísaním logickej jednotky:

digitalWrite(číslo_pinu, HIGH); - alebo digitalWrite(číslo_pinu, 1) - čo je to isté.

podobne, LED zhasneme takto:

digitalWrite(číslo_pinu, LOW); - alebo digitalWrite(číslo_pinu, 0) - čo je to isté.

Arduino však stihne za sekundu vykonať 16 miliónov inštrukcií (taktovacia frekvencia procesora je 16 MHz) a tak, aby sme si blikanie LED stihli všimnúť, musíme po každej zmene pinu nejaký čas počkať - na to slúži funkcia delay(čas_v_milisekundách). Celý program na blikanie LED teda vyzerá takto:

void setup() {
 pinMode(13, OUTPUT);
}

void loop() {
 digitalWrite(13, HIGH);
 delay(500);
 digitalWrite(13, LOW);
 delay(500);
}

Aby sa nám Arduino programovalo jednoduchšie, ak ho máme pripojené káblom, môžeme z neho cez kábel (čiže cez sériový port) do PC poslať nejakú textovú správu:

Vo funkcii setup() najskôr nastavíme rýchlosť prenosu (počet prenesených bitov za sekundu), napr.

Serial.begin(115200);

a potom môžeme používať funkcie na vstup a výstup cez sériový port, napr.

Serial.println("Ahoj");

Celý takýto text sa odvysiela cez jediný pin TXD mikropočítača ATMega328 (pozri obrázok hore). Ako sa to udeje? Každý znak (písmeno, číslica, znamienko a pod.) má nejaký číselný kód - väčšinou sa na to používa medzinárodný štandard ASCII. Vidíme, že napríklad znak 'A' má kód 65, znak 'o' má kód 111, atď.

ASCII tabuľka

Tieto kódy sú v Arduine uložené v dvojkovej sústave, tak ako všetky ostatné čísla! Počítače totiž všetky čísla ukladajú v dvojkovej sústave, keďže na to stačí, aby na príslušnom pine bolo kladné napätie (logická jednotka) alebo nulové napätie (logická nula).

Ľudia na výpočty používajú desiatkovú sústavu, keďže majú 10 prstov, je im prirodzenejšia: obsahuje 10 číslic: 0, 1, 2, ..., 9. Za poslednou číslicou nasleduje číslo 10 zložené z dvoch číslic, za posledným dvojciferným číslo 99 nasleduje číslo 100, atď. V čísle, ktoré má viac číslic stojí každá číslica na nejakom mieste, napr. v čísle 2016: je číslica 6 na mieste jednotiek (má hodnotu 6 x 1), číslica 1 na mieste desiatok (má hodnotu 1 x 10), číslica 0 na mieste stoviek (hodnota 0 x 100) a číslica 2 na mieste tisícok (hodnota 2 x 1000). Podobne to funguje aj v dvojkovej sústave, ale namiesto 10 číslic máme k dispozícii iba číslice dve: 0 a 1. Čísla tam nasledujú za sebou takto:

    0      - zodpovedá 0 v desiatkovej sústave)
    1      - 1
   10      - 2
   11      - 3
  100      - 4
  101      - 5
  110      - 6
  111      - 7
 1000      - 8
 1001      - 9
 1010      - 10
 1011      - 11
 1100      - 12
 1101      - 13
 1110      - 14
 1111      - 15
10000      - 16
10001      - 17
 atď.

ľahko si všimneme, že aj tu majú číslice svoje "rády", napr. v čísle 10110 (čiže 22 v desiatkovej sústave) máme:

 0 - rád jednotiek 
 1 - rád dvojek (1 x 2) 
 1 - rád štvoriek (1 x 4)
 0 - rád osmičiek
 1 - ráď šestnástok (1 x 16)
1 x 2 + 1 x 4 + 1 x 16 = 22

Takže na odvysielanie čísla 8-bitového čísla 65 cez pin TXD sa tam postupne odvysielajú číslice 01000001 - a pri rýchlosti 115200 číslic za sekundu tam každá bude iba 1/115200 s, čo je približne 8,68 mikrosekúnd.

Predchádzajúci program upravme tak, aby okrem blikania LEDkou aj vypisoval texty ON a OFF:

void setup() {
 pinMode(13, OUTPUT);
 Serial.begin(115200);
}

void loop() {
 digitalWrite(13, HIGH);
 Serial.println("ON");
 delay(500);
 digitalWrite(13, LOW);
 Serial.println("OFF");
 delay(500);
}

Dobrý robot by ale iba s výstupmi nevystačil, musí nejakým spôsobom získavať informácie z prostredia - pomocou senzorov, ktoré tvoria jeho vstupné zariadenia. Napríklad ak nárazník narazí do prekážky, stlačí sa mikrospínač a hodnota na výstupe z vypínača sa zmení z logickej nuly na logickú jednotku. Potrebujeme napísať program, ktorý hodnotu na svojom pine dokáže prečítať.

Pin 2 nastavíme na vstupný:

pinMode(2, INPUT);

a funkcia

digitalRead(2)

nám vráti buď 0 alebo 1 - podľa toho, či je na pine 2 logická nula, alebo jednotka. Túto hodnotu môžeme použiť napríklad v podmienke, ktorá sa v jazyku C++ (na ktorom je Arduino založené) používa takto:

if (podmienka) {
  príkazy, ktoré sa majú vykonať, ak je podmienka splnená
}
else {
  príkazy, ktoré sa majú vykonať, ak podmienka nie je splnená, čiže neplatí
}

časť else je nepovinná - môže a nemusí tam byť. V našom prípade môžeme program naprogramovať tak, že pri stlačení tlačidla LED zasvieti:

void setup() 
{
  pinMode(2,INPUT);
  pinMode(13, OUTPUT);
}

void loop() 
{
  if (digitalRead(2)) {
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(13,LOW);
  }
}

Ako to však zapojiť?

Mikrospínač, ktorý je v stavebnici Acroba funguje tak, že bez stlačenia sú prepojené len kontakty cez dlhšie strany obdĺžnika a po stlačení sú prepojené všetky 4 kontakty.

Microswitch.jpg

Preto do pinu D2 pripojíme jeden výstup z tlačidla. Druhý výstup tlačidla spojíme s napájaním (VCC), ktoré má hodnotu napätia ako logická 1. Tým zabezpečíme, že pri stlačení tlačidla bude na D2 logická jednotka. Lenže, ak tlačidlo nestlačíme - logická nula tam nebude, bude tam len pripojený "vo vzduchu visiaci" káblik a to nie je dobre. Preto ho treba prepojiť so zemou. Ale pozor - ak by sme ho so zemou prepojili len tak - priamo, tak by sme pri stlačení tlačidla spôsobili skrat - priamymi vodičmi by bolo spojené VCC (plus na baterke) so zemou (mínus na baterke) a takúto situáciu nesmieme dopustiť ani na krátky okamih. Preto pin D2 spojíme so zemou cez rezistor s dostatočne veľkým odporom, napr. 2 kOhm:

zapojenie s mikroswitchom

Robot Acrob je poháňaný dvoma servomotormi. Servomotor je zaujímavá súčiastka - je to motor s prevodovkou a riadiacou elektronikou. Vnútri vyzerá nejak takto:

vnútornosti servomotorov

používajú sa väčšinou v robotických ramenách, pričom sa môžu otáčať v rozsahu 0-180 stupňov (90 je stredná poloha). Viac otočiť im nedovolí zabudovaná zarážka. Potenciometer je v skutočnosti rezistor s premenlivou hodnotou a používa sa ako spätná väzba, ktorá riadiacu elektroniku serva informuje o tom, ako je práve servo otočené. Cez signálny káblik (biely, alebo žltý) elektronika dostáva pokyn z počítača (napr. z Arduina), do akej polohy sa má servo nastaviť. Elektronika porovná aktuálnu hodnotu s požadovanou a podľa toho rozbehne motor správnym smerom a vhodnou rýchlosťou.

Servá, ktoré sú zabudované do Acrobov, sú tzv. modifikované servá - zarážka, ktorá bráni súvislému otáčaniu je odstránená a potenciometer je nahradený rezistorom so zafixovanou - pevnou hodnotou. Elektronika serva si preto "myslí", že servo je stále v strede (na hodnote 90) a pri pokyne nastavenia do polohy napr. 120 sa roztočí jedným smerom a bude sa tak točiť donekonečna. Pri pokyne napr. 30 sa bude točiť donekonečna opačným smerom. Pri požadovenej polohe 90 sa zastaví a pri polohách blízko 90 sa bude otáčať iba pomaly, pretože už je skoro "v cieli".

Ako servo riadiť - ako mu vysvetliť, že sa má nastaviť do požadovanej polohy napr. 30 stupňov?

Riadiaci signál do serva (biely alebo žltý káblik) by mal každých 20 ms obsahovať pulz (logickú jednotku na krátky okamih). Dĺžka tohto okamihu určuje do akej polohy sa servo má nastaviť. Typicky to býva od 0.5 - 1.5 ms. Nasledujúci program teda roztočí servo jedným smerom:

void setup() 
{
  pinMode(10, OUTPUT);
}

void loop() 
{
  digitalWrite(10, LOW);
  delay(20);
  digitalWrite(10, HIGH);
  delayMicroseconds(500);
} 

program vyšle na pin D10 krátky pulz 0.5 ms každých 20 ms. Toľko teória. Arduino je však vymyslené tak, aby sme sa nemuseli starať o každý bit sami a stačí použiť knižnicu Servo, ktorá sa o generovanie riadiaceho signálu stará sama v spolupráci so zabudovanými časovačmi počítača. Program, ktorý pohne robotom teda vyzerá takto:

#include <Servo.h>

Servo lavy, pravy; 

void setup() 
{
  lavy.attach(9);  // lave servo je na pine 9
  pravy.attach(10);  // prave servo je na pine 10
} 

void loop() 
{
  // rozbehni sa
  lavy.write(120);
  pravy.write(30);
  // tri sekundy bez
  delay(3000);
  // zastan
  lavy.write(90);
  pravy.write(90);
  // tri sekundy cakaj
  delay(3000);
}