1

Dependencies:   CircularBuffer Radio Servo Terminal mbed

Fork of WalkingRobot by Patrick Clary

main.cpp

Committer:
pclary
Date:
2013-01-31
Revision:
9:a6d1502f0f20
Parent:
8:db453051f3f4
Child:
10:dc1ba352667e

File content as of revision 9:a6d1502f0f20:

#include "mbed.h"
#include "RobotLeg.h"
#include "Matrix.h"
#include "CircularBuffer.h"
#include "Radio.h"
#include "Terminal.h"
#include "utility.h"
#include <cstring>
#include <cmath>

#define MAXSPEED 0.1f
#define MAXTURN 1.0f
#define RESET_STEP_TIME 0.4f
#define DIM_A 0.125f
#define DIM_B 0.11f
#define DIM_C 0.0025f
#define DIM_D 0.025f
#define CIRCLE_X 0.095f
#define CIRCLE_Y 0.095f
#define CIRCLE_Z -0.12f
#define CIRCLE_R 0.09f

enum state_t
{
    walk,
    reset
};

enum legstate_t
{
    A,
    B,
    C,
    D
};

CircularBuffer<float,16> dataLog;
Radio radio(p5, p6, p7, p16, p17, p18);
Timer stepTimer;
RobotLeg legA(p26, p29, p30, false); // Start the legs disabled
RobotLeg legB(p13, p14, p15, false);
RobotLeg legC(p12, p11, p8, false);
RobotLeg legD(p23, p24, p25, false);
state_t state;
legstate_t legState;
float stepDistance, stepDistanceTarget;



CmdHandler* log(Terminal* terminal, const char* input)
{
    int start = 0;
    int end = 15;
    char output[256];
    
    if (sscanf(input, "log %d %d", &start, &end) == 1)
    {
        // Print only one item
        sprintf(output, "%4d: %f\n", start, dataLog[start]);
        terminal->write(output);
    }
    else
    {
        // Print a range of items
        for (int i = start; i <= end; i++)
        {
            sprintf(output, "%4d: %f\n", i, dataLog[i]);
            terminal->write(output);
        }
    }  
    
    return NULL;
} // log()



CmdHandler* read(Terminal* terminal, const char* input)
{
    char output[256];
    uint32_t data;

    data = radio.rx_controller;
    sprintf(output, "%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d : %4d %4d %4d %4d", 
    (data>>31)&1, (data>>30)&1, (data>>29)&1, (data>>28)&1, (data>>27)&1, (data>>26)&1, (data>>25)&1, (data>>24)&1, 
    (data>>23)&1, (data>>22)&1, (data>>21)&1, (data>>20)&1, (data>>19)&1, (data>>18)&1, (data>>17)&1, (data>>16)&1, 
    (data>>15)&1, (data>>14)&1, (data>>13)&1, (data>>12)&1, (data>>11)&1, (data>>10)&1, (data>>9)&1, (data>>8)&1, 
    (data>>7)&1, (data>>6)&1, (data>>5)&1, (data>>4)&1, (data>>3)&1, (data>>2)&1, (data>>1)&1, (data>>0)&1, 
    (int8_t)((data>>24)&0xff), (int8_t)((data>>16)&0xff), (int8_t)((data>>8)&0xff), (int8_t)((data)&0xff));
    terminal->write(output);

    return NULL;
} // read()



CmdHandler* resetc(Terminal* terminal, const char* input)
{
    char output[256];
    float f;
    vector3 v;
    
    if (sscanf(input, "reset %f", &f) == 1)
    {
        v = legA.reset(f);
        sprintf(output, "reset: %f %f %f", v.x, v.y, v.z);
        terminal->write(output);
    }
    else
    {
        sprintf(output, "syntax error");
        terminal->write(output);
    } 

    return NULL;
} // reset()



CmdHandler* rndp(Terminal* terminal, const char* input)
{
    char output[256];
    
    sprintf(output, "%f %f %f", legA.nDeltaPosition.x, legA.nDeltaPosition.y, legA.nDeltaPosition.z);
    terminal->write(output);

    return NULL;
} // step()



int deadzone(int input, int zone)
{
    if (input > zone) return input;
    else if (input < -zone) return input;
    else return 0;
} // deadzone()



void resetLegs()
{
    legA.reset(-0.5f);
    legB.reset(0.0f);
    legC.reset(0.5f);
    legD.reset(1.0f);
    stepTimer.reset();
    state = reset;
    legState = D;
} // resetLegs()



void walkLegs()
{
    state = walk;
    legState = A;
    stepDistanceTarget = CIRCLE_R / 2.0f;
    stepDistance = 0;
} // walkLegs()



int main()
{
    Timer deltaTimer;
    float xaxis, yaxis, turnaxis, speed, angle;
    float deltaTime, cycleTime;
    vector3 v;
    matrix4 T;
    matrix4 PA, QA;
    matrix4 PB, QB; 
    matrix4 PC, QC; 
    matrix4 PD, QD;
    Terminal terminal;
    bool freeA, freeB, freeC, freeD;
    
    terminal.addCommand("log", &log);
    terminal.addCommand("read", &read);
    terminal.addCommand("reset", &resetc);
    terminal.addCommand("ndp", &rndp);
    
    
    DigitalOut debug1(LED1);
    DigitalOut debug2(LED2);
    DigitalOut debug3(LED3);
    DigitalOut debug4(LED4);
    
    
    radio.reset();
    
    // Set leg parameters
    legA.setDimensions(DIM_A, DIM_B, DIM_C, DIM_D);
    legB.setDimensions(DIM_A, DIM_B, DIM_C, DIM_D);
    legC.setDimensions(DIM_A, DIM_B, DIM_C, DIM_D);
    legD.setDimensions(DIM_A, DIM_B, DIM_C, DIM_D);
    legA.setAngleOffsets(0.7853982f, 0.0f, 0.0f);
    legB.setAngleOffsets(0.7853982f, 0.0f, 0.0f);
    legC.setAngleOffsets(0.7853982f, 0.0f, 0.0f);
    legD.setAngleOffsets(0.7853982f, 0.0f, 0.0f);
    legA.setStepCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_Z, CIRCLE_R);
    legB.setStepCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_Z, CIRCLE_R);
    legC.setStepCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_Z, CIRCLE_R);
    legD.setStepCircle(CIRCLE_X, CIRCLE_Y, CIRCLE_Z, CIRCLE_R);
    legA.theta.calibrate(1000, 2000, 45.0f, -45.0f);
    legA.phi.calibrate(1000, 2000, 70.0f, -45.0f);
    legA.psi.calibrate(2000, 1000, 70.0f, -60.0f);
    legB.theta.calibrate(1000, 2000, 45.0f, -45.0f);
    legB.phi.calibrate(1000, 2000, 70.0f, -45.0f);
    legB.psi.calibrate(2000, 1000, 70.0f, -60.0f);
    legC.theta.calibrate(2000, 1000, 45.0f, -45.0f);
    legC.phi.calibrate(2000, 1000, 70.0f, -45.0f);
    legC.psi.calibrate(1000, 2000, 70.0f, -60.0f);
    legD.theta.calibrate(2000, 1000, 45.0f, -45.0f);
    legD.phi.calibrate(2000, 1000, 70.0f, -45.0f);
    legD.psi.calibrate(1000, 2000, 70.0f, -60.0f);
    
    // Initialize leg position deltas
    legA.nDeltaPosition = vector3(0.0f, 0.01f, 0.0f);
    legB.nDeltaPosition = vector3(0.0f, -0.01f, 0.0f);
    legC.nDeltaPosition = vector3(0.0f, 0.01f, 0.0f);
    legD.nDeltaPosition = vector3(0.0f, -0.01f, 0.0f);

    // Create matrices to change base from robot coordinates to leg coordinates
    QA.translate(vector3(0.1f, 0.1f, 0.0f));
    PA = QA.inverse();
    QB.translate(vector3(-0.1f, -0.1f, 0.0f));
    QB.a11 = -1.0f; QB.a22 = -1.0f;
    PB = QB.inverse();
    QC.translate(vector3(0.1f, -0.1f, 0.0f));
    QC.a11 = -1.0f;
    PC = QC.inverse();
    QD.translate(vector3(-0.1f, 0.1f, 0.0f));
    QD.a22 = -1.0f;
    PD = QD.inverse();
    
    // Start timers
    deltaTimer.start();
    stepTimer.start();
    
    // Go to initial position
    legA.move(vector3(0.15f, 0.15f, 0.05f));
    legB.move(vector3(0.15f, 0.15f, 0.05f));
    legC.move(vector3(0.15f, 0.15f, 0.05f));
    legD.move(vector3(0.15f, 0.15f, 0.05f));
    legA.theta.enable(); wait(0.1f);
    legB.theta.enable(); wait(0.1f);
    legC.theta.enable(); wait(0.1f);
    legD.theta.enable(); wait(0.1f);
    legA.phi.enable(); wait(0.1f);
    legB.phi.enable(); wait(0.1f);
    legC.phi.enable(); wait(0.1f);
    legD.phi.enable(); wait(0.1f);
    legA.psi.enable(); wait(0.1f);
    legB.psi.enable(); wait(0.1f);
    legC.psi.enable(); wait(0.1f);
    legD.psi.enable(); wait(0.1f);
    wait(0.4f);
    resetLegs();
    
    /*
    // Dump debug info 
    sprintf(output, "T =\t%f\t%f\t%f\t%f\n\t%f\t%f\t%f\t%f\n\t%f\t%f\t%f\t%f\n\t0\t\t0\t\t0\t\t1\n",
            T.a11, T.a12, T.a13, T.a14,
            T.a21, T.a22, T.a23, T.a24,
            T.a31, T.a32, T.a33, T.a34);
    terminal.write(output); 
    */
    
    
    while(true)
    {
        switch (state)
        {
        case walk:
            // Debug stuff
            switch (legState)
            {
            case A: debug1 = 1; debug2 = 0; debug3 = 0; debug4 = 0; break;
            case B: debug1 = 0; debug2 = 1; debug3 = 0; debug4 = 0; break;
            case C: debug1 = 0; debug2 = 0; debug3 = 1; debug4 = 0; break;
            case D: debug1 = 0; debug2 = 0; debug3 = 0; debug4 = 1; break;
            }
            
            // Get delta-time
            deltaTime = deltaTimer.read();
            deltaTimer.reset();
        
            // Read controller input
            xaxis = 0.0078125f * deadzone((int8_t)((radio.rx_controller>>0)&0xff), 8); // Convert to +/-1.0f range
            yaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>8)&0xff), 8);
            turnaxis = -0.0078125f * deadzone((int8_t)((radio.rx_controller>>16)&0xff), 8);
            
            // Compute delta movement vector and delta angle
            speed = sqrt(xaxis*xaxis + yaxis*yaxis) * MAXSPEED;
            v.x = -xaxis;
            v.y = -yaxis;
            v.z = 0;
            v = v * MAXSPEED * deltaTime;
            angle = -turnaxis * MAXTURN * deltaTime;
            stepDistance += deltaTime * (speed + fabs(angle * 0.141f));
            
            // Compute movement transformation in robot coordinates
            T.identity().rotateZ(angle).translate(v).inverse();
            
            // Update legs
            freeA = legA.update(PA*T*QA);
            freeB = legB.update(PB*T*QB);
            freeC = legC.update(PC*T*QC);
            freeD = legD.update(PD*T*QD);
            
            // Update state
            switch (legState)
            {
            case A:
                if (!freeB || !freeC || !freeD) resetLegs();
                else if (!freeA || stepDistance > stepDistanceTarget)
                {
                    legA.reset(1.0f);
                    legState = B;
                    stepDistanceTarget += CIRCLE_R / 2.0f - stepDistance;
                    stepDistance = 0;
                }
                break;
            
            case B:
                if (!freeA || !freeC || !freeD) resetLegs();
                else if (!freeB || stepDistance > stepDistanceTarget)
                {
                    legB.reset(1.0f);
                    legState = C;
                    stepDistanceTarget += CIRCLE_R / 2.0f - stepDistance;
                    stepDistance = 0;
                }
                break;
            
            case C:
                if (!freeA || !freeB || !freeD) resetLegs();
                else if (!freeC || stepDistance > stepDistanceTarget)
                {
                    legC.reset(1.0f);
                    legState = D;
                    stepDistanceTarget += CIRCLE_R / 2.0f - stepDistance;
                    stepDistance = 0;
                }
                break;
            
            case D:
                if (!freeA || !freeB || !freeC) resetLegs();
                else if (!freeD || stepDistance > stepDistanceTarget)
                {
                    legD.reset(1.0f);
                    legState = A;
                    stepDistanceTarget += CIRCLE_R / 2.0f - stepDistance;
                    stepDistance = 0;
                }
                break;
            }
            
            dataLog.push(stepDistanceTarget);
            
            
            
            break; // case walk:
            
            
            
        case reset:
            // Debug stuff
            switch (legState)
            {
            case A: debug1 = 0; debug2 = 1; debug3 = 1; debug4 = 1; break;
            case B: debug1 = 1; debug2 = 0; debug3 = 1; debug4 = 1; break;
            case C: debug1 = 1; debug2 = 1; debug3 = 0; debug4 = 1; break;
            case D: debug1 = 1; debug2 = 1; debug3 = 1; debug4 = 0; break;
            }
        
            cycleTime = stepTimer.read();
        
            if ((cycleTime <= RESET_STEP_TIME) && legState != A)
            {
                legA.reset(-0.5f);
                legState = A;
            }
            else if ((cycleTime > RESET_STEP_TIME) && legState == A)
            {
                legB.reset(0.0f);
                legState = B;
            }
            else if ((cycleTime > RESET_STEP_TIME * 2) && legState == B)
            {
                legC.reset(0.5f);
                legState = C;
            }
            else if ((cycleTime > RESET_STEP_TIME * 3) && legState == C)
            {
                legD.reset(1.0f);
                legState = D;
            }
            else if ((cycleTime > RESET_STEP_TIME * 4) && legState == D)
            {
                walkLegs();
            }
            
            T.identity();
            
            freeA = legA.update(T);
            freeB = legB.update(T);
            freeC = legC.update(T);
            freeD = legD.update(T);
            
            break; // case reset:
        } // switch (state)
    } // while (true)
} // main()