Hexapod on a Budget – Part 3: Movement Algorithm Prototyping with Pololu Maestro Control Center

Introduction

In part 2, I talked about the electronics layout for the hexapod. Now it’s time to make it move.

So it’s been a while since I last worked on this, so I’ve decided to get it out of the cupboard, blow the dust off it and figure out where I got to.

First off, a quick recap of the architecture:

The electrics consist of a power supply in the form of a 7.4 V Li-Po battery, running through a voltage regulator. The regulator powers an Arduino Uno board and a Pololu Mini Maestro servo control board. The Arduino will send instructions to the Mini Maestro via UART, which will determine the position of the 12 servos. 2 Sharp infra-red sensors are connected to the Arduino to give the thing some awareness of its surroundings – these will be expanded on in future.

Hexapod overview

Maestro Control Center

One of the great things about the Mini Maestro control board is the ‘Maestro Control Center’ software. This allows the servos to be controlled via a USB connection with a host PC, with no other connection to a microcontroller. What this has given me is a platform for prototyping movement algorithms before I code them on the Arduino, allowing me to get a feel for the way the limbs behave much more rapidly than I could if I was coding from the outset.

The user interface is really simple:

The 11 servos are presented as sliders which can be used to move the servos in real-time:

UI

‘Frames’, which consist of target positions for the servos can be saved in a sequence. The speed and acceleration properties can be used to control how long it takes for the servo to reach its target position each time the frame is played back. Setting them to zero, as I have done here, leaves it up to the speed of the servo itself to reach its position.

The servos are connected up so that the 6 ‘hip’ joints are identified as servos 0 – 5, numbered clockwise from the front-right to front-left. The 6 ‘knee’ joints are servos 6 – 11, such that servo 6 is the knee to servo 0, servo 7 is the knee to servo 1, and so on (see below).

Capture

With a bit of trial and error, I came up with six frames that give me a simple walking motion, moving in direction ‘A’:

Sequence

Initial position:

Frame1

Knees down 1

Frame2

Knees up 1

Frame3

Walk

Frame4

Knees down 2

Frame5

Knees up 2

Frame6

With the USB connection in place, Maestro Control Center sends this sequence to the Mini Maestro control board (nothing is stored on the board itself at this point, it is all executed from the PC). I’ve disconnected the Arduino, and connected an old laptop power supply to the SBEC voltage regulator so my development time isn’t limited by battery life. Playing the above frames in a loop gives a starting point for the movement algorithm. It’s quite fast and hectic, but with a little more control it will give me the desired results. Also for some reason while the robot was laid up, Servo 0 – the front-right hip joint – has died. I tried swapping the connectors over with another channel and the same servo still doesn’t move, so it looks like I’ll need to replace that one. Nevertheless, the little critter still seems to move quite smoothly.

Using a similar method, I’ve created sequences to reset the legs to the centre position and rotate clockwise and anti-clockwise (whilst fending off any attacking cats).

Algorithm development

Now I have the simple movements worked out, I want to put them together into some sort of logic, will allow it to move in any direction. Because of the rotational symmetry of the robot, the movements for walking in direction ‘A’ can easily be translated to the other directions, simply by offsetting the movements by the desired number of servos. For example to move in direction ‘B’, the servo numbers in the waking sequence need to be offset by 1, for direction ‘C’ an offset of 2 is needed and so on. In terms of programming, this will become arrays for the servo positions of the hips and knees in sequence. There will be an array that represents the current sequence to run, which will be loaded from the sequence array as follows (code theoretical and untested):


#define NUM_LEGS (6)
#define NUM_SEQ_STEPS (6)

/* 6-step sequences for hips and knees */
typedef struct {
 int hip[NUM_SEQ_STEPS];
 int knee[NUM_SEQ_STEPS];
} legPositions_t;

/* Array of legs containing the movement sequence (direction A) */
const legPositions_t sequenceLegScript[NUM_LEGS] = {
    /* Leg0 */  {       
    /* Hip0 - servo0 */  {1240, 1240, 1240, 2000, 2000, 2000}, 
    /* Knee0- servo6 */  { 992, 2000, 2000, 2000, 2000,  992} 
                },
    /* Leg1 */  {
    /* Hip1 - servo1 */  {1920, 1920, 1920,  992,  992,  992}, 
    /* Knee1- servo7 */  {2000, 2000,  992,  992, 2000, 2000} 
                },
    /* Leg2 */  { 
    /* Hip2 - servo2 */  { 992,  992,  992, 1755, 1755, 1755},
    /* Knee2- servo8 */  { 992, 2000, 2000, 2000, 2000,  992} 
                },
    /* Leg3 */  {
    /* Hip3 - servo3 */  {1255, 1255, 1255, 2000, 2000, 2000},
    /* Knee3- servo9 */  {2000, 2000,  992,  992, 2000, 2000}
                },
    /* Leg4 */  {
    /* Hip4 - servo4 */  {2000, 2000, 2000,  992,  992,  992},
    /* Knee4- servo10 */ { 992, 2000, 2000, 2000, 2000,  992} 
                },
    /* Leg5 */  {
    /* Hip5 - servo5 */  { 992,  992,  992, 1760, 1760, 1760},
    /* Knee4- servo11 */ {2000, 2000,  992,  992, 2000, 2000}
                }
 };

/* Array to run the sequence from */ 
legPositions_t sequenceLegRun[NUM_LEGS];

/* Directions */
typedef enum {DIR_A=0, DIR_B=1, DIR_C=2, DIR_D=3, DIR_E=4, DIR_F=5} directions_t;

/* Function to perform the direction offset on the sequence */
void loadLegMovements(directions_t directionOffset){
    int legNum, step, offsetLegNum;
 
    for(legNum = 0; legNum < NUM_LEGS; legNum++){ 
        /* apply offset */ 
        offsetLegNum = legNum + (int)directionOffset; 

        /* wrap-around legs (hehe) */ 
        if(offsetLegNum >= NUM_LEGS){
            offsetLegNum -= NUM_LEGS; 
        } 
 
        /* load sequence values into 'run' array */
        for(step = 0; step < NUM_SEQ_STEPS; step++){ 
            sequenceLegRun[legNum].hip[step] = sequenceLegScript[offsetLegNum].hip[step]; 
            sequenceLegRun[legNum].knee[step] = sequenceLegScript[offsetLegNum].knee[step]; 
        }
    }
}

Using this algorithm, the robot will have 5 degrees of movement (A to D, B to E, C to F, Rotate Clockwise and Rotate Anti-clockwise). There are another three degrees that I could implement, which are along the planes of the legs rather than between them. I haven’t given this much thought, but I’ve seen some people do this by lifting two legs and then walking like a quadruped.

In the next part, I will begin to put this theory into practice and start coding the Arduino software…

Advertisements

Tell me what you think...

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s