Crea sito

Archive for July, 2011

Arduino and real time charts in Excel

One of the most important things in the robot design is the possibility to check and control the values feeded by the analogic sensors, i.e. accelerometers, gyros, IR sensors.
In order to view the sensor values you can use the Serial Port that can be displayed in the Serial Monitor inside the Arduino IDE environment.
But it isn’t possible to show charts or save the data read from the sensors.
There are several software that allow to show the graphs derived from the sensors data, and I published in the past a tutorial (here).
Usually you use Processing or similar language that require always to write some code. You have to write code to change the charts or to implement new lines in the graphs.
I thought that the ideal situation would be to use a software that everyone knows: Microsoft Excel.

If it were possible to use Excel to receive the data from the serial port, it would be easy to make very nice and user friendly charts.
I searched in Google and i found a sw that allows easily to view the serial port values in Excel.
The sw is made by a competitor of Arduino, Parallax, the company that sells the Boe-Bot and the Propeller, wich are in direct competition with Arduino.

The sw is called PLX-DAQ and it is a free software. You can download it here. It works only in Windows, sorry.
In practice it is a little sw in VBA that adds some features to Excel to receive and elaborate real time data. If the data are in Excel it is also possible to save them in a file and it is possible to use the amazing function library already present in the spreadsheet software. The documentation about PLX-DAQ is complete and clear.

The PLX-DAQ takes commands in uppercase and every data row have to end with a ‘carriage return’. The serial port speed required by PLX-DAQ is particular, because it derives from Parallax world. In any case the rate is from 9600 bit/sec to 128.000 bit/sec. The speed of 128.000 bit/sec works fine in the Arduino!!

The main commands are:

  • LABEL used to define the column headings. The command format is:  Serial.println (“LABEL, INT_COLUMN”);
  • DATE, TIME that allows the serial port to send data to Excel. The first field is always TIME, then the fields of interest (val). The command format is:  Serial. print (“DATE, TIME,”);  Serial.println (val)
  • ROW, SET, k,  allows you to define the next line to write. It is useful if you want to plot n data and then go back to first row and cycle. For example, you can plot 1000 data on the chart and then start again from the first position, in order to avoid a graph too large. The command format is: Serial.println (ROW, SET, 2) put the cursor in the second line next step.

Here’s an example that shows Excel function sin (x).

The Arduino code:

 

int x = 0;
int row = 0;
void setup() {
  Serial.begin(128000); // opens serial port, sets data rate to 128000 bps
  Serial.println("CLEARDATA");
  Serial.println("LABEL,Time,x,sin(x)");
}

void loop() {
  Serial.print("DATA,TIME,"); Serial.print(x); Serial.print(","); Serial.println(sin(x*PI/180));
  row++;
  x++;
  if (row > 360) 
   {
    row=0;
    Serial.println("ROW,SET,2");
   }
  delay(100);
}

 

PLX-DAQ enable a more complex interaction with Excel. It can take the cell values from Excel, it can read and write check box. You can see the PLX-DAW documentation for other details.

Tags: , ,

Simple talking robot

 Giving the voice to a toy always has been a dream when I was a child. There weren’t talking toys and the dream was destinated to stay a dream. With the power of the modern microcontrollers, like Arduino, to have a talking robot is one of the things that always I desidered to do. You can build a talking robot in two ways:

  • with the tex-to-speech, writing a text that the robot says
  • recording some audio files with inside the voice already recorded that the robot repeats

The text-to-speech is the best way to do a robot talking. You write a text, and he reads the text: this is the fastest way, but you need a chip that implements the text-to-speech. It is easy if your language is English, not easy if your language is different. For me, the language is the Italian and I haven’t found any cheap chip for italian text-to-speech.

So I used the second method, recording the voice. The method is more complex, but at the end the result is the same.
I built a simple robot, that can be made by every beginner, that does 2 things:

  • it goes around, avoiding obstacles with an ultrasound sensor
  • it talks, thanks to an audio chip

The robot is basically a toy, that fascinates my son, a little child of few months old. He enjoys to see the robot turn around, talking with robotic voice. I did it just for that. Let me to introduce Geronimo 2, the little talking robot:

Geronimo in action:

The little robot is based on two projects already presented in the past: this and this. In these links you can find some details on the building and the hardware. It uses a DFRobot URM37 Ultrasound sensor and a SOMO-14D audio chip, used to talk. This audio chip is low cost (20 euros) and it works with few components (only one 220uf capacitor) and it can be set with an Arduino.
The SOMO-14D plays only files codified with a proprietary format (AD4). But it is available a practical sw that converts MP3 in AD4 format.
In order to allows to talk to the robot, I used a software for italian speech(called Er Finestra), but you can use the speech software you want. For almost all the languages a similar little utility is available.
One problem resolved is due to the fact that Er Finestra can only say something. It can’t at the same time to say and to record. So I downloaded Audacity, an editor audio free, that can record every sound that pass in the sound card.
So you have to start Er Finestra and at the same time to start Audacity that records the phrases read by Er Finestra. Then you can convert the Phrase from MP3 to AD4. The process could be seem complex, but it is more difficult to say than to do.
I read with Er Finestra 40 pieces, I converted them and the robot can say them randomly.
It is possible to use an intelligent algorithm in order to say something responding to external stimulus. For example, to say ‘turn right’, ‘turn left’ or something of similar. The audio chip can play also musical pieces, songs, so it is possible to see the robot going around singing !

The code used for Arduino is simple and it is organized in two parts:
– one for the robot navigation
– one for audio playing
The code is commented, so I don’t think you will have comprehension problems:

//Semplice robot autonomo con sensore ad ultrasuoni per evitare gli ostacoli e chip audio per parlare o suonare una canzone.
//Simple autonomous robot with ultrasonic sensor for obstacles avoidance and audio player chip. It can speak or play a song. 
// written by alegiaco
// 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;
}

 

This is the SOMO-14D code part:

 

// ------------------ 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

}
}

/************************************************** ********************************
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;
}

 

How to choose the motors for the robot

 

One of the problem building a robot is the choice of motors. I’m speaking about a mobile robot with wheel. So, I’m not speaking about legs or others geometries.
A simple robot with 2 wheel that goes around in the house. So a robot moving on a flat surface, no hills. Without tracks, without rough terrain. No SUV!
In this situation the calculations are complex and out of the aim of this little tutorial for beginners.
First we can start from the value usually reported in any motor datasheet: the torque. The torque is, in the rotation, the equivalent of force in the linear motion. To push a box, bigger it is the force, bigger it is the acceleration. For a wheel, bigger it is the torque, bigger it is the wheel acceleration (rotational).

In the datasheets often it speaks about stall torque (start-up torque, stall torque) and, somethimes, about nominal torque (rated torque).

The start-up torque is the maximum torque that the motor can provide. But when the motor is in stall, the motor is stopped. So it isn’t very useful. It would be useful to have the rated torque, that is, (approximately) the maximum torque that ensures continous operation of the engine, without problems.

If the rated torque is not present in the datasheet, we can consider the first formula (approximated):

Rated torque=star-up torque / 2

Now, we can consider the robot motion formulas. There is a formula that links the motor torque with the robot weight and acceleration. So this formula provides us a very important information. That is, knowing the robot weight (in kg), knowing the acceleration desired, this formulas says wich is the torque that we have to consider in the motor choice.

Some information are required:
– robot mass (you can put the robot in a balance and read the weight in kg).
– the wheels radius (in cm.). Please note that the radius is half the diameter
– the robot acceleration desired. For example, 0.5 m/s^2. This means that we start the robot motion, after 2 seconds it will have a speed of v=a*t=0.5*2=1 m/s, i.e. a meter for each second. Not so bad for a home robot.

The motion formula is:

C/r=m*a + Fattr

where: C is the rated torque of the motor, r is the wheel radius, m is the mass, a is the acceleration and Fattr is the attrition force (here mostly rolling) between the wheel and the floor.
The Fattr is complicated. We can do a semplification:

Fattr=m*a

Basically, when we have to calculate the torque, we can double the torque deriving from the m*a calcolation. Maybe, this could be a conservative calculation, but we can be serene in the motor choice.

So let’s recap:

C/r=2*m*a

We must consider that the robot is pushed by two engines, the right one and the left one, so we just need half torque. The formula becames:

C/r=m*a –> C=m*a*r

Let’s take an example. Suppose you have a little robot that weights 2 kg, with two wheels with 8 cm diameter (4 cm radius) and we want an acceleration of 0.5 m/s^2. You get:

C=2*0,5*4=4 N*cm.

So the engine should have a 4 N*m torque. The motors often have a torque indicated in kg*cm. So we have to divide by 9.81 (approximately 10).

So you get a motor with a rated torque of 0.4 kg*cm, and 0.8 kg*cm of start-up torque. Easy or not?

Now consider the speed. Suppose we want a robot whit 1 m/s of speed, that means 3.6 km/h.
If the wheel has a 4 cm radius, the distance traveled at each revolution is:
d=2*pi*r = 6.28 * 4 = 25.12 cm
So, to make 1 meter per second:
100/25.12 revolution per second = 3.98 revolution per second.
knowing that in a minute there are 60 seconds, you get the revolutions per minute (rpm), another data often written in a motor datasheet.

rpm = revolutions per second * 60 = 3.98 * 60 = 239 rpm

With the data of torque and the rpm we are able to choose the right motor.
All the formulas are simplified, however, it is enough for beginners and for DIY robot builders!

Tags: ,