RC Boat using a C# GUI over XBee communication.

Dependencies:   MODSERIAL LSM9DS0 Motordriver PID mbed-rtos mbed

RC Boat Wiki Page

Revision:
6:c0a2ac7a8c26
Parent:
4:6f6a9602e92d
Child:
7:bde99b0b3a86
--- a/main.cpp	Wed Apr 29 17:30:02 2015 +0000
+++ b/main.cpp	Thu Apr 30 20:16:00 2015 +0000
@@ -4,7 +4,7 @@
 #include "PID.h"
 #include "motordriver.h"
 #include "MODSERIAL.h"
-//#include "IMUfilter.h"
+
 
 //Gravity at Earth's surface in m/s/s
 #define g0 9.812865328
@@ -29,7 +29,9 @@
 #define LSM9DS0_XM  0x1E // Would be 0x1E if SDO_XM is LOW
 #define LSM9DS0_G   0x6A // Would be 0x6A if SDO_G is LOW
 #define RATE  0.05 // Define rate for PID loop
-
+//Multiply the linear and angular speed to change from [-1,1] to [-Multiplier, Multiplier]
+#define LINEAR_MULTIPLIER 5
+#define ANGULAR_MULTIPLIER 90
 
 Serial pc(USBTX, USBRX);
 LSM9DS0 imu(p28, p27, LSM9DS0_G, LSM9DS0_XM);
@@ -60,13 +62,13 @@
 double w_xBias;
 double w_yBias;
 double w_zBias;
- 
+
 //Offsets for the accelerometer.
 //Same as with the gyroscope.
 double a_xBias;
 double a_yBias;
 double a_zBias;
- 
+
 //Accumulators used for oversampling and then averaging.
 double a_xAccumulator = 0;
 double a_yAccumulator = 0;
@@ -74,7 +76,7 @@
 double w_xAccumulator = 0;
 double w_yAccumulator = 0;
 double w_zAccumulator = 0;
- 
+
 //Accelerometer and gyroscope readings for x, y, z axes.
 double a_x;
 double a_y;
@@ -87,7 +89,7 @@
 double last_a_x;
 double last_a_y;
 double last_a_z;
- 
+
 //Buffer for accelerometer readings.
 int readings[3];
 //Number of accelerometer samples we're on.
@@ -100,12 +102,16 @@
 double v_y = 0;
 double v_z = 0;
 double v_mag2 = 0; // linear velocity squared. sqrt() is comupationally difficult
- 
- /*
+
+
 //values for pwm wave to motors
+/*
 float linearOutput = 0;
 float angularOutput = 0;
 */
+float leftMotorCO = 0;
+float rightMotorCO = 0;
+
 
 //setpoints from xbee
 float setLinear = 0;
@@ -125,186 +131,283 @@
 //Take a set of samples and average them.
 void sampleGyroscope(void);
 
-void startPID() {
+
+
+void debug(void const *args)
+{
+    while(1) {
+        //pc.printf("linearOutput: %f    angularOutput: %f\n",linearOutput, angularOutput);
+        //pc.printf("leftMotorCO: %f     rightMotorCO: %f\n", leftMotorCO, rightMotorCO);
+        pc.printf("setLinear: %f     setAngular: %f\n", setLinear, setAngular);
+        pc.printf("linearMagnitude: %f     angularSpeed: %f\n", v_mag2, w_z);
+        pc.printf("leftMotorCO: %f     rightMotorCO: %f\n", leftMotorCO, rightMotorCO);
+        Thread::wait(2000);
+    }
+}
+
+
+void startPID()
+{
     linearController.setMode(AUTO_MODE);
     angularController.setMode(AUTO_MODE);
     usePID = 1;
 }
-    
-void stopPID() {
+
+void stopPID()
+{
     linearController.setMode(MANUAL_MODE);
     angularController.setMode(MANUAL_MODE);
     usePID = 0;
 }
 
 //Variables for storing commands
-char commBuffer[2][64];
+char commBuffer [64];
 int currentBuff = 0;
 
-void parseCommand() {
-    float tempForward, tempAngular;
+
+void parseCommand()
+{
+    float *tempForward, *tempAngular;
+    volatile char forwardBuffer [4];
+    volatile char angularBuffer [4];
     int tempEnabled, tempPID;
-    sscanf(commBuffer[currentBuff], "F%f A%f E%d P%d\r", &tempForward, &tempAngular, &tempEnabled, &tempPID);
+    char statusChar;
+    
+    
+    // First char (commBuffer[0]) is header info. commBuffer[1-4] is forward direction in raw float value. CommBUffer[5-8] is reverse direction in raw float value.
+    //memcpy(&tempForward, (commBuffer + 1), 4);
+    //memcpy(&tempAngular, (commBuffer + 5), 4);
+    
+
     
+    // now convert the char arrays into floats
+    tempForward = (float*) (commBuffer + 1);
+    tempAngular = (float*) (commBuffer + 5);
+    
+    
+    //tempForward = (float*) forwardBuffer;
+    //tempAngular = (float*) angularBuffer;
+    
+    statusChar = commBuffer[9]; //contains data for enable and enablePID
+    tempPID = (int) (statusChar & 0x0F); //extract the last 4 bits and type cast to an int
+    tempEnabled = (int) (statusChar & 0xF0); //extract the first 4 bits and type cast to an int
     //Change global variables
-    setLinear = tempForward;
-    setAngular = tempAngular;
+    setLinear = *tempForward * LINEAR_MULTIPLIER;
+    setAngular = *tempAngular * ANGULAR_MULTIPLIER;
     enabled = tempEnabled;
-    
+
     if (tempPID) {
         startPID();
     } else {
         stopPID();
     }
-     
+
 }
- 
-void parseInput(void const *args) {    
+
+void parseInput(void const *args)
+{
     static int i = 0;
+    
     while (1) {
+        /*
         while (xbee.readable()) {
             commBuffer[1 - currentBuff][i] = xbee.getc();
-            if (commBuffer[1 - currentBuff][i] == '\r') {
-                commBuffer[1 - currentBuff][i+1] = '\0';
+            if (commBuffer[1 - currentBuff][i] == 0xAA) {
                 i = 0;
                 currentBuff = 1 - currentBuff;
-                parseCommand();
-                commReceived = 1;
+                if (commBuffer[currentBuff][0] == 0xFF) {
+                    parseCommand();
+                    commReceived = 1;
+                }
+            } else {
+                ++i;
+            }
+        }
+        */
+        
+        while (xbee.readable()) {
+            commBuffer[i] = xbee.getc();
+            if (commBuffer[i] == 0xAA) { //end of message char
+                i = 0;
+                if (commBuffer[0] == 0xFF) { // buffer recieved is correct length and bit. parse the data
+                    parseCommand();
+                    commReceived = 1;
+                }
             } else {
                 ++i;
             }
         }
-        Thread::wait(50);
+        
+
+
+
+
+
+        /*
+        while (xbee.readable()) {// something arrived from the xbee
+            commBuffer [0] = xbee.getc(); //[1 - currentBuff][i] = xbee.getc();
+            commBuffer [1] = xbee.getc();
+            if (commBuffer [0] == 0x5 && commBuffer[1] == 0x5) { //the frame from xbee has ended // [1 - currentBuff][i] == '\r') {
+                // next 4 chars (32 bits) are going to be the forward speed
+                for (int fBi = 0; fBi < 4; ++fBi) {
+                    forwardBuffer[fBi] = xbee.getc();
+                }
+                for (int rBi = 0; rBi < 4; ++rBi) {
+                    reverseBuffer[rBi] = xbee.getc();
+                }
+                enabled = (int) xbee.getc();
+                tempPID = (int) xbee.getc();
+                if (tempPID) {
+                    startPID();
+                } else {
+                    stopPID();
+                }
+                commBuffer [2] = xbee.getc();
+                commBuffer [3] = xbee.getc();
+                if (commBuffer [3] == 0xA && commBuffer [4] == 0xA) {
+                commReceived = 1;
+                }
+
+            }
+        }
+        */
+        Thread::wait(100);
     }
 }
- 
+
 
-void checkCOMRecieved() {
- if (commReceived == 0) {
-    stopPID();
-    enabled = 0;
-    led1 = led2 = led3 = led4 = 1;
+void checkCOMRecieved()
+{
+    if (commReceived == 0) {
+        stopPID();
+        enabled = 0;
+        led1 = led2 = led3 = led4 = 1;
     } else {
         led1 = led2 = led3 = led4 = 0;
     }
     commReceived = 0;
 }
 
-void sampleAccelerometer(void const *args) {
- while(1) {
-    while(usePID != 1) {
-    Thread::wait(1000); //wait 1 sec and check if we are using the PID loop again.
-    }
-    //Have we taken enough samples?
-    if (accelerometerSamples == SAMPLES) {
- 
-        //Average the samples, remove the bias, and calculate the acceleration
-        //in m/s/s.
-        a_x = ((a_xAccumulator / SAMPLES) - a_xBias) * ACCELEROMETER_GAIN;
-        a_y = ((a_yAccumulator / SAMPLES) - a_yBias) * ACCELEROMETER_GAIN;
-        a_z = ((a_zAccumulator / SAMPLES) - a_zBias) * ACCELEROMETER_GAIN;
- 
-        a_xAccumulator = 0;
-        a_yAccumulator = 0;
-        a_zAccumulator = 0;
-        accelerometerSamples = 0;
-        pcMutex.lock();
-        pc.printf("a_x: %f  a_y: %f  a_z: %f \n",a_x,a_y,a_z);
-        pcMutex.unlock();
-        
-        // integrate to get velocity. make sure to subtract gravity downwards!
-        
-        v_x = v_x + (a_x + last_a_x)/2 * ACC_RATE * SAMPLES;
-        v_y = v_y + (a_y + last_a_y)/2 * ACC_RATE * SAMPLES;
-        v_z = v_z + (a_z + last_a_z)/2 * ACC_RATE * SAMPLES;
-        
-        last_a_x = a_x;
-        last_a_y = a_y;
-        last_a_z = a_z;
-        pcMutex.lock();
-        pc.printf("v_x: %f  v_y: %f  v_z: %f \n",v_x,v_y,v_z);
-        pcMutex.unlock();
- 
-    } else {
-        //Take another sample.
-        imu.readAccel();
-        pcMutex.lock();
-        pc.printf("A: ");
-        pc.printf("%d", imu.ax);
-        pc.printf(", ");
-        pc.printf("%d",imu.ay);
-        pc.printf(", ");
-        pc.printf("%d\n",imu.az);
-        pcMutex.unlock();
-        
-        a_xAccumulator += imu.ax;
-        a_yAccumulator += imu.ay;
-        a_zAccumulator += imu.az;
- 
-        accelerometerSamples++;
-        Thread::wait(ACC_RATE * 1000);
-    }
+void sampleAccelerometer(void const *args)
+{
+    while(1) {
+        while(usePID != 1) {
+            Thread::wait(1000); //wait 1 sec and check if we are using the PID loop again.
+        }
+        //Have we taken enough samples?
+        if (accelerometerSamples == SAMPLES) {
+
+            //Average the samples, remove the bias, and calculate the acceleration
+            //in m/s/s.
+            a_x = ((a_xAccumulator / SAMPLES) - a_xBias) * ACCELEROMETER_GAIN;
+            a_y = ((a_yAccumulator / SAMPLES) - a_yBias) * ACCELEROMETER_GAIN;
+            a_z = ((a_zAccumulator / SAMPLES) - a_zBias) * ACCELEROMETER_GAIN;
+
+            a_xAccumulator = 0;
+            a_yAccumulator = 0;
+            a_zAccumulator = 0;
+            accelerometerSamples = 0;
+            //pcMutex.lock();
+            //pc.printf("a_x: %f  a_y: %f  a_z: %f \n",a_x,a_y,a_z);
+            //pcMutex.unlock();
+
+            // integrate to get velocity. make sure to subtract gravity downwards!
+
+            v_x = v_x + (a_x + last_a_x)/2 * ACC_RATE * SAMPLES * 1000;
+            v_y = v_y + (a_y + last_a_y)/2 * ACC_RATE * SAMPLES * 1000;
+            v_z = v_z + (a_z + last_a_z)/2 * ACC_RATE * SAMPLES * 1000;
+
+            last_a_x = a_x;
+            last_a_y = a_y;
+            last_a_z = a_z;
+            //pcMutex.lock();
+            //pc.printf("v_x: %f  v_y: %f  v_z: %f \n",v_x,v_y,v_z);
+            //pcMutex.unlock();
+
+        } else {
+            //Take another sample.
+            imu.readAccel();
+            /*
+            pcMutex.lock();
+            pc.printf("A: ");
+            pc.printf("%d", imu.ax);
+            pc.printf(", ");
+            pc.printf("%d",imu.ay);
+            pc.printf(", ");
+            pc.printf("%d\n",imu.az);
+            pcMutex.unlock();
+            */
+            a_xAccumulator += imu.ax;
+            a_yAccumulator += imu.ay;
+            a_zAccumulator += imu.az;
+
+            accelerometerSamples++;
+            Thread::wait(ACC_RATE * 1000);
+        }
 
 
-}
+    }
 }
- 
-void calibrateAccelerometer(void) {
+
+void calibrateAccelerometer(void)
+{
 
     led1 = 1;
-    
+
     a_xAccumulator = 0;
     a_yAccumulator = 0;
     a_zAccumulator = 0;
-    
-    
+
+
     //Take a number of readings and average them
     //to calculate the zero g offset.
     for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
- 
+
         imu.readAccel();
- 
+
         a_xAccumulator += (double) imu.ax;
         a_yAccumulator += (double) imu.ay;
         a_zAccumulator += (double) imu.az;
 
         wait(ACC_RATE);
- 
+
     }
- 
+
     a_xAccumulator /= CALIBRATION_SAMPLES;
     a_yAccumulator /= CALIBRATION_SAMPLES;
     a_zAccumulator /= CALIBRATION_SAMPLES;
- 
+
     //At 4mg/LSB, 250 LSBs is 1g.
     a_xBias = a_xAccumulator;
     a_yBias = a_yAccumulator;
     //a_zBias = (a_zAccumulator - (1/0.00006103515625));
     a_zBias = a_zAccumulator; // calibrate so that gravity is already out of the equation
-    
+    pc.printf("A_Bias     ax: %f     ay: %f     az: %f \n", a_xBias,a_yBias,a_zBias);
+    /*
     pcMutex.lock();
-    pc.printf("A_Bias: ");
+    pc.printf("A_Bias     ax: %f     ay: %f     az: %f \n", a_xBias,a_yBias,a_zBias);
     pc.printf("%f", a_xBias);
     pc.printf(", ");
     pc.printf("%f",a_yBias);
     pc.printf(", ");
     pc.printf("%f\n",a_zBias);
     pcMutex.unlock();
-    
+    */
     a_xAccumulator = 0;
     a_yAccumulator = 0;
     a_zAccumulator = 0;
     pc.printf("done calibrating accel\n");
     led1 = 0;
 }
- 
- 
-void calibrateGyroscope(void) {
+
+
+void calibrateGyroscope(void)
+{
     led2 = 1;
     w_xAccumulator = 0;
     w_yAccumulator = 0;
     w_zAccumulator = 0;
- 
+
     //Take a number of readings and average them
     //to calculate the gyroscope bias offset.
     for (int i = 0; i < CALIBRATION_SAMPLES; i++) {
@@ -313,18 +416,18 @@
         w_yAccumulator += (double) imu.gy;
         w_zAccumulator += (double) imu.gz;
         Thread::wait(GYRO_RATE * 1000);
- 
+
     }
- 
+
     //Average the samples.
     w_xAccumulator /= CALIBRATION_SAMPLES;
     w_yAccumulator /= CALIBRATION_SAMPLES;
     w_zAccumulator /= CALIBRATION_SAMPLES;
- 
+
     w_xBias = w_xAccumulator;
     w_yBias = w_yAccumulator;
     w_zBias = w_zAccumulator;
-     
+
     pcMutex.lock();
     pc.printf("G_Bias: ");
     pc.printf("%f", w_xBias);
@@ -333,75 +436,77 @@
     pc.printf(", ");
     pc.printf("%f\n",w_zBias);
     pcMutex.unlock();
-    
+
     w_xAccumulator = 0;
     w_yAccumulator = 0;
     w_zAccumulator = 0;
     pc.printf("done calibrating gyro\n");
     led2 = 0;
 }
- 
-void sampleGyroscope(void const *args) {
- while(1){
-    while(usePID != 1) {
-        Thread::wait(1000); //wait 1 sec and check if we are using the PID loop again.
+
+void sampleGyroscope(void const *args)
+{
+    while(1) {
+        while(usePID != 1) {
+            Thread::wait(1000); //wait 1 sec and check if we are using the PID loop again.
         }
-    //Have we taken enough samples?
-    if (gyroscopeSamples == SAMPLES) {
- 
-        //Average the samples, remove the bias, and calculate the angular
-        //velocity in deg/s.
-        w_x = ((w_xAccumulator / SAMPLES) - w_xBias) * GYROSCOPE_GAIN;
-        w_y = ((w_yAccumulator / SAMPLES) - w_yBias) * GYROSCOPE_GAIN;
-        w_z = ((w_zAccumulator / SAMPLES) - w_zBias) * GYROSCOPE_GAIN;
-        pcMutex.lock();
-        pc.printf("w_x: %f  w_y: %f  w_z: %f \n",w_x,w_y,w_z);
-        pcMutex.unlock();
-        w_xAccumulator = 0;
-        w_yAccumulator = 0;
-        w_zAccumulator = 0;
-        gyroscopeSamples = 0;
- 
-    } else {
-        imu.readGyro();
-        pcMutex.lock();
-        pc.printf("G: ");
-        pc.printf("%d", imu.gx);
-        pc.printf(", ");
-        pc.printf("%d",imu.gy);
-        pc.printf(", ");
-        pc.printf("%d\n",imu.gz);
-        pcMutex.unlock();
-        
-        w_xAccumulator += imu.gx;
-        w_yAccumulator += imu.gy;
-        w_zAccumulator += imu.gz;
-        
-        gyroscopeSamples++;
+        //Have we taken enough samples?
+        if (gyroscopeSamples == SAMPLES) {
+
+            //Average the samples, remove the bias, and calculate the angular
+            //velocity in deg/s.
+            w_x = ((w_xAccumulator / SAMPLES) - w_xBias) * GYROSCOPE_GAIN;
+            w_y = ((w_yAccumulator / SAMPLES) - w_yBias) * GYROSCOPE_GAIN;
+            w_z = ((w_zAccumulator / SAMPLES) - w_zBias) * GYROSCOPE_GAIN;
+            //pcMutex.lock();
+            //pc.printf("w_x: %f  w_y: %f  w_z: %f \n",w_x,w_y,w_z);
+            //pcMutex.unlock();
+            w_xAccumulator = 0;
+            w_yAccumulator = 0;
+            w_zAccumulator = 0;
+            gyroscopeSamples = 0;
+
+        } else {
+            imu.readGyro();
+            /*
+            pcMutex.lock();
+            pc.printf("G: ");
+            pc.printf("%d", imu.gx);
+            pc.printf(", ");
+            pc.printf("%d",imu.gy);
+            pc.printf(", ");
+            pc.printf("%d\n",imu.gz);
+            pcMutex.unlock();
+            */
+            w_xAccumulator += imu.gx;
+            w_yAccumulator += imu.gy;
+            w_zAccumulator += imu.gz;
+
+            gyroscopeSamples++;
+            Thread::wait(GYRO_RATE * 1000);
+        }
+
         Thread::wait(GYRO_RATE * 1000);
     }
+}
 
-Thread::wait(GYRO_RATE * 1000);
-}
-}
- 
+
 
- 
- 
- void setup()
+
+void setup()
 {
     pc.baud(9600); // Start serial at 115200 bps
     // Use the begin() function to initialize the LSM9DS0 library.
     // You can either call it with no parameters (the easy way):
     //uint16_t status = dof.begin();
-    
+
     //Or call it with declarations for sensor scales and data rates:
     //uint16_t status = imu.begin(dof.G_SCALE_2000DPS,
     //                            dof.A_SCALE_2G, dof.M_SCALE_2GS);
-                                
+
     uint16_t status = imu.begin(imu.G_SCALE_245DPS, imu.A_SCALE_2G, imu.M_SCALE_2GS,
                                 imu.G_ODR_760_BW_100, imu.A_ODR_400, imu.M_ODR_50);
-    
+
     // begin() returns a 16-bit value which includes both the gyro
     // and accelerometers WHO_AM_I response. You can check this to
     // make sure communication was successful.
@@ -409,28 +514,32 @@
     pc.printf("%x\n",status);
     pc.printf("Should be 0x49D4\n");
     pc.printf("\n");
-    
+
     // Set up PID Loops
-    linearController.setInputLimits(-1.0, 1.0);
-    angularController.setInputLimits(-1.0, 1.0);
-    linearController.setOutputLimits(0.0, 1.0);
-    angularController.setOutputLimits(0.0, 1.0);
+    linearController.setInputLimits(-LINEAR_MULTIPLIER * LINEAR_MULTIPLIER, LINEAR_MULTIPLIER * LINEAR_MULTIPLIER);
+    angularController.setInputLimits(-ANGULAR_MULTIPLIER, ANGULAR_MULTIPLIER);
+    linearController.setOutputLimits(-1.0, 1.0);
+    angularController.setOutputLimits(-1.0, 1.0);
     linearController.setSetPoint(0.0);
     angularController.setSetPoint(0.0);
     linearController.setMode(AUTO_MODE);
     angularController.setMode(AUTO_MODE);
-    
+
 }
 
 
-int main() {
+int main()
+{
     float linearOutput = 0;
     float angularOutput = 0;
- 
+    /*
+    float leftMotorCO = 0;
+    float rightMotorCO = 0;
+*/
     pc.printf("Starting IMU filter test...\n");
     setup();
-    
-    
+
+
     //Initialize inertial sensors.
     calibrateAccelerometer();
     calibrateGyroscope();
@@ -438,36 +547,37 @@
     Thread accelThread(sampleAccelerometer);
     Thread gyroThread(sampleGyroscope);
     Thread commThread(parseInput);
+    Thread debugThread(debug);
     commTicker.attach(&checkCOMRecieved, 2.0); // the address of the function to be attached (checkCOMRecieved) and the interval (2 seconds)
     /*
-    pcMutex.lock();
-   pc.printf("done attaching tickers\n\n");
-   pcMutex.unlock();
-*/
+    //pcMutex.lock();
+    pc.printf("done attaching tickers\n\n");
+    //pcMutex.unlock();
+    */
     while (1) {
-        //pc.printf("in loop\n");    
+        //pc.printf("in loop\n");
         if(usePID) {
-            linearController.setSetPoint(setLinear);
+            linearController.setSetPoint(setLinear * setLinear);
             angularController.setSetPoint(setAngular);
-            
+
             v_mag2 = v_x * v_x + v_y * v_y;
             linearController.setProcessValue(v_mag2);
-            angularController.setProcessValue(w_z); // w_z = degrees per second 
+            angularController.setProcessValue(w_z); // w_z = degrees per second
             linearOutput = linearController.compute();
             angularOutput = angularController.compute();
         } else {
-            linearOutput = setLinear;
-            angularOutput = setAngular;
+            linearOutput = setLinear/LINEAR_MULTIPLIER;
+            angularOutput = setAngular/ANGULAR_MULTIPLIER;
         }
-        
+
         if (enabled) {
-            float leftMotorCO = (linearOutput + angularOutput);
-            float rightMotorCO = (linearOutput - angularOutput);
-            
+            leftMotorCO = (linearOutput - angularOutput);
+            rightMotorCO = (linearOutput + angularOutput);
+
             leftMotor.speed(leftMotorCO);
             rightMotor.speed(rightMotorCO);
-            
-            
+
+
             /*
             leftMotor.speed(setLinear);
             rightMotor.speed(setAngular);
@@ -476,15 +586,15 @@
             leftMotor.coast();
             rightMotor.coast();
         }
-            
+
         Thread::wait(RATE * 1000);
- /*
-        pcMutex.lock();
-        pc.printf("%f,%f,%f\n",toDegrees(imuFilter.getRoll()),
-                  toDegrees(imuFilter.getPitch()),
-                  toDegrees(imuFilter.getYaw()));
-        pcMutex.unlock();
-*/
+        /*
+               //pcMutex.lock();
+               pc.printf("%f,%f,%f\n",toDegrees(imuFilter.getRoll()),
+                         toDegrees(imuFilter.getPitch()),
+                         toDegrees(imuFilter.getYaw()));
+               //pcMutex.unlock();
+        */
     }
 
 }
\ No newline at end of file