six legged walker

Hello

As a part of a design class at uni, we (a group of other folk and I) are making a six legged walker. We're using twelve servos to move the legs, two servos per leg, all of them controlled by an Arduino Uno. As usually happens with these things, we've run into some problems. Whenever the power is disconnected from the servos and reconnected, the legs start going mad (random angles, freezing, basically nothing like the gait programmed). Resetting the board doesn't always help. In fact, sometimes as many as 10 resets and/or reprogramming is necessary to sort it out. Anyone have any ideas as to why this might happen?

Knee servos are New Power XL-9HMB
Hip servos are Tower Pro SG-90
The board is Arduino Uno.
Programmed using Arduino 1.0 on Ubuntu 10.04.
Servos are currently powered from a K and H Products PP272 Powered Project Board (it's got 5V with a 1A fuse).
Legs are made of acrylic, are fairly light and the joints are definitely loose enough.

Any help/ideas appreciated.

EDIT: Probably worth adding the code as well.

#include <Servo.h>

//create servo objects, comments are aliases for short-hand notation
Servo hipFrontRight;     //FR
Servo hipMiddleRight;    //MR
Servo hipRearRight;      //RR
Servo hipFrontLeft;      //FL
Servo hipMiddleLeft;     //ML
Servo hipRearLeft;       //RL
Servo kneeFrontRight;    //FR
Servo kneeMiddleRight;   //MR
Servo kneeRearRight;     //RR
Servo kneeFrontLeft;     //FL
Servo kneeMiddleLeft;    //ML
Servo kneeRearLeft;      //RL

//software switch for convenience - if !1, then the loop routine is empty
int sw = 0;

//define the initial range and position of knees and hips
//polarity or ranges different for sides because of the way the servos
//are placed on the body
int hipRange = 10;
int kneeRange = 20;

int FRHipRange = 10;
int MRHipRange = 10;
int RRHipRange = 10;
int FLhipRange = 10;
int MLHipRange = 10;
int RLHipRange = 10;
int FRKneeRange = 20;
int MRKneeRange = 20;
int RRKneeRange = 20;
int FLKneeRange = 20;
int MLKneeRange = 20;
int RLKneeRange = 20;

int FRInitHip = 90;
int MRInitHip = 90;
int RRInitHip = 90;
int FLInitHip = 90;
int MLInitHip = 90;
int RLInitHip = 90;
int FRInitKnee = 90;
int MRInitKnee = 90;
int RRInitKnee = 90;
int FLInitKnee = 90;
int MLInitKnee = 90;
int RLInitKnee = 90;
 
//define speed of movement - smaller value gives higher speed
int movSpeed = 15;
  
//generic counter variable
int i = 0;

void setup()
{
  //attach servos to pins on the board
  hipFrontRight.attach(1);
  hipMiddleRight.attach(2);
  hipRearRight.attach(3);
  hipFrontLeft.attach(4);
  hipMiddleLeft.attach(5);
  hipRearLeft.attach(6);
  kneeFrontRight.attach(7);
  kneeMiddleRight.attach(8);
  kneeRearRight.attach(9);
  kneeFrontLeft.attach(10);
  kneeMiddleLeft.attach(11);
  kneeRearLeft.attach(12);
  
  //initialise servos to their initial positions
  hipFrontRight.write(FRInitHip);
  hipMiddleRight.write(MRInitHip);
  hipRearRight.write(RRInitHip);
  hipFrontLeft.write(FLInitHip);
  hipMiddleLeft.write(MLInitHip);
  hipRearLeft.write(RLInitHip);
  kneeFrontRight.write(FRInitKnee);
  kneeMiddleRight.write(MRInitKnee);
  kneeRearRight.write(RRInitKnee);
  kneeFrontLeft.write(FLInitKnee);
  kneeMiddleLeft.write(MLInitKnee);
  kneeRearLeft.write(RLInitKnee);
  
  if (sw == 0)
  {
    for (i = 0; i <= kneeRange; i++) //lift knees FR, RR, ML to initialise motion
    {
      kneeFrontRight.write(FRInitKnee - i);
      kneeRearRight.write(RRInitKnee - i);
      kneeMiddleLeft.write(MLInitKnee + i);
      delay(movSpeed);
    }
  }
}

void loop()
{ 
  if (sw == 1)
  {
    for (i = 0; i <= hipRange; i++) //hips FR, RR, ML go forwards, hips FL, RL, MR go backwards
    {
      hipFrontRight.write(FRInitHip + i);
      hipRearRight.write(RRInitHip + i);
      hipMiddleLeft.write(MLInitHip - i);
      hipMiddleRight.write(MRInitHip - i);
      hipRearLeft.write(RLInitHip + i);
      hipFrontLeft.write(FLInitHip + i);
      delay(movSpeed);
    }
    
    for (i = 0; i <= kneeRange; i++) //lower knees FR, RR, ML
    {
      kneeFrontRight.write(FRInitKnee - kneeRange + i);
      kneeRearRight.write(RRInitKnee - kneeRange + i);
      kneeMiddleLeft.write(MLInitKnee + kneeRange - i);
      delay(movSpeed);
    }
    
    for (i = 0; i <= kneeRange; i++) //lift knees MR, FL, RL
    {
      kneeMiddleRight.write(MRInitKnee - i);
      kneeFrontLeft.write(FLInitKnee + i);
      kneeRearLeft.write(RLInitKnee + i);
      delay(movSpeed);
    }
    
    for (i = 0; i <= hipRange; i++) //all hips return to initial position
    {
      hipFrontRight.write(FRInitHip + hipRange - i);
      hipRearRight.write(RRInitHip + hipRange - i);
      hipMiddleLeft.write(MLInitHip - hipRange + i);
      hipMiddleRight.write(MRInitHip - hipRange + i);
      hipRearLeft.write(RLInitHip + hipRange - i);
      hipFrontLeft.write(FLInitHip + hipRange - i);
      delay(movSpeed);
    }
    
    for (i = 0; i <= hipRange; i++) //hips FR, RR, ML go backwards, hips MR, FL, RL go forwards
    {
      hipMiddleRight.write(MRInitHip + i);
      hipRearLeft.write(RLInitHip - i);
      hipFrontLeft.write(FLInitHip - i);
      hipFrontRight.write(FRInitHip - i);
      hipRearRight.write(RRInitHip - i);
      hipMiddleLeft.write(MLInitHip + i);
      delay(movSpeed);
    }
    
    for (i = 0; i <= kneeRange; i++) //lower knees FL, RL, MR
    {
      kneeMiddleRight.write(MRInitKnee - kneeRange + i);
      kneeRearLeft.write(RLInitKnee + kneeRange - i);
      kneeFrontLeft.write(FLInitKnee + kneeRange - i);
      delay(movSpeed);
    }
   
    for (i = 0; i <= kneeRange; i++) //lift knees ML, FR, RR
    {
      kneeMiddleLeft.write(MLInitKnee + i);
      kneeFrontRight.write(FRInitKnee - i);
      kneeRearRight.write(RRInitKnee - i);
      delay(movSpeed);
    }    
    
    for (i = 0; i <= hipRange; i++) //all hips return to initial position
    {
      hipMiddleRight.write(MRInitHip + hipRange - i);
      hipRearLeft.write(RLInitHip - hipRange + i);
      hipFrontLeft.write(FLInitHip - hipRange + i);
      hipFrontRight.write(FRInitHip - hipRange + i);
      hipRearRight.write(RRInitHip - hipRange + i);
      hipMiddleLeft.write(MLInitHip + hipRange - i);
      delay(movSpeed);
    }
  }
}

5V @ 1 amp is not likely enough to power 12 servos at one time (a single standard servo can easily pull up to amp of current by itself, under load; yours are smaller servos though); what is powering the Arduino? You should first figure out a few things before delving into the code as being an issue:

  1. How much current does a single servo take (and since you are using two different brands of servos - measure each) - when under load and without a load?
  2. How many servos are going to running under load -at the same time-?

Multiply the maximum current from 1) with the number of servos from 2) - this will give you a rough number of the amount of current needed for the servos. Add an extra 250-300 mA or so for the Arduino (if being powered by the same supply).

I have a feeling you are trying to run the servos from the same supply as the Arduino (this is just a guess though; it isn't clear from your post); if so, likely a current sag is happening, causing the Arduino to constantly reset. Given that you can -sometimes- get it to work, I wonder if you are somehow right on the edge of what is needed current wise, and sometimes things "settle" just right (or not as many servos move at one time in a gait cycle, or the same number aren't loaded, or something), allowing it to work briefly?

  hipFrontRight.attach(1);

Quite possibly not the problem as you aren't doing serial comms, but it's not always wise to use the serial TX pin for anything else.

cr0sh:
5V @ 1 amp is not likely enough to power 12 servos at one time (a single standard servo can easily pull up to amp of current by itself, under load; yours are smaller servos though); what is powering the Arduino? You should first figure out a few things before delving into the code as being an issue:

  1. How much current does a single servo take (and since you are using two different brands of servos - measure each) - when under load and without a load?
  2. How many servos are going to running under load -at the same time-?

Multiply the maximum current from 1) with the number of servos from 2) - this will give you a rough number of the amount of current needed for the servos. Add an extra 250-300 mA or so for the Arduino (if being powered by the same supply).

I have a feeling you are trying to run the servos from the same supply as the Arduino (this is just a guess though; it isn't clear from your post); if so, likely a current sag is happening, causing the Arduino to constantly reset. Given that you can -sometimes- get it to work, I wonder if you are somehow right on the edge of what is needed current wise, and sometimes things "settle" just right (or not as many servos move at one time in a gait cycle, or the same number aren't loaded, or something), allowing it to work briefly?

Thanks for the quick reply.

Currently I don't have the calculations with me but the power supply is enough for this sort of testing. Currently the robot is just sitting on the bench and legs are moving freely in the air. Besides, if they were drawing more than an amp, the fuse would've burned out on the board. Of course for it to actually walk, we will need more current.

The board has its own battery to power it (or sometimes the USB cable connected to my laptop). So there shouldn't be any current sags when starting the servos.

kbaumen:
Thanks for the quick reply.

Currently I don't have the calculations with me but the power supply is enough for this sort of testing. Currently the robot is just sitting on the bench and legs are moving freely in the air. Besides, if they were drawing more than an amp, the fuse would've burned out on the board. Of course for it to actually walk, we will need more current.

The board has its own battery to power it (or sometimes the USB cable connected to my laptop). So there shouldn't be any current sags when starting the servos.

Ok - it wasn't clear on the first post you were doing this (good idea, though!) - so, I would defer to dxw00d's suggestion (you might have to resort to using an analog input pin as a digital pin; though I would suggest going with a separate servo controller)...

:slight_smile:

I've played with many kinds of servos. I second the idea that a 1-Amp supply isn't nearly
enough current for 12 servos, no matter that the fuse doesn't blow, or whatever else
you might think. Maybe the supply simply drops out momentarily, and the servo control
loops go bonkers. I also doubt that your USB port can supply enough current.

I always use 5-6 NiMH rechargeable AA-cells in series to power my walking robots, and
they will easily provide enough juice for 12 standard servos [44 oz-in]. Allow about 300-mA
for each standard servo, so the supply needs to be in the 4-Amp range. You need to know
how much current your particular servos draw, for starters.

Also, many servos go totally berserk, and run over to the mechanical stops, when the +V
voltage drops too low. Also, on many types, when you first apply power, the servo horns jerk
a bunch of degrees. My GWS servos will move over 90-180 degrees if I power them on/off a few
times. I don't know about your particular type. These issues have long been a problem with
walking robots.

oric_dan(333):
I've played with many kinds of servos. I second the idea that a 1-Amp supply isn't nearly
enough current for 12 servos, no matter that the fuse doesn't blow, or whatever else
you might think. Maybe the supply simply drops out momentarily, and the servo control
loops go bonkers. I also doubt that your USB port can supply enough current.

I always use 5-6 NiMH rechargeable AA-cells in series to power my walking robots, and
they will easily provide enough juice for 12 standard servos [44 oz-in]. Allow about 300-mA
for each standard servo, so the supply needs to be in the 4-Amp range. You need to know
how much current your particular servos draw, for starters.

Also, many servos go totally berserk, and run over to the mechanical stops, when the +V
voltage drops too low. Also, on many types, when you first apply power, the servo horns jerk
a bunch of degrees. My GWS servos will move over 90-180 degrees if I power them on/off a few
times. I don't know about your particular type. These issues have long been a problem with
walking robots.

Cheers for the tips. We'll have a look at using a different power supply for testing and I'll post some results/issues then.

A small servo hexapod that might be of interest. As to power search ebay for UBEC to see the better and inexpensive power converters used with servos.

http://letsmakerobots.com/node/19257

zoomkat:
A small servo hexapod that might be of interest. As to power search ebay for UBEC to see the better and inexpensive power converters used with servos.

http://letsmakerobots.com/node/19257

Ha, that is very cool. Moves a lot like the A-Pod part 1 - YouTube

We tested ours with a power source that can supply up to 5 amps (when legs move freely, the servos draw at most 200 mA, thus 2.4 would've sufficed) and got exactly the same behaviour. We'll keep using it, since oric_dan(333)'s post makes sense, but it didn't solve the problem. Any other ideas?

Whenever the power is disconnected from the servos and reconnected, the legs start going mad (random angles, freezing, basically nothing like the gait programmed).

Have you tried putting some delay between the initialization of each servo so the servos are not all initialized at the same time?

Looking at your code, I'd say several things.

First off, disconnect 11 of the servos, and write a simple routine to test just one, using
very simple movements. Just move the servo back and forth, and don't worry about trying
control the speed. Get that to work first, then, add more servos and speed control.

Secondly, increase the MoveSpeed from delay(15) to something like delay(50). The
standard servo update rate is 20-msec, which is what I suppose the Servo library uses
invisibly, and you're changing the position value faster.

Thirdly, I'm not sure you can connect a servo to pin 1, as that is used by the Arduino
serial port, ie, connected to the USB chip.

Cheers for the answers guys.

I will try putting some delay between the initialization of the servos and reduce the moving speed to see what happens.

Nothing is connected to pin 1 now, the code is slightly outdated (it was up to date when I posted it).

I have tried simple routines with the servos (with one and six at a time) and never encountered such a problem. This only started happening with all 12 running at the same time. And on the first attempts it wasn't as bad but lots of things had to be mechanically adjusted and eventually it got worse.

I will see the robot again on Tuesday afternoon, so that's when I'll post an update.