0,00 €

V košarici ni izdelkov.

0,00 €

V košarici ni izdelkov.

More
    DomovRevijaProgramiranjeGeekcreit UNO R3 starter kit (7) - servo in koračni motor

    Geekcreit UNO R3 starter kit (7) – servo in koračni motor

    Svet elektronike colorAvtorja: Vladimir Mitrović in Robert Sedak
    V tem članku bomo pokazali, kako krmiliti servo in koračni motorja iz Geekcreit kompleta!
    Servo motor
    Servo motor je sestavljen iz ”navadnega” enosmernega motorja, zobniškega prenosa (zaradi katerega se os servo motorja vrti počasneje od osi pogonskega DC motorja), potenciometra in ustreznega elektronskega vezja. Sestavni deli enega tipičnega servo motorja so prikazani na sliki 46.

    Slika hkrati prikazuje tudi kako servo motor vežemo na napajalno napetost. Nazivna napetost večine malih modelarskih servo motorjev znaša 5 V, pa tudi njihova poraba ni prevelika. Zato jih lahko direktno povežemo na Arduino Uno. Seveda servo motor ne bo deloval, če ga samo povežemo na napajalno napetost: da bi ga zagnali mu je potrebno na tretji priključek (rumene ali bele barve) trajno dovajati ustrezne krmilne impulze. Ti impulzi se morajo ponavljati vsakih 20 ms (frekvenca impulzov = 50 Hz), položaj osi motorja pa je odvisen od trajanja krmilnih impulzov.
    Ko je trajanje impulza 1500 µs, se bo os nahajala v srednjem položaju. Če povečujemo trajanje impulza, se bo os zavrtela v smeri kazalca na uri; pri impulzih krajšega trajanja se bo os zavrtela v nasprotni smeri. Kot obrata je tipično 180°, po 90° v vsaki smeri. Na sliki 47 so prikazani samo srednji in skrajni položaji, vendar je servo motor lahko tudi zelo natančno krmiliti: impulzi trajanja 1550 µs bodo obrnili os samo malo ”v desno” od srednjega položaja, impulzi trajanja 1600 µs še malo več v desno itd.
    Da bi zagotovili zanesljivo odvisnost položaja osi od trajanja krmilnih impulzov, se v servo motorje vgrajuje potenciometer, ki je povezan z osjo motorja (ta potenciometer ni viden na sliki 46). Drsnik potenciometra elektronskemu vezju v vsakem trenutku ”javlja” položaj osi servo motorja, da lahko naredi potrebne korekcije, takoj, ko ugotovi, da položaj osi ne ustreza trajanju krmilnih impulzov.
    Podatki o trajanju impulzov so prikazani na sliki 47, nanašajo se na mali servo motor SG90 iz Geekcreit kompleta. Tudi druge modelarske servo motorje se krmili na enak način, vendar nekateri od njih dopuščajo večji razpon krmilnih impulza, npr. 700-2300 µs, vendar je lahko smer vrtenja tudi nasprotna od prikazane. Pred uporabo je potrebno preveriti dokumentacijo uporabljenega motorja in pazljivo preveriti znotraj katerega razpona se os nekega motorja lahko svobodno zavrti! Dovajanje prekratkih ali predolgih impulzov, kot tudi dovajanje impulzov, katerih  frekvenca pomembno odstopa od nazivnih 50 Hz, se bo končalo s poskušanjem postavljanja osi v nedovoljeni položaj, preko omejitve: servo motor bo ”zablokiral”, pri čemer se lahko poškodujejo tudi njegovi zobniki!
    Delo servo motorja SG90 bomo preizkusili s pomočjo vezja, katerega je shema prikazana na sliki 48. Motor bomo krmilili z obračanjem osi potenciometra P1 in tipko T1. Tipka je vezana na A3 priključek Arduino Uno ploščice, katerega v tem primeru uporabljamo kot digitalni vhod 17. Komponente bomo zložili na veliko testno ploščico po sliki 49. Trimer P2, ki služi za nastavljanje kontrasta alfanumeričnega displeja, se ne nahaja v Geekcreit kompletu: v 5. poglevju je podrobno opisano, kako ga lahko nadomestimo!
    Servo motor bomo vezali direktno na Arduino Uno ploščico na naslednji način:
    • rumeno žico vežemo na priključek ~9,
    • rjavo žico vežemo na priključek GND,
    • če Arduino Uno napajamo iz omrežnega adapterja, katerega napetost višja od 5 V, bomo rdečo žico vezali na priključek 5V (v tem primeru se servo motor napaja preko napetostnega stabilizatorja na Arduino Uno ploščici),
    • če Arduino Uno napajamo preko USB kabla, rdečo žico vežemo na priključek Vin (v tem primeru servo motor napajamo direktno z vhodno napetostjo).
    13. programska naloga
    Napišite program za vezje na slikah 48 in 49, kjer bomo krmilili servo motor na naslednji način:
    • z obračanjem osi potenciometra P1 določamo kot obrata servo motorja v razponu 0°do 180°;
    • servo motor se postavlja v želeni položaj s pritiskom na tipko T1;
    • če se os potenciometra P1 obrača dokler je tipka T1 pritisnjena, se mora os motorja obračati sočasno s spremembo položaja drsnika potenciometra.
    Odčitek položaja drsnika potenciometra P1 in kot obrata servo motorja se prikazujeta na LCD-ju po skici na sliki 48.
    Arduino rešitev (program Geekcreit_13.ino)
    Program pričnemo z navajanjem knjižnic, ki jih bomo uporabili:
    #include <Servo.h>
    #include <LiquidCrystal.h>
    Nato definiramo objekt S1 za servo motor in objekt lcd za LCD, čemur sočasno pridružimo komunikacijske priključke:
    Servo S1;
    LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
    V funkciji setup() definiramo priključek A3 kot vhodni z vključenim pull-up uporom, objektu servo motorja S1 pridružimo priključek 9, definiramo vrsto alfanumeričnega displeja in izpišemo tekst na začetku obeh vrstic:
    void setup(){
    pinMode(A3, INPUT_PULLUP);
    S1.attach(9);
    lcd.begin(16, 2);
    lcd.print(”A/D izhod:”);
    lcd.setCursor(0, 1);
    lcd.print(”servo:”);
    }
    V funkciji loop() preberemo stanje na analognem vhodu A0 in ga shranimo v spremenljivko potValue. Definiramo začetek izpisa vrednosti na alfanumeričnem displeju, odkrijemo iz koliko številk je sestavljeno število shranjeno v spremenljivko potValue, dodamo potrebno število praznih mest, da bi bila enica vedno na istem mestu in ga izpišemo:
    void loop(){
    int potValue = analogRead(A0);
    lcd.setCursor(12,0);
    if (potValue > 999 ) {
    } else if (potValue > 99) {
    lcd.print(””);
    } else if (potValue > 9) {
    lcd.print(””);
    } else {
    lcd.print(””);
    }
    lcd.print(potValue);
    Odvisno od položaja drsnika potenciometra bo odčitek v razponu 0-1023. Ta razpon bomo pretvorili v razpon 0-180 s pomočjo funkcije map():
    int S1Value = map(potValue, 0, 1023, 0, 180);
    Definiramo začetek izpisa v drugi vrsti alfanumeričnega displeja, ugotovimo koliko številk sestavlja število, ki je shranjeno v spremenljivki S1Value in dodamo potrebno število praznih mesta, da bi bila enica vedno na istem mestu in ga izpišemo:
    lcd.setCursor(12,1);
    if (S1Value > 99 ) {
    } else if (S1Value > 9) {
    lcd.print(””);
    } else{
    lcd.print(””);
    }
    lcd.print(S1Value);
    lcd.print(char(223));
    Na koncu smo izpisali znak za stopinje. Ostane nam še, da preverimo, ali je tipka T1 pritisnjena. Samo če je, pretvorjeno vrednost posredujemo funkciji write() objekta S1 in tako zaženemo os servo motorja S1:
    if (!digitalRead(A3)) {
    S1.write(S1Value);
    }
    }
    Koračni motor
    Koračni (step) motorji se ne vrtijo kontinuirano, ampak postopno (v ”korakih”) in se lahko zaustavijo samo v določenih položajih. Če so te koraki dovolj kratki, bomo lahko koračni motor zelo natančno zavrteli za želeni kot, kar tudi je njegova najvažnejša lastnost.
    Slika 50 zgoraj prikazuje skico enostavnega unipolarnega koračnega motorja, ki je sestavljen iz permanentnega magneta (rotorja) in štirih elektromagnetov (statorja). Rotor se obrne proti tistim polom statorja, ki so v določenem trenutku magnetizirani. To je lahko samo en pol, ali po dva sosednja, kakor smo ju na sliki prikazali. Če se statorski elektromagneti vklapljajo po vrsti prikazani na sliki, se  bo rotor obračal nasprotno od smeri gibanja urinega kazalca.
    Če primerjate kateri koli dve sosednji skici v horizontalnem nizu na sliki 50, boste opazili, da se rotor med njima obrnil za 90°. Za takšen motor pravimo, da ima 90° korak. Isti motor lahko naredimo dvakrat bolj natančen, če ga poganjamo s pol-korakom: takrat rotor izmenično privlači en statorski elektromagnet in dva sosednja, zaradi česar je korak prepolovljen na 45°. V spodnjem delu slike 50 je prikazan vrstni red vključevanja elektromagnetov s polnim korakom (levo) in s pol-korakom (desno) za obe smeri vrtenja: ”1” pomeni, da je posamezni elektromagnet vklopljen, ”0” da čez njega ne teče noben tok. V vseh teh primerih korakov ne smemo preskakovati, ker bomo samo tako zagotovili zanesljivo krmiljenje motorja!
    Za večino primerov uporabe potrebujemo bolj natančno kontrolo pomika, zato se koračni motorji v praksi proizvajajo z večjim številom statorskih navitij od prikazanih, zato je njihov korak deset ali manj stopinj. Dodatno se korak lahko zmanjša z uporabo zobniškega ali polžastega prenosa. V Geekcreit kompletu se nahaja koračni motor 28BYJ-48, ki ima 32 statorjev in skladno s tem je potrebnih 32 korakov za polni krog osi motorja, če uporabljamo pomik s polnim korakom. V motor je vgrajen zobniški prenos prenosnega razmerja 64:1 zato bo se izhodna os obračala 64-krat počasneje. Z drugimi besedami za en polni obrat je potrebnih 32×64 = 2048 korakov oziroma dosežemo pomik 0,176° po koraku!
    Risba na sliki 51 desno prikazuje koračni motor 28BYJ-48 in njegov shematični prikaz. Motor ima pet priključkov, od katerih je rdeči skupen vsem navitjem in se veže na pozitivni pol napajalne napetosti, svobodni priključki statorskih navitij so povezani na preostale štiri priključke. Z vezanjem enega od teh priključkov na negativni pol napajalne napetosti se bo magnetizirali tisti deli statorja, čez katero navitje je stekel tok. Barve posameznih priključkov na risbi ustrezajo barvam priključnih žic na ”realnem” motorju, kot tudi barvam in črkovnim oznakam na sliki 50.
    Upornost posameznega navitja motorja je 27 Ω in skozi aktivirana navitja teče toko okoli 180 mA. Zato priključkov ne smemo direktno vezati na priključke Arduino Uno ploščice, pač pa potrebujemo ustrezno krmilno vezje. Shema tega vezja, ki se tudi nahaja v Geekcreit kompletu, je prikazana na sliki 51 levo. V njemu se nahaja integrirano vezje ULN2003, ki vsebuje 7 tranzistorskih stikal. Mi uporabljamo samo 4 stikala: ko na enega od IN vhodov priključimo na 5 V (to so enice na sliki 50!), se bo ustrezno tranzistorsko stikalo sklenilo in skozi navitje, ki ga krmili, bo stekel tok. Sočasno se bo vklopila tudi ena od LED-ic, da bi videli, kaj se dogaja.
    Delo koračnega motorja bomo preizkusili s pomočjo vezja, katerega shema je prikazana na sliki 52. Motor bomo krmilili z obračanjem osi potenciometra P1 in s tipko T1. Tipka je vezana na A3 priključek Arduino Uno ploščice, katerega v tem primeru uporabljamo kot digitalni vhod 17. Komponente bomo zložili na veliko testno ploščico po sliki 49 in opombam, ki smo jih napisali pri tej sliki!
    Koračni motor vežemo na Arduino Uno ploščico preko krmilnega vezja. Konektor na kraju priključnih vodov koračnega motorja 28BYJ-48 ustreza konektorju na ploščici krmilnega vezja, zato tukaj ni lahko zgrešiti. Vhodne priključke IN1-IN4 vežemo po vrsti na priključke 11-8 Arduino Uno ploščice, ”-” priključek krmilnega vezja pa povežemo na GND priključek Arduino Uno ploščice. Kje bomo vezali ”+” priključek krmilnega vezja je odvisno od načina napajanja Arduino Uno ploščice:
    • če Arduino Uno napajamo iz omrežnega adapterja, ki ima napetost višjo od 5 V, ”+” priključek vežemo na priključek 5V (v tem primeru se koračni motor napaja preko napetostnega stabilizatorja na Arduino Uno ploščici),
    • če Arduino Uno napajamo preko USB kabla, ”+” priključek vežemo na priključek Vin (v tem primeru servo motor direktno napajamo z vhodno napetostjo).
    Na krmilni ploščici moramo še postaviti kratkostičnik na priključke desno od ”+” priključka (na sliki 52, kratkostičnik je obarvan z rumeno barvo). Preko tega kratkostičnika je koračni motor vezan na pozitivni pol napajalne napetosti. Če kratkostičnik odstranimo bo motor ostal brez napajanja, vendar bomo stanje izhodnih priključkov še naprej lahko spremljali preko LED-ic A-D.
    14. programska naloga
    Napišite program za vezje na slikah 52 in 49, s katerim bomo krmilili koračni motor na naslednji način:
    • z vrtenjem osi potenciometra P1 določamo število korakov in smer vrtenja koračnega motorja v razponu od -2048 do 2048 (- označuje vrtenje v smeri nasprotno urinemu kazalcu);
    • koračni motor se zažene pritiskom na tipko T1;
    • motor se vrti s hitrostjo 500 korakov/s (oziroma, s pavzo dolgo 2 ms med dvema korakoma);
    • če se tipko T1 drži pritisnjeno, se motor se vrti počasneje, s pavzo dolžine 1 s med dvema korakoma, da bi se stanja motorja lahko spremljala LED-icah krmilnega vezja;
    • ko naredi zadano število korakov, mora program postaviti vse IN priključke v stanje 0, da preko navitij ne bi po nepotrebnem tekel tok dokler motor miruje.
    Odčitek položaja drsnika potenciometra P1 in število korakov koračnega motorja prikazuje se na LCD-ju po skici na sliki 52.
    Arduino rešitev (program Geekcreit_14.ino)
    Program bomo začeli navajanjem knjižnice, ki jo bomo uporabili za prikaz na LCD-ju in z definiranjem objektov s z imenom lcd, kateremu sočasno pridružujemo komunikacijske priključke:
    #include <LiquidCrystal.h>
    LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
    V funkciji setup() definiramo priključke 8, 9, 10  in 11 kot izhodne, priključek A3 pa kot vhodni z vključenim pull-up uporom in definiramo vrsto alfanumeričnega displeja. Nato izpišemo tekst na začetku obeh vrstic:
    void setup(){
    pinMode(8,OUTPUT);
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    pinMode(A3, INPUT_PULLUP);
    lcd.begin(16, 2);
    lcd.print(”A/D izhod:”);
    lcd.setCursor(0, 1);
    lcd.print(”koraki:”);
    }
    V funkciji loop() preberemo stanje na analognem vhodu A0 in ga shranimo v spremenljivko potValue. Definiramo začetek izpisa vrednosti na LCD-ju, ugotovimo iz koliko številk je sestavljeno število shranjeno v spremenljivko potValue, dodamo potrebno število praznih mest, da bi enota vedno bila na istem mestu in ga izpišemo:
    void loop(){
    int potValue = analogRead(A0);
    lcd.setCursor(12,0);
    if (potValue > 999 ) {
    } else if (potValue > 99) {
    lcd.print(””);
    } else if (potValue > 9) {
    lcd.print(””);
    } else {
    lcd.print(””);
    }
    lcd.print(potValue);
    Odčitek napetosti na drsniku potenciometra bo v razponu 0-1023, nam pa je za krmiljenje s koračnim motorjem potreben razpon od -2048 do 2048. Dobili ga bomo tako, da od števil manjših od 512 odštejemo 512, od števil večjih od 511 odštejemo 511; v obeh primerih rezultat pomnožimo s 4:
    int steps = 0;
    if (potValue<512) {
    steps = (potValue – 512) * 4;
    } else {
    steps = (potValue – 511) * 4;
    }
    Definiramo začetek izpisa v drugi vrsti alfanumeričnega displeja, ugotovimo iz koliko številk je sestavljen število, ki je shranjeno v spremenljivki steps in dodamo potrebno število praznih mesta, da bi enota bila vedno na istem mestu in ga izpišemo. Opazili boste, da smo glede na predhodno nalogo  začetek izpisa premaknili za eno mesto v levo, da bi lahko izpisati tudi znak minus:
    lcd.setCursor(11,1);
    if (steps > 999 ) {
    lcd.print(””);
    } else if (steps > 99) {
    lcd.print(””);
    } else if (steps > 9) {
    lcd.print(””);
    } else if (steps > 0) {
    lcd.print(””);
    } else if (steps > -10) {
    lcd.print(””);
    } else if (steps > -100) {
    lcd.print(””);
    } else if (steps > -1000) {
    lcd.print(””);
    }
    lcd.print(steps);
    Če je tipka T1 pritisnjena, bomo določili smer vrtenja motorja z vpisom vrednosti 1 ali -1 v spremenljivko s_direction:
    if (!digitalRead(A3)) {
    int s_direction = 0;
    if (steps > 0) {
    s_direction = 1;
    } else {
    s_direction = -1;
    }
    Funkcijo step_move() kličemo tolikokrat, kolikor je vpisano v spremenljivki steps. Ta vrednost je lahko pozitivna in negativna, kar nam ne ustreza za for petlju! Pomagali si bomo z abs() funkcijo:
    for (int i = 0; i < abs(steps); i++) {
    step_move(i*s_direction);
    Z druge strani je funkciji step_move() potrebna ta negativna vrednost, da bi lahko določila smer vrtenja; zato smo števec i pomnožili s spremenljivko s_direction.
    Pri določanju pavze med koraki moramo preveriti, ali je pritisnjena tipka T1. V skladu s postavljeno nalogo moramo pri pritisnjeni tipki upočasnili izvrševanje programa:
    if(!digitalRead(A3)) {
    delay(1000);
    } else {
    delay(2);
    }
    }
    Da preko navitij ne bi po nepotrebnem tekel tok dokler motor miruje, po zaključku for zanke postavljamo vse IN priključke v stanje 0. Za to bomo uporabili makro ukaz, ki nam omogoča zapisovanje stanja direktno v register PORTB:
    PORTB &= ~(0b001111);
    }
    }
    V funkciji step_move() definiramo niz štirih elementov z imenom s_table, ki vsebuje definicije vseh veljavnih korakov in zagotavljamo, da indeks si ne bo večji od 3:
    void step_move(int si) {
    //                         DCBA
    const byte s_table[4] = {0b1001,
    0b0011,
    0b0110,
    0b1100};
    si = si & 0b0000011;
    Indeksirano vrednost iz tabele moramo prenesti na priključke 11-8 Arduino Uno ploščice. To bi lahko naredili priključek po priključku s pomočjo digitalWrite() ukaza, ampak je boljša rešitev to, da sočasno postavimo vse štiri priključke. Da bi to dosegli, bomo najprej prenesli trenutno stanje registra PORTB v spremenljivko s_step
    byte s_step = PORTB;
    nato pa zbrišemo bite 3-0
    s_step &= ~(0b001111);
    in jih zamenjamo s podatkom iz tabele, na katerega trenutno kaže indeks si:
    s_step |= s_table[si];
    Sedaj smo končali s pripravo in lahko vsebino spremenljivke s_step prenesemo na PORTB, da bi motor napravil naslednji korak:
    PORTB = s_step;
    }
    Opazili boste, da opisani postopek ne menja bitov 5 in 4 porta B, ki ustrezajo priključkom 13 in 12 Arduino Uno ploščice, in to je en lep primer dobro premišljenega programiranja. V tej nalogi teh priključkov ne uporabljamo, zato smo lahko postopali enostavneje in samo prenesli trenutno indeksirani podatek iz tabele na PORTB!
    Opomba: Programe Geekcreit_13.ino in Geekcreit_14.ino lahko brezplačno dobite od uredništva revije Svet elektronike.
    https://svet-el.si