Showing posts with label Technology. Show all posts
Showing posts with label Technology. Show all posts

Sunday, October 30, 2011

3

CLEVERBOT: 59% HUMAN

Cleverbot is an Artificial Intelligence conversation system specially designed to learn from the conversations that it has with other people trying to mimic the human behavior in a conversation.



To find out the level of intelligence of this kind of artificial entities the archi-famous mathematician Alan Turing proposed in 1950 the Turing Test .  Basically, a human judge engages in a natural language conversation with a human and a machine designed to generate performance indistinguishable from that of a human being. All participants are separated from one another. If the judge cannot reliably tell the machine from the human, the machine is said to have passed the test.

Every year the Turing Test  takes place, this year was celebrated on September 3rd at Techniche 2011, IIT Guwahati, India. In this scenario, several human judges had 5 minutes conversations with another entity (they ignored whether the entity was human or not). Some people believe that if 50% of the judges classify the entity they are talking to as human when in reality it is a machine, then the machine has passed the test. 

This year Cleverbot was classified as human 59% of the times and people might say it passed the Turing Test, but we humans still have hope... humans where classified as humans 63% of the time. I will start getting scared when Cleverbot is classified more often as a human than real humans xD

Anyway, it is fun to talk to Cleverbot, you really have to try it! How? You can do it right here! Just enter some text in the text bar above and hit the "Think About It!" button. Have fun!!

EDIT [2011/11/14]: I removed the widget to talk to Cleverbot directly because it was causing undesired behavior on the website. You can still talk to it by clicking on its logo and visiting Cleverbot's homepage.

Thursday, July 28, 2011

1

SMARTBIRD: A ROBOT THAT FLIES LIKE A BIRD

Today I came across a video of a tech talk at TED conference where a guy, working for the German automation company Festo, presented an astonishing development: A robot that flies like a real bird




Enjoy the video.

Monday, May 30, 2011

11

LIBSSC32: ARDUINO + SSC32

Today I would like to share a library for Arduino that makes it easy to control a SSC32.

But, what is a SSC32?
The SSC32 is a Serial Servo Controller, capable of controlling up to 32 servo motors at a time. Very useful in robotic projects such as arms or humanoids.


You can buy it at http://www.lynxmotion.com for about $40.  The thing about this piece of hardware is that it is very flexible. It is not only a servo controller, it also provides some pins where you can connect sensors and read  its values. And the most useful of its features (in my humble opinion) is that you can specify a group of servos, set each servo inside the group to move to a different location and specify how long will it take for all the servos to finish the movement. It doesn't matter if each servo is far or near its final location, SSC32 will calculate and apply the speed for each servo so all them finish at the same time!! 

This is very powerful to create complex movements. And they will be performed smoothly

Lets get down to business.
In my case, I am using the SSC32 to control an arm with 6 servos (more about this in future posts)  and I thought it would be nice to be able to command it from an Arduino.


The only "problem" is that the serial protocol defined by the SSC32 is a bit "uncomfortable" to handle, so I created a class to handle it and make it a bit more comfortable.

You can find the library for Arduino here (decompress it inside the "libraries" folder of your arduino environment):




And here is an example of how to use the library:

#include <SSC32.h>

/*
  Tests the SSC32 library. By Martin Peris (http://www.martinperis.com)
  This example code is in the public domain.
 */

SSC32 myssc = SSC32();

void setup() {


  //Start comunications with the SSC32 device  
  myssc.begin(9600);



}

void loop() {

  //Move motor 0 to position 750
  //The first command should not define any speed or time, is used as initialization by SSC32
  myssc.servoMove(0,750);

  delay(1000);

  //Move motor 1 to position 750
  //The first command should not define any speed or time, is used as initialization by SSC32
  myssc.servoMove(1,750);

  delay(1000);

  //Move motor 0 to position 1500. It will take 5 seconds to finish the movement.
  myssc.servoMoveTime(0,1500,5000);

  delay(5500);

  //Move motor 1 to position 900. It will take 5 seconds to finish the movement
  myssc.servoMoveTime(1,900,5000);

  //Move both servos to position 750 at the same time. 
  //The movement will take 5 seconds to complete
  //Notice that currently motor 0 is at position 1500 and motor 1 is at position 900,
  //but they will reach position 750 at the same time
  myssc.beginGroupCommand(SSC32_CMDGRP_TYPE_SERVO_MOVEMENT);
  myssc.servoMoveTime(1,750,5000);
  myssc.servoMoveTime(5,750,5000);
  myssc.endGroupCommand();

  delay(5500);

}



[EDIT 2011/11/24]: The library has been adapted to the new version of arduino's IDE. Thanks to Marco Schwarz.

Monday, April 11, 2011

0

ARDUINO + WIICHUCK

Lately I have been playing around with a WiiChuck connected to an Arduino. I bought an adapter to connect the WiiChuck to the arduino and downloaded the source code from the arduino playground, by Tim Hirzel.


I compiled the example and uploaded it to the arduino, but there was no response from the Wiichuck. The example was supposed to print all the data coming from the Wiichuck on the serial port, but it was not working.

I found the solution in this forum. The problem was that you need to define the "Power" and "Gnd" pins for the Wiichuck in order to power it up. So here is the modified WiiChuckClass:

/*
 * Nunchuck -- Use a Wii Nunchuck
 * Tim Hirzel http://www.growdown.com
 * 
 notes on Wii Nunchuck Behavior.
 This library provides an improved derivation of rotation angles from the nunchuck accelerometer data.
 The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data
 from teh combination of the x and z axis accelerometer data using the math library atan2. 

 It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii),
 and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii).  (read more below)

 In terms of mapping the wii position to angles, its important to note that while the Nunchuck
 sense Pitch, and Roll, it does not sense Yaw, or the compass direction.  This creates an important
 disparity where the nunchuck only works within one hemisphere.  At a result, when the pitch values are 
 less than about 10, and greater than about 170, the Roll data gets very unstable.  essentially, the roll
 data flips over 180 degrees very quickly.   To understand this property better, rotate the wii around the
 axis of the joystick.  You see the sensor data stays constant (with noise).  Because of this, it cant know
 the difference between arriving upside via 180 degree Roll, or 180 degree pitch.  It just assumes its always
 180 roll.


 * 
 * This file is an adaptation of the code by these authors:
 * Tod E. Kurt, http://todbot.com/blog/
 *
 * The Wii Nunchuck reading code is taken from Windmeadow Labs
 * http://www.windmeadow.com/node/42


 * Modified by Martin Peris, http://blog.martinperis.com to declare which are the power pins
 * for the wiichuck, otherwise it will not be powered up
 */

#ifndef WiiChuck_h
#define WiiChuck_h

#include "WProgram.h"
#include <Wire.h>
#include <math.h>


// these may need to be adjusted for each nunchuck for calibration
#define ZEROX 510  
#define ZEROY 490
#define ZEROZ 460
#define RADIUS 210  // probably pretty universal

#define DEFAULT_ZERO_JOY_X 124
#define DEFAULT_ZERO_JOY_Y 132

//Set the power pins for the wiichuck, otherwise it will not be powered up
#define pwrpin PORTC3
#define gndpin PORTC2


class WiiChuck {
    private:
        byte cnt;
        uint8_t status[6];              // array to store wiichuck output
        byte averageCounter;
        //int accelArray[3][AVERAGE_N];  // X,Y,Z
        int i;
        int total;
        uint8_t zeroJoyX;   // these are about where mine are
        uint8_t zeroJoyY; // use calibrateJoy when the stick is at zero to correct
        int lastJoyX;
        int lastJoyY;
        int angles[3];

        boolean lastZ, lastC;


    public:

        byte joyX;
        byte joyY;
        boolean buttonZ;
        boolean buttonC;
        void begin()
        {
            //Set power pinds
            DDRC |= _BV(pwrpin) | _BV(gndpin);

            PORTC &=~ _BV(gndpin);

            PORTC |=  _BV(pwrpin);

            delay(100);  // wait for things to stabilize   


            //send initialization handshake
            Wire.begin();
            cnt = 0;
            averageCounter = 0;
            Wire.beginTransmission (0x52);      // transmit to device 0x52
            Wire.send (0x40);           // sends memory address
            Wire.send (0x00);           // sends memory address
            Wire.endTransmission ();    // stop transmitting
            update();
            for (i = 0; i<3;i++) {
                angles[i] = 0;
            }
            zeroJoyX = DEFAULT_ZERO_JOY_X;
            zeroJoyY = DEFAULT_ZERO_JOY_Y;
        }


        void calibrateJoy() {
            zeroJoyX = joyX;
            zeroJoyY = joyY;
        }

        void update() {

            Wire.requestFrom (0x52, 6); // request data from nunchuck
            while (Wire.available ()) {
                // receive byte as an integer
                status[cnt] = _nunchuk_decode_byte (Wire.receive()); //
                cnt++;
            }
            if (cnt > 5) {
                lastZ = buttonZ;
                lastC = buttonC;
                lastJoyX = readJoyX();
                lastJoyY = readJoyY();
                //averageCounter ++;
                //if (averageCounter >= AVERAGE_N)
                //    averageCounter = 0;

                cnt = 0;
                joyX = (status[0]);
                joyY = (status[1]);
                for (i = 0; i < 3; i++)
                    //accelArray[i][averageCounter] = ((int)status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2))); 
                    angles[i] = (status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2)));

                //accelYArray[averageCounter] = ((int)status[3] << 2) + ((status[5] & B00110000) >> 4); 
                //accelZArray[averageCounter] = ((int)status[4] << 2) + ((status[5] & B11000000) >> 6); 

                buttonZ = !( status[5] & B00000001);
                buttonC = !((status[5] & B00000010) >> 1);
                _send_zero(); // send the request for next bytes

            }
        }


    // UNCOMMENT FOR DEBUGGING
    //byte * getStatus() {
    //    return status;
    //}

    float readAccelX() {
       // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[0] - ZEROX;
    }
    float readAccelY() {
        // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[1] - ZEROY;
    }
    float readAccelZ() {
        // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT;
        return (float)angles[2] - ZEROZ;
    }

    boolean zPressed() {
        return (buttonZ && ! lastZ);
    }
    boolean cPressed() {
        return (buttonC && ! lastC);
    }

    // for using the joystick like a directional button
    boolean rightJoy(int thresh=60) {
        return (readJoyX() > thresh and lastJoyX <= thresh);
    }

    // for using the joystick like a directional button
    boolean leftJoy(int thresh=60) {
        return (readJoyX() < -thresh and lastJoyX >= -thresh);
    }


    int readJoyX() {
        return (int) joyX - zeroJoyX;
    }

    int readJoyY() {
        return (int)joyY - zeroJoyY;
    }


    // R, the radius, generally hovers around 210 (at least it does with mine)
   // int R() {
   //     return sqrt(readAccelX() * readAccelX() +readAccelY() * readAccelY() + readAccelZ() * readAccelZ());  
   // }


    // returns roll degrees
    int readRoll() {
        return (int)(atan2(readAccelX(),readAccelZ())/ M_PI * 180.0);
    }

    // returns pitch in degrees
    int readPitch() {
        return (int) (acos(readAccelY()/RADIUS)/ M_PI * 180.0);  // optionally swap 'RADIUS' for 'R()'
    }

    private:
        byte _nunchuk_decode_byte (byte x)
        {
            x = (x ^ 0x17) + 0x17;
            return x;
        }

        void _send_zero()
        {
            Wire.beginTransmission (0x52);      // transmit to device 0x52
            Wire.send (0x00);           // sends one byte
            Wire.endTransmission ();    // stop transmitting
        }

};


#endif


Works like a charm for me :)

Wednesday, March 2, 2011

0

ARDUINO NIGHT RIDER

Today I would like to share an idea that I had some time ago. Since I came to Tsukuba I've met  a lot of nice people, one of them is my good friend Rob Howland. You see, he is a skater. And he loves going around in his skate, sometimes even late at night.

The problem is that the area where we live is kind of dark at night and sometimes you don't even see the road. Not to mention the potential danger of cars not being able to see you.


So, that is why I designed the prototype board for the "Arduino Night Rider":



It will have 30 LEDs, 24 of which will be blue, they will be placed surrounding the skate and used to make cool effects. There will be a white one in the front (I sketched it as a single white LED, but it will be a group of white leds so it can light up the way in front of you), this led will be always on. 

There will be a red LED at the back that will continously blink (like in F1 cars) so you will be easily noticed from behind. There will be 4 yellow leds, one on each corner of the skate and will be used as "direction lights".

3 Tilt sensors will be placed along the skate, two of them will sense which direction you are turning when you turn (left or right) and if you turn left then the 2 yellow leds placed on the left side will blink. The same for the right side when you turn right. 

The last tilt sensor will sense when you raise up the skate and triggers some cool stuff with the blue leds.

The electronics is quite simple and program the arduino would take me a couple of afternoons but I think the most difficult part will be to make it "look professional" 

I don't know if we will have the time, but it would be very cool if we finally do this :) 

Tuesday, December 21, 2010

2

KINECT: HELLO WORLD


The first shot taken with Microsoft Kinect. Thanks a lot to Fukui-sensei for providing such a nice tool.

Sunday, November 28, 2010

2

MICROSOFT KINECT FOR ROBOTIC APPLICATIONS

In the last few days Kinect, a product developed by Microsoft and oriented to the gaming industry, has been making quite an impression in the robotic world. 


This device was announced by Microsoft as the gadget that would change the history of the gaming industry. Well, I don't know if that would be true. Only time will tell. But, on the way, they created a tool with practically endless possibilities for robotic applications. I wonder if Microsoft saw it coming...

But, what makes it so appealing for robotics?

The device offers a RGB camera and an IR camera with a frame size of 640x480 pixels and a frame rate of 30FPS. But the really interesting feature is its  Depth camera. This depth camera enables to build a 3D view of the environment surrounding the Kinect, which allows many applications in robotics. 

Here is an example:




Another very interesting fact is its price: around $199. The price of other similar sensors is at least 10 times more expensive, for example the price of a Point Grey Bumblebee2 stereo camera is around $1900. Not everyone can afford to spend almost $2000 in a sensor, but almost every hobbyist can buy a Kinect (and when you get tired of playing with your robot you can use it to play with XBOX too :P)

Of course, a lot of people quickly realized the immense potential of this device and several initiatives appeared to build an Open Source driver that enabled people to use Kinect on a PC.  Being OpenKinect one of the most active projects at the moment.

Recently, the people at ROS (Robot Operating System) integrated OpenKinect on his system and as a result now anyone using ROS can easily take advantage of Kinect:



As long as Kinect is a device engineered to be used on indoor environments its behavior on outdoor environments can be predictably poor. And as you can see on the experiment carried out by the researchers at  Meiji University's AMSL Racing group the results outdoors in a sunny environment is quite poor, but the result in a shady environment is not too bad, though.



If I were Microsoft I would integrate Kinect into Microsoft Robotic Developer Studio right away.

Tuesday, November 16, 2010

0

HRP2 PROMET: MADE IN JAPAN

Today I visited AIST JRL (Advance Institute of Science and Technology - Joint Japanese-French Robot Laboratory) where my fellow Pablo F. Alcantarilla and his supervisor, Dr. Olivier Stasse, kindly introduced me to this guy:


Its name is HRP2 Promet, a 1.6 meters tall, state of the art, humanoid robot. It was built by Kawada Industries, Inc and is used at AIST as a research platform. I had seen this robot on the internet before but nothing compared to seeing it in action in real life.

During the visit the robot performed several demos, including walking in a constrained environment (see next picture) and moving to a goal position by using Computer Vision.


On that same laboratory they are developing HRP4-C, the little sister of HRP2. As she is the youngest in the family she wants to be an artist, but unfortunately I have no pictures of HRP4-C, they still keep it under a lot of secrecy. But you can see this video taken at "Digital Contents Expo 2010":




 Any way, meeting HRP2 was fascinating.

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!

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

Tuesday, August 31, 2010

0

DO NOT REINVENT THE WHEEL!

Sometimes when you work in a complex robotic project you face the question: Should I build myself a certain part or should I buy a manufactured one?

Recently I faced that question, the robot ITINERA needs a new circuit to control 2 DC motors because the old one is malfunctioning. Then it came to my mind that some years ago I implemented such a circuit by using a self-made PCB board,  an L298 integrated circuit and some other components (diodes, resistors, etc...)



So now I could build it again and use it, but lets think about it... if I buy all the components I would spend about 15€ and it would take me about 2 hours to build it. Time is money, so if we translate two hours of work into money, lets say that is equivalent to 40€. In total: 55€ (Not taking into account the time spent going to the store and getting the components)

In the other hand, performing a quick search on Internet you can find products matching your needs. In my case an  L298 h-bridge with a price of 12,42€


I think, in this case, the answer to the question raised at the beginning of this post is pretty clear: Do not reinvent the wheel!!! 

By the way, the circuit in the last picture is the one that will replace the faulty motor controller of ITINERA.