In questo terzo articolo dedicato all’albero robot realizzato da Carlo leggerai come sono fatti gli sketch usati per i singoli microcontrollori.
Negli articoli precedenti hai letto come Carlo ha realizzato sia la parte di assemblaggio meccanico sia la parte elettronica, ora esploriamo gli sketch.
Sketch dell’albero robot
Gli sketch sono 3 come i micro controllori presenti nel progetto ciascuno commentato direttamente nello sketch dall’autore.
Non ho voluto modificare gli sketch di Carlo per rispetto del progetto, ho solo rimosso i blocchi non utilizzati per ridurre la quantità di righe da leggere e non appesantire arduino confondendoti le idee.
Il primo sketch proposto è da caricare sull’arduino/genuino installato sul primo ripiano dell’albero robot
ed ha come scopo il controllo dei motori e dei sensori in modo che l’albero robot possa andare in giro senza urtare contro mobili od altro:
/* *************************************************************** */ /* CHRISTMAS TREE BOT */ // Firenze, 17 dicembre 2015 /* Realizzazione di un albero di Natale robotico */ /* a cura di Carlo Villoresi */ /* *************************************************************** */ //SEZIONE SENSORI (TIPO AD ULTRASUONI SRF04) /* Definizione delle costanti per i sensori e attribuzione pin Arduino */ // Sensore centrale #define ECHOPIN_CENTRALE 2 // ECHOPIN riceve l' impulso ad ultrasuoni #define TRIGPIN_CENTRALE 4 // TRIGPIN emette l' impulso ad ultrasuoni // Sensore di sinistra #define ECHOPIN_SINISTRA 3 // come sopra #define TRIGPIN_SINISTRA 5 // come sopra //Sensore di destra #define ECHOPIN_DESTRA 6 // come sopra #define TRIGPIN_DESTRA 7 // come sopra // Sensore posteriore #define ECHOPIN_POSTERIORE 14 // il pin 14 equivale al pin A0 #define TRIGPIN_POSTERIORE 15 // il pin 15 equivale al pin A1 // Dichiaro le variabili di tipo int che conterranno i valori delle varie letture (4) dei sensori int lettura_centrale = 0; // lettura del sensore centrale int lettura_sinistra = 0; // lettura del sensore di sinistra int lettura_destra = 0; // lettura del sensore di destra int lettura_posteriore = 0; // lettura del sensore posteriore // DICHIARAZIONE VARIABILI DINAMICHE PER SENSORI E MOVIMENTO int letture_sensori[4]; // Dichiaro un array di lettura ( deve contenere 4 elementi in tutto) per le letture dei sensori int presenza_ostacolo = 0; // Dichiaro una variabile di tipo int per segnalare la presenza di un ostacolo (on/off) oppure (0/1) int i; // Dichiaro una variabile di tipo int come contatore // FINE DICHIARAZIONE VARIABILI DINAMICHE PER SENSORI E MOVIMENTO /* SEZIONE MOTORIDUTTORI */ //Inizializzazione parametri motori //motore A int motorPinDirA = 8; // pin polarità motore A int motorPinDirB = 11; // pin polarità motore A int motorPinA = 9; // pin velocità motore A //motore B int motorPinDirC = 12; // pin polarità motore B int motorPinDirD = 13; // pin polarità motore B int motorPinB = 10; // pin velocità motore B // FINE SEZIONE MOTORIDUTTORI void setup() { /* SEZIONE SENSORI */ /* associo ai vari pin la modalità I/0 */ pinMode(ECHOPIN_CENTRALE, INPUT); // Associo al pin ECHOPIN_CENTRALE la modalità INPUT) pinMode(TRIGPIN_CENTRALE, OUTPUT); // Associo al pin ECHOPIN_CENTRALE la modalità OUTPUT) pinMode(ECHOPIN_SINISTRA, INPUT); // Associo al pin ECHOPIN_SINISTRA la modalità INPUT) pinMode(TRIGPIN_SINISTRA, OUTPUT); // Associo al pin ECHOPIN_SINISTRA la modalità OUTPUT) pinMode(ECHOPIN_DESTRA, INPUT); // Associo al pin ECHOPIN_DESTRA la modalità INPUT) pinMode(TRIGPIN_DESTRA, OUTPUT); // Associo al pin ECHOPIN_DESTRA la modalità OUTPUT) pinMode(ECHOPIN_POSTERIORE, INPUT); // Associo al pin ECHOPIN_POSTERIORE la modalità INPUT) pinMode(TRIGPIN_POSTERIORE, OUTPUT); // Associo al pin ECHOPIN_POSTERIORE la modalità OUTPUT) /* FINE SEZIONE SENSORI */ /* SEZIONE MOTORI */ //Inizializzazione pin motori // Motore A pinMode(motorPinDirA, OUTPUT); pinMode(motorPinDirB, OUTPUT); pinMode(motorPinA, OUTPUT); // Motore B pinMode(motorPinDirC, OUTPUT); pinMode(motorPinDirD, OUTPUT); pinMode(motorPinB, OUTPUT); // Fine inizializzazione pin motori //Inizializzazione pin velocità dei motori // Motore A analogWrite(motorPinA, 255); // Motore B analogWrite(motorPinB, 255); // Fine inizializzazione pin velocità motori /* velocità tramissione dati della seriale */ Serial.begin(9600); } #define isdigit(n) (n >= '0' && n <= '9') // La funzione isdigit() verifica se il char in parentesi è un numero; in quel caso restituisce TRUE void loop() { /* LETTURA SENSORI SRF04 */ // Lettura sensore centrale digitalWrite(TRIGPIN_CENTRALE, LOW); // Setta il pin trigger a low per 2uS delayMicroseconds(2); digitalWrite(TRIGPIN_CENTRALE, HIGH); // Spedisce al trigger un livello higs per 10uS delayMicroseconds(10); digitalWrite(TRIGPIN_CENTRALE, LOW); // Setta il pin a low nuovamente int lettura_centrale = pulseIn(ECHOPIN_CENTRALE, HIGH);// Legge gli intervalli di impulso lettura_centrale= lettura_centrale/58; // Calcola la distanza fra due impulsi Serial.print("sensore centrale: "); Serial.println(lettura_centrale); delay(500); // Lettura sensore sinistra digitalWrite(TRIGPIN_SINISTRA, LOW); delayMicroseconds(2); digitalWrite(TRIGPIN_SINISTRA, HIGH); delayMicroseconds(10); digitalWrite(TRIGPIN_SINISTRA, LOW); int lettura_sinistra = pulseIn(ECHOPIN_SINISTRA, HIGH); lettura_sinistra= lettura_sinistra/58; Serial.print("sensore sinistra: "); Serial.println(lettura_sinistra); delay(500); // Lettura sensore destra digitalWrite(TRIGPIN_DESTRA, LOW); delayMicroseconds(2); digitalWrite(TRIGPIN_DESTRA, HIGH); delayMicroseconds(10); digitalWrite(TRIGPIN_DESTRA, LOW); int lettura_destra = pulseIn(ECHOPIN_DESTRA, HIGH); lettura_destra = lettura_destra/58; Serial.print("sensore destra: "); Serial.println(lettura_destra); delay(500); // Lettura sensore posteriore digitalWrite(TRIGPIN_POSTERIORE, LOW); delayMicroseconds(2); digitalWrite(TRIGPIN_POSTERIORE, HIGH); delayMicroseconds(10); digitalWrite(TRIGPIN_POSTERIORE, LOW); int lettura_posteriore = pulseIn(ECHOPIN_POSTERIORE, HIGH); lettura_posteriore= lettura_posteriore/58; Serial.print("sensore posteriore: "); Serial.println(lettura_posteriore); delay(500); // FINE LETTURA SENSORI SRF04 */ // SEZIONE UTILIZZO DELLE LETTURE SENSORI PER FAR MUOVERE IL ROBOT */ // immagazzinamento letture sensori in un array letture_sensori[0] = lettura_centrale; letture_sensori[1] = lettura_sinistra; letture_sensori[2] = lettura_destra; letture_sensori[3] = lettura_posteriore; //Lettura dell' array da seriale. I valori letti corrispondono alle distanze rilevate dai sensori ( scommentare se si vuole analizzare tali letture ) /*for (i = 0; i < 4; i = i + 1) { Serial.print("sensore: "); Serial.print(i); Serial.print(" "); Serial.println(letture_sensori[i]); Serial.print(" "); delay(500); }*/ Serial.print(" "); // stampa una riga vuota Serial.print(" "); // stampa una riga vuota Serial.print(" "); // stampa una riga vuota //azione dei motori in presenza di ostacoli presenza_ostacolo = checkDistance(letture_sensori); // La funzione checkDistance restituisce un valore (0 oppure 1) a seconda della presenza di un ostacolo motori(presenza_ostacolo); // La funzione presenza_ostacolo() determina il moto del robot agendo sul comportamento dei motori Serial.print(presenza_ostacolo); // In seriale viene letta il valore della funzione checkDistance() Serial.print(" "); // stampa una riga vuota } void motori(int presenza_ostacolo) { if(presenza_ostacolo == 1) { Stop(); delay(2000); // l' intervallo di tempo viene impostato in conseguenza della scelta precedente di commentare la 'Scelta del brano musicale' come intervallo di arresto del robot // azione motore successiva Indietro(); // viene eseguita la funzione Indietro() delay(6000); Sinistra();// azione motore successiva delay(3000); } else if(presenza_ostacolo == 0) { Avanti(); // azione motore } } // comanda il movimento dei motori in avanti void Avanti() { //impostazione direzione di rotazione motore A digitalWrite(motorPinDirA, HIGH); // associo un valore HIGH al pin motorPinDirA digitalWrite(motorPinDirB,LOW ); // associo un valore LOW al pin motorPinDirB //impostazione direzione di rotazione motore B digitalWrite(motorPinDirC, LOW); // associo un valore LOW al pin motorPinDirC digitalWrite(motorPinDirD, HIGH); // associo un valore HIGH al pin motorPinDirD } // comanda il movimento dei motori indietro void Indietro() { //motore A digitalWrite(motorPinDirA, LOW); // associo un valore LOW al pin motorPinDirA digitalWrite(motorPinDirB,HIGH ); // associo un valore HIGH al pin motorPinDirB //motore B digitalWrite(motorPinDirC, HIGH); // associo un valore HIGH al pin motorPinDirC digitalWrite(motorPinDirD, LOW); // associo un valore LOW al pin motorPinDirD } // comanda il movimento dei motori a sinistra void Sinistra() { //motore A digitalWrite(motorPinDirA, HIGH); // associo un valore HIGH al pin motorPinDirA digitalWrite(motorPinDirB,LOW ); // associo un valore LOW al pin motorPinDirB //motore B digitalWrite(motorPinDirC, HIGH); // associo un valore HIGH al pin motorPinDirC digitalWrite(motorPinDirD, LOW); // associo un valore LOW al pin motorPinDirD } // comanda il movimento dei motori a destra void Destra() { //motore A digitalWrite(motorPinDirA, LOW); // associo un valore LOW al pin motorPinDirA digitalWrite(motorPinDirB,HIGH ); // associo un valore HIGH al pin motorPinDirA //motore B digitalWrite(motorPinDirC, LOW); // associo un valore LOW al pin motorPinDirC digitalWrite(motorPinDirD, HIGH); // associo un valore HIGH al pin motorPinDirD } // comanda l' arresto dei motori void Stop() { digitalWrite(motorPinDirA, LOW); // associo un valore LOW al pin motorPinDirA digitalWrite(motorPinDirB, LOW); // associo un valore LOW al pin motorPinDirA digitalWrite(motorPinDirC, LOW); // associo un valore LOW al pin motorPinDirC digitalWrite(motorPinDirD, LOW); // associo un valore LOW al pin motorPinDirD } // Funzione che restituisce un valore (0 oppure 1) a seconda che ci si trovi davanti ad un ostacolo oppure no int checkDistance(int lettura_sensori[]) { int esito = 0; // Dichiaro la variabile di tipo int che accoglie il valore finale della funzione int i; // Dichiaro la variabile di tipo int i come indice dell' array contenente lettura_sensori[] //Lettura distanze sensori dall' array for (i = 0; i < 4; i = i + 1) { if ((lettura_sensori[i] < 15)&& (lettura_sensori[i] > 0)) // impongo che l' ostacolo si debba trovare entro la distanza di 15 cm { esito = 1; } } // Stampa su seriale del valore di checkDistance() per analisi sensori Serial.print("checkDistance: "); Serial.println(esito); Serial.println(" "); Serial.println(" "); Serial.println(" "); return esito; // restituisce il valore contenuto nella variabile esito }
come hai letto il codice è scritto in modo chiaro ed ogni parte dello stesso è commentata a dovere.
Passa al secondo sketch, da caricare sull’arduino ( o genuino ) che hai installato sul secondo ripiano:
/* Il programma consente la riproduzione di canzoni in formato mp3. Scaricare il programma in Arduino (la scheda situata al piano superiore 2) e scegliere la costante corretta da inserire nello sketch per ottenere la sequenza di riproduzione voluta. */ // Elenco delle librerie necessarie #include <SD.h> #include <SPI.h> #include <arduino.h> #include <MusicPlayer.h> void setup() { Serial.begin(9600); player.begin(); //inizializza l'hardware e definisce la modalità di default player.setPlayMode(PM_SHUFFLE_PLAY); //definisce la modalità di riproduzione dei brani come SHUFFLE (altrimenti PM_NORMAL_PLAY,PM_REPEAT_LIST,PM_REPEAT_ONE (vedere la libreria MusicPlayer.h) player.scanAndPlayAll(); //Se la playlist corrente è vuota saranno eseguite tutte le canzoni contenute nell cartella root della playlist. } void loop() { player.play(); }
è decisamente più semplice del precedente ed il suo scopo ti è certamente già chiaro: controllare l’esecuzione dei brani musicali presenti nella SD Card che avrai inserito nella MusicShield.
Il lavoro è quasi totalmente affidato alla libreria che comunica con la shield ed esegue i brani.
L’ultimo sketch da caricare è quello che puoi caricare nella Adafruit Trinket 5V per la gestione delle luci dell’albero di natale:
int led1 = 4; int led2 = 5; int led3 = 6; int led4 = 8; void setup() { pinMode(led1,OUTPUT); pinMode(led2,OUTPUT); pinMode(led3,OUTPUT); pinMode(led4,OUTPUT); } void loop() { digitalWrite(led1,HIGH); digitalWrite(led2,LOW); digitalWrite(led3,LOW); digitalWrite(led4,LOW); delay(100); digitalWrite(led1,LOW); digitalWrite(led2,HIGH); digitalWrite(led3,LOW); digitalWrite(led4,LOW); delay(100); digitalWrite(led1,LOW); digitalWrite(led2,LOW); digitalWrite(led3,HIGH); digitalWrite(led4,LOW); delay(100); digitalWrite(led1,LOW); digitalWrite(led2,LOW); digitalWrite(led3,LOW); digitalWrite(led4,HIGH); delay(100); }
anche questa parte del codice è molto semplice, tanto che Carlo non ha inserito dei commenti alle linee di controllo dei 5 led connessi alla scheda.
Il video dell’Albero Robot
Ecco il video realizzato dall’autore e condiviso su YouTube:
3 commenti
Complimenti a Carlo per il bellissimo progetto da cui sto prendendo spunto, dopo l’uscita al cinema di “star wars”, per realizzare un piccolo R2-D2.
Nella mia rielaborazione sto usando i sensori ad ultrasuoni in modo separato :
Sensore di destra fa girare leggermente a sinistra, sensore di sinistra fa girare leggermente a destra, sensore anteriore fa andare indietro e girare a destra o sinistra dipendente dai sensori laterali, il sensore posteriore “dovrebbe” impedire di andare contro un ostacolo quando il robot fa retromarcia.
Il problema è proprio sulla retromarcia perché i motori si muovono indietro per “x” millisecondi escludendo il sensore.
Volevo chiedere se c’era un modo per ovviare a questo problema.
Ti ringrazio
Tiziano
Autore
Ciao Tiziano,
il modo per risolverlo è usare il comando millis() al posto del comando delay().
Il primo non interrompe il ciclo ma necessita di una sintassi di programmazione un po’ più complessa.
Il secondo è semplice da utilizzare ma impedisce qualunque operazione durante i movimenti.
Grazie Mauro
Ho trovato il tuo articolo “Tutorial: millis() contro delay()” con il link a Vittorio Zuccalà.
Ci “studio” sopra e poi ti farò sapere.
Ciao
Tiziano