Fórum témák

» Több friss téma
Cikkek » WILL-I V2.0 (Robotika és AVR kezdőknek)
WILL-I V2.0 (Robotika és AVR kezdőknek)
Szerző: Fizikus, idő: Feb 5, 2010, Olvasva: 39973, Oldal olvasási idő: kb. 4 perc
Lapozás: OK   8 / 9

WILL-I V2.0

A továbbfejlesztett verzióban WILL-I-t egy mikroszervóra szerelt Sharp infravörös távolságérzékelő szenzorral szereltem fel. Így nemcsak lát (érzékeli az előtte lévő tárgyak távolságát), de képes körülnézni is.


Sharp szenzor

Egy 3-30 cm méréstartományú GP2D120XJ00F szenzort használtam. Az első dolog, amit meg kellett tenni, hogy ki kell mérni a szenzor feszültség-távolság görbéjét, mert nincs két egyforma szenzor. Ugyanazon típuson belül is mindegyiknek kicsit eltérő a görbéje. Az alábbi ábráról látható, hogy észrevehetően eltér a gyártó által megadott referenciagörbe az adott szenzorok tényleges, mért görbéjétől (akár 1 cm-es eltérés is lehet a mért és a referencia adatok között).

A fenti ábráról látható, hogy a Sharp szenzor maximális feszültsége 3,1V (ez nagyobb mint a belső 2,56V-os belső referenciafeszültség). Azt is lehetne használni, de akkor a 2,56V-nál nagyobb jeleket nem tudjuk mérni és a méréstartomány leszűkül kb. 6-30 cm-re.

Ha referenciafeszültségnek a stabilizált 5V-ot választjuk (0 és 5V között mérünk) , akkor nem használjuk ki a teljes méréstartományt mert a szenzor maximális jele 3,1 V.

10 bites ADC felbontás esetén a mért ADC értékek 0-634 közé esnek.
8 bites ADC felbontás esetén pedig 0-158 közötti értékeket kapunk.

Az általam használt feladatra a 8 bites felbontás is bőven elegendő lenne (elég csak 1-2cm-es pontossággal mérni), de korábban RoboMoly programjánál a 8 bites ADC-t már használtam, ezért most példaként a 10 bites felbontást fogom használni.
 


Mikroszervó

A szenzort a mikroszervó fogja mozgatni. WILL-I esetben elég csak 3 pozíció (jobb, bal, középállás).
A szervót hardveresen generált PWM jellel fogom vezérelni (a PWM-ről részletesebben az előző cikkben esett szó LINK).
A hardveres PWM előállítás előnye, hogy néhány utasítással beállítható, és a háttérben fut (nem terheli a mikrokontrollert). Az Atmega8-nak 3 lába van, ami képes PWM jel generálására: 15-ös és a 16-os lábat (OC1A és OC1B) a 16 bites Timer1 vezérli. (A Timer1-nek 2 csatornája és 8 bites működési módja is van.) A 17-es lábat (OC2) pedig a 8 bites Timer2 vezérli.
A szervó nagyfelbontású meghajtására a 16 bites Timer1 lenne az ideális. Mivel Timer1-nek 2 csatornája van, és azt már elhasználtam a DC motorok vezérlésére, ezért kénytelen leszek a 8 bites Timer2-t használni, ami csak alacsony felbontású szervóvezérlést tesz lehetővé (kevés lépésszám van a két szélső érték között). Szerencsére az infravörös szenzor mozgatásához nem is kell nagy felbontás. (Láthatjuk hogy elértük az Atmega8 határait, mert ha később olyan irányba fejlesztjük a robotunkat, hogy szeretnénk egynél több szervót vezérelni ( pl. karokat, érzékelőket mozgatni), akkor két választásunk marad:

  • Szoftveresen oldjuk meg a PVM jel előállítását (ekkor bármelyik digitális kimenetre generálhatunk PWM jelet).
  • kicseréljük az Atmega8-at egy olyan AVR-re, amelyiknek több timere és több PWM kimenete van.
    Pl. az Atmega168-nak szintén 28 lába van (belefér a motorvezérlő panelbe), 2 db 8 bites és 1 db 10 bites timer-je és összesen 6db PWM csatornája van (4db kisfelbontású (8bit-es) és 2 nagyfelbontasú (10bit-es))


Nézzük meg hogyan lehet a szervót Timer2-vel vezérelni:

Láthattuk, hogy a szervót egy 1-2ms hosszú négyszögjellel vezérelhetjük, amelyeknek kb. 20ms-onként ismétlődniük kell. Tehát a vezérlőjel kitöltési tényezője 5-10% között változik (a teljes periódusidő 5%-át használjuk ki). Egy 8 bites timer esetén kevés lépésszám lehetséges a szervó két szélső pozíciója között. 
Timer2  számlálója 0-255-ig számol, 255 után a számláló túlcsordul és lenullázódik,  ezzel kell egy   nagyjábol 20 ms-onként ismétlődő vezérlőjelet előállítani.  Az alábbi ábráról látható, hogy a Timer2 előosztását 64-nek választva egy 61Hz-es, 16,4 ms-onként ismétlődő impulzust tudunk generálni, ami egy kicsit gyors a referencia 20ms-hoz viszonyítva, de az általam használt mikroszervó minden gond nélkül vezérelhető vele.

A négyszögimpulzus hosszát az OCR2 regiszter értékével tudjuk változtatni. Ahhoz hogy az impulzus hossza 1 és 2 ms között legyen OCR2 értéke 16-31 között lehet csak (lásd az alábbi táblázatot), ezért a szervó tűrésétől függően csak kb. 12-15 pozíciót tudunk beállítani (256-nak az 5%-a kb. 13). Egy 180°-os szervónal ez kb. 12-15°-os lépésközt jelent. Az általam használt mikroszervó szögtartománya 90°, ezért 6-8°-os lépésekben tudom a szervót pozícionálni, ami a célnak bőven megfelel.

 

A fentiek alapján Timer2 előosztását 64-nek megadva, OCR2 értékét pedig 16-31  közötti változtatva vezérelhetjük a PB3-as lábra kötött szervót a különböző pozíciókba.


WILL-I összeállítása

A Sharp IR szenzor kimenetét a PC0 (ADC0) lábra csatlakoztattam, a szervót a PB3-as lábra a nyomógombot pedig a PD2-es lábra.


WILL-I programja

Ez a vezérlőprogram sem bonyolult. Bekapcsolás után WILL-I gombnyomásra vár (PD2 lábra kötött gomb), majd elindul előre. A 10 bites ADC-vel beolvassuk a távolságérzékelő szenzor jelét. Ha WILL-I kb. 15 cm-nél közelebb (ADC >= 200) akadályt érzékel akkor:

  1. megáll
  2. balra néz
  3. távolságot mér (ADC méres)
  4. jobbra néz
  5. távolságot mér (ADC méres)
  6. majd arra fordul amerre nem érzékel akadályt, vagy az érzékelt akadály messzebb van mint a másik irányban érzékelt akadály.

A fenti algoritmus folyamatábrán ábrázolva így néz ki:
(minden ADC mérés és szervó forgatás után van egy fél másodperces késleltetés, hogy a szervónak legyen elég ideje az új pozícióba álláshoz, ez a folyamatábrán nincs feltüntetve)

 

(Ahhoz hogy az alábbi kód működjön, kell az előző cikkben leírt motor.h kód is! (LINK))

  1. /* WILL-I V2.0 vezerlo program
  2. Nyomogomb: PD2-es labra kotve
  3. Sharp IR szenzor: PC0-as (ADC0) labra kotve
  4. Szervo: PB3-as labra kotve
  5. */
  6. //---------------------------------------------------------------------
  7. #define F_CPU 1000000UL /* 1 MHz-es CPU orajel megadasa*/
  8. #define jobbra 16   // Szervo jobb szelso pozicio
  9. #define kozepre 23   // Szervo kozepso (Neutral) pozicio
  10. #define balra 31   // Szervo bal szelso pozicio
  11. #include <util/delay.h> // idozito, keslelteto rutinokat tart. fajl
  12. #include <avr/io.h> //AVR konstansokat, beallitasokat tart. fájl
  13. #include <util/motor.h> // motorvezerlo utasitasokat tart. fajl
  14.  
  15. volatile int SharpIR = 0;
  16. volatile int SharpIRjobb = 0;
  17. volatile int SharpIRbal = 0;
  18.  
  19. void Konfig10bitADC()        // ADC konfiguralas (beallitas)
  20. {
  21.  
  22.     ADMUX |= (1<<REFS0);    // Vcc mint referencia
  23.     ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // ADC engedelyezese, ADC eloosztas = 8 (125 KHz)
  24. }
  25.  
  26. unsigned int Beolvas10bitADC(unsigned char csatorna)
  27. {
  28.     ADMUX = (ADMUX & 0b11110000) | csatorna;   //ADC csatorna kivalasztasa
  29.     ADCSRA |= (1<<ADSC);    // elso ADC konverzio elinditasa
  30.     while (ADCSRA & (1<<ADSC));        // varas az atalakitasra
  31.     ADCSRA |= (1<<ADSC);          // masodik ADC konverzió elindítás
  32.     while (ADCSRA & (1<<ADSC));        // varas az atalakitasra
  33.     return (ADCL | (ADCH<<8));        // ADC ertek kiolvasasa
  34. }
  35.  
  36. void KonfigSzervo()        // Szervo konfiguralas (beallitas)
  37. {
  38.     DDRB = _BV(DDB3); // PORTB 3. lab kimenet (Szervo PWM)
  39.  
  40.     TCCR2 = _BV(WGM20)  // Timer2 8bites gyors PWM mod
  41.           | _BV(WGM21)  // Timer2 8bites gyors PWM mod
  42.           | _BV(COM21)  // nem-invertalt PWM
  43.           | _BV(CS22);     // Timer2 eloosztas: 1/64 (61 Hz-es PWM impulzus frekvencia)
  44.  
  45.     OCR2 = 23; // 1.5ms-os kezdeti PWM impulzus (Szervo kozepso (Neutral) pozicio)
  46. }
  47.  
  48. void Szervo(unsigned char pozicio)    // Szervo pozicionalo utasitas
  49. {
  50.     OCR2 = pozicio;
  51. }
  52.  
  53. int main (void)
  54. {
  55.     PORTD |= (1<<PD2);    // PD2-es lab bemenet, pull-up bekapcs (nyomogomb)
  56.     DDRC &= ~(1<<PC0);    // PC0-as lab bemenet (Sharp IR szenzor)
  57.     PORTC = 0x00;    // PORTC osszes laban a felhuzoellenallasok kikapcsolva
  58.  
  59.     KonfigSzervo();    // Szervo beallitas lefuttatasa
  60.    
  61.     Konfig10bitADC();    // ADC beallitas lefuttatasa
  62.  
  63.     while (PIND & (1<<PD2)); // várakozó cilkus amíg PD2 erteke nem 0 (amig a gomb nincs lenyomva)
  64.  
  65.     while (1)
  66.     {
  67.         elore(100); // teljes gozzel elore!
  68.         SharpIR = Beolvas10bitADC(0);
  69.         if ( SharpIR > 200 )  
  70.         {  
  71.             motor_stop(mind);
  72.             Szervo(balra);
  73.             _delay_ms(500);     // 0.5 s kesleltetes
  74.             SharpIRbal = Beolvas10bitADC(0);
  75.             _delay_ms(500);     // 0.5 s kesleltetes
  76.             Szervo(jobbra);
  77.             _delay_ms(500);     // 0.5 s kesleltetes
  78.             SharpIRjobb = Beolvas10bitADC(0);
  79.             _delay_ms(500);     // 0.5 s kesleltetes
  80.             Szervo(kozepre);
  81.             if ( SharpIRbal > SharpIRjobb)
  82.                 {
  83.                     fordul_jobb(100); // fordulas balra 0.5 s
  84.                     _delay_ms(500);
  85.                 }
  86.                 else
  87.                 {
  88.                     fordul_bal(100); //fordulas jobbra 0.5 s
  89.                     _delay_ms(500);
  90.                 }
  91.         }
  92.         else
  93.         {
  94.             _delay_ms(100);     // 0.1 s kesleltetes
  95.         }    
  96.            
  97.     }
  98. }

 


A cikk még nem ért véget, lapozz!
Következő: »»   8 / 9
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem