Cesarino
Cesarino è un robot che cerca la luce. Se non ne trova abbastanza continuerà a girare all'infinito, o almeno fino a che non finiscono le batterie. Il cuore e lo chassis di Cesarino è OttoBot. Anzi: sono proprio lo stesso robot con due sistemi di guida differenti. Per saperne di più sulla programmazione dell'ATmega8, usato per la logica di Cesarino, vi rimando alla pagina di OttoBot. In questa guida faremo come se si stesse usando un qualsiasi Arduino.
La prima versione, quasi funzionante
Componenti
Cesarino è stato assemblato con:
- Un ATmega8 con il bootloader di Arduino (potete usare qualsiasi Arduino-like)
- Un HC-SR04, sensore a ultrasuoni (per evitare gli ostacoli, su Ardubottino ne trovate uno simile)
- Due motori DC (con ruote)
- Una fotoresistenza
- Una resistenza da 1K
- Il ponte a H L298, lo stesso usato in Ardubottino al quale vi rimando per sapere come funziona
- Batterie: nel dettaglio una 9V per i motori e 4 AA per l'ATmega8 e il resto della logica.
- Uno chassis, stampato malamente in 3D!
La fotoresistenza, questa sconosciuta
In realtà non c'è molto da sapere. È una resistenza che cambia il suo valore a seconda di quanta luce riceve. Il rapporto luce/resistenza è inversamente proporzionale ovvero più luce riceve, meno resistenza oppone. Per contro, più luce riceve, più corrente lascia passare. La fotoresistenza ha 2 pin, uno va messo a +5V, l'altro in un'entrata analogica dell'Arduino. L'entrata analogica va poi messa a terra (usando un'opportuna resistenza) in modo da fare un divisore di voltaggio.
Il resto della roba, come funziona?
La trovate tutta su Ardubottino. L'unica differenza è che l'HC-SR04 non ha la possibilità di usare il trigger dell'ultrasuono e l'echo sullo stesso filo. Ha bisogno di due fili (questo significa che lo sketch di esempio dell'IDE di Arduino ha bisogno di essere modificato).
E ora il codice!
const int fw1 = 5; const int bk1 = 6; const int fw2 = 7; const int bk2 = 8; const int am1 = 9; const int am2 = 10; //motor pins, fw=forward, bk=back, am=enable const int lightSensor = A0; //pin for light sensor const int lightThreshold = 60; const int pingPin = 4; const int trigPin = 3 ; int changeDir = 0; void setup() { Serial.begin(19200); Serial.println("Ready"); pinMode(fw1,OUTPUT); pinMode(bk1,OUTPUT); pinMode(fw2,OUTPUT); pinMode(bk2,OUTPUT); pinMode(am1,OUTPUT); pinMode(am2,OUTPUT); pinMode(pingPin, INPUT); pinMode(trigPin, OUTPUT); } void motorAction(int fwm, int bkm,int anm,int motspeed) { //requires fd pin, bk pin, en pin and speed (PWM) if (motspeed > 0 ) { //going forward digitalWrite(fwm,HIGH); digitalWrite(bkm,LOW); } else if (motspeed < 0) { //reverse digitalWrite(fwm,LOW); digitalWrite(bkm,HIGH); } else { //stop digitalWrite(fwm,LOW); digitalWrite(bkm,LOW); } analogWrite(anm,abs(motspeed)); } void straight(int spd) { //all of these functions must be rewritten if motorAction(fw1,bk1,am1,spd); //a different kind of motors (stepper, servo..) motorAction(fw2,bk2,am2,spd); //are used } void right(int spd) { motorAction(fw1,bk1,am1,spd); motorAction(fw2,bk2,am2,0); } void left(int spd) { motorAction(fw1,bk1,am1,0); motorAction(fw2,bk2,am2,spd); } void halt() { motorAction(fw1,bk1,am1,0); motorAction(fw1,bk1,am2,0); } bool proximity(){ long duration; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(5); digitalWrite(trigPin, LOW); duration = pulseIn(pingPin, HIGH); if (duration/29/2 < 10) { //avoids obstacles 10 cm away return true; } else { return false; } } void loop(){ if (analogRead(lightSensor) < lightThreshold) { //if the light is not enough go FORWARD Serial.println("FORWARD"); //serial output for debugging reasons (plug the motors off and see how it works) straight(100); changeDir ++; if (changeDir > 1000) { //sometimes it changes direction; it's just for not letting the robot to follow right(150); //a straight line, anyway the path is quite predictable left(-150); delay(500); changeDir = 0; } } else { Serial.println("HALT"); //it found enough light, so it stays still halt(); } while(proximity()) { Serial.println("PROXIMITY"); //found an obstacle right(-150); left(150); } }
Non ho testato bene il codice. Si può fare di meglio ma non ho avuto molto tempo. Ci guarderò con calma nelle prossime settimane. In particolare non ho testato i delay (avevo usato delayMicroseconds al posto di delay, ma ho scoperto che accetta solo interi) e il sistema per far cambiare direzione è pratico ma brutale. Ad ogni modo Cesarino è andato in giro per la mia cucina, sbattendo qua e là e correndo come un pazzo, fino a che non si è messo sotto la finestra. Lì si è fermato.
Sst! Non disturbatelo!