Berrino – Il robot portabirra

Ammettetelo: chi, almeno una volta nella vita, non ha desiderato possedere un robot in grado di portargli una lattina di birra e stappargliela? Bene, grazie a Berrino i vostri problemi sono finiti! Infatti, d'ora in poi, potrete essere finalmente un tutt'uno con il vostro divano, senza però dover rinunciare a quel dolce nettare che vi disseta durante gli "intensi" pomeriggi domenicali!

Presentazione

In questo articolo, andrò a descrivere come è stato realizzato il mio progetto del robot porta-birra. Esso sarà in grado di riconoscere un determinato input vocale, procedere fino al punto stabilito, stappare la lattina di birra e porgerla all'utente. Per prima cosa è opportuno spendere due parole sulla struttura generica del robot, fissando subito alcuni punti fermi i quali, poi, verranno approfonditi uno alla volta. Il robot è equipaggiato con un elettronica composta da un Raspberry Pi B+, che si occupa di fare da tramite con il mondo esterno, e da un Arduino Uno, a cui è affidato il compito di svolgere tutte le operazioni fisiche, come il movimento dei vari motori e la gestione dei sensori. Il compito di tradurre le “intenzioni” infatti è affidata a due motori passo-passo (con i relativi circuiti di pilotaggio) e ad un motore a spazzole controllato grazie alla Motor Shield Infineon. Il nome che ho deciso di dargli è un gioco di parole realizzato fondendo insieme sia i nomi di "Raspberry" e "Arduino", sia la parola "beer" che tutti sappiamo cosa significa. Bene! Conclusa questa doverosa premessa, cominciamo!

Materiale utilizzato:

- Arduino Uno R3;
- RaspberryPi B+ con Raspbian modificato dai creatori di Jasper, l'assistente vocale;
- Infineon MotorShield per Arduino;
- Sensore ultrasuoni HC-SR04;
- Motori Passo-Passo (Nema17) con relativi circuiti integrati di pilotaggio (EasyDriver 4.4);
- 2x Batteria Usb per l'alimentazione del Raspberry e dei motori passo-passo;
- 2x Pila da 9V ( per alimentare Arduino e l'altra per alimentare il motore);
- Cavi e connettori vari;
- Una vecchia macchinina radiocomandata opportunamente riadattata.

RaspberryPi e controllo vocale

Per il mio progetto ho fatto uso di un software (al momento disponibile solo per Raspbian, uno dei SO del Raspberry) di riconoscimento vocale, chiamato Jasper. La presentazione e la documentazione di questo software è esaustivamente descritta sul sito degli sviluppatori, ma se volessimo farla in breve possiamo dire che la sua funzione principale è, una volta chiamato col nome “Jasper”, quella di ascoltare i comandi dati vocalmente, interpretarli e lanciare sottoprogrammi opportuni. In particolare, nel mio progetto, il suo compito è quello di mandare in esecuzione uno script Python (chiamato modulo) che a sua volta lancerà un programma in C che, gestendo direttamente la porta GPIO, andrà a dare il segnale di avvio all'Arduino. L'enorme apertura di Jasper permette di aggiungere sempre nuovi moduli semplicemente salvandoli dentro la cartella 'Modules', ponendo come limite semplicemente la fantasia di chi si trova a creare nuove funzionalità. Di seguito sono scritti rispettivamente il codice python del modulo che ho creato e il codice C per la gestione della GPIO.

Beer.py
import re
import osWORDS = ["I","WANT","MY","BEER"]def isValid(text):
return bool(re.search(r'\bi want my beer\b',text,re.IGNORECASE))def handle(text,mic,profile):
os.system("sudo /home/pi/Desktop/interrupt")
message="I'm coming"
mic.say(message)

- La lista WORDS deve contenere esattamente le parole che volete utilizzare come comando.
- La funzione isValid compara il testo tradotto dal segnale vocale con quello all'interno della lista e restituisce true al chiamante se corrispondono.
- La funzione handle contiene il vero e proprio corpo del nostro programma: col il metodo system si invoca il programma in C con la stessa sintassi che si userebbe sul terminale linux. La seconda riga semplicemente dichiara e inizializza la stringa “message” che poi, tramite la chiamata al metodo say viene letta da Jasper.

interrupt.c
#include <wiringPi.h>
int main(){
wiringPiSetup();
pinMode(0,OUTPUT);digitalWrite(0,HIGH);
delay(1000);
digitalWrite(0,LOW);return 0;
}

Il programma qui sopra è piuttosto autoesplicativo, comunque per chi non fosse molto pratico ci basta dire che una volta importata la libreria per la gestione della GPIO e inizializzata quest'ultima tramite wiringPiSetup si da semplicemente un segnale alto al pin digitale 0 (pin fisico 11), si attende un secondo per essere sicuri che Arduino riesca a identificarlo, e si riporta a 0 semplicemente. Inizialmente avevo pensato di utilizzare un bus come lo SPI o l'I2C, ma con scarso successo: il primo è inutilizzabile in quanto, su Arduino, utilizza gli stessi pin (che sono pin fisici sul microcontrollore) dei controlli della motorshield, mentre il secondo ha una gestione, sempre su Arduino, che poco si prestava alle mie esigenze. Inoltre ci sarebbe stata un'inutile complicazione sia del codice che della rete, perché in fondo ci basta semplicemente un segnale “alto” generico.
NOTA: come vedrete di seguito, io ho collegato direttamente i pin di Arduino con quelli del Raspberry. Questo si può fare solo in questo caso perché è unicamente il Raspberry a inviare segnali, mentre Arduino fa semplicemente da ricevitore. Ricordiamo infatti che il Raspberry ha logica a 3.3V e NON tollera i 5V, mentre Arduino ha logica a 5V ed è in grado di riconoscere il segnale del Raspberry.
Fatto ciò, il Raspberry cessa il suo compito e lascia tutto il resto nelle mani dell'Arduino. Vediamo, quindi, come è stato realizzata tutta la parte restante del robot.

Arduino e attuatori

In tutto questo Arduino è stato sempre in attesa dell'interrupt da Raspberry e una volta ricevuto il segnale, il microcontrollore può iniziare ad eseguire il suo compito. Per prima cosa verifica, tramite il sensore ad ultrasuoni, di non avere ostacoli davanti a sé perché, diciamocelo, non c'è cosa peggiore di vedere cadere la propria birra ancor prima di averla potuta assaggiare! Effettuato tale controllo, se la via è libera, il nostro robot inizierà ad accelerare gradualmente fermandosi solo quando si troverà di fronte ad un ostacolo. Arrivato quindi nella posizione corretta, inizieranno le operazioni di stappo! Il primo motore passo passo, posto sopra la lattina tramite una staffa, imprimerà la forza necessaria ad aprire la birra, mentre il secondo motore provvederà ad azionare un meccanismo che farà ruotare il “braccio” verso l'utente. Fatto ciò, il robot avrà finito e noi potremo finalmente dissetarci.

Robot_2b

 

Ecco qui riportato lo schema del circuito, mentre di seguito riportiamo il codice caricato sull'Arduino, commentato nel dettaglio:

robot.ino
#define IN_1 3                      //inizializza i pin fisici della motorshield
#define INH_1 12
#define DCMAX 30             //definisce il valore massimo del duty cyclebyte echoPin=13;                 // inizializza il pin 13 come pin di “echo” del sensore ultrasuoni
byte trigPin=2;                    //inizializza il pin 2 come pin di “trigger” del sensore ultrasuoni
unsigned int distance;       // dichiara la variabile che conterrà il valore della distanza da un possibile ostacolo
int dc;                                   //dichiara la variabileche conterrà il valore corrente del duty cycle del motore a spazzole
int interrupt=A2;              // definisce come pin di ingresso dell'interupt il pin analogico A2
int flag;                               //dichiara la variabile flag che conterrà il valore letto dal pin A2
int dir1=6;                        //variabile per la direzione del primo motore passo-passo sul pin 6
int dir2=7;                       //variabile per la direzione del primo motore passo-passo sul pin 7
int step1=8;                     //variabile per il singolo passo del primo motore passo-passo sul pin 8
int step2=9;                     //variabile per il singolo passo del secondo motore passo-passo sul pin 9void setup(){pinMode(trigPin, OUTPUT);           //imposta il pin di “trigger” come pin di output
pinMode(echoPin, INPUT);
pinMode(IN_1, OUTPUT);
pinMode(INH_1, OUTPUT);
pinMode(flag, INPUT);
digitalWrite(INH_1,HIGH);              //imposta il valore logico alto sul pin INH_1 per inibire il motore a spazzole
pinMode(dir1,OUTPUT);
pinMode(dir2, OUTPUT);
pinMode(step1, OUTPUT);
pinMode(step2, OUTPUT);
digitalWrite(dir1, LOW);
digitalWrite(dir2, LOW);
digitalWrite(step1, LOW);
digitalWrite(step2, LOW);}

void loop(){
flag=analogRead(interrupt);                                   //legge il valore dal pint analogico A2 e lo salva in flag
if(flag>100){                          //se il valore letto in precedenza è superiore alla soglia indicata allora prosegui
byte i; //dichiara la variabile i

delay(1000);                      //aspetta un secondo
distance=distanza();   //chiama la funzione che calcola la distanza dall'ostacolo e salva il valore in distance
if(distance>10){              // se la distanza è maggiore di 10 cm
for(i = 0; i<DCMAX; i++){                    //finchè non hai raggiunto il valore massimo di duty cycle
dc= map(i,0,100,0,255);               //porta il valore percentuale di dc in un range di 256 valori
analogWrite(IN_1,dc);             //dai il segnale con duty cycle appena calcolato al motore
}
distance=distanza();                       //misura la distanza
delay(100);                                //aspetta 100 millisecondi
while(distance>10){                           //finchè la distanza è maggiore di 10 cm
distance=distanza();                     //misura la distanza
delay(100);
}
delay(500);                           //aspetta mezzo secondo
dc=0;                        //duty-cycle a zero
digitalWrite(IN_1,dc);           //dai il nuovo duty cycle al motore per fermarlo
delay(1000);                   // aspetta un secondo
stappa();                //chiama la funzione che stappa e muove la lattina
}
}

int distanza(){                //funzione che calcola la distanza
long duration,r;               //dichiara le variabili duration ed r

digitalWrite(trigPin, LOW); //mette a zero il pin di trigger
delayMicroseconds(2); //aspetta due microsecondi
digitalWrite(trigPin, HIGH); //mette a uno il pin di trigger producendo onde ad ultrasuoni
delayMicroseconds(10); //aspetta dieci microsecondi
digitalWrite(trigPin, LOW); //smette di generare onde ultrasoniche
duration = pulseIn(echoPin, HIGH); //misura il tempo di ritorno dell'onda
r=0.034*duration/2; // calcola la distanza

return r;
}

void stappa(){           //funzione che stappa e muove la lattina
int i;

digitalWrite(dir1, LOW);
digitalWrite(dir2, LOW);

for(i=0; i<1000; i++){ //il primo motore stappa la lattina.
digitalWrite(step1, HIGH);
delay(1);
digitalWrite(step1, LOW);
delay(1);

}

delay(1000);

digitalWrite(dir1, HIGH); //cambia il senso di rotazione

for(i=0; i<1000; i++){ //il primo motore torna indietro
digitalWrite(step1, HIGH);
delay(1);
digitalWrite(step1, LOW);
delay(1);
}

for(i=0; i<1000; i++){ //il secondo motore fa girare il braccio
digitalWrite(step2, HIGH);
delay(1);
digitalWrite(step2, LOW);
delay(1);
}

delay(3000);
digitalWrite(dir2,HIGH); //cambia il senso di rotazione del secondo motore

for(i=0; i<1000; i++){
digitalWrite(step2, HIGH); //il secondo motore torna indietro
delay(1);
digitalWrite(step2, LOW);
delay(1);
}
}

Nota: i motori passo-passo utilizzati sono i Nema17, pilotati tramite i circuiti EasyDriver 4.4.

Struttura del robot

Come ultimissima cosa non ci resta altro che parlare dello scheletro del nostro robot. La struttura si basa sull'utilizzo di una vecchia macchinina radiocomandata alla quale ho lasciato semplicemente il motore per muoversi e le ruote. Ho aggiunto un pianale di legno per poter alloggiare tutta l'elettronica, una staffa di ferro che tiene in posizione il motore per stappare e un “braccio” che ha il compito di ruotare e porgere la lattina. Questa è la parte in cui ognuno può metterci un po' del suo personalizzando il robot a suo piacere e a seconda delle esigenze.

Conclusioni

Ecco fatto! A questo punto il Berrino è pronto per potervi servire ogni qualvolta desideriate una bella birra fresca, senza però rinunciare al legame simbiotico sviluppato col proprio divano! Chiaramente è possibile farlo lavorare in versione analcolica, ma sarebbe un po' come andare a fare la spesa con una Ferrari!
Tornando seri per un attimo, ci tenevo a ringraziare tutto lo staff di “Elettronica Open Source” per la possibilità che mi ha dato grazie a questo contest e lo stimolo grazie al quale questo progetto ha visto la luce. Lo ringrazio anche per la motorshiel che mi sarà sicuramente utile per qualche altro progetto!

Qui trovate il video del prototipo funzionante.
Grazie e a presto!

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS

STAMPA     Tags:, ,

5 Commenti

  1. Massimo Spiezia Massimo Spiezia 8 ottobre 2015
  2. dodo 10 ottobre 2015
  3. vetrucci vetrucci 27 novembre 2015
  4. Paolo Ardissone 1 dicembre 2015
    • Francesco Scordino 14 aprile 2017

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS