Dependencies:   mbed PID

main.cpp

Committer:
narshu
Date:
2012-02-29
Revision:
0:c8c04928d025

File content as of revision 0:c8c04928d025:

/**********************************************************************
 * @file        i2c_monitor.c
 * @purpose     Eurobot 2012 - Primary Robot MD25 Interface
 * @version     0.2
 * @date        13. Feb. 2012
 * @author      Crispian Poon
 * @email       pooncg@gmail.com
 ______________________________________________________________________

 Setup information:
 1. Put pull up 2.2k resistors to +3.3v on I2C SCL and SDA
 2. Connect P28 SDA to MD25 yellow cable, P27 SCL to MD25 blue cable

 **********************************************************************/

#include "mbed.h"
#include "PID.h"
//Sonar includes
#include "RF12B.h"
#include "SRF05.h"

//Constants declaration
const int md25Address = 0xB0;
const char cmdSetMotor1 = 0x00;
const char cmdSetMotor2 = 0x01;
const char cmdByte = 0x10;
const char cmdDisableAcceleration = 0x30;
const char cmdSetMode = 0x0F;
const char cmdResetEncoders = 0x20;
const char cmdGetEncoder1 = 0x02;
const char cmdGetEncoder2 = 0x06;
const int encoderRevCount = 1856;
const int wheelmm = 314;
const int robotCircumference = 1052;
#define RATE 0.01
//#include <queue>
#define CODE 0x88


//Global variables declaration
int tempByte;
PID PIDController1(0.9, 2, 0, RATE);

//Interface declaration
I2C i2c(p28, p27);        // sda, scl
Serial pc(USBTX, USBRX); // tx, rx
DigitalOut     OBLED1(LED1);
DigitalOut     OBLED2(LED2);
SRF05 my_srf1(p13,p21);
SRF05 my_srf2(p13,p22);
SRF05 my_srf3(p13,p23);
RF12B RF_Robot(p5,p6,p7,p8,p9);

//Functions declaration
void resetEncoders();
long getEncoder1();
long getEncoder2();
void move(long distance, int speed);
void turn(int angle, int speed);
int getSignOfInt(int direction);
void stop();
void setSpeed(int speed);
void setSpeed(int speed1, int speed2);
void setMode(int mode);
long encoderToDistance(long encoder);
long distanceToEncoder(long distance);
void sendCommand(char command);
void sendCommand(char command1, char command2 );
long get4Bytes(char command);

//Main loop
int main() {
    int Cmd = 30;


    //PID controller initialisation
    PIDController1.setMode(AUTO_MODE);
    PIDController1.setInputLimits(0, 2500);   //arbitarily set limit of 10000, can change!
    PIDController1.setOutputLimits(0, 2500);


    //TODO serial interface code, maybe with interrupt?

    while (1) {

        //Read serial to change variable
        if (pc.readable() == 1) {
            pc.scanf("%i", &Cmd);
        }

        //Tune PID referece
        PIDController1.setTunings(0.4, 2, 0);

        //Debug info
        pc.printf("%i",Cmd);


        move(500, Cmd);
        wait_ms(2000);
        //move(-200, 70);

    }
}

//***************************************************************************************
//Primary robot specific instructions
//***************************************************************************************

float getSonar() {
    float distance[3];
    float result = 0;

    RF_Robot.write(CODE);
    my_srf1.trig();
    wait_ms(50);

    distance[0] = my_srf1.read();
    distance[1] = my_srf2.read();
    distance[2] = my_srf3.read();

    for (int i = 0; i < 3; i++) {
        if ( distance[i] > result) {
            result = distance[i];
        }
    }
    return result;
}

//*********************************************
//Parameter @distance in mm, @speed is 0 to 127
//Description: moves robot by @distance mm at @speed in straight line
//*********************************************
void move(long distance, int speed) {

    long tempEndEncoder = 0;
    long startEncoderCount = 0;
    long previousEncoder1Count = 0;
    long previousEncoder2Count = 0;
    long tempEncoder1Speed = 0;
    long tempEncoder2Speed = 0;
    int directionFlag = 0;
    float encoderSpeedConstant = 0;

    //Variables initialisation
    resetEncoders();    //reset MD25 encoder TODO too large distance may cause overflow
    tempEndEncoder = distanceToEncoder(abs(distance));     //Convert distance to end encoder value
    directionFlag = getSignOfInt(distance);     //get direction from distance e.g. -1mm, +1mm converter to - and + operator

    //setSpeed(speed);
    //wait_ms(100);

    while (abs(getEncoder1() - startEncoderCount) < tempEndEncoder) {

        //TODO loop counter

        //calculate speed of encoder1 and encoder 2 change
        tempEncoder1Speed = abs(getEncoder1() - previousEncoder1Count);
        tempEncoder2Speed = abs(getEncoder2() - previousEncoder2Count);


        //TODO optimize so only 1 calc is done per function call
        //get encoder speed to @speed conversion ratio
        encoderSpeedConstant = double(speed) / double(tempEncoder1Speed);

        //set previous loop encoder values
        previousEncoder1Count = getEncoder1();
        previousEncoder2Count = getEncoder2();

        //Set PID input value, tries to adjust encoder2 speed to encoder1 speed
        PIDController1.setSetPoint(tempEncoder1Speed);
        PIDController1.setProcessValue(tempEncoder2Speed);

        float tempVal = PIDController1.compute();
        //Debug Info
        //pc.printf("%f \n", tempVal);
        //PID control of real motor speeds, Motor2 actual speed mirros Motor1 actual speed
        setSpeed(directionFlag*speed, directionFlag * tempVal * encoderSpeedConstant);

        //delay to increase significant encoder counts
        wait(RATE);

    }

    //Stop robot
    stop();

    //Debug info - see if loop is completed.
    OBLED1 = true;

    //Reset encoder values
    resetEncoders();
}

void turn(int angle, int speed) {
    resetEncoders();
    long tempDistance = long((float(angle) / 360) * float(robotCircumference));
    long tempEndEncoder = 0;
    long startEncoderCount = 0;

    tempEndEncoder = distanceToEncoder(abs(tempDistance));
    startEncoderCount = getEncoder1();
    setSpeed(getSignOfInt(tempDistance) * speed, -getSignOfInt(tempDistance) * speed);

    while (abs(getEncoder1() - startEncoderCount) < tempEndEncoder) {
        setSpeed(getSignOfInt(tempDistance) * speed,-getSignOfInt(tempDistance) * speed);

    }

    resetEncoders();
    stop();
}


//***************************************************************************************
//Primary robot specific helper functions
//***************************************************************************************

int getSignOfInt(int direction) {

    direction = (direction < 0);

    switch (direction) {
        case 1:
            return -1;
        case 0:
            return 1;
    }

    return 0;
}

long encoderToDistance(long encoder) {
    return long((float(encoder) / float(encoderRevCount)) * wheelmm);
}

long distanceToEncoder(long distance) {
    return long((float(distance) / float(wheelmm)) * encoderRevCount);
}


//***************************************************************************************
//MD25 instructions
//***************************************************************************************

void stop() {
    sendCommand(cmdSetMotor1, 0);
    sendCommand(cmdSetMotor2, 0);
}

void disableAcceleration() {
    sendCommand(cmdByte, cmdDisableAcceleration);
}

void setSpeed(int speed) {
    setMode(1);
    disableAcceleration();
    sendCommand(cmdSetMotor1, speed);
    sendCommand(cmdSetMotor2, speed);
}

void setSpeed(int speed1, int speed2) {
    setMode(1),
    disableAcceleration();
    sendCommand(cmdSetMotor1, speed1);
    sendCommand(cmdSetMotor2, speed2);
}

void setMode(int mode) {
    sendCommand(cmdSetMode, mode);
}

void resetEncoders() {
    sendCommand(cmdByte, cmdResetEncoders) ;
}

long getEncoder1() {
    return get4Bytes(cmdGetEncoder1);
}

long getEncoder2() {
    return get4Bytes(cmdGetEncoder2);
}


//***************************************************************************************
//Abstract MD25 communication methods and functions
//***************************************************************************************

void sendCommand(char command) {
    char buffer[1];
    buffer[0] = command;
    i2c.write(md25Address, &buffer[0], 1);
}

void sendCommand(char command1, char command2 ) {

    char buffer[2];
    buffer[0] = command1;
    buffer[1] = command2;

    i2c.write(md25Address, &buffer[0], 2);
}

long get4Bytes(char command) {
    long tempWord = 0;
    char cmd[4];

    //i2c request
    sendCommand(command);

    //i2c read data back
    i2c.read(md25Address, cmd, 4);// Request 4 bytes from MD25

    //FIXED 22FEB2012 CRISPIAN Taken 0.07 delay off.

    //First byte is largest, shift 4 bytes into tempWord
    tempWord += cmd[0] << 24;
    tempWord += cmd[1] << 16;
    tempWord += cmd[2] << 8;
    tempWord += cmd[3] ;

    return tempWord;
}