Prodotti
Alessandro
Semplice robot che parla
Tutorials -
Domenica 27 Febbraio 2011 12:38
Scritto da Alessandro

Dare voce ad un giocattolo è sempre stato uno dei miei sogni quando ero bambino. Al tempo non c’erano giocattoli parlanti e quindi era un sogno destinato a rimanere tale. Con le possibilità che offre Arduino, avere un robottino parlante è quindi una delle cose che ho sempre voluto fare. Si può far parlare un robottino in più modi:

-        Con il text-to-speech, cioè semplicemente scrivendo un testo che il robot recita

-        Registrando dei brani audio contenenti la voce già registrata che il robottino ripete

Il text-to-speech è il modo più bello di far recitare qualcosa al robot. Si scrive un testo e lui lo recita. E’ il metodo più veloce: però richiede un chip che implementi il text-to-speech. Ne esistono più di uno per l’inglese, non ne ho trovato nessuno per l’italiano, a costi umani.

La registrazione dei brani audio è più macchinosa, ma alla fine garantisce lo stesso risultato. Ho allora realizzato un semplice robottino, alla portata di qualsiasi principiante che fa due cose: va in giro senza andare a sbattere, grazie ad un sensore ad ultrasuoni e parla, grazie ad un chip audio.

Il robot è in sostanza un giocattolo, che affascina molto mio figlio di pochi mesi. Si diverte un mondo a vederlo girare e parlare con voce robotica.  L’ho fatto proprio per questo.

Vi presento Geronimo, il robottino parlante:

 

 




Ecco il robottino in azione mentre va in giro parlando:

 

Il robottino è basato su due progetti che avevo già illustrato in passato: questo e questo. Lì si possono trovare dettagli sulla costruzione e parte hardware.

E’ dotato di un sensore ad ultrasuoni URM37 di DFRobot che è in grado di rilevare un ostacolo da 0 a 300 cm. E’ inoltre dotato di un chip audio SOMO-14D della 4D-System per farlo parlare. E’ un chip audio a basso costo (20 euro circa) che con pochissimi componenti (un solo condensatore da 220uf) può essere comandato da un microcontrollore come Arduino.

Il chip audio riproduce dei brani codificati in un formato proprietario (AD4). Tuttavia è disponibile un comodo sw convertitore da file mp3 o da wav.  Per far parlare il robottino ho utilizzato una voce robotica famosa (quella di radio Deejay) che si può riprodurre con un sw che si chiama Er Finestra che è scaricabile da molti siti (ad esempio qui).

Il problema è che Er Finestra non registra in formato mp3 o simili. Parla soltanto, cioè fa il vero text-to-speech. Ho scaricato allora Audacity, un editor audio che permette di registrare qualsiasi cosa passi attraverso la scheda audio. In pratica, si fa il text-to-speech con Er Finestra e contemporaneamente si avvia la registrazione con Audacity che permette di salvare in mp3 o in wav. Una volta registrati i brani si convertono con il sw del SOMO-14D nel formato AD4. Si caricano su una schedina SD e il robottino è pronto a riprodurli. Il procedimento sembra molto macchinoso, in realtà è più difficile a dirsi che a farsi.

Ho fatto leggere a Er Finestra 40 brani, li ho convertiti e il robottino li riproduce a caso. Chiaramente nulla vieta di utilizzare un algoritmo più intelligente del caso per fargli dire delle cose ‘sensate’. Ad esempio, gira a destra, gita a sinistra eccetera. L’unico limite è dato dalla fantasia. Il chip audio è in grado di riprodurre fedelmente anche brani musicali, quindi si può fare in modo che vada in giro cantando canzoni!

Il sw del robottino è abbastanza semplice. E’ diviso in due parti: una parte che governa la navigazione e il sensore ad ultrasuoni e l’altra parte che governa la riproduzione audio.  Il codice è abbondantemente commentato, quindi non credo ci siano grossi problemi di comprensione.

Per scaricare l’intero codice si può cliccare su questo link.

 

Ecco il codice della parte navigazione:

//Simple autonomous robot with ultrasonic sensor for obstacles avoidance and audio player chip. It can speak or play a song.
//Semplice robot autonomo con sensore ad ultrasuoni per evitare gli ostacoli e chip audio per parlare o suonare una canzone.
// written by Alessandro Giacomel
// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
//include URM Library - Includi la libreria URM
#include "URMSerial.h"
#include   //include servo library - includi la libreria del servo
Servo sservo;
Servo dservo;
Servo uservo;
int ang=0;
int angolomax=0;
int distmax=0;
int value=100;
int ind=0;
int rotazione=0;

// Definizione delle misure per il sensore ad ultrasuoni URM37
// Measures definition for ultrasound URM37
#define DISTANCE 1
#define TEMPERATURE 2
#define ERROR 3
#define NOTREADY 4
#define TIMEOUT 5

//angolo di riposo dei servi delle ruote
// standing angle for servos
#define RIPOSOS 93
#define RIPOSOD 93

// inizializza l'oggetto della libreria urm del sensore ultrasuoni
// initialize object for urm library
URMSerial urm;

//parte relativa al SOMO-14D - Chip Audio - SOMO-14D initial variables assegnation
const unsigned int minVol= 0xfff0;    // Minimum volume - Volume minimo
const unsigned int maxVol= 0xfff7;    // Max Volume  - Volume massimo
const unsigned int PlyPse = 0xfffe;   // Play or Pause
const unsigned int Stop= 0xFFFF;      // Stop
const int pinClock= 4;                // clock sul pin dell'arduino - Clock on Arduino pin
const int pinData =5;                 // data sul pin dell'arduino - Data on arduino pin
const int pinBusy =8;                 // busy sul pin dell'arduino - Byte on Arduino pin
const int pinReset=12;                // reset sul pin dell'arduino - Reset on arduino pin
unsigned int volLevel=0x0005;         // imposta massimo livello volume - volume max level
int Song;                             // current Song - canzone attuale
unsigned int vol;                     // volume
int secondi=0, ultimotempo=0;         // varibili per durata brani - variables for songs time
int brano=0;                          // brano riprodotto - song played
int durata[40]={
7,8,14,19,5,8,33,28,5,5,5,5,6,5,5,5,5,6,6,7,6,5,7,8,8,10,4,6,5,6,5,10,5,6,7,6,4,5,6,5}; // durata singoli brani - single songs time

//****************** fine variabili iniziali ************************************
//****************** end initial variables **************************************



void setup()
{
Serial.begin(9600);                          // baud rate - 9600
urm.begin(6,7,9600);                         // RX Pin, TX Pin, Baud Rate
sservo.attach(10);                           // Attacca il servo sinistro al pin 10 - servo left to pin 10
dservo.attach(9);                            // Attacca il servo destro al pin 9 - - servo right to pin 9
uservo.attach(3);                            // Attacca il servo degli ultrasuoni al pin 3 - ultrasonic sensor servo to pin 3
delay(100);
uservo.write(90);                            // metti il servo degli ultrasuoni dritto - ultrasonic servo straight

pinMode(pinData,OUTPUT);                     // set pin 4 to output for Data -
pinMode(pinClock,OUTPUT);                    // set pin 3 to output for clock
pinMode(pinReset,OUTPUT);                    // set pin 7 to allow software reset - imposta pin 7 per il sw reset
pinMode(pinBusy,INPUT);                      // set pin 6 to monitor while Song is playing - pin 6 di monitoraggio mentre il brano è suonato
Reset();                                     // resetta il somo-14D chip audio - somo-14d chip audio reset
}

void loop()
{

playSOMO14D();                                 // suona un brano con chip audio - play song with chip audio
delay(30);                                     // attendi allineamento dei servi - wait for servo alignement
sempreDritto();                                // fai andare il robot sempre dritto - always straight
getMeasurement(DISTANCE);                      // richiedi una nuova lettura della distanza - ask for new distance reading

if (value 0)                    // se il valore e' < 20 cm stiamo per sbattere - if the value is < 20 we are crashing
{
fermaServi();                                // ferma il robot mentre controlla gli ostacoli intorno - stop servos
scandisciAmbiente();                         // controlla gli ostacoli ogni 30 gradi - control obstacles every 30 degrees
ruotaServi();                                // fai girare i servi nella direzione della max strada libera - turn servos in the free direction

}
}


// ------------------ ferma i servi dei motori: robot fermo -----------------------
// ------------------ stop robot - stop servos              -----------------------
void fermaServi()
{
sservo.write(RIPOSOS); // ferma ruota sinistra - stop left wheel
dservo.write(RIPOSOD); // ferma ruota destra - stop right wheel
}



// ------------------ fai andare il robot sempre dritto -----------------------
// ------------------ go straight  -----------------------
void sempreDritto()
{
sservo.write(RIPOSOS + 80); // fai andare il robot dritto - go straight
dservo.write(RIPOSOD - 80); // fai andare il robot dritto - go straight
}


// ------------------ controlla gli ostacoli ogni 30 gradi -----------------------
// ------------------ control obstacles every 30 degrees -----------------------
void scandisciAmbiente()
{
angolomax=0; // imposta l'angolo di migliore uscita a zero - set exit angle to zero
distmax=0;   // imposta la distanza di uscita migliore a zero - set max distance read to zero
for (ang=0; ang<=6; ang++) // fai un ciclo per controllare dove sono gli ostacoli - cycle to control where are the obstacles
{
delay(100); //attendi allineamento servo ultrasuoni - wait for ultrasonic sensor alignment
uservo.write(ang*30); // imposta il servo degli ultrasuoni sul valore assunto da ang - set to ultrasonic sensor servo to value of ang variable
float sommadist=0;
int contavalori=0;
// 5 letture della distanza. sommale e fai la media
// read 5 time the distance, sum and average
for (int lettura=1; lettura<=5; lettura++)
{
value=-2;
getMeasurement(DISTANCE); //richiedi una nuova lettura della distanza - ask for a new distance read
delay(20);
if (value >= -1 && value < 300) // solo se la distanza è tra -1 e 300 - only if the distance is between -1 and 300
{
if (value==-1) value=1000; //-1 = infinito
sommadist = sommadist + value;
contavalori++;
}
}
int dist=sommadist/contavalori;
if (dist > distmax) // verifica che la distanza letta sia maggiore del max - distance read > max
{
angolomax=ang;  // se e' maggiore del max imposta il nuovo angolo max e - if > max, set new angle max
distmax=dist;  // la nuova distanza max - new max distance

}
}
uservo.write(90); //rimetti il servo degli ultrasuoni dritto - ultrasonic servo straight
}


// ------------------ ruota i servi nella direzione di massimo spazio libero -----------------------
// ------------------ turn servos to max free distance   -----------------------
void ruotaServi()
{
for (ind=1; ind < (abs(angolomax-3))*3; ind++)
{
if (angolomax <= 3) { //tra 0 e 90 gradi. between 0 and 90 degrees
sservo.write(RIPOSOS-90);
dservo.write(RIPOSOD-90);
}
else // tra 90 e 180 gradi - between 90 and 180 degrees
{
sservo.write(RIPOSOS+90);
dservo.write(RIPOSOD+90);
}
delay (50); // attendi allineamento servi - wait for servos alignment
}
}

// ------------------ acquisisci misurazione distanza -----------------------
// ------------------ take distance -----------------------
int getMeasurement(int mode)
{
// Request a distance reading from the URM37 - richiedi distanza da URM37
switch(urm.requestMeasurementOrTimeout(mode, value)) // Find out the type of request - verifica tipo richiesta
{
case DISTANCE: // Double check the reading we recieve is of DISTANCE type - doppio check che sia una distanza
return value;
break;
case TEMPERATURE:
return value;
break;
case ERROR:
Serial.println("Error");
break;
case NOTREADY:
Serial.println("Not Ready");
break;
case TIMEOUT:
Serial.println("Timeout");
break;
}

return -2;
}


// ------------------ Suona il brano su SOMO-14D -----------------------
// ------------------ play song on SOMO-14D -----------------------
void playSOMO14D()
{
if (int(millis()/1000) > ultimotempo + durata[brano]) { //verifica se il brano precedente è terminato - verify if previous song is finished
ultimotempo=int(millis()/1000);
brano=int(random(1, 41)); // prendi un brano a caso - take random song
PlaySong(brano); // suona brano - play song

}
}


Questa è la parte di riproduzione della voce:

/************************************************** ********************************
Send Sequence - Invia sequenza
************************************************** ********************************/

void sendData(int ThisSong)
{
int TheSong = ThisSong;
int ClockCounter=0;
int ClockCycle=15;//0x0f;

digitalWrite(pinClock,HIGH);     // Hold (idle) for 300msec to prepare data start
delay(300);
digitalWrite(pinClock,LOW);       //Hold for 2msec to signal data start
delay(2);  //2msec delay

while(ClockCounter <= ClockCycle)
{ digitalWrite(pinClock,LOW);
if (TheSong & 0x8000)
{digitalWrite(pinData,HIGH);
}
else
{digitalWrite(pinData,LOW);
}
TheSong = TheSong << 1;
delayMicroseconds(200);      //Clock cycle period is 200 uSec - LOW
digitalWrite(pinClock,HIGH);
ClockCounter++;
delayMicroseconds(200);      //Clock cycle period is 200 uSec - HIGH
}

digitalWrite(pinData,LOW);
digitalWrite(pinClock,HIGH);    // Place clock high to signal end of data
}

/************************************************** ********************************
Plays Stored Song by Number - Suona un brano per numero del brano
************************************************** ********************************/

void PlaySong(int numero)
{ sendData(Stop);
int SongNumber=numero;
if (SongNumber >= 0 && SongNumber < 512){     // Song is within range limit
Serial.print("-> Song No.");
Serial.println(SongNumber);
sendData(SongNumber);}

}



/************************************************** ********************************
Reset SOMO
************************************************** ********************************/
void Reset()
{
//Serial.println("RESET.");
digitalWrite(pinReset,LOW);
delay(50);
digitalWrite(pinReset,HIGH);
Song=0;
}
 

Gioblu Robotics © 2010 - 2012 · Sitemap · privacy

gioscarab@gmail.com · Via Savona 123 20146 Milano MI · PI 06977550968 · Codice fiscale MTLGNN86S09F205F

Gioblu BOTServer è online dal 10 Aprile 2010 - 319.232 Visite - 1.027.175 Pagine visualizzate - 182.309 Visitatori unici - 536 utenti attivi