BT control

robot.cpp

Committer:
Throwbot
Date:
2014-05-20
Revision:
0:603c28b75dc1

File content as of revision 0:603c28b75dc1:

/* mbed ROBOT Library, for SUTD evobot project, Generation 1
 * Copyright (c) 2013, SUTD
 * Author: Mark VanderMeulen
 *
 * Dec 18, 2013
 *
 * You may want to rewrite this entire library, as this one is only half-finished
 *
 * This library allows the user to use each module on the Evobot Generation 1
 * Functionality:
 *      -Bluetooth connection
 *      -MPU (accelerometer/gyroscope) connection
 *      -Orientation in the XY plane (using Z-axis gyroscope only)
 *      -Remote control functionality (via bluetooth)
 *
 * Future functions:
 *      -Switch to turn bluetooth on/off
 *      -Switch to turn MPU on/off (in case of connection errors with the MPU: restart and reconnect
 *      -Calculation of distance travelled (use integration of accelerometer, maybe use Kalman filter)
 *      -Access to the DMP (Digital motion processor) on the MPU to calculate 3D orientation.
 *      -RF mesh network so robots can connect to eachother
 *      -Camera (requires an add-on to the circuit board at the moment)
 */


#include "robot.h"
#include "math.h"
//*********************************CONSTRUCTOR*********************************//
Robot::Robot() : bt(tx_bt,rx_bt),
    rf24(PTD2, PTD3, PTD1, PTD0, PTD5, PTD4),
    mpu(PTE0, PTE1),
    myled(LED),
    btSwitch(PTE25),
    currentSensor(CURRENTSENSOR_PIN),
    irSensorL(irL),
    irSensorC(irC),
    irSensorR(irR),
    voltageSensor(VOLTAGESENSOR_PIN),
    PWMA(MOT_PWMA_PIN),
    PWMB(MOT_PWMB_PIN),
    AIN1(MOT_AIN1_PIN),
    AIN2(MOT_AIN2_PIN),
    BIN1(MOT_BIN1_PIN),
    BIN2(MOT_BIN2_PIN),
    STBY(MOT_STBY_PIN)
{

    stop();  //Initialize motors as stopped//

    btSwitch = 1;    //turn on bluetooth
    myled = 0;   //turn ON status LED (0 = on, 1 = 0ff)
    timeNext = 0;
    //currentAvg = 0;          /////////////REMOVE currentAvg LATER. TESTING PURPOSES ONLY////////

    target_angle = 0;    //direction we want the robot to be pointed
    angle_origin = 0;    //you can use this to modify the angle of origin
    origin = 0;          //the (x,y) location of the origin (this should be a point, not a double)
    rz = 0;          //The current rotation in the Z-axis
    dx = 0;          //The current displacement in the x-axis    (side-side)
    dy = 0;          //The current displacement in the y-axis    (forward-back)
    dz = 0;          //The current displacement in the z-axis    (up-down)

    AUTO_ORIENT = 1;     //robot will automatically orient iteslf using the gyroscope
    REMOTE_CONTROL = 1;  //robot can be controlled over bluetooth

    tt.start();   //start timer
    mpu.testConnection();
    wait(1);
    MPU_OK = 0;

    //initialize MPU
    if (mpu.testConnection()) {
        mpu.setBW(MPU6050_BW_10);   //default set low pass filter bandwidth to 10HZ
        mpu.setGyroRange(MPU6050_GYRO_RANGE_500); //default set the gyro range to 500deg/s (robot turning exceeds 250deg/s)
        mpu.setAcceleroRange(MPU6050_ACCELERO_RANGE_2G);        //default set accelero range to 2g
        MPU_OK=1;
        myled = 0;  //turn on LED
        calibrate();
    } else if(0) { //this section is current disabled. change to (1) if you want to retry the accelerometer connection.
        myled = 1;  //turn off LED
        for (int i = 0; i<25; i++) {
            myled = !myled;
            wait_ms(50);
            if (mpu.testConnection()) {
                i = 25;
                myled = 0;
                MPU_OK=1;
            } else
                myled = 1;
            wait_ms(50);
        }
    }
    myled = MPU_OK;  //If LED is off, it is ok. If LED is on, there was a MPU error. Board needs to be restarted.
    //In the future, at a transistor to switch on/off the mpu in case there is an MPU error. Right now it needs a manual restart.

    bt.baud(BaudRate_bt);    //Set bluetooth baud rate

    //Initialize RF chip
//char txData[TRANSFER_SIZE], rxData[TRANSFER_SIZE];
// int txDataCnt = 0;
// int rxDataCnt = 0;
    rf24.powerUp();
    rf24.setTransferSize( TRANSFER_SIZE );

    rf24.setReceiveMode();
    rf24.enable();



}

//*********************************MOTORS*********************************//
void Robot::motor_control(int Lspeed, int Rspeed)
{
    //Controls the motors. 0 = stopped, 100 = full speed, -100 = reverse speed
    if (!Lspeed && !Rspeed)     //stop//
        STBY = 0;
    else
        STBY = 1;

    //make sure 'speeds' are between -100 and 100, and not between abs(0 to 10)
    if(Lspeed > 100) Lspeed = 100;
    else if (Lspeed < -100) Lspeed = -100;
    else if (Lspeed < 0 && Lspeed > -15)   Lspeed = -15;    //prevent speed from being less than 15
    else if (Lspeed > 0 &&  Lspeed < 15)    Lspeed = 15;
    if(Rspeed > 100) Rspeed = 100;
    else if (Rspeed < -100) Rspeed = -100;
    else if (Rspeed < 0 && Rspeed > -15)   Rspeed = -15;
    else if (Rspeed > 0 &&  Rspeed < 15)    Rspeed = 15;

    if (!Rspeed) {  //if right motor is stopped
        AIN1 = 0;
        AIN2 = 0;
        PWMA = 0;
    } else if (!Lspeed) { //if left motor is stopped
        BIN1 = 0;
        BIN2 = 0;
        PWMB = 0;
    }
    //RIGHT MOTOR//
    if(Rspeed > 0) {     //Right motor fwd
        AIN1 = MOTOR_R_DIRECTION;   //set the motor direction
        AIN2 = !AIN1;
    } else {     //Right motor reverse
        AIN2 = MOTOR_R_DIRECTION;
        AIN1 = !AIN2;
    }
    PWMA = abs(Rspeed/100.0);
    //LEFT MOTOR//
    if(Lspeed >0) {
        BIN1 = MOTOR_L_DIRECTION;
        BIN2 = !BIN1;
    } else {
        BIN2 = MOTOR_L_DIRECTION;
        BIN1 = !BIN2;
    }
    PWMB = abs(Lspeed/100.0);
}

void Robot::stop()
{
    motor_control(0,0);
}
void Robot::set_speed(int Speed)
{
    speed = Speed;
    motor_control(speed,speed);
}

//************************Setting direction of robot****************************//
void Robot::set_direction(double angle)
{
    //Set the direction the robot should be facing from origin(in radians)
    target_angle = angle;
}
void Robot::set_direction_deg(double angle)
{
    //Set the direction the robot should be facing from origin (in degrees)
    target_angle = angle*M_PI/180;
}
void Robot::auto_enable(bool x)
{
    AUTO_ORIENT = x;
}

//************************UPDATE: To be called in main loop***************************//
//This calculates position and angle
//Also orients robot in the correct direction
//if 'print' is 1, print acceleration and gyro data over bluetooth
void Robot::update()
{
    double SP;
    int rotationSpeed;
    //int n=50;

    double Kp = 100; //weighting values for PID controller. Only Proportional component is used.
    double Ki = 0;  //Integral component is not used
    double Kd = 0;  //derivative component is not used

    if(MPU_OK) { //only do this if MPU is connected
        wait(0.1);
        mpu.getAcceleroRaw(accdata);
        mpu.getGyroRaw(gyrodata);
        time = tt.read();
//bt.printf("s;t_%d;1_%lf;2_%lf;3_%d;4_%d;5_%d;6_%d;7_%d;8_%d;9_%lf;10_%lf;11_%lf;s\n\r",time_robot,getCurrent(),getVoltage(),accdata[0],accdata[1],accdata[2],gyrodata[0],gyrodata[1],gyrodata[2],irReadL(),irReadC(),irReadR());
        /*if(REMOTE_CONTROL) {    //if remote control over bluetooth is enabled
            m_ctrl=remote_ctrl();      //call the romote control function
        }*/
        if(AUTO_ORIENT) {       //enable PID control of angle
            SP = target_angle;  //desired angle (radians)
            rz = rz + ((gyrodata[2]-gyroOffset[2])*(time-timePrev)/gyroCorrect);    //rz is the rotation(radians) from start
            Irz = Irz + (rz-SP)*(time-timePrev);    //Irz needs to be reset every so often, or it should be ignored
            rotationSpeed = (Kp*(rz-SP) + Ki*Irz + Kd*gyrodata[2]/gyroCorrect);
            /*data[0]= getCurrent();
            data[1]= getVoltage();
            data[2]= accdata[0];
            data[3]= accdata[1];
            data[4]= accdata[2];
            data[5]= gyrodata[0];
            data[6]= gyrodata[1];
            data[7]= gyrodata[2];
            data[8]= irReadL();
            data[9]= irReadC();
            data[10]= irReadC();
            data[11]= rz;*/

            //TODO: pull "rotationspeed" up to 10 if it is less than 10. This will(should) improve the ability to drive straight

            if(time > timeNext || (speed==0 && rotationSpeed ==0)) {   //prevent the motor control from being set too often
                timeNext = time + MOTOR_INTERVAL/1000.0;   //only set the motor speed every 10ms
                //    if(abs(rz-SP)>(10*M_PI/180))
                //  {
                //  motor_control((speed+rotationSpeed)/20, (speed-rotationSpeed)/20);    //Set motor speeds
                //}
                // else
                //{
                motor_control((speed+rotationSpeed), (speed-rotationSpeed));    //Set motor speeds
                //}
            }
        }
        timePrev = time;
    }
}

void Robot::remote_ctrl(char c,int desired_speed,int desired_angle)
{
    //This is a private function
    Irz = 0;
    switch (c) {
        case ctrl_forward:
            speed = -1*desired_speed;
            break;
        case ctrl_backward:
            speed = 1*desired_speed;
            break;
        case ctrl_right:
            target_angle += 90*M_PI/180;
            break;
        case ctrl_left:
            target_angle -= 90*M_PI/180;
            break;
        case ctrl_calibrate:
            calibrate();
            break;
        case ctrl_turn_angle_cw:
            target_angle +=desired_angle*M_PI/180;
            break;
        case ctrl_turn_angle_ccw:
            target_angle -=desired_angle*M_PI/180;
            break;
        default:
            speed = 0;
            stop();
            break;
    }
}
//*********************************CALIBRATE*********************************//
void Robot::calibrate()
{
    stop();
    wait(1.5);
    double timeNOW = tt.read();
    int count=0;
    int i;

    //set the accelerometer and gyro offsets
    while(tt.read()<timeNOW+1.5) { //calculate gyro offset
        mpu.getGyroRaw(gyrodata);
        mpu.getAcceleroRaw(accdata);
        for(i=0; i<3; i++) {
            gyroOffset[i] += gyrodata[i];
            accOffset[i] += accdata[i];
        }
        count++;
    }
    for(i=0; i<3; i++) {
        gyroOffset[i] = gyroOffset[i]/count; //rxOffset
        accOffset[i] = accOffset[i]/count;
    }
    accOffset[2] = 0;   //we don't want to remove GRAVITY from the z-axis accelerometer.
}

//*********************************ROBOT-SENSORS*********************************//

double Robot::getCurrent()
{

    double Vsensor = currentSensor.read();
    Vsensor = 1000*((.8998-Vsensor)/.6411);
    return Vsensor;
}
double Robot::getVoltage()
{
    float voltage = 3.3*(voltageSensor.read()); // convert analog value to voltage at node
    voltage *= 1.5; // inverse of voltage divider
    return voltage;
}
void Robot::getIMU(float *adata, float *gdata)
{
    mpu.getAcceleroRaw(accdata);
    mpu.getGyroRaw(gyrodata);
    /*imuFilter.updateFilter(gyrodata[0],gyrodata[1],gyrodata[2],accdata[0],accdata[1],accdata[2]);
       imuFilter.computeEuler();
       gdata[0]=(float)imuFilter.getRoll();
       gdata[1]=(float)imuFilter.getPitch();
       gdata[2]= (float)imuFilter.getYaw();*/
    // adata[0] = (float) (accdata[0]);
    //adata[1] = (float) (accdata[1]);
    //adata[2] = (float) (accdata[2]);
    adata[0] = ((float) (accdata[0]-accOffset[0]))/32655*9.81*2;
    adata[1]= ((float) (accdata[1]-accOffset[1]))/32655*9.81*2;
    adata[2]= ((float) (accdata[2]-accOffset[2]))/32655*9.81*2;
    gdata[0]=(((float)(gyrodata[0]-gyroOffset[0]))/((float)gyroCorrect))*180/(M_PI);
    gdata[1]=(((float)(gyrodata[1]-gyroOffset[1]))/((float)gyroCorrect))*180/(M_PI);
    gdata[2]=(((float)(gyrodata[2]-gyroOffset[2]))/((float)gyroCorrect))*180/(M_PI);
}

double Robot::irReadL()
{
    int C = 14;
    double D = -1.1;
    double r = irSensorL.read();
    double reading=(pow(r,D)* C )+ 4;
    return reading;

}

double Robot::irReadC()
{
    int C = 14;
    double D = -1.1;
    double r = irSensorC.read();
    double reading=(pow(r,D)* C )+ 4;
    return reading;
}

double Robot::irReadR()
{
    int C = 14;
    double D = -1.1;
    double r = irSensorR.read();
    double reading=(pow(r,D)* C )+ 4;
    return reading;
}
double Robot::return_rotation()
{
    return rz;
}
int Robot::isMPU()
{
    return MPU_OK;
}

//******************RF24 CHIP FUNCTIONS****************************//
void Robot::rf24_power(int x)
{
    if(x)   //power up
        rf24.powerUp();
    else    //power down
        rf24.powerDown();
}