Questo progetto mostra le potenzialità di Arduino. Esso è stato presentato come tesina d’esame al mio esame di maturità.
Materiali utilizzati
Elettronica:
- Arduino Mega (1x)
- Arduino Uno (1x)
- Onesheeld (1x)
- Arduino Motor Shield R3 (1x)
- Adafruit Motor Shield v2.3 (1x)
- Motoriduttore L149.12.90 (6x)
- Mozzo esagonale MR101-001.2 (6x)
- HS-422 Deluxe Standard Servo (4x)
- TowerPro SG90 Servo (2x)
- Batteria FullPower 11.1V 2200mAh (Silver Edition V2)
- Telecamera wireless con ricevitore AV esterno
- Sensore prossimità HC-SR04 (2x)
Struttura:
- Barre metallo 12x12mm, foro 10x10mm
- Lastre plexiglas spessore 2mm
- Stampe 3D (PLA) con la stampante Prusa i3
- Jumper e cavi
- Viteria varia
Realizzazione
Meccanica
Dal punto di vista della meccanica il rover è stato progettato affinché possa superare ostacoli proporzionali alla propria grandezza (5 centimetri se inclinazione ostacolo 100%) al fine di esplorare agevolmente su diversi tipi di terreno. Il corpo è rialzato e il sistema di sospensioni è il rocker bogie.
Il corpo del rover è stato pensato per essere semplice e rappresentare l’idea dell’ ‘’open source’’, Vi è infatti un telaio metallico atto a garantire rigidità, mentre la carrozzeria è trasparente in modo da dare la possibilità di osservare i componenti elettronici. Sul corpo è collegato con un piccolo asse il bilanciere che garantisce equilibrio al corpo in relazione all’inclinazione delle sospensioni.
Il sistema rocker bogie impone l’uso di un motore elettrico per ruota per garantire la trazione integrale poiché risulterebbe più dispendioso avere assi di trasmissione e differenziali distributori di coppia lungo i bracci del rocker bogie dunque per il movimento sono utilizzati 6 motori elettrici DC, in particolare Motoriduttore L149.12.90
Per lo sterzo è stata garantita la possibilità che il rover si muova agevolmente con raggio di sterzo tendente a zero; infatti sono stati utilizzati 4 servo motori HS-422 Deluxe Standard Servo che garantiscono lo sterzo alle 2 ruote anteriori ed alle 2 posteriori. Esse ruotando di circa 45 gradi ed utilizzando marcia inversa tra quelle di destra e quelle di sinistra garantiscono uno sterzo circolare, con il corpo che rimane al centro della circonferenza descritta dalle 4 ruote ai vertici. Tutto il sistema è controllato elettronicamente dal processore dell’Arduino Mega il quale consente inoltre di regolare la traiettoria del mezzo in marcia.
Le ruote hanno un battistrada di 55 millimetri, tale larghezza offre ampia superficie di appoggio ed evita affondamenti su suoli sabbiosi poiché distribuisce il peso esercitando meno pressione su un singolo punto (Pressione = F/S), inoltre sono dotate di sistema di smaltimento di materiale sabbioso (materiale largamente presente sul suolo del pianeta rosso), favorito dalla conformazione elicoidale dei raggi delle ruote la quale tende a far defluire il materiale depositato nella ruota sempre nello stesso senso, ciò comporta la fuoriuscita del materiale sabbioso dai fori sopracitati.
La testa del rover garantisce la possibilità di visualizzare il territorio con invio di immagini e visualizzazione video da monitor in tempo reale di ciò che si presenta intorno al rover nelle sue esplorazioni. La testa è costituita da due alloggiamenti che garantiscono due gradi di libertà, nel primo vi è collocato il servo motore che garantisce il movimento della telecamera trasversale al terreno, nel secondo è collocata la telecamera. I due gradi di libertà sono garantiti da due servo motori TowerPro SG90 Servo, uno posto al di sotto della superficie del corpo centrale, l’altro posto su una delle due parti che compongono la testa vera e propria.
Informatica ed elettronica
Il modello presentato monta tecnologie ispirate a quelle realmente montate sui rover:
- Telecamera wireless con ricevitore AV esterno, ad emulazione della Pancam. Il movimento della camera è affidato a due microservo, i quali consentono una visione a 360° dell’ambiente circostante. La telecamera trasmette in tempo reale.
- Sensori di prossimità (HB-SR04) (2x) nella parte anteriore ad emulazione dell’Hazcam anteriore. Il funzionamento di tali sensori è però differente: sfruttano gli ultrasuoni per poter rilevare gli ostacoli. Sono stati inseriti per sviluppare un primitivo sistema di autoguida (WIP).
- Servomotori (4x) ad emulazione del sistema di sterzata.
- Motoriduttori (6x) per consentire il movimento.
I due modelli di Arduino impiegati sono connessi tramite protocollo I2C con un rapporto di master (Mega) e slave (Uno). L’I2C è un protocollo che mette in comunicazione le due schede di programmazione mediante 3 jumper (cavi): un ground (GND) comune, il pin A4 (SDA) di Uno con il pin SDA di Mega ed il pin A5 (SCL) di Uno con il pin SCL di Mega. Il pin SDA (Serial DAta) serve a scambiare dati tra le due schede, mentre il pin SCL (Serial CLock) per sincronizzarne i clock. Funziona tramite la libreria Wire.h tramite comandi quali “read()” e “write()” e riesce a trasmettere e ricevere fino ad 8 bit a pacchetto (128 diverse combinazioni di numeri). Tale connessione è risultata necessaria per via dell’esigenza di controllare 6 motori in modo indipendente, ma non esiste alcuna motor shield in grado di gestirne tanti.
I comandi di input vengono invece impartiti al master attraverso il Onesheeld, uno shield bluetooth in grado di comunicare con il proprio smartphone attraverso l’apposita app. Di tale app viene sfruttata la scheda “gamepad”, attraverso la quale vengono impartiti gli ordini ai servomotori e ai motoriduttori.
Codice
E’ possibile scaricare i programmi del progetto direttamente dalla mia cartella Onedrive:
//Sviluppa if(2 pulsanti premuti) > switch tra autopilot e comandi /* Up; #7 Motori Right; #6 Down; #5 Left; #4 Yellow; #10 Camera Red; #9 Green; #8 Blue; #2 ????; #1 Stop; #0 */ #define CUSTOM_SETTINGS #define INCLUDE_GAMEPAD_SHIELD #include <Wire.h> #include <Servo.h> #include <OneSheeld.h> Servo servoAntSx; Servo servoAntDx; Servo servoPostSx; Servo servoPostDx; int pwmA = 3; int dirA = 12; int pwmB = 11; int dirB = 13; byte x; void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); pinMode(10, INPUT); pinMode(9, INPUT); pinMode(8, INPUT); pinMode(7, INPUT); pinMode(6, INPUT); pinMode(5, INPUT); pinMode(4, INPUT); pinMode(2, INPUT); pinMode(pwmA, OUTPUT); pinMode(dirA, OUTPUT); pinMode(pwmB, OUTPUT); pinMode(dirB, OUTPUT); servoAntSx.attach(23); servoAntDx.attach(25); servoPostSx.attach(27); servoPostDx.attach(29); servoAntSx.write(90); servoAntDx.write(90); servoPostSx.write(90); servoPostDx.write(90); delay(200); } void loop() { //MOTORI if (digitalRead(4)) // Left { left(); } else if (digitalRead(6)) // Right { right(); } else if (digitalRead(7)) // Up { up(); } else if (digitalRead(5)) // Down { down(); } // CAMERA else if (digitalRead(9)) // Red (Right) { x = 9; } else if (digitalRead(2)) // Blue (Left) { x = 2; } else if (digitalRead(8)) // Green(down) { x = 8; } else if (digitalRead(10)) // Yellow(up) { x = 10; } else { stopMotor(); } Wire.beginTransmission(4); // transmit to device #4 Wire.write(x); // sends one byte Wire.endTransmission(); // stop transmitting Serial.println(x); delay(500); } //VOID SINGOLI //MOTORI void left() { x = 4; servoAntSx.write(45); servoAntDx.write(135); servoPostSx.write(135); servoPostDx.write(45); digitalWrite(dirA, HIGH); analogWrite(pwmA, 1023); digitalWrite(dirB, HIGH); analogWrite(pwmB, 1023); } void right() { x = 6; servoAntSx.write(45); servoAntDx.write(135); servoPostSx.write(135); servoPostDx.write(45); digitalWrite(dirA, LOW); analogWrite(pwmA, 1023); digitalWrite(dirB, LOW); analogWrite(pwmB, 1023); } void up() { x = 7; servoAntSx.write(90); servoAntDx.write(90); servoPostSx.write(90); servoPostDx.write(90); digitalWrite(dirA, HIGH); analogWrite(pwmA, 1023); digitalWrite(dirB, LOW); analogWrite(pwmB, 1023); } void down() { x = 5; servoAntSx.write(90); servoAntDx.write(90); servoPostSx.write(90); servoPostDx.write(90); digitalWrite(dirA, LOW); analogWrite(pwmA, 1023); digitalWrite(dirB, HIGH); analogWrite(pwmB, 1023); } void stopMotor() { x = 0; // Stop servoAntSx.write(90); servoAntDx.write(90); servoPostSx.write(90); servoPostDx.write(90); digitalWrite(dirA, HIGH); analogWrite(pwmA, 0); digitalWrite(dirB, HIGH); analogWrite(pwmB, 0); }
//SLAVE #include <Wire.h> #include <Servo.h> #include <Adafruit_MotorShield.h> #include "utility/Adafruit_PWMServoDriver.h" Adafruit_MotorShield AFMS = Adafruit_MotorShield(); Adafruit_DCMotor *M1 = AFMS.getMotor(1); Adafruit_DCMotor *M2 = AFMS.getMotor(2); Adafruit_DCMotor *M3 = AFMS.getMotor(3); Adafruit_DCMotor *M4 = AFMS.getMotor(4); Servo servoUp; //attacca al pin 9 Servo servoDown; //attacca al pin 10 int asseX = 90; int asseY = 90; int x; int timer = 1; int spaziatura = 5; void setup() { AFMS.begin(); M1->setSpeed(1023); M1->run(RELEASE); M2->setSpeed(1023); M2->run(RELEASE); M3->setSpeed(1023); M3->run(RELEASE); M4->setSpeed(1023); M4->run(RELEASE); servoUp.attach(3); servoDown.attach(2); servoUp.write(asseY); servoDown.write(asseX); Wire.begin(4); // join i2c bus with address #8 Wire.onReceive(receiveEvent); // register event Serial.begin(9600); } void receiveEvent(int howMany) { while (0 < Wire.available()) { x = Wire.read(); // receive byte as an integer } } void loop() { if (x == 4) //Left { left(); } else if (x == 6) //Right { right(); } else if (x == 7) //Up { up(); } else if (x == 5) //Down { down(); } else if (x == 9) // Red (Right) { red(); } else if (x == 2) // Blue (Left) { blue(); } else if (x == 8) // Green(down) { green(); } else if (x == 10) // Yellow(up) { yellow(); } else if (x == 0) //Stop { servoUp.write(asseY); servoDown.write(asseX); stopMotor(); } Serial.println(x); delay(500); } //VOID SINGOLI //MOTORI void left() { M1->run(FORWARD); M2->run(BACKWARD); M3->run(FORWARD); M4->run(BACKWARD); delay(50); } void right() { M1->run(BACKWARD); M2->run(FORWARD); M3->run(BACKWARD); M4->run(FORWARD); delay(50); } void up() { M1->run(BACKWARD); M2->run(BACKWARD); M3->run(FORWARD); M4->run(FORWARD); delay(50); } void down() { M1->run(FORWARD); M2->run(FORWARD); M3->run(BACKWARD); M4->run(BACKWARD); delay(50); } void stopMotor() { M1->run(RELEASE); M2->run(RELEASE); M3->run(RELEASE); M4->run(RELEASE); delay(50); } //CAMERA void red() { if (asseX > 0); { asseX = asseX + spaziatura; servoDown.write(asseX); delay(100); } } void blue() { if (asseX < 180); { asseX = asseX - spaziatura; servoDown.write(asseX); delay(100); } } void green() { if (asseY > 0); { asseY = asseY + spaziatura; servoUp.write(asseY); delay(100); } } void yellow() { if (asseY > 0); { asseY = asseY - spaziatura; servoUp.write(asseY); delay(100); } } void stopCam() { servoUp.write(asseY); //Stopcam servoDown.write(asseX); delay(100); } /*void frontCamera() { servoUp.write(45); servoDown.write(90); delay(100); }*/
Questo è il progetto ultimato e funzionante in un video dimostrativo. I sensori di prossimità verranno implementati con successivi aggiornamenti per lo sviluppo del sistema di autoguida.
Ciao!
un progetto molto interessante, con notevoli potenzialità di sviluppo.
purtroppo in questo momento non si vede il video, appena avrai sistemato non vdo l’ora di poterlo vedere in azione!
solo una domanda, non vedo l’iniziallizzazione della OneSheeld nel codice tramite creazione dell’oggetto (OneSheeld.begin();), forse una dimenticanza?
complimenti e non vedo l’ora di vedere ulteriori sviluppi del tuo rover!
Ciao teohell!
Il video io lo vedo perfettamente, credo che sia un problema di WordPress, e non credo di poterci fare molto. Provo a linkarti il video dalla cartella media del blog sperando riesca a vederlo: http://www.robotstore.it/blog/wp-content/uploads/2016/07/Video-dimostrativo.mp4
Per quanto riguarda l’inizializzazione si, è una dimenticanza, ma per fortuna il programma ha girato ugualmente senza problemi il giorno dell’esame 🙂
Ciao, se ci invii il file via email ho ci dai un link esterno proviamo a reinserirlo noi
Eccomi! Il video linkato lo vedo, ma nel post mi dà ancora “error loading this resource”… decisamente un problema di wordpress, speriamo l’admin riesca a risolverlo
Per quel che riguarda l’inizializzazione della OneSheeld è curioso che la board funzioni comunque… probabilmente l’inizializzaizone serve per gestire le comunicazioni arduino->smartphone mentre in modalità gamepad con comunicazione smartphone->arduino, non c’è bisogno di inizializzazione… indagherò 😉
Sarebbe bello vedere un video dove magari gli fai salire qualche scalino o superare qualche ostacolo, il sistema di sospensioni dovrebbe permetterlo e dovrebbe essere anche alquanto “cool” 😀
Il movimento della telecamera mi pare un pò “legnoso”, ma giustamente deriva dal movimento proprio dei servomotori. Per ovviare, io di solito uso un ciclo dove incremento la posizione del servo di pochi gradi alla volta, intervallati da un delay, fino ad arrivare alla posizione finale desiderata. Ad esempio per l’asse x avremmo:
void red()
{
if (asseX > 0);
{
while (asseX < (asseX + spaziatura))
{
asseX += spaziatura/10;
servoDown.write(asseX);
delay(10);
}
delay(100);
}
}
questo "spacchetta" il movimento in 10 micromovimenti che rendono il tutto più fluido. Giocando con il numero di micromovimenti e il delay tra uno e l'altro, si può tarare in modo che sembri visivamente accattivante.
Una domanda invece, le immagini della telecamera a cosa/dove vengono inviate? Devi ancora implementare il modulo A/V o hai già pronto qualcosa?
Un'ultima cosa sugli HC-SR04, secondo me dovresti trovargli un'altra collocazione, perchè il loro cono d'azione guardando il video mi pare ostacolato lateralmente dai montanti, e inoltre non arriva a inquadrare il terreno di fronte al rover, se per esempio volessi fargli evitare un crepaccio o una scarpata. Io li collocherei più in basso e leggermente più in fuori, magari inclinandoli leggermente anche verso il basso.
Com'è andato l'esame alla fine? 🙂 sicuramente bene, il progetto è veramente molto ma molto bello!
Fammi sapere se trovi qualcosa in merito all’inizializzazione che sono interessato e purtroppo non ho molto tempo da dedicargli al momento.
Per quanto riguarda il superamento degli ostacoli al momento il rover è stato smontato e verrà riassemblato a settembre per la partecipazione ad un concorso. Inoltre, purtroppo, la stampante 3D impiegata mi è stata messa a disposizione dal mio professore, ma la qualità di stampa è piuttosto scarsa, pertanto i pezzi risultano essere fragili.
Il movimento legnoso è dato dalla comunicazione I2C che, essendo temporizzata, implica quel movimento legnoso. Proverò a settembre ad implementare il tuo consiglio sperando che la situazione migliori.
La telecamera invece ha un suo ricevitore wireless AV esterno ed indipendente (se avessi avuto una scheda wireless in grado di riprodurre in tempo reale il video non avrei usato Onesheel per il comando a distanza, ma purtroppo costano ehehehe)
I sensori di prossimità sono abbastanza provvisori, ma sono stati posizionati in seguito a rilevazione da parte dei sensori stessi in modo tale che non rilevino i montanti 🙂 Per il basso pensavo di montarne un terzo a faccia in giù, in modo da poter rilevare i dislivelli e calcolarne l’altezza.
L’esame orale è andato benone, un po’ meno gli scritti ma nel complesso non mi lamento, poteva andare peggio ahahaha
Ciao a tutti,
abbiamo riconvertito il file video e ora dovrebbe funzionare correttamente 😉