USMA Jumping Agile Ground Robot

Dependencies:   mbed Servo PPM_USMA UM7_USMA CAN_FIFO_USMA Roboteq_CANOpen_USMA

main.cpp

Committer:
DGonz
Date:
2020-08-25
Revision:
25:83e71ad747ce
Parent:
23:81a709626a96

File content as of revision 25:83e71ad747ce:

/*
JAGBot main program
USMA Jumping Agile Ground Robot
Fall 2019

Authors: 
Dr. Daniel J. Gonzalez - daniel.gonzalez@westpoint.edu
CDT Andy Rodriguez - andres.rodriguez@westpont.edu
CDT Josh Loyd - joshua.loyd@westpoint.edu 
*/
#include "main.h"

using namespace FastMath;

void setupServo() {
    float myRange = .000675;
    float myDegrees = 90;
    myservo0.calibrate(myRange, myDegrees);   
    myservo1.calibrate(myRange, myDegrees);  
    myservo2.calibrate(myRange, myDegrees);  
    myservo3.calibrate(myRange, myDegrees); 
}

void setup(){
    pcSerial.baud(115200);
    pcSerial.printf("----------- Start! -----------\n");
    //Create instance of PPM class
    //Pass in interrupt pin, minimum output value, maximum output value, minimum pulse time from transmitter, maximum pulse time from transmitter, number of channels, throttle channel (used for failsafe)
    ppmInputs = new PPM(PPMinterruptPin, 0, 1, 1000, 1900, 8, 3);
    
    setupServo();
    setupIMU(); //IMU Reading is handled through a Serial Interrupt
    
    //set up timer
    timer.start();
    tPrev = timer.read_us()/1000000.0;
    t = timer.read_us()/1000000.0;
    dt = t - tPrev;
    
    //------------------------------    Servo Out
    myservo0.write(0.5);
    myservo1.write(0.5);
    myservo2.write(0.5);
    myservo3.write(0.5);
    
    //------------------------------    ODrive Out
    odrv0axis0.write(0.5);
    odrv0axis1.write(0.5);
    odrv1axis0.write(0.5);
    odrv1axis1.write(0.5);
    
}

int main() {
    if      (CANTEST){
//        CANTest();
    }else if(SERVOTEST){
//        calibMain(); 
    }else if(RCTEST){
//        RCTest(); 
    }else if(IMUTEST){
//        IMUTest();
    }else{
        wait(0.5);
        setup();
        pcSerial.printf("----------- Loop Start! -----------\n");
        wait(0.5);
        pcSerial.printf("roll, pitch, rollDot, pitchDot, T1, T2, T3, T4, acc, state\n");
        while(isRunning){
            loop();
        }
    }
}

void getRCInputs(){
    //------------------------------    Get RC Input
    //Get channel data (mapped to between 0 and 1 as I passed these in as my max and min in the PPM constructor)
    //The throttle channel will return -1 if the signal from the transmitter is lost (the throttle pulse time goes below the minimum pulse time passed into the PPM constructor)
    ppmInputs->GetChannelData(rcCommandInputsRaw);
    
    // Channels: LUD, RRL, RUD, LRL, Pot1, Pot2, LeftSwitch, Right trigger
    for(int i = 0; i < 8; i++){
        rcCommandInputsRaw[i]*=100;
        rcCommandInputs[i]=rcCommandInputsRaw[i];
        if(i==1){  //If RRL
            rcCommandInputs[i] = map(rcCommandInputs[i], RRL_MIN, RRL_MAX,-100,100);
        }else if(i==0){ //if LUD
            rcCommandInputs[i] = map(rcCommandInputs[i], LUD_MIN, LUD_MAX,-100,100);
        }else if(i==3){ //if LRL
            rcCommandInputs[i] = map(rcCommandInputs[i], LRL_MIN, LRL_MAX,-100,100);
        }else if(i==4 || i==5){ //if Pot1 or Pot 2
            rcCommandInputs[i] = map(rcCommandInputs[i], LRL_MIN, LRL_MAX,0.0,1.0); //Do scaling factor for potentiometers
        }
        
        //Implement deadband
        if(i>=0 && i<=3){
            if(rcCommandInputs[i]<DEADBAND && rcCommandInputs[i]>-DEADBAND){
                rcCommandInputs[i] = 0;
            }else if(rcCommandInputs[i]>=DEADBAND){
                rcCommandInputs[i] = map(rcCommandInputs[i], DEADBAND, 100, 0, 100);
            }else if(rcCommandInputs[i]<=-DEADBAND){
                rcCommandInputs[i] = map(rcCommandInputs[i], -100, -DEADBAND, -100, 00);
            }
        }
    }
}

void scaleSkidSteer(){
    bool flag = 0;
    double maxVal = 0;
    for(int i=0; i<4; i++){
        if(fabs(odrvCmds[i])>100 && fabs(odrvCmds[i])>maxVal){
            flag = 1;
            maxVal = fabs(odrvCmds[i]);
        }
    }
    if(flag){
        for(int i=0; i<4; i++){
            odrvCmds[i] = odrvCmds[i]*100.0/maxVal;
        }
    }
}

void loop(){
    t = timer.read_us()/1000000.0;
    loopCounter++;
    
    //Take Average of IMU Readings (Handled by interrupts)
    pitchAvg+=pitch;
    rollAvg+=roll;
    yawAvg+=yaw;
    rollDotAvg+=rollDot;
    pitchDotAvg+=pitchDot;
    yawDotAvg+=yawDot;
    accXAvg+=accXAvg;
    accYAvg+=accYAvg;
    accZAvg+=accZAvg;
    
    if((t-tPrev)>=PERIOD){
        dt = t - tPrev;
        tPrev = t;
        badTime = (dt>1.20*PERIOD); //If more than 20% off
        getRCInputs();
        
        pitchAvg/=loopCounter;
        rollAvg/=loopCounter;
        yawAvg/=loopCounter;
        rollDotAvg/=loopCounter;
        pitchDotAvg/=loopCounter;
        yawDotAvg/=loopCounter;
        accXAvg/=loopCounter;
        accYAvg/=loopCounter;
        accZAvg/=loopCounter;
        
        if(CONTROL_MODE == 0){ //Do nothing
            //----    Servo Out
            myservo0.write(0.5);
            myservo1.write(0.5);
            myservo2.write(0.5);
            myservo3.write(0.5);
            //----    ODrive Out
            odrv0axis0.write(0.5);
            odrv0axis1.write(0.5);
            odrv1axis0.write(0.5);
            odrv1axis1.write(0.5);
        }else if(CONTROL_MODE==1){ //Pure Skid Steer
            //----    Servo Out
            myservo0.write(0.5);
            myservo1.write(0.5);
            myservo2.write(0.5);
            myservo3.write(0.5);
            //----    ODrive Out
            odrvCmds[0] = rcCommandInputs[3] + rcCommandInputs[0]; // LRL+LUD
            odrvCmds[1] = -rcCommandInputs[3] + rcCommandInputs[0];
            odrvCmds[2] = rcCommandInputs[3] + rcCommandInputs[0];
            odrvCmds[3] = -rcCommandInputs[3] + rcCommandInputs[0];
            
            //Skid Steer Scaling
            scaleSkidSteer();
            
            //Final Scaling with Potentiometer
            for(int i=0; i<4; i++){
                odrvCmds[i]*=rcCommandInputs[4];
            }
            
            odrv0axis0.write(map(odrvCmds[0],-100,100,0,1));
            odrv0axis1.write(map(-odrvCmds[1],-100,100,0,1));
            odrv1axis0.write(map(-odrvCmds[2],-100,100,0,1));
            odrv1axis1.write(map(odrvCmds[3],-100,100,0,1));
        }else if(CONTROL_MODE==2){ //OmniSteer
            // Channels: LUD, RRL, RUD, LRL, Pot1, Pot2, LeftSwitch, Right trigger
                // Channels: LUD, RRL, RUD, LRL, Pot1, Pot2, LeftSwitch, Right trigger
                if(rcCommandInputs[0]==0 && rcCommandInputs[3]==0 && rcCommandInputs[1]!=0 ){  //Turn on Dime
                    myservo0.write(0.75);
                    myservo1.write(0.25);
                    myservo2.write(0.75);
                    myservo3.write(0.25);            
                    odrvCmds[0] = -rcCommandInputs[1]; 
                    odrvCmds[1] = rcCommandInputs[1];
                    odrvCmds[2] = rcCommandInputs[1];
                    odrvCmds[3] = -rcCommandInputs[1];
                }else if(rcCommandInputs[1]==0 && rcCommandInputs[3]!=0 && rcCommandInputs[0]==0){  //Strafe Left-Right
                    myservo0.write(1);
                    myservo1.write(0);
                    myservo2.write(1);
                    myservo3.write(0);
                    odrvCmds[0] = -rcCommandInputs[3]; 
                    odrvCmds[1] = rcCommandInputs[3];
                    odrvCmds[2] = -rcCommandInputs[3];
                    odrvCmds[3] = rcCommandInputs[3];
                }else{  // Steer while driving
                    myservo0.write(0.5 - map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo1.write(0.5 - map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo2.write(0.5 + map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo3.write(0.5 + map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    odrvCmds[0] = -0.1*rcCommandInputs[1] + rcCommandInputs[0]; //LRL+LUD, 3 and 0
                    odrvCmds[1] = 0.1*rcCommandInputs[1] + rcCommandInputs[0];
                    odrvCmds[2] = 0.1*rcCommandInputs[1] + rcCommandInputs[0];
                    odrvCmds[3] = -0.1*rcCommandInputs[1] + rcCommandInputs[0];
                }
                
                //Skid Steer Scaling
                scaleSkidSteer();
                
                //Final Scaling with Potentiometer
                for(int i=0; i<4; i++){
                    odrvCmds[i]*=rcCommandInputs[4];
                    map(odrvCmds[i],-25,25,-25,25);   
                }
                
                odrv0axis0.write(map(odrvCmds[0],-100,100,0,1));
                odrv0axis1.write(map(-odrvCmds[1],-100,100,0,1));
                odrv1axis0.write(map(-odrvCmds[2],-100,100,0,1));
                odrv1axis1.write(map(odrvCmds[3],-100,100,0,1));
        }else if(CONTROL_MODE==3){ //Only Balance
            double kP1 = 10;
            double kD1 = 25;
            double kP2 = 10;
            double kD2 = 25;
            Tx = (kP1*(0 - roll) + kD1*(0 - rollDot))*DEG2RAD;
            Ty = (kP2*(0 - pitch) + kD2*(0 - pitchDot))*DEG2RAD;
        
            myservo0.write(0.75);
            myservo1.write(0.25);
            myservo2.write(0.75);
            myservo3.write(0.25);            
            odrvCmds[0] = KV*HSIN*(Ty + Tx)/2;
            odrvCmds[1] = KV*HSIN*(Ty - Tx)/2;
            odrvCmds[2] = KV*HSIN*(Ty + Tx)/2;
            odrvCmds[3] = KV*HSIN*(Ty - Tx)/2;
            
            //Final Scaling with Potentiometer
            for(int i=0; i<4; i++){
                odrvCmds[i]*=rcCommandInputs[4];
                map(odrvCmds[i],-25,25,-25,25);
            }
            
            odrv0axis0.write(map(odrvCmds[0],-25,25,0,1));
            odrv0axis1.write(map(-odrvCmds[1],-25,25,0,1));
            odrv1axis0.write(map(-odrvCmds[2],-25,25,0,1));
            odrv1axis1.write(map(odrvCmds[3],-25,25,0,1));
        }else if(CONTROL_MODE==4){ //State Machine
            if(state==0){ //Omnisteer
                // Channels: LUD, RRL, RUD, LRL, Pot1, Pot2, LeftSwitch, Right trigger
                if(rcCommandInputs[0]==0 && rcCommandInputs[3]==0 && rcCommandInputs[1]!=0 ){  //Turn on Dime
                    myservo0.write(0.75);
                    myservo1.write(0.25);
                    myservo2.write(0.75);
                    myservo3.write(0.25);            
                    odrvCmds[0] = -rcCommandInputs[1]; 
                    odrvCmds[1] = rcCommandInputs[1];
                    odrvCmds[2] = rcCommandInputs[1];
                    odrvCmds[3] = -rcCommandInputs[1];
                }else if(rcCommandInputs[1]==0 && rcCommandInputs[3]!=0 && rcCommandInputs[0]==0){  //Strafe Left-Right
                    myservo0.write(1);
                    myservo1.write(0);
                    myservo2.write(1);
                    myservo3.write(0);
                    odrvCmds[0] = -rcCommandInputs[3]; 
                    odrvCmds[1] = rcCommandInputs[3];
                    odrvCmds[2] = -rcCommandInputs[3];
                    odrvCmds[3] = rcCommandInputs[3];
                }else{  // Steer while driving
                    myservo0.write(0.5 - map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo1.write(0.5 - map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo2.write(0.5 + map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    myservo3.write(0.5 + map(rcCommandInputs[1],-100,100,-0.5,0.5));
                    odrvCmds[0] = -0.1*rcCommandInputs[1] + rcCommandInputs[0]; //LRL+LUD, 3 and 0
                    odrvCmds[1] = 0.1*rcCommandInputs[1] + rcCommandInputs[0];
                    odrvCmds[2] = 0.1*rcCommandInputs[1] + rcCommandInputs[0];
                    odrvCmds[3] = -0.1*rcCommandInputs[1] + rcCommandInputs[0];
                }
                
                //Skid Steer Scaling
                scaleSkidSteer();
                
                //Final Scaling with Potentiometer
                for(int i=0; i<4; i++){
                    odrvCmds[i]*=rcCommandInputs[4];
                    map(odrvCmds[i],-25,25,-25,25);   
                }
                
                odrv0axis0.write(map(odrvCmds[0],-100,100,0,1));
                odrv0axis1.write(map(-odrvCmds[1],-100,100,0,1));
                odrv1axis0.write(map(-odrvCmds[2],-100,100,0,1));
                odrv1axis1.write(map(odrvCmds[3],-100,100,0,1));
                
                if(rcCommandInputs[5]*sqrt((accX*accX + accY*accY + accZ*accZ))<0.5){ //units are gs
                    state = 1; //If we are in freefall, transition to aerial balance state.
                    tAirStart = t;
                }
            }else if(state==1){ //Aerial Balance
                double kP1 = 75;
                double kD1 = 12;
                double kP2 = 75;
                double kD2 = 12;
                Tx = (kP1*(-1.3 - roll) + kD1*(0 - rollDot))*DEG2RAD;
                Ty = (kP2*(1.5 - pitch) + kD2*(0 - pitchDot))*DEG2RAD;
            
                myservo0.write(0.75);
                myservo1.write(0.25);
                myservo2.write(0.75);
                myservo3.write(0.25);            
                odrvCmds[0] = KV*HSIN*(Ty + Tx)/2;
                odrvCmds[1] = KV*HSIN*(Ty - Tx)/2;
                odrvCmds[2] = KV*HSIN*(Ty + Tx)/2;
                odrvCmds[3] = KV*HSIN*(Ty - Tx)/2;
                
                //Final Scaling with Potentiometer
                for(int i=0; i<4; i++){
                    odrvCmds[i]*=rcCommandInputs[4];
                    odrvCmds[i] = map(odrvCmds[i],-25,25,-25,25);
                }
                
                odrv0axis0.write(map(odrvCmds[0],-25,25,0,1));
                odrv0axis1.write(map(-odrvCmds[1],-25,25,0,1));
                odrv1axis0.write(map(-odrvCmds[2],-25,25,0,1));
                odrv1axis1.write(map(odrvCmds[3],-25,25,0,1));
                 
//                if(rcCommandInputs[5]*sqrt((accX*accX + accY*accY + accZ*accZ))>4){ //units are m/(s^2)   
                if((rcCommandInputs[5]*sqrt((accX*accX + accY*accY + accZ*accZ))>2)||(t-tAirStart>1.5)){ //units are m/(s^2)
                    state = 2; //If we land, transition back to omnidirectional control
                }
            }else if(state==2){ //Land
                myservo0.write(0.75);
                myservo1.write(0.25);
                myservo2.write(0.75);
                myservo3.write(0.25);
                odrvCmds[0] = 0;
                odrvCmds[1] = 0;
                odrvCmds[2] = 0;
                odrvCmds[3] = 0;
                odrv0axis0.write(map(0,-100,100,0,1));
                odrv0axis1.write(map(0,-100,100,0,1));
                odrv1axis0.write(map(0,-100,100,0,1));
                odrv1axis1.write(map(0,-100,100,0,1));
            }
        }
        
        //Telemetry
        teleCounter++;
        if(teleCounter > SERIAL_RATIO and USESERIAL and !inInt){ //and pcSerial.writable()
            //inWrite = 1;
            if(badTime){
                pcSerial.printf("b%f\n",dt-1.25*PERIOD); //(dt-PERIOD)
                badTime = 0;
            }
            teleCounter = 0;            
//            pcSerial.printf("%f, %f, %f, %f, %f, %f, %f, %f\r\n", rcCommandInputsRaw[0], rcCommandInputsRaw[1], rcCommandInputsRaw[2], rcCommandInputsRaw[3], rcCommandInputsRaw[4], rcCommandInputsRaw[5], rcCommandInputsRaw[6], rcCommandInputsRaw[7]);
//            pcSerial.printf("%f, %f, %f, %f, %f, %f, %f, %f, %f, \n", rcCommandInputs[0], rcCommandInputs[1], rcCommandInputs[3], rcCommandInputs[4], rcCommandInputs[5], odrvCmds[0], odrvCmds[1], odrvCmds[2], odrvCmds[3]);
//            pcSerial.printf("%f, %f, %f, \n", roll, pitch, yaw);
//            pcSerial.printf("%f, %f, %f, ", rollDot, pitchDot, yawDot);
//            pcSerial.printf("%f, %f, %f, %f, %f, %f, %f, %f, %i\n",
//                            accX, accY, accZ, accXAvg, accYAvg, accZAvg,
//                            sqrt(accX*accX + accY*accY + accZ*accZ), sqrt(accXAvg*accXAvg + accYAvg*accYAvg + accZAvg*accZAvg), state);
            //            pcSerial.printf("%f, %f, %f, \n", roll, pitch, yaw);
            pcSerial.printf("%f, ",t);
            pcSerial.printf("%f, %f, ", roll, pitch);
            pcSerial.printf("%f, %f, ", rollDot, pitchDot);
            pcSerial.printf("%f, %f, %f, %f ", odrvCmds[0], odrvCmds[1], odrvCmds[2], odrvCmds[3]);
            pcSerial.printf("%f, %i \n", sqrt(accX*accX + accY*accY + accZ*accZ), state);
            
//            pcSerial.printf("%f, %f, %f, %f, %f, %f, %f, %f, %i\n",
//                            accX, accY, accZ, accXAvg, accYAvg, accZAvg,
//                            sqrt(accX*accX + accY*accY + accZ*accZ), sqrt(accXAvg*accXAvg + accYAvg*accYAvg + accZAvg*accZAvg), state);
        }
        pitchAvg=0;
        rollAvg=0;
        yawAvg=0;
        rollDotAvg=0;
        pitchDotAvg=0;
        yawDotAvg=0;
        accXAvg=0;
        accYAvg=0;
        accZAvg=0;
        loopCounter = 0;
    }
}