Quadruped Robot: Programming a walk cycle

I’ve been wracking my brain over the past few days trying to think how I can get a smooth walk cycle working on the robot.

I’ve been completely unable to find a tutorial or resource online that describes how one would go about implementing a control system for a multi-legged robot whose legs are configured in a biological fashion such as my robot, and not like a spider as you see in many hobby robots, such as the one in the video below:

Trying to do this is going to mean thinking this all through from scratch, and to be honest, I was rather hoping to be able to piggy back off the work other people had done a bit here…

I have heard about people using curves on a graph to control servo positions over time before, and thought that might be the way to go, and having come from an animation background that sort of makes sense to me, but the maths involved and keeping track of it all seemed a bit painful.

So how to control multiple servos to create a walk cycle? Well, here is my solution:

I decided to go back to what I know, and use keyframes. Keyframes are what we use when animating (https://youtu.be/u5YxwHkjMHc) in computer animation software. In simple terms, you tell something to be in one position at a certain time, then tell it where to be at another time and the software takes care of smoothing out all the points in between. As this workflow is familiar to me, it seems like something I could achieve, and fully understand.

First, read the tutorial on Inverse Kinematics for a quick introduction to how I got leg control working properly. From there, you know that I can now just tell each foot where I want it to be in relation to the shoulder. I can just send 2 coordinates (x & y) and the IK will figure out where all the angles of the joints need to be in order to get it there.

With all that working, I should just need to record the foot in different positions, and send those positions to the legs. Okay, so here’s the 8 positions I chose to start with:

The foot starts directly underneath the shoulder, moves in a straight line backwards over 2 steps, then lifts up, forward and down again over then next 4 until the foot touches the ground again, where it moves backwards to be underneath the shoulder once more over the next two frames. This cycle then repeats ad infinitum.

Here are the foot positions sat inside a 2-dimensional array in my code:

float walk[8][2]={
  {0,70},
  {-30,70},
  {-60,70},  
  {-30,55},
  {0,40},
  {30,40},
  {60,70},
  {30,70}
};

I may need to tweak that a bit in practice, but for the time being, lets test that. So, here is the front left arm stepping through the keyframes:

Okay! That seems to be working great. Next I need to smooth that motion out, because it’s not going to work jerking about like that. The servos are moving too quickly from one step to the next.

I achieved this by doing a couple of things:

First, I need to ensure my Arduino code is running constantly. Anyone used to programming on the Arduino knows about the deadly delay() function, that pauses the code for a number of milliseconds and is useful for adding a bit of delay to slow things down a bit. In truth, this is bad practice – because I don’t want to pause the code – if I pause things to slow down the movement of one leg, it won’t be able to continue executing code to control the other legs in the meantime, and things will quickly spiral out of control.

I had to use the Arduino’s built in millis() function. This counts the number of milliseconds since the Arduino started. This is useful because you have an ever-increasing count that keeps track of time for you. Then all you need to do is check is a certain number of miliseconds have passed since you last checked, and you can execute a bit of code:

long previousMillis=0; //The previous count of milliseconds
int temp=500; //The length of your delay

void loop() {
  if(millis()>previousMillis+tempo){
    previousMillis=millis();
    //DO SOMETHING
  }
}

Now that I can tune the delay, and thus the speed at which the leg moves, without affecting any other code running alongside.

I implemented interpolation by getting the current keyframe values, and subtracting them from the next keyframe values. This gives me the spatial difference between each keyframe. I can then divide that value by however many in-between points I want (tweens) to give me smaller increments. I can then multiply that by the number of steps we’re currently on and add that value back to the original keyframe.

I know that probably sounds really complicated, but in truth, it’s really simple. Here’s the code:

int tempo=10;
int tweenSteps=20;
int tween=1;
long previousMillis=0;
int walkFrame=0;

void loop() {
  if(millis()>previousMillis+tempo){
    previousMillis=millis();

    float curX=walk[walkFrame][0];
    float curY=walk[walkFrame][1];
    float nextX;
    float nextY;
    
    if(walkFrame==7){
      nextX=walk[0][0];
      nextY=walk[0][1];
    } else {
      nextX=walk[walkFrame+1][0];
      nextY=walk[walkFrame+1][1];
    }

    float tmpStep=(nextX-curX)/tweenSteps;    
    frLeg->x=walk[walkFrame][0]+(tmpStep*tween);
    tmpStep=(nextY-curY)/tweenSteps;    
    frLeg->y=walk[walkFrame][1]+(tmpStep*tween);

    tween=tween+1;
    if(tween>=tweenSteps){
      tween=0;
      walkFrame+=1;
      if(walkFrame>=8){
        walkFrame=0;
      }
    }
  }
  
  flLeg->setAngles();
  frLeg->setAngles();
  blLeg->setAngles();
  brLeg->setAngles();

}

I’m sure anyone with 10 minutes more experience of programming on the Arduino will wince horribly at my code there, but I’m trying to keep it human-readable at the moment.

As you can see in the code, I can control the delay between each step (tempo) and the number of steps between each keyframe (tweenSteps)

Here it is with 5 steps interpolated between keyframes and 800 milliseconds delay:

And here it is with 20 steps interpolated and only 10 milliseconds delay:

So pretty successful in all. I’ll probably need to adjust that cycle an awful lot as I progress to make sure that everything keeps running smoothly and no legs crash into one another. But I can probably just reuse the same keyframes for all the legs and just offset the steps for each one, and we’ll have something approximating a walk cycle.

I’m working on trying to tidy the whole thing up and getting the power distribution working properly, because my clever idea of using a power bank has fallen through. There just isn’t enough amps to power all the motors under load.

Check back soon and I’ll try and write up how I learned about object-oriented programming on the Arduino, which has been a bit of a lifesaver when controlling the legs.

Infinite Monkeys

The infinite monkey theorem states that a monkey hitting keys at random on a typewriter keyboard for an infinite amount of time will almost surely type a given text, such as the complete works of William Shakespeare.


Wikipedia Infinite Monkey Theorem 

A while ago, I thought it might be fun to put the above idea to the test. But obviously I don’t have a monkey. So I’m struck with a problem: Where can I find an enormous number of barely literate primates, mashing away mindlessly at their keyboards? 

Well, it struck me quite quickly…. Twitter obviously.

I spent some time tinkering with the Twitter API to query the latest tweets for text containing all the words in the entirety of Shakepeare’s combined works.

Check it out…

empathi.co.uk/monkeys