Small advanced robot

This robot will be a test bed for the Arduino Pro and sensors. Using the Accelerometer as a tilt sensor for the base the small robot will be less likely to tip over. Also, using the front bottom IR sensor will detect drops. This, however, may need to be extended out. I will most likely be adding on a second Arduino pro stacked on the first so I can test how well parallel processors will do on such a robot.

A simple sketch (not quite to scale)

http://i155.photobucket.com/albums/s291/ollopat/DSC00491-1.jpg

parts list
3 Standard servo’s: 2 Continuous rotation versions
1 Arduino Pro
1 ADXL330 Accelerometer
2 GP2D12 IR Sensors
2 2.75 inch Foam wheels
1 5v PsP Backup Battery
1 Small piece of acrylic
1 small Castor
1 metal tube
1 small breadboard

Work done so far (Wired up power and five General purpose i/o lines up. As well as soldered the accelerometer straight to the board)

http://i155.photobucket.com/albums/s291/ollopat/DSC00488-1.jpg

Programing the Arduino Pro though USB

http://i155.photobucket.com/albums/s291/ollopat/DSC00493-1.jpg

Simple Code for raw data from Accelerometer

[code]int groundpin = 18; // analog input pin 4
int powerpin = 19; // analog input pin 5
int xpin = 3; // x-axis of the accelerometer
int ypin = 2; // y-axis
int zpin = 1; // z-axis (only on 3-axis models)

void setup()
{
Serial.begin(9600);

pinMode(groundpin, OUTPUT);
pinMode(powerpin, OUTPUT);
digitalWrite(groundpin, LOW);
digitalWrite(powerpin, HIGH);
}

void loop()
{
Serial.print(analogRead(xpin));
Serial.print(" “);
Serial.print(analogRead(ypin));
Serial.print(” ");
Serial.print(analogRead(zpin));
Serial.println();
delay(1000);
}
[/code]

Hi DocDoc,

Interesting project! What is going to be the main purpose of your bot? I like the “Da Vinciâ€

Thanks for the reply Xan

The main purpose is to create a cheap but advanced mobile robot to experiment with complex sensors, like the accelerometer, and to start up the long road of parallel processing by using more then one Arduino to run a single robot. One may handle sensors and movement and the other may run simple AI or learning code.

The head will be able to pan left and right to look for a more open area to advance forward. I believe the height is important for the sensors to get a better look the surroundings.

If the robot runs over any objects and the body tilts too far the robot will detect it with the accelerometer and try to get off the angle before the robot tips over and is unable to get back up.

Here is a better sketch then before this one showing a different location for the second IR sensor and two Arduino Pro’s.

http://i155.photobucket.com/albums/s291/ollopat/DSC00504-1.jpg

DocDoc

Here is a few pictures of stacking the Arduino pro’s using headers

http://i155.photobucket.com/albums/s291/ollopat/DSC00511-1.jpg

http://i155.photobucket.com/albums/s291/ollopat/DSC00513-1.jpg

Also the head finished with the IR sensor mounted.

http://i155.photobucket.com/albums/s291/ollopat/DSC00519-1.jpg

It will be a while till my next update I need to get some servo’s ordered.
Comments are always welcome on changes or questions about the project.

DocDoc

Hi DocDoc,

I think that the “headâ€

Great sketches. I appreciate the photos showing the progress, it’s very interesting. I can’t help but think WALL-E when I see the design.

Xan Thanks for the reply

There is no real need for the three lines like you say it’s just the stacking of the two Arduino’s worked out better with a connection bigger than one or two as far as structure is concerned, :slight_smile: And since I have three I may be able to use them in different ways as, one being as you said:

Which gives me enough control for this size of robot

  1. Forward
  2. Backward
  3. Spin left
  4. Spin right
  5. Sleep
  6. Error
  7. undecided
  8. undecided

DocDoc

Got around to putting the head on a servo I had lying around here are a few of the pictures to show the progress.

I used a small rod of aluminum, Epoxy, and 3 servo horns for the entire assembly and I’m very happy with the results.

I also added a very small piece of acrylic which as of now is my test stand but later will become the robot base.

Bottom:
http://i155.photobucket.com/albums/s291/ollopat/DSC00541-1.jpg

Top:
http://i155.photobucket.com/albums/s291/ollopat/DSC00543-2.jpg

Entire assembly:
http://i155.photobucket.com/albums/s291/ollopat/DSC00565-1.jpg

Here is a small section of code to test the neck servo which simply tells the servo to go to its two extents and the to center.

[code]int servoPinL = 12; // Control pin for the neck servo
int pulseL = 1500; // Amount to pulse the servoL
int delayValueMax = 20000; // the 2 millisecond maxiumum pulse range for the servo
int delayValue = 20000; // the actual value the code should wait, determined later

void setup()
{
pinMode(servoPinL, OUTPUT); // Set servo pin as an output
pulseL = 1500; // Set the motor position values to the minimum high is 2250 low is 750
}

void loop()
{
center();
delay (3000);
left();
delay (3000);
right();
delay (3000);
}

void right()
{
pulseL = 2250;
for (int i=0; i <= 40; i++){
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
i;
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}
}

void left()
{
pulseL = 750;
for (int i=0; i <= 40; i++){
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
i;
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}
}

void center()
{
pulseL = 1500;
for (int i=0; i <= 40; i++){
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
i;
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}
}
[/code]

DocDoc

Hi,

Compliments on the mounting of the rod. 8) How is the stability of the head? I think that it will get more solid if you add some weight (read servos for the wheels) on the body so that will be fine.

I quickly looked at your code and I have to say that normally I’m not so happy with delays in (for) loops. I don’t know much about your uC but I think it isn’t multi threaded. This means that if the uC is in such loop it can’t do anything else. To solve this you should use the main loop and add a delay in there.

Example :
take one counter from 0 to 900 and let it loop.
If the counter is between 0 and 299 go left
If the counter is between 300 and 599 go center
If the counter is between 600 and 900 go right
If this goes to fast add a bigger pause in the main loop. You will need to decrease this pause as your code gets bigger and bigger…

Ps. If you want to start in the center, you could initialize the counter to 300 :wink:

Xan

The head is stable enough for the moment I used servo tape which is very strong tape. I do believe the same as you that the true strength relies in the two servo’s adjacent to the center servo.

You are right the processors I’m using are not multi threaded. I tried the counter suggestion the new program does work well, also It will also be nice not to take up precious micro processing time on just one servo.

Thanks Xan for your help

Here is the revised code:

[code]int servoPinL = 12; // Control pin for the neck servo
int pulseL = 1500; // Amount to pulse the servoL
int delayValueMax = 20000; // the 2 millisecond maxiumum pulse range for the servo
int delayValue = 20000; // the actual value the code should wait, determined later

void setup()
{
pinMode(servoPinL, OUTPUT); // Set servo pin as an output
pulseL = 1500; // Set the motor position values to the minimum high is 2250 low is 750
}

void loop()
{
for (int counter=0; counter < 900;counter++){

if(counter > -1 && counter < 300)
center ();
if(counter > 299 && counter < 600)
left ();
if(counter > 599 && counter < 901)
right ();
}
}

void right()
{
pulseL = 2250;
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}

void left()
{
pulseL = 750;
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}

void center()
{
pulseL = 1500;
digitalWrite(servoPinL, HIGH); // Turn the L motor on
delayMicroseconds(pulseL); // Length of the pulse sets the motor position
digitalWrite(servoPinL, LOW); // Turn the L motor off
delayValue = delayValueMax - pulseL ;
delayMicroseconds (delayValue);
}
[/code]

DocDoc

Hi DocDoc,

I’ve looked at your code and was amazed how you managed to get the same result with a total new subroute! :smiley:

Let me explain it:

[code] void loop()
{
//Do calculations…

for (int counter=0; counter < 900;counter++){

if(counter > -1 && counter < 300)
center ();
if(counter > 299 && counter < 600)
left ();
if(counter > 599 && counter < 901)
right ();
}[/code]
You’ve got your main loop. Where you can do all your calculations. Then you enter the for loop, do a total scan of the head (left, middle, right) and return to your calculations. This means that you do your calculations one every 900 counts. This could be enough for the application but it can be much better!

The first thing I’ve learned programming single threaded applications is avoid loops! BlackWido has got only one loop, the main one :wink:

You can improve your main sub by making something like this:

[code] counter = 0
void loop()
{
//Do calculations…

//Drive servo
if(counter = 300)
center ();
if(counter = 600)
left ();
if(counter = 900)
right ();

//Update counter
If(counter < 900)
Counter ++
Else
Counter = 0

//Add a small delay from just a few ms if this goes to fast

}[/code]
Can you see the difference by using the main loop as counter? Now you do your calculations EVER count! A small difference of 900 :wink:

There is another part of your code that could use some improvement. If you look at one of your subroutes:

void right() { pulseL = 2250; digitalWrite(servoPinL, HIGH); // Turn the L motor on delayMicroseconds(pulseL); // Length of the pulse sets the motor position digitalWrite(servoPinL, LOW); // Turn the L motor off delayValue = delayValueMax - pulseL ; delayMicroseconds (delayValue); }
This code shows 2 delays. The first one gives a delay of 2250 ms and the second one 20.000 ms. This means that this little sub will cause your processor to sleep for more then 22sec!

The second thing I’ve learned is to avoid sleeps! If the processor is sleeping it doesn’t do anything else. It is better to give him some sort of “timeâ€

Thank you agian for finding area’s in my code that need improvement it has lead me too the most complete code yet, well actually I found a library of code that helps myself control servo’s :smiley:

There is a very good explanation of it here arduino.cc/playground/ComponentLib/Servo

I also took your counter to help with the neck servo positioning below is the most simplified code I could come up with.

[code]#include <Servo.h>
Servo servo1;
int counter = 0;

void setup()
{
servo1.attach(17); //Anolog pin 3
servo1.setMaximumPulse(2250);
servo1.setMinimumPulse(750);
}

void loop()
{
//Drive servo
if(counter > 280 && counter < 300)
center ();
if(counter > 580 && counter < 600)
left ();
if(counter > 880 && counter < 900)
right ();

//Update counter
if(counter < 900)
{
counter ++;
}
else
{
counter = 0;
}

//Add a small delay for just a few ms if this goes to fast
delayMicroseconds (4000);
Servo::refresh();
}

void left()
{
servo1.write (0);
}

void right()
{
servo1.write (180);
}

void center()
{
servo1.write (100);
}

[/code]

DocDoc

Nice work! This sure is a big improvement! I haven’t got any improvements for this part of the code. I don’t know why you use a counter range instead of a single value to drive the servo to a certain position but I’m sure you’ve got a good reason for that though. :wink:

Nice found about the library!

Xan

hehe

Its been a while since I was working on this project.

Work and School/ Eve online hehe

Xan If i remember correctly I put a counter range in so that the servo would not only go to the commanded scan points but to also have a slight pause so the IR sensor can keep up (take multiple readings and Avg them) and for effect.

The library has been very good find and I’m onto other sections of the main code I will try to upload some soon…

DocDoc

Hi DocDoc,

I know exactly what you’re talking about. It’s always a challenge to combine normal life with this time consuming hobby. :wink:

Now the range makes sense 8)

Looking forward to see your progress.

Xan

Ok so I went online to finish buying all the parts that I want and came across a few extra sensors I liked along the way. :smiley:

Updated parts list
3 Hitec HS-475HB (76 oz. in.) Standard Servo’s; two modified for continuous rotation
2 Arduino’s Pro found at www.sparkfun.com
1 FTDI FT232RL USB to program the microprocessors
1 Logic Level Converter for 5v to 3.3v
1 ADXL330 Accelerometer
2 GP2D12 IR Sensors
1 Servo Tire and Wheel - 2.63" x 0.35" (pair) found at www.lynxmotion.com
1 line “Tracker Sensor” also found at www.lynxmotion.com
1 MLX90614 Infra Red Thermometer Module (90° FOV) (Cant wait for this one to get here :smiley:) found at www.parallax.com
1 Ping))) sensor ultrasonic sensor also found at www.parallax.com
1 ServoPAL (think really small 2 servo controler) also found at www.parallax.com
1 5v PsP Backup Battery
1 Small piece of acrylic
1 small Castor
1 metal tube
1 small breadboard

Sorry no pics yet still waiting on all the parts to arrive…
But never fear I have a new section of code for reading the Infra Red Thermometer 8)

This simple code uses Peter Fleurys libray here:

homepage.hispeed.ch/peterfleury/ … tware.html

Scroll down and download the i2c master libraries. Create a folder in /{arduino root}/hardware/libraries and copy the
(i2cmaster.h and twimaster.c).

You need to change the .c file to .cpp (otherwise it won’t link when compiling) and don’t forget to change some of the values
in the .h and .c file depending on your mcu etc.

Hehe the original coding I found only converted to degrees C so I added a line for degrees F

[code]//Simple program to read data from the MLX90614 infra Red Therm sensor convert from degrees
//kelvin to degrees C then degress F and print to serial port.

#include <i2cmaster.h>

void setup()
{
Serial.begin(9600);
i2c_init(); //Initialise the i2c bus

}

void loop()
{
int dev = 0x5A<<1; //Address must be bit shifted left, library does not automatically do it
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev+I2C_WRITE); //send start condition and write bit
i2c_write(0x07); //send command for device to action

i2c_rep_start(dev+I2C_READ); //send repeated start condition, device will ack
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak(); //Read error check byte and send Nack to tell device no more data to send
i2c_stop(); //Release bus, end transaction

//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
double tempFactor = 0.02; // 0.02 degrees per LSB
int tempData = 0x0000;

// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (int)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
tempData = tempData - 273.15; // Convert Kelvin to Celcius
tempData = (tempData * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
Serial.println(tempData); //Print temp in degrees F to serial
delay(1000);
}[/code]

Well I’m on to try to think what I want the robot to do I was thinking of having as my all around desktop robot pet. :wink:
Were he would be in sleep mode most of the time and wake up when the IR sensor was changed then proceed to start-up, check the main battery and the area by scanning for a heat signature and start roaming around the desk… Any ideas of what else It could do please write. I also may have to go with a third Arduino processor soon… Oh almost forgot I found the wire that I’m using is too small and breaks easy so I’m going to switch out all the wires and use epoxy to secure the connections.

docdoc

Well here are some updated pictures showing a few different improvements to the last pictures.

First being I added a buzzer to the first level Arduino which is clear to see in Fig 1. I also hardwired the I.R. sensor and power for the accelerometer to the first level as well.
Before I was wasting two analog inputs to power the Accelerometer so it has freed up those for the IR and a voltage divider circuit built under that level to monitor the main battery voltage.
Also rewired all of it with stronger wire and epoxied wire breaking points for added durability.
There is now a hardwired break-out board for power and sensors (I fried one of my servo’s by hooking it up backwards in the breadboard :frowning: ).

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01413-1.jpgFig 1

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01412.jpgFig 2

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01414-1.jpgFig 3
I think the wire harness adds a nice touch…

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01416-1.jpgFig 4

More “not quite finished” code section for monitoring the main battery and beeping when it gets low. :smiley:

[code]// function to print the voltage on the given pin to the serial port
// the pin should be an analog port that has two 6.7k resistors
// connected as a voltage divider to a 6 volt battery
// CAUTION, the voltage on the pin must not exceed 3 volts
int Voltage = 5; // select the pin for the voltage divider
int posbuz = 5; // positive side Buzzer connected to digital pin 5
int negbuz = 4; // negetive side Buzzer connected to digital pin 4

void setup()
{
Serial.begin(9600);
pinMode(Voltage, INPUT);
pinMode(posbuz, OUTPUT); // sets the digital pin as output
pinMode(negbuz, OUTPUT); // sets the digital pin as output
digitalWrite(posbuz, LOW); // makes sure the Buzzer to off
digitalWrite(negbuz, LOW); // makes sure the Buzzer neg is on

}

void loop()

{
int value = analogRead(Voltage);
Serial.print(“voltage is: “);
Serial.print(value / 160,DEC); // print the integer value of volts
Serial.print(”.”); // decimal point
Serial.println(value % 103,DEC); // hundredths of a volt
value = value - 160; //value of volts
if (value < 4)
{
digitalWrite(posbuz, HIGH); // makes sure the Buzzer to on
delay(1000); // waits for 1 seconds
digitalWrite(posbuz, LOW); // makes sure the Buzzer to off
delay(1000); // waits for 1 seconds
digitalWrite(posbuz, HIGH); // makes sure the Buzzer to on
delay(1000); // waits for 1 seconds
digitalWrite(posbuz, LOW); // makes sure the Buzzer to off
delay(1000); // waits for 1 seconds
digitalWrite(posbuz, HIGH); // makes sure the Buzzer to on
delay(1000); // waits for seconds
digitalWrite(posbuz, LOW); // makes sure the Buzzer to off
delay(30000); // waits for 30 seconds
}
}

[/code]

All and all I think this project is coming together well…

Still waiting on parts to arrive… :frowning:

docdoc

Woooh :smiley: got my parts it here is a few pics from construction

I damaged the base when i decided that would be a good place for a hole for the wires from the bottom of the bot. (I was wrong lol) :frowning:

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01431.jpg
Hole drill FAIL… :frowning:

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01436.jpg
Stealing a little bit of silicone grease from the servo to use on the castor so it will spin more smoothly 8)

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01428-1.jpg
almost done…

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01439.jpg
Added the line/edge detector to the bottom of the servo’s by using 5min epoxy and two female header strips.

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01438.jpg
View of the edge detector working…

http://i248.photobucket.com/albums/gg194/DoCDoC_2008/DSC01446.jpg
(Under the hood shot)
Needed more I/O brought down to the breakout board.

More to come questions or comments welcome :smiley:

docdoc