Me and my Quadrabot

First of all, hi to all.

By way of introduction;

I had dreamed of building a robot for years and years. 18 months ago on the 9th of June 2010 I found out about Arduino and fell in love. I had not done electronics or computer programming before. The most I'd done was 3D modelling on the computer (and that's just a professional hobby). This is not the sum-total of a year's worth of dedicated work. I am 32, I have a full-time job (working swing shift), I'm dating a wonderful and understanding lady (for over a year now), I spend time with my kids and I do all the other things that people generally do in life.

Here is my robot that Im making, and started making using an Arduino Duemilanove:

and

I then downsized the brain to an Arduino Pro Mini (3.3V, 8 MHz) w/ ATmega328:

I also mounted the batteries on top.

To give you some idea of what this is, is it's a four-legged, autonomous robot.
Each leg has three servos, giving them 3 degrees of freedom.
It has one sensor, an EZ0 Ultrasonic sensor on the front for obstacle avoidance.

The programming is set up with several components:

  • Stand
  • StandtoForward
  • Forward
  • ForwardtoStand
  • RotateLeft

Because I only have one sensor, once I turn it on, it starts in Forward mode.
It then walks forward until it meets an object.
It then stands, then rotates left, approximately 90 degrees.
Then it either continues walking, or if there is an object in the way it rotates left again.

There is not much code in this robot. It's just repetitive because of the way I have set the robots movements. I have posted the main part of the code, but I haven't entered all the movements because they are just repetitions of servo.write(x), but I've included the Stand component.

Please note that I am in the process of reducing the code (currently sitting at around 500 lines). I intend on putting all the components into arrays to keep it tidy.

#include <Servo.h> 
Servo myservo2;
Servo myservo3;
Servo myservo4;

Servo myservo5;
Servo myservo6;
Servo myservo7;

Servo myservo8;
Servo myservo9;
Servo myservo10;

Servo myservo11;
Servo myservo12;
Servo myservo13;

int pause = 300;
int sensorValue;
int f=0;
int rl=0;

void setup() 
{
  pinMode(0, OUTPUT);

  myservo2.attach(2); //tip blue
  myservo3.attach(3);
  myservo4.attach(4);

  myservo5.attach(5);
  myservo6.attach(6);
  myservo7.attach(7); //tip red

  myservo8.attach(8); //tip green
  myservo9.attach(9);
  myservo10.attach(10);

  myservo11.attach(11);
  myservo12.attach(12);
  myservo13.attach(13); //tip yellow
} 

void loop() 
{  
  sensorValue = analogRead(A0);   
  Serial.print(sensorValue);
  Serial.println(); 

  if (sensorValue > 20) //if far from object
  {
    if (f==1){
      doForward();
    }
    else
      if (f==0){
        doStandtoForward(); 
        f=1;
      } 
  }
  else 
  {
    if(f==1) {
      doForwardtoStand();
      f=0;
    }
    else
      if (f==0) 
      {
        doStand();
        delay(pause);
        doRotateLeft();  
        doRotateLeft();
      }     
  }
} //void end

void doStand()
{
  myservo2.write(77); //tip blue
  myservo3.write(57);
  myservo4.write(90);

  myservo5.write(90);
  myservo6.write(123);
  myservo7.write(103); //tip red

  myservo8.write(77); //tip green
  myservo9.write(57);
  myservo10.write(90);

  myservo11.write(90);
  myservo12.write(123);
  myservo13.write(103); //tip yellow  
}

Just thought that I would add some more of what I've done tonight.

I am using a EZ0 UltraSonic sensor on an analog pin, but it was giving fluctuating readings

example over 20 readings on a stationary, surface mounted sensor:
79
83
78
79
79
79
79
79
79
79
79
79
79
79
79
79
79
79
78
79

The sensor is mounted on my robot, so it is subject to all sorts of shaking and other movement from itself, and any non-solid objects that might come in its way, (eg., a hand) so I wanted to determine a more accurate/stable reading.

I needed the reading at the start of each move and I wanted a fast reading so if the reading is taken between loops, of say the walking gait, that it would not appear to stop between each step.

So, like above I have taken a series of 20 readings all within a split second. I have then determined what the lowest number is and used that. (The lowest number is the most important, because if it gives a high reading and there is an object in the way, then it will continue to move).

Heres the code:

int sensorValue;
int g=20;
int average[20];

int i,j,val;

void setup() 
{
  pinMode(0, OUTPUT);
} 

void loop() 
{  
  sensorValue = analogRead(A0);   
  //Take g x readings and save them to sensorValue[]s
  for (i=0; i<=g-1; i++)
  {
    sensorValue = analogRead(A0);  
    average[i]=sensorValue;
  }

  //read readings and determine the lowest reading
  val=average[0];
  for (i=1; i<=g-1; i++)
  {
    if (average[i]<=average[i-1] && average[i]<=val) {
      val=average[i];
    }
  }
} //loop end

Hey - nice job! Now you just need to get it running faster, and chase after the pets! :smiley:

cr0sh:
Hey - nice job! Now you just need to get it running faster, and chase after the pets! :smiley:

Thanks for the comment :slight_smile:

Hahaha, just to attest to my persistence with my programming, I just spent an hour trying to find fault with my new lines of code and wondering why the servos weren't moving, when I had a look at the servos...well, they were unplugged.

Once plugged in, they worked perfectly! Good to see that at least my programming is sound; and I now have a greater confidence in my debugging ability :slight_smile:

Well today's been tiring and fruitful. I managed to re-code my program to use arrays to store the leg movements. I still have more tidy up to do though, because at the end of the code I have a lot of repetition. I have spend several hours already trying to work out how to reduce all the movement 'voids' into one void doMovement. I sure it will come to me eventually. Even so, I have reduced the code from 500 lines to 220 lines. The future slimming will reduce the code down by about 35 lines.

The only problem I am having though, is that the eleventh servo is not powering up. It works fine on the old code, but not with this code??? Could it be something wrong with 'arrays'? It's not the last servo on the array, and all the others appear to be working fine. Oh well, I guess I'll just have to try work it out.

#include <Servo.h> 
Servo myservo[12];
 
int pause = 300;
 int g=20;
 int average[20];
 int sensorValue;
 int f=0;
 int e,h,i,j,k;
 
int move;
 
//-------------------------------------------------
 int standcount=1;
 int stand[12][1]={
 { 77},
 { 57},
 { 90},
 { 90},
 {123},
 {103},
 { 77},
 { 57},
 { 90},
 { 90},
 {123},
 {103}
 };
 //-------------------------------------------------
 int forwardcount=8;
 int forward[12][8]={
 { 58, 51, 51, 51,109, 77, 77, 77},
 { 53, 53, 53, 0, 69, 57, 57, 57},
 { 72, 45, 45, 45,101, 90, 90, 90},
 { 79, 90, 90, 90,108,135,125,135},
 {111,123,123,123,127,126,126,182},
 { 71,103,103,103,122,129,129,129},
 {109, 51, 51, 51, 58, 77, 77, 77},
 { 69, 0, 53, 53, 53, 57, 57, 57},
 { 79,135,135,135,108, 90, 90, 90},
 { 72, 90, 90, 90,101, 45, 45, 45},
 {127,123,123,123,111,182,126,126},
 {122,103,103,103, 71,129,129,129}
 };
 //-------------------------------------------------
 int standtoforwardcount=3;
 int standtoforward[12][3]={
 { 77, 77, 77},
 { 57, 57 ,57},
 { 90, 90, 90},
 { 90, 90, 90},
 {123,123,168},
 {103,103,113},
 { 77, 77, 77},
 { 57, 57, 57},
 { 90, 90, 90},
 { 45, 45, 45},
 {182,126,126},
 {129,129,129}
 };
 //-------------------------------------------------
 int forwardtostandcount=2;
 int forwardtostand[12][2]={
 { 77, 77},
 { 57, 57},
 { 90, 90},
 { 90, 90},
 {123,123},
 {103,103},
 { 77, 77},
 { 57, 57},
 { 90, 90},
 { 45, 45},
 {126,182},
 {129,129}
 };
 //-------------------------------------------------
 int rotateleftcount=7;
 int rotateleft[12][7]={
 { 27, 88, 83, 83, 79, 79, 77},
 { 40, 61, 59, 59, 58, 58, 57},
 {135,136,123,123,109,109, 90},
 { 71, 71,123,123,109,109, 90},
 {122,122,153,121,122,122,123},
 {100,100,140, 97,100,100,103},
 { 75, 75, 83, 83, 88, 88, 27},
 { 58, 58, 59, 59, 61, 61, 40},
 { 79, 79, 57, 57, 44, 44, 90},
 { 71, 71, 57, 57,109,109, 90},
 {122,122,121,121,153,122,123},
 {100,100, 91, 91,140,101,103},
 };
 //-------------------------------------------------
 void setup() 
{
 pinMode(0, OUTPUT);
 
for (k=2; k<=13; k++)
 { 
myservo[k].attach(k);
 }
 } 
//-------------------------------------------------
 void loop() 
{ 
doSensor();
 
if (sensorValue > 20) //if far from object
 {
 if (f==1){
 doForward();
 }
 else
 if (f==0){
 doStandtoForward(); 
f=1;
 } 
}
 else 
{
 if(f==1) {
 doForwardtoStand();
 f=0;
 }
 else
 if (f==0) 
{
 doStand();
 delay(pause);
 doRotateLeft(); 
doRotateLeft();
 } 
}
 
} //loop end
 //-------------------------------------------------
 //Take 20 x readings and save them to sensorValue[]s
 void doSensor()
 { 
average[0] = analogRead(A0);

 for (i=1; i<9; i++)
 {
 sensorValue = analogRead(A0); 
average[i]=sensorValue;
 if (average[i]<=average[i-1] && average[i]<=sensorValue) 
{
 sensorValue=average[i];
 }}
 }
 //------------------------------------------------- 
void doForward()
 {
 for (h=0; h<forwardcount; h++)
 { 
for (e=0; e<12; e++)
 {
 move=forward[e][h];
 myservo[e+2].write(move);
 }
 delay(pause);
 }
 }
 //-------------------------------------------------
 void doStand()
 {
 for (h=0; h<standcount; h++)
 { 
for (e=0; e<12; e++)
 {
 move=stand[e][h];
 myservo[e+2].write(move);
 }
 delay(pause);
 }
 }
 //-------------------------------------------------
 void doStandtoForward()
 {
 for (h=0; h<standtoforwardcount; h++)
 { 
for (e=0; e<12; e++)
 {
 move=standtoforward[e][h];
 myservo[e+2].write(move);
 }
 delay(pause);
 }
 }
 //-------------------------------------------------
 void doForwardtoStand()
 {
 for (h=0; h<forwardtostandcount; h++)
 { 
for (e=0; e<12; e++)
 {
 move=forwardtostand[e][h];
 myservo[e+2].write(move);
 }
 delay(pause);
 }
 }
 //-------------------------------------------------
 void doRotateLeft()
 {
 for (h=0; h<rotateleftcount; h++)
 { 
for (e=0; e<12; e++)
 {
 move=rotateleft[e][h];
 myservo[e+2].write(move);
 }
 delay(pause);
 }
 }
 //-------------------------------------------------

Just a side note:

I just wrote a short program (the shortest Ive ever written) so my kids can play with three buttons attached to a tri-colour LED. In fact, I could have just dispensed with the Arduino and just attached it to a 5V battery.

void setup() 
{
 int i;
 for (i=11; i<=13; i++){
 pinMode(i, OUTPUT); 
 digitalWrite(i, HIGH);
 }
 }

 void loop()
 {
 }

For all those that want to follow a little closer I have set up a Facebook page:

http://www.facebook.com/home.php#!/pages/Quadrabot/246637268735818

Feel free to stop by and leave a comment.

I have spend several hours already trying to work out how to reduce all the movement 'voids' into one void doMovement.

Your skill level is probably about as high as it is going to get until you learn to speak the language correctly. There are not movement 'voids'. There are movement functions.

You're having some issues with your arrays that need addressing - you're using elements that you haven't declared, which will lead to unpredictable results. Such as, perhaps, servo eleven failing to function.

Your myservo array has twelve elements, numbered 0 to 11. Here you're using 12 and 13

for (k=2; k<=13; k++)
  { 
  myservo[k].attach(k);
 }

Similarly, here e varies between 0 and 11 (which is good) but myservo[e+2] hits our old friends myservo[12] and myservo[13] again.

for (e=0; e<12; e++)
  {
  move=forward[e][h];
  myservo[e+2].write(move);
  }

@PaulS
Thanks for the comment. I didnt realize that knowing the model of car you drive makes you a better driver. Thanks for the increase in knowledge

@wildbill
Thanks, that information might actually help me.

Ive just changed the front legs over, so I cant test it just yet, but Ive altered the code:

  for (k=0; k<=12; k++)
  {                                   
   myservo[k].attach(k+2);
  }

and

for (h=0; h<forwardcount; h++)
  {  
    for (e=0; e<12; e++)
  {
    move=forward[e][h];
    myservo[e].write(move);
  }
  delay(pause);
  }

Close, but no cigar:

for (k=0; k<=12; k++)
  {                                   
   myservo[k].attach(k+2);
  }

k varies between 0 and 12. 12 is too many (thirteen is right out).

@wildbill

Thanks again,
I'm rewiring at the moment, so I still havent tried it, you saved me some time :slight_smile:

@wildbill
I changed the code and its working now as it shuold, cheers! :smiley:

Well, after changing the leg around; I have had to reprogram the movements. I thought I'd do a test gait with it walking on tip-toes. It seems to work alright. Next trick will be to adjust the logic so that when it comes to an object, it has a look up to see if it's a low obstruction, then if it is, lift its body up and walk on tip-toes. I'm not sure how to make it decide when to lower down again... oh well, a problem for another day.

Also, I'm not too sure yet, why my LiPo battery isn't giving sufficient power. I will have to investigate that too, but I just wanted to have a bit of a play at the moment.

Oh, and the reason that it tips over at the end is because I ran out of range with the external battery wires

For all those that want to follow a little closer I have set up a Facebook page:
http://www.facebook.com/home.php#!/pages/Quadrabot/246637268735818

Congrats on the awesome robot, sir. I could never have made a robot with legs, they're too hard for me to program.

Sorry I have taken my sweet time returning to this forum, life has been busy.

All I've done at this stage is make a to the change to the movements. Now instead of making the foot move from point A to point B, it moves in a path between point A to point B, stopping at a predetermined (set at three in this example) number of points along the path. I have done this in an attempt to create a more accurate path. The path is made from the original coordinates and mathematically added within the program.

There are still a few glitches in it and it looks quite dumb imo, but its a start.

void doTest()
{
  for (h=0; h<testcount; h++) //step
  {  
    for (e=0; e<12; e++) //servo
  {
    for (d=1; d<testcount; d++)
    {
        if (h==0)  //if first step
      {
        move=test[e][h];
        myservo[e].write(move);
      }
      else
      {
        if (h!=0 && h<=testcount) //if subsequent steps
        {
          if (test[e][h]==test[e][h-1]) //if move-to is equal to
          {
            move=test[e][h];
            myservo[e].write(move);
          }
          else if (test[e][h]>test[e][h-1]) //if move-to is greater than
          {
            c=test[e][h]-test[e][h-1];
            c=c/3;
            move=test[e][h]-(c*d);
            myservo[e].write(move);
            delay(pause);
          }
          else if (test[e][h]<test[e][h-1]) //if move-to is less than
          {
            c=test[e][h-1]-test[e][h];
            c=c/3;
            move=test[e][h]+(c*d);
            myservo[e].write(move);
            delay(pause);
          }
        }
      }
    }
  }
  delay(pause);
  }
}

For all those that want to follow a little closer I have set up a Facebook page:
http://www.facebook.com/home.php#!/pages/Quadrabot/246637268735818

Opps, I put the wrong code on there, sorry:

void doTest()
{
  for (h=0; h<testcount; h++) //step
  { 
    for (d=divisor; d>0; d--) //divisions per movement
    {
      for (e=0; e<12; e++) //servo
      {
        savepos[e]=test[e][h];
        if (h==0) //if first step
        {
          if (test[e][h]==savepos[e]) //if move-to is equal to
          {
            move=test[e][h];
            myservo[e].write(move);
          }
          else if (test[e][h]>savepos[e]) //if move-to is greater than
          {
            c=test[e][h]-savepos[e];
            c=c/3;
            move=test[e][h]-(c*d);
            myservo[e].write(move);
          }
          else if (test[e][h]<savepos[e]) //if move-to is less than
          {
            c=savepos[e]-test[e][h];
            c=c/3;
            move=test[e][h]+(c*d);
            myservo[e].write(move);
          }
        }
        else
        {
          if (h!=0 && h<=testcount) //if subsequent steps
          {
            if (test[e][h]==test[e][h-1]) //if move-to is equal to
            {
              move=test[e][h];
              myservo[e].write(move);
            }
            else if (test[e][h]>test[e][h-1]) //if move-to is greater than
            {
              c=test[e][h]-test[e][h-1];
              c=c/3;
              move=test[e][h]-(c*d);
              myservo[e].write(move);
            }
            else if (test[e][h]<test[e][h-1]) //if move-to is less than
            {
              c=test[e][h-1]-test[e][h];
              c=c/3;
              move=test[e][h]+(c*d);
              myservo[e].write(move);
            }
          }
        }
        delay(pause/(divisor*2));
      }
    }
  }
}

Hi
Nice project!
Would you mind to do a litte "instructables" with any photo, to explain how to assembly the legs,wires and sensor?
Thanks for all