Differenze tra le versioni di "Ardubottino"
Riga 41: | Riga 41: | ||
long duration; | long duration; | ||
long dursx; | long dursx; | ||
− | long durdx; | + | long durdx; |
− | const int | + | const int en1 = 11; //pin enable |
− | const int m1fd = 4; | + | const int en2 = 9; |
− | const int | + | const int m1fd = 4; //controlli motore |
− | const int | + | const int m2fd = 7; |
− | const int m2bk = | + | const int m1bk = 5; |
− | const int pinping = 13; | + | const int m2bk = 6; |
− | const int distanza = 500; | + | const int pinping = 13; //pin sensore distanza |
+ | const int sterzo = 600; //durata dello sterzo | ||
+ | const int distanza = 500; //distanza minima ostacoli | ||
+ | int motore1 = 67;//pwm motore dx | ||
+ | int motore2 = 74;//pwm motore sx | ||
void setup() { | void setup() { | ||
Riga 55: | Riga 59: | ||
pinMode(m2fd, OUTPUT); | pinMode(m2fd, OUTPUT); | ||
pinMode(m2bk, OUTPUT); | pinMode(m2bk, OUTPUT); | ||
+ | pinMode(en1, OUTPUT); | ||
+ | pinMode(en2, OUTPUT); | ||
+ | analogWrite(en1,motore1); | ||
+ | analogWrite(en2,motore2); | ||
dritto(); | dritto(); | ||
} | } | ||
void loop() { | void loop() { | ||
− | if (echo() < distanza){ | + | if (echo() < distanza){ //trovato un ostacolo |
− | + | analogWrite(en1,170); | |
− | + | analogWrite(en2,170); | |
− | + | ferma(); | |
− | + | sinistra(); | |
− | + | delay(sterzo); | |
− | + | ferma(); | |
− | + | dursx = echo(); //guarda a sinistra | |
− | + | destra(); | |
− | + | delay(sterzo*2); | |
− | + | ferma(); | |
− | + | durdx = echo(); //guarda a destra | |
− | + | if (dursx < distanza && durdx < distanza){ | |
− | + | destra(); | |
− | + | delay(sterzo); | |
− | + | } else if (dursx > durdx) { | |
+ | sinistra(); | ||
+ | delay(sterzo*2); | ||
+ | } //sceglie dove c'è più spazio | ||
+ | dritto(); | ||
+ | analogWrite(en1,motore1); | ||
+ | analogWrite(en2,motore2); | ||
} | } | ||
} | } | ||
void dritto() { | void dritto() { | ||
− | |||
− | |||
digitalWrite(m1bk,LOW); | digitalWrite(m1bk,LOW); | ||
digitalWrite(m2bk,LOW); | digitalWrite(m2bk,LOW); | ||
+ | digitalWrite(m2fd,HIGH); | ||
+ | digitalWrite(m1fd,HIGH); | ||
+ | } | ||
+ | |||
+ | void rovescia() { | ||
+ | digitalWrite(m1fd,LOW); | ||
+ | digitalWrite(m2fd,LOW); | ||
+ | digitalWrite(m1bk,HIGH); | ||
+ | digitalWrite(m2bk,HIGH); | ||
} | } | ||
Riga 104: | Riga 125: | ||
digitalWrite(m1bk,LOW); | digitalWrite(m1bk,LOW); | ||
digitalWrite(m2bk,LOW); | digitalWrite(m2bk,LOW); | ||
− | delay( | + | delay(50); |
} | } | ||
Versione delle 04:37, 1 feb 2014
Ardubottino è stato creato soprattutto per testare tre componenti: l'Arduino, il sensore della distanza a ultrasuoni e il ponte ad H. Lo chassis e i motori sono Tamiya.
Componenti
Ardubottino ha questi componenti:
- Arduino UNO [1]
- Sensore di distanza a ultrasuoni SRF05 [2]
- Il board con montato il ponte ad H L298 [3]
- Kit Tamiya per lo chassis e i motori
- Batteria da 9v
Il sensore di distanza è sprovvisto di pin, occorre quindi saldarne una strip prima di procedere.
Il sensore di distanza a ultrasuoni SRF05
È piuttosto semplice da usare. Seguendo le istruzioni [ http://www.robot-electronics.co.uk/htm/srf05tech.htm trovate qui] si può notare che ha due modalità di comunicazioni, date dal pin Mode. Se questo pin è collegato alla 0v il sensore userà un solo pin per la comunicazione dei dati dell'eco (Echo) e la ricezione dei comandi (Trigger), se, al contrario, non è connesso a niente allora saranno usati due pin diversi. Nel caso dell'Ardubottino ho preferito usare la prima modalità, quella con un pin solo (soprattutto per pigrizia: perché è già così lo sketch di esempio "ping" nella libreria di Arduino!). Oltre al pin Mode e al pin Trigger/Echo occorre collegare il primo e l'ultimo pin rispettivamente a +5v e a terra. Nella foto si può vedere, da sinistra: +5v, non usato, Trigger/Echo (collegato al pin 13 di Arduino), Mode (terra), Terra (terra).
Il board ponte ad H L298
Il ponte ad H L298 è utilissimo per manovrare due motori indipendenti. Può essere usato anche per muovere un motore passo-passo. Ha due ingressi per la corrente: tramite un ponticello può essere separata fra corrente per la logica e corrente per i motori. La logica dev'essere alimentata da +5v; se l'alimentazione è separata, i motori possono ricevere fino a +12v. Per comodità (e anche dopo diversi goffi tentativi per capire come funzionava) ho preferito alimentare i motori solo con i 5v.
Sui lati ci sono le connessioni per i motori mentre, a fianco dell'alimentazione, ci sono i pin che servono per comandarli. I pin sono sei, due sono gli enable per i motori e quattro servono per dare la direzione, due per motore. I pin dell'enable si possono chiudere con dei ponticelli, comandarli da Arduino/Raspberry Pi oppure gli si può mandare un impulso PWM per regolare la velocità.
Motori ad encoder, gioie (poche) e dolorer (tanto)
Il problema di Ardubottino è che non va dritto. Il motivo? Forse il ponte ad H non dà gli stessi voltaggi ai motori, forse i motori sono un po' diversi, forse si stanno usurando in modo diverso, forse i cingoli hanno qualche imperfezione, forse le ruote sono storte, forse è sbilanciato. Ad ogni modo ognuno di questi problemi (tranne le ruote storte e le imperfezioni dei cingoli) si sarebbero risolti scoprendo a che velocità vanno i motori. Per scoprire questo dato sono necessari gli encoder. Un encoder è una rotellina con dei fori e un sensore o due, composti da un LED e da un ricevitore a infrarossi, che sentono quando un foro è passato. Encoder di questo tipo si trovano ad esempio nelle rotelline dei mouse o in quelli che hanno ancora la pallina.
Ora: questi sarebbero degli encoder "fatti apposta" per il kit Tamiya. Uso il condizionale perché, se non sono stato io ad averli montati in modo approssimativo, il loro utilizzo è alquanto scomodo. Anzitutto la rotella non sta fissa sull'albero. Il foro esagonale è troppo grande e ha un notevole gioco. Il range del sensore è minimo e non tiene conto della struttura del kit Tamiya (la rotella va quasi a sfregare contro le viti che lo fissano allo chassis). Inoltre sono estremamente fragili: una delle rotelle si è spaccata subito in due. I sensori stessi, poi, non si incastrano nella sede e occorre incollarli. La lettura degli encoder andrebbe fatta sfruttando gli interrupt di Arduino. Gli interrupt sono dei pin che restano in ascolto e fanno scattare degli eventi quando cambiano valore[4]. Purtroppo uno dei due pin (sull'Arduino Uno sono il pin 2 e il pin 3) dava dei risultati estremamente inaffidabili. Dopo varie prove, il risultato migliore l'ho ottenuto usando la libreria Encoder [5] su due pin non di interrupt. Il risultato di tutta questa fatica è un robottino che grosso modo va dritto. Un risultato mediocre di molto inferiore alla calibrazione a occhio. Alla fine, infatti, ho preferito quest'ultima.
Lo sketch
Lo sketch deriva per una parte dall'esempio Ping già presente nella libreria di Arduino. In pratica fa avanzare Ardubottino fino a che non incontra un ostacolo. Se lo incontra sterza in un senso e poi nell'altro e alla fine prosegue per la direzione dove ha trovato più campo libero. 4 7 6 5 sono i pin a cui ho collegato il ponte ad H. Sterzo è il tempo che deve impiegare per sterzare. pinping è il pin a cui è attaccato il trigger/echo del sensore a ultrasuoni.
long duration; long dursx; long durdx; const int en1 = 11; //pin enable const int en2 = 9; const int m1fd = 4; //controlli motore const int m2fd = 7; const int m1bk = 5; const int m2bk = 6; const int pinping = 13; //pin sensore distanza const int sterzo = 600; //durata dello sterzo const int distanza = 500; //distanza minima ostacoli int motore1 = 67;//pwm motore dx int motore2 = 74;//pwm motore sx void setup() { pinMode(m1fd, OUTPUT); pinMode(m1bk, OUTPUT); pinMode(m2fd, OUTPUT); pinMode(m2bk, OUTPUT); pinMode(en1, OUTPUT); pinMode(en2, OUTPUT); analogWrite(en1,motore1); analogWrite(en2,motore2); dritto(); } void loop() { if (echo() < distanza){ //trovato un ostacolo analogWrite(en1,170); analogWrite(en2,170); ferma(); sinistra(); delay(sterzo); ferma(); dursx = echo(); //guarda a sinistra destra(); delay(sterzo*2); ferma(); durdx = echo(); //guarda a destra if (dursx < distanza && durdx < distanza){ destra(); delay(sterzo); } else if (dursx > durdx) { sinistra(); delay(sterzo*2); } //sceglie dove c'è più spazio dritto(); analogWrite(en1,motore1); analogWrite(en2,motore2); } } void dritto() { digitalWrite(m1bk,LOW); digitalWrite(m2bk,LOW); digitalWrite(m2fd,HIGH); digitalWrite(m1fd,HIGH); } void rovescia() { digitalWrite(m1fd,LOW); digitalWrite(m2fd,LOW); digitalWrite(m1bk,HIGH); digitalWrite(m2bk,HIGH); } void destra() { digitalWrite(m1fd,LOW); digitalWrite(m2fd,HIGH); digitalWrite(m1bk,HIGH); digitalWrite(m2bk,LOW); } void sinistra() { digitalWrite(m1fd,HIGH); digitalWrite(m2fd,LOW); digitalWrite(m1bk,LOW); digitalWrite(m2bk,HIGH); } void ferma() { digitalWrite(m1fd,LOW); digitalWrite(m2fd,LOW); digitalWrite(m1bk,LOW); digitalWrite(m2bk,LOW); delay(50); } long echo() { pinMode(pinping, OUTPUT); digitalWrite(pinping, LOW); delayMicroseconds(2); digitalWrite(pinping, HIGH); delayMicroseconds(5); digitalWrite(pinping, LOW); pinMode(pinping, INPUT); duration = pulseIn(pinping,HIGH); return duration; }