Friday, September 24, 2010

1

ARDUINO + RKL298 + LIMIT SWITCHES

A couple of weeks ago I talked about how to control 2 DC motors using an Arduino and a RKL298. Here is a small improvement to that idea.

I added two limit switches to each motor. This way the Arduino would stop the motors automatically if any limit switch is activated. The following picture illustrates better the concept.

There is some additional wiring to do in order to use the switches, here you can see how to wire the Limit Switch A1 to the Arduino

As you can see, when the Limit Switch A1 closes the input to the Arduino's digital port 9 becomes HIGH and when the switch is released it becomes LOW. When digital port 9 goes to HIGH state the Arduino will stop motor A automatically. The wiring is analogous for the rest of the switches the difference is that Limit Switch A2, B1 and B2 uses digital port 8, 4 and 3 respectively.

You can find out more details by reading the source code:

/*
   Serial Motor Interface
   Author: Martin Peris-Martorell - www.martinperis.com

   Description: This program is a serial port motor interface.
   It is used to command an H-Bridge motor controller based on
   L298. 
   This motor controller can be found at www.rkeducation.co.uk
   under the reference part number: RKL298 PCB

   The RKL298 PCB can control 2 DC motors. The control is achieved
   by using 6 control lines: ENA, IP1, IP2, ENB, IP3 and IP4.

   ENA, IP1 and IP2 are used to command the motor A
   ENB, IP3 and IP4 are used to command the motor B

   Limit switches: LIA1, LIA2, LIB1, LIB2
   LIA1, LIB1 are the forward limit switches for motor A and B
   LIA2, LIB2 are the reverse limit switches for motor A and B

   Wiring with arduino: 
  
   RKL298 PCB |     Arduino
   -----------------------------
   ENA       <-> Digital port 12
   IP1       <-> Digital port 11
   IP2       <-> Digital port 10
   LIA1      <-> Digital port 9
   LIA2      <-> Digital port 8
   
   ENB       <-> Digital port 7
   IP3       <-> Digital port 6
   IP4       <-> Digital port 5
   LIB1      <-> Digital port 4
   LIB2      <-> Digital port 3 

   A LED can be connected to digital port 13  

   Serial port configuration: 9600 bauds

   Comunication protocol: Connect the arduino via USB to
   a PC, or via digital pins 0 and 1 to a serial port.

   Open the serial port for communication and send 3 bytes.
   The format is:

   Byte 0: 255  //Sync. signal
   Byte 1: Motor identificator. 0 for motor A, 1 for motor B.
   Byte 2: Command. A value between 0 and 63. 
                    0       = Full stop (free running)
                    1 - 31  = Backward with PWM ( 1: slowest, 31: fastest)
                    32      = Full stop (active braking)
                    33 - 63 = Forward with PWM (33: slowest, 63: fastest)

  For example, if you want to move motor A backward at 50% of speed
  the command would be:  255 0 16
  If you want to stop motor A the command would be: 255 0 0

  Additionally there are two limit switches for each motor. 
  If a motor is running and a limit switch is activated, it will
  stop automatically. This is useful for permitting the automatic
  protection of your device, without the direct involvement of the
  controlling computer. 

  This program is distributed under the terms of the GNU General Public License.
   
  Enjoy it.
*/


#define STOP 0
#define FORWARD 1
#define REVERSE -1

/* Declarations for serial communications */
int incomingByte[128];
int numBytes = 0;

/* Declarations for wiring */
int pinEN[2];
int pinIP1[2];
int pinIP2[2];
int pinLIA[2];
int pinLIB[2];

/* Declarations for motor state */
int stateMotor[2];

void setup(){
  int i = 0;
  //0 refers to Motor A; 1 refers to Motor B
  pinEN[0] = 12;
  pinEN[1] = 7;

  pinIP1[0] = 11;
  pinIP2[0] = 10;
  pinLIA[0] = 9;
  pinLIA[1] = 8;

  pinIP1[1] = 6;
  pinIP2[1] = 5;
  pinLIB[0] = 4;
  pinLIB[1] = 3;

  //Set pin modes
  for (i = 0; i < 2; i++){
    pinMode(pinEN[i], OUTPUT);
    digitalWrite(pinEN[i],HIGH);
    pinMode(pinIP1[i], OUTPUT);
    digitalWrite(pinIP1[i],LOW);
    pinMode(pinIP2[i], OUTPUT);
    digitalWrite(pinIP2[i],LOW);
    pinMode(pinLIA[i], INPUT);
    pinMode(pinLIB[i], INPUT);
  }

  //Set initial state of the motors
  stateMotor[0] = STOP;
  stateMotor[1] = STOP;

  //Light up the led
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

  //Open serial port
  Serial.begin(9600);
}

void loop(){
  int i = 0;
  int motor = 0;
  int action = 0;

  //Check for data in serial port
  numBytes = Serial.available();
  if (numBytes >= 3){

    //Read all the data in the buffer
    for(i = 0; i < numBytes; i++){
      incomingByte[i] = Serial.read();
    }

  /* The data received should be: 255 M A
       Where:
        255 is the sync byte 
        M is the motor number (0 or 1)
        A is the action (a number between 0 and 63)
    */
    if (incomingByte[0] != 255 || incomingByte[1] < 0 || incomingByte[1] > 1 || incomingByte[2] < 0 || incomingByte[2] > 63){
      Serial.flush();
      return;
    }

    /* The received data is correct -> activate the appropriate pins */
    motor = incomingByte[1];
    action = incomingByte[2];

    if (action == 0){
      //Full stop (free running)
      digitalWrite(pinIP1[motor],LOW);
      digitalWrite(pinIP2[motor],LOW);
      stateMotor[motor] = STOP;
      return;
    }

    if (action == 32){
      //Full stop (active braking)
      digitalWrite(pinIP1[motor],HIGH);
      digitalWrite(pinIP2[motor],HIGH);
      stateMotor[motor] = STOP;
      return;
    }

    if (action >= 1 && action <= 31 ){
      //Check limit switches
      if ((motor==0 && digitalRead(pinLIA[1])==HIGH) || (motor==1 && digitalRead(pinLIB[1])==HIGH)){
        //Full stop (active braking)
        digitalWrite(pinIP1[motor],HIGH);
        digitalWrite(pinIP2[motor],HIGH);
        stateMotor[motor] = STOP;
      }else{
        //Reverse with PWM
        analogWrite(pinIP1[motor],0);
        analogWrite(pinIP2[motor],(action-1)*8);
        stateMotor[motor] = REVERSE;
      }
    return;
    }

    if (action >= 33 && action <= 63 ){
      //Check limit switches
      if ((motor==0 && digitalRead(pinLIA[0])==HIGH) || (motor==1 && digitalRead(pinLIB[0])==HIGH)){
        //Full stop (active braking)
        digitalWrite(pinIP1[motor],HIGH);
        digitalWrite(pinIP2[motor],HIGH);
        stateMotor[motor] = STOP;
      }else{
        //Forward with PWM
        analogWrite(pinIP1[motor],(action-33)*8);
        analogWrite(pinIP2[motor],0);
        stateMotor[motor] = FORWARD;
      }
      return;
    }

  }else{
    //If no serial message has arrived then poll the status of the limit switches
    //and stop the motors as necessary

    if (stateMotor[0] == REVERSE && digitalRead(pinLIA[1]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[0],HIGH);
      digitalWrite(pinIP2[0],HIGH);
      stateMotor[0] = STOP;
    }
    if (stateMotor[1] == REVERSE && digitalRead(pinLIB[1]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[1],HIGH);
      digitalWrite(pinIP2[1],HIGH);
      stateMotor[1] = STOP;
    }
    if (stateMotor[0] == FORWARD && digitalRead(pinLIA[0]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[0],HIGH);
      digitalWrite(pinIP2[0],HIGH);
      stateMotor[0] = STOP;
    }
    if (stateMotor[1] == FORWARD && digitalRead(pinLIB[0]) == HIGH){
      //Full stop (active braking)
      digitalWrite(pinIP1[1],HIGH);
      digitalWrite(pinIP2[1],HIGH);
      stateMotor[1] = STOP;
    }
  }
}
Enjoy it!

Thursday, September 16, 2010

1

ITINERA'S NEW VOICE

Here is the result of the poll about the new voice for the robot.

And the winner is...(drum roll)....:



Many thanks for helping me to choose!

Thursday, September 9, 2010

5

VOICE SINTHESYS, TEXT TO SPEECH

As I mentioned on the post about damage evaluation of ITINERA, the sound interface was missing. But today the new one arrived. So, it is time to give back to the robot its ability to speak.

In order to do that, I installed the Festival Speech Synthesis System. Since the OS of the robot is Debian this task is quite easy:

$ sudo apt-get install festival festvox-ellpc11k

The package festvox-ellpc11k contains the default Spanish male voice, which is the voice that the robot had previously.

I also installed 2 new Spanish voices, developed by Junta de Andalucia for Guadalinex. Those were quite easy to install as well:

$ wget http://forja.guadalinex.org/frs/download.php/154/festvox-sflpc16k_1.0-1_all.deb
$ wget http://forja.guadalinex.org/frs/download.php/153/festvox-palpc16k_1.0-1_all.deb
$ sudo dpkg -i festvox-palpc16k_1.0-1_all.deb
$ sudo dpkg -i festvox-sflpc16k_1.0-1_all.deb

And can be tested by doing this:

$ festival
Festival Speech Synthesis System 1.96:beta July 2004
Copyright (C) University of Edinburgh, 1996-2004. All rights reserved.
For details type `(festival_warranty)'
festival> (voice_JuntaDeAndalucia_es_sf_diphone)
JuntaDeAndalucia_es_sf_diphone
festival> (SayText "Hola, soy la nueva femenina de itinera")

festival> (quit)

$ festival
Festival Speech Synthesis System 1.96:beta July 2004
Copyright (C) University of Edinburgh, 1996-2004. All rights reserved.
For details type `(festival_warranty)'
festival> (voice_JuntaDeAndalucia_es_pa_diphone)
JuntaDeAndalucia_es_sf_diphone
festival> (SayText "Hola, soy la nueva masculina de itinera")

festival> (quit)

Now I have a problem... I don't know which voice I like the most!!!
Could you help me to choose please?

Here you are the samples of the 3 voices:

Original Voice


Feminine Voice


Masculine Voice

Which voice do you like?

Tuesday, September 7, 2010

6

ARDUINO 4x4x4 LED CUBE


This post is dedicated to my dear friend Luis Reig. Some time ago we found an interesting instructable explaining how to build a 4x4x4 LED cube so we decided to start building it.



We bought all the components and after soldering together all the LEDs we kind of abandoned the project due to lack of time.

The LED cube described in the instructable was controlled using an Atmel Atmega16 micro-controller and some custom circuitry. But with arduino it is extremely easy to control the cube.

You see, there is 64 LEDs in the cube. If you want to control each LED individually you would need 64 digital control lines. Running a wire to each individual LED would be very impractical and look really bad, fortunately there is a trick that you can do: split the cube in 4 layers of 16 LEDs.

The cube is distributed in 4 horizontal layers and 16 vertical columns. All the LEDs in a given layer share the negative pole and the LEDs in a given column share the positive pole.  So all we need now is 4+16 = 20 control lines. Arduino provides 14 digital control lines (Digital 0 to 13) and 6 analog lines (Analog 0 to 5) that can be used as Digital lines (referenced as Digital 14 to 19) making a total of 20 digital control lines.

With this you can light up all the LEDs individually or light up all the LEDs in the same layer or all the LEDs in the same column. Of course, there is combinations that give some trouble but you can avoid them by using Persistence of Vision.

Here you can see a video testing the cube:



And the source code for arduino (persistence of vision is not yet implemented):

/*

   LED Cube test
   Author: Martin Peris-Martorell - www.martinperis.com


   This program is designed to perform a basic test
   on a 4x4x4 LED cube.

   It lights up each led individually, lights up
   the hole cube and starts again.

   This program is distributed under the terms of the 
   GNU General Public License.
   
   Enjoy it.

*/


void setup(){

  pinMode(0,OUTPUT);
  pinMode(1,OUTPUT);
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  pinMode(12,OUTPUT);
  pinMode(13,OUTPUT);
  pinMode(14,OUTPUT);
  pinMode(15,OUTPUT);
  pinMode(16,OUTPUT);
  pinMode(17,OUTPUT);
  pinMode(18,OUTPUT);
  pinMode(19,OUTPUT);

  digitalWrite(16,LOW);
  digitalWrite(17,LOW);
  digitalWrite(18,LOW);
  digitalWrite(19,LOW);
}

void loop(){
  int i,j;


  /* Light up LED by LED */
  for (i = 16; i < 20; i++){
    digitalWrite(i,HIGH);
    for (j = 0; j < 16; j++){
      digitalWrite(j,HIGH);
      delay(200);
      digitalWrite(j,LOW);
    }
    digitalWrite(i,LOW);
  }

   /* BLINK COMPLETE LED */
  for (i = 0; i < 20; i++){
    digitalWrite(i,HIGH);
  }
  delay(1000);
  for (i = 0; i < 20; i++){
    digitalWrite(i,LOW);
  }

}

Sunday, September 5, 2010

3

(CONTROLLING RKL298 WITH ARDUINO) ARDUINO: THE BEST PIECE OF HARDWARE EVER!

 Arduino is an open-source electronics prototyping platform based on flexible, easy-to-use hardware and software. And it is also very cheap! Under 20€!



In a previous post I talked about an L298 based motor controller. It is the circuit that is going to replace a faulty motor controller of the robot ITINERA. Now I need a way to command the new motor controller via a PC serial port. The previous motor controller had a Serial Motor Interface, it costs over 50€ and it is not compatible with the new motor controller.

Another issue is that the robot is programmed to use the protocol of the old Serial Motor Interface and I would not like to change that program because it took me so long to build it :p

The solution is my new best friend: Arduino. I have never used it before but thanks to its features I could program it to do what I need in less than 1 hour... and the best of all... it worked at the first attempt!!!!

Here you have the source code, it could be useful if you want to reproduce this kind of motor control or if you just want to see how easy it is to program an arduino.

I recommend you to read it, you will find much more details than in this post ;)

/*
   Serial Motor Interface
   Author: Martin Peris-Martorell - www.martinperis.com

   Description: This program is a serial port motor interface.
   It is used to command an H-Bridge motor controller based on
   L298. 
   This motor controller can be found at www.rkeducation.co.uk
   under the reference part number: RKL298 PCB

   The RKL298 PCB can control 2 DC motors. The control is achieved
   by using 6 control lines: ENA, IP1, IP2, ENB, IP3 and IP4.

   ENA, IP1 and IP2 are used to command the motor A
   ENB, IP3 and IP4 are used to command the motor B

   Wiring with arduino: 
  
   RKL298 PCB |     Arduino
   -----------------------------
   ENA       <-> Digital port 12
   IP1       <-> Digital port 11
   IP2       <-> Digital port 10
   
   ENB       <-> Digital port 7
   IP3       <-> Digital port 6
   IP4       <-> Digital port 5 

   A LED can be connected to digital port 13  

   Serial port configuration: 9600 bauds

   Comunication protocol: Connect the arduino via USB to
   a PC, or via digital pins 0 and 1 to a serial port.

   Open the serial port for communication and send 3 bytes.
   The format is:

   Byte 0: 255  //Sync. signal
   Byte 1: Motor identificator. 0 for motor A, 1 for motor B.
   Byte 2: Command. A value between 0 and 63. 
                    0       = Full stop (free running)
                    1 - 31  = Backward with PWM ( 1: slowest, 31: fastest)
                    32      = Full stop (active braking)
                    33 - 63 = Forward with PWM (33: slowest, 63: fastest)

  For example, if you want to move motor A backward at 50% of speed
  the command would be:  255 0 16
  If you want to stop motor A the command would be: 255 0 0


  This program is distributed under the terms of the GNU General Public License.
   
  Enjoy it.
*/


/* Declarations for serial communications */
int incomingByte[128];
int numBytes = 0;

/* Declarations for wiring */
int pinEN[2];
int pinIP1[2];
int pinIP2[2];


void setup(){
int i = 0;
//0 refers to Motor A; 1 refers to Motor B
pinEN[0] = 12;
pinEN[1] = 7;

pinIP1[0] = 11;
pinIP2[0] = 10;

pinIP1[1] = 6;
pinIP2[1] = 5;

//Set pin modes
for (i = 0; i < 2; i++){
pinMode(pinEN[i], OUTPUT);
digitalWrite(pinEN[i],HIGH);
pinMode(pinIP1[i], OUTPUT);
digitalWrite(pinIP1[i],LOW);
pinMode(pinIP2[i], OUTPUT);
digitalWrite(pinIP2[i],LOW);
}

//Light up the led
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);

//Open serial port
Serial.begin(9600);
}

void loop(){
int i = 0;
int motor = 0;
int action = 0;

//Check for data in serial port
numBytes = Serial.available();
if (numBytes >= 3){

//Read all the data in the buffer
for(i = 0; i < numBytes; i++){
incomingByte[i] = Serial.read();
}

/* The data received should be: 255 M A
       Where:
        255 is the sync byte 
        M is the motor number (0 or 1)
        A is the action (a number between 0 and 63)
    */
if (incomingByte[0] != 255 || incomingByte[1] < 0 || incomingByte[1] > 1 || incomingByte[2] < 0 || incomingByte[2] > 63){
Serial.flush();
return;
}

/* The received data is correct -> activate the appropriate pins */
motor = incomingByte[1];
action = incomingByte[2];

if (action == 0){
//Full stop (free running)
digitalWrite(pinIP1[motor],LOW);
digitalWrite(pinIP2[motor],LOW);
return;
}

if (action == 32){
//Full stop (active braking)
digitalWrite(pinIP1[motor],HIGH);
digitalWrite(pinIP2[motor],HIGH);
return;
}

if (action >= 1 && action <= 31 ){
//Reverse with PWM
analogWrite(pinIP1[motor],0);
analogWrite(pinIP2[motor],(action-1)*8);
return;
}

if (action >= 33 && action <= 63 ){
//Forward with PWM
action = action - 32;
analogWrite(pinIP1[motor],(action-1)*8);
analogWrite(pinIP2[motor],0);
return;
}

}

}

Here you can see a video demonstrating how it works, sorry for my Spanish accent xD

Saturday, September 4, 2010

0

THE COST OF GOOGLE'S BUCKMINSTERFULLERENE

Today Google is celebrating the 25th anniversary of the finding of the Buckminsterfullerene. And to celebrate it, they decided to make a funny and entertaining interactive logo (also known as "doodle").

They changed one of the "o" from "Google" by a  Buckminsterfullerene that you can move with your mouse. It is really entertaining, so entertaining that I found myself playing with it for over 2 minutes.




Then it came to my mind... what if I am at work and I loose that time playing with google's logo? 

Let's make some numbers: Google receives about 8.172.420 visits per day. Consider that the half of that visits come from people at work: 4.086.210 visits per day at work. 

From that amount of visits per day from work, let's say that the mean time spent playing with the logo is about 1 minute (there is people that procrastinates more than other :P). 

If the mean salary for a worker is 20€ per hour, that means that he earns 0,33€ per minute.

Now the compute is easy:  4.086.210 visits per day * 0.33€ per visit = 1.362.070€

So thanks to Google and the procrastination will of the workers the total cost of the buckminsterfullerene's celebration could be 1,3 Million euro.

Of course I'm just kidding ;)