First trial

Dependencies:   MPU6050 Motor ledControl2 mbed

Fork of BalancingRobotPS3 by Kristian Lauszus

Revision:
4:0b4c320bc948
Parent:
3:c3963f37d597
Child:
5:fc6c7a059759
--- a/BalancingRobot.cpp	Sun Feb 26 13:11:10 2012 +0000
+++ b/BalancingRobot.cpp	Fri Mar 02 09:06:47 2012 +0000
@@ -1,371 +1,398 @@
-/*
- * The code is released under the GNU General Public License.
- * Developed by Kristian Lauszus
- * This is the algorithm for my balancing robot/segway.
- * It is controlled by a PS3 Controller via bluetooth.
- * The remote control code can be found at my other github repository: https://github.com/TKJElectronics/BalancingRobot
- * For details, see http://blog.tkjelectronics.dk/2012/02/the-balancing-robot/
- */
-
-#include "mbed.h"
-#include "BalancingRobot.h"
-#include "Encoder.h"
-
-/* Serial communication */
-Serial xbee(p13,p14); // For wireless debugging
-Serial ps3(p9,p10); // For remote control
-Serial debug(USBTX, USBRX); // USB
-
-/* Setup encoders */
-Encoder leftEncoder(p29,p30);
-Encoder rightEncoder(p28,p27);
-
-/* Timer instance */
-Timer t;
-
-int main() {
-    xbee.baud(115200);
-    ps3.baud(115200);
-    debug.baud(115200);
-
-    leftPWM.period(0.00005); // The motor driver can handle a pwm frequency up to 20kHz (1/20000=0.00005)
-    rightPWM.period(0.00005);
-
-    calibrateSensors(); // Calibrate the gyro and accelerometer relative to ground
-
-    xbee.printf("Initialized\n");
-    processing(); // Send output to processing application
-
-    // Start timing
-    t.start();
-    loopStartTime = t.read_us();
-    timer = loopStartTime;
-
-    while (1) {
-        // See my guide for more info about calculation the angles and the Kalman filter: http://arduino.cc/forum/index.php/topic,58048.0.html
-        accYangle = getAccY();
-        gyroYrate = getGyroYrate();
-
-        pitch = kalman(accYangle, gyroYrate, t.read_us() - timer); // calculate the angle using a Kalman filter
-        timer = t.read_us();
-
-        //debug.printf("Pitch: %f, accYangle: %f\n",pitch,accYangle);
-
-        if (ps3.readable()) // Check if there's any incoming data
-            receivePS3();
-        if (xbee.readable()) // For setting the PID values
-            receiveXbee();
-
-        if (pitch < 70 || pitch > 110) // Stop if falling or laying down
-            stopAndReset();
-        else
-            PID(targetAngle,targetOffset);
-
-
-        loopCounter++;
-        if (loopCounter == 10) { // Update wheel velocity every 100ms
-            loopCounter = 0;
-            wheelPosition = leftEncoder.read() + rightEncoder.read();
-            wheelVelocity = wheelPosition - lastWheelPosition;
-            lastWheelPosition = wheelPosition;
-            //xbee.printf("WheelVelocity: %i\n",wheelVelocity);
-        }
-
-        /* Used a time fixed loop */
-        lastLoopUsefulTime = t.read_us() - loopStartTime;
-        if (lastLoopUsefulTime < STD_LOOP_TIME)
-            wait_us(STD_LOOP_TIME - lastLoopUsefulTime);
-        lastLoopTime = t.read_us() - loopStartTime; // only used for debugging
-        loopStartTime = t.read_us();
-
-        //debug.printf("%i,%i\n",lastLoopUsefulTime,lastLoopTime);
-    }
-}
-void PID(double restAngle, double offset) {
-    if (steerForward) {
-        offset += (double)wheelVelocity/velocityScale; // Scale down offset at high speed and scale up when reversing
-        restAngle -= offset;
-        //xbee.printf("Forward offset: %f\t WheelVelocity: %i\n",offset,wheelVelocity);
-    } else if (steerBackward) {
-        offset -= (double)wheelVelocity/velocityScale; // Scale down offset at high speed and scale up when reversing
-        restAngle += offset;
-        //xbee.printf("Backward offset: %f\t WheelVelocity: %i\n",offset,wheelVelocity);
-    } else if (steerStop) {
-        long positionError = wheelPosition - targetPosition;
-        if(abs(positionError) > 500) {
-            restAngle -= (double)positionError/positionScale;
-            restAngle -= (double)wheelVelocity/velocityScale;
-        } else
-            restAngle -= (double)wheelVelocity/(velocityScale*2);
-        
-        if (restAngle < 80) // Limit rest Angle
-            restAngle = 80;
-        else if (restAngle > 100)
-            restAngle = 100;
-        //xbee.printf("restAngle: %f\t WheelVelocity: %i positionError: %i\n",restAngle,wheelVelocity,positionError);
-    }
-    double error = (restAngle - pitch)/100;
-    double pTerm = Kp * error;
-    iTerm += Ki * error;
-    double dTerm = Kd * (error - lastError);
-    lastError = error;
-
-    double PIDValue = pTerm + iTerm + dTerm;
-
-    //debug.printf("Pitch: %5.2f\tPIDValue:  %5.2f\tpTerm: %5.2f\tiTerm: %5.2f\tdTerm: %5.2f\tKp: %5.2f\tKi: %5.2f\tKd: %5.2f\n",pitch,PIDValue,pTerm,iTerm,dTerm,Kp,Ki,Kd);
-
-    double PIDLeft;
-    double PIDRight;
-    if (steerLeft) {
-        PIDLeft = PIDValue-(0.1);
-        PIDRight = PIDValue+(0.1);
-    } else if (steerRotateLeft) {
-        PIDLeft = PIDValue-(0.2);
-        PIDRight = PIDValue+(0.2);
-    } else if (steerRight) {
-        PIDLeft = PIDValue-(-0.1);
-        PIDRight = PIDValue+(-0.1);
-    } else if (steerRotateRight) {
-        PIDLeft = PIDValue-(-0.2);
-        PIDRight = PIDValue+(-0.2);
-    } else {
-        PIDLeft = PIDValue;
-        PIDRight = PIDValue;
-    }
-    PIDLeft *= 0.9; // compensate for difference in the motors
-
-    //Set PWM Values
-    if (PIDLeft >= 0)
-        move(left, forward, PIDLeft);
-    else
-        move(left, backward, PIDLeft * -1);
-    if  (PIDRight >= 0)
-        move(right, forward, PIDRight);
-    else
-        move(right, backward, PIDRight * -1);
-}
-void receivePS3() {
-    char input[16]; // The serial buffer is only 16 characters
-    int i = 0;
-    while (1) {
-        input[i] = ps3.getc(); // keep reading until it reads a semicolon or it's larger than the serial buffer
-        if (input[i] == ';' || i == 15)
-            break;
-        i++;
-    }
-    //debug.printf("Input: %s\n",input);
-
-    // Set all false
-    steerForward = false;
-    steerBackward = false;
-    steerStop = false;
-    steerLeft = false;
-    steerRotateLeft = false;
-    steerRight = false;
-    steerRotateRight = false;
-
-    /* For remote control */
-    if (input[0] == 'F') { // Forward
-        strtok(input, ","); // Ignore 'F'
-        targetOffset = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-        //xbee.printf("%f\n",targetOffset); // Print targetOffset for debugging
-        steerForward = true;
-    } else if (input[0] == 'B') { // Backward
-        strtok(input, ","); // Ignore 'B'
-        targetOffset = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-        //xbee.printf("%f\n",targetOffset); // Print targetOffset for debugging
-        steerBackward = true;
-    } else if (input[0] == 'L') { // Left
-        if (input[1] == 'R') // Left Rotate
-            steerRotateLeft = true;
-        else
-            steerLeft = true;
-    } else if (input[0] == 'R') { // Right
-        if (input[1] == 'R') // Right Rotate
-            steerRotateRight = true;
-        else
-            steerRight = true;
-    } else if (input[0] == 'S') { // Stop
-        steerStop = true;
-        targetPosition = wheelPosition;
-    }
-
-    else if (input[0] == 'T') { // Set the target angle
-        strtok(input, ","); // Ignore 'T'
-        targetAngle = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-        xbee.printf("%f\n",targetAngle); // Print targetAngle for debugging
-    } else if (input[0] == 'A') { // Abort
-        stopAndReset();
-        while (ps3.getc() != 'C'); // Wait until continue is send
-    }
-}
-void receiveXbee() {
-    char input[16]; // The serial buffer is only 16 characters
-    int i = 0;
-    while (1) { // keep reading until it reads a semicolon or it's larger than the serial buffer
-        input[i] = xbee.getc();
-        if (input[i] == ';' || i == 15)
-            break;
-        i++;
-    }
-    //debug.printf("Input: %s\n",input);
-
-    if (input[0] == 'T') { // Set the target angle
-        strtok(input, ","); // Ignore 'T'
-        targetAngle = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-    } else if (input[0] == 'P') {
-        strtok(input, ",");//Ignore 'P'
-        Kp = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-    } else if (input[0] == 'I') {
-        strtok(input, ",");//Ignore 'I'
-        Ki = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-    } else if (input[0] == 'D') {
-        strtok(input, ",");//Ignore 'D'
-        Kd = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
-    } else if (input[0] == 'A') { // Abort
-        stopAndReset();
-        while (xbee.getc() != 'C'); // Wait until continue is send
-    } else if (input[0] == 'G') // The processing application sends this at startup
-        processing(); // Send output to processing application
-}
-void processing() {
-    /* Send output to processing application */
-    xbee.printf("Processing,%5.2f,%5.2f,%5.2f,%5.2f\n",Kp,Ki,Kd,targetAngle);
-}
-void stopAndReset() {
-    stop(both);
-    lastError = 0;
-    iTerm = 0;
-}
-double kalman(double newAngle, double newRate, double dtime) {
-    // KasBot V2  -  Kalman filter module - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1284738418 - http://www.x-firm.com/?page_id=145
-    // with slightly modifications by Kristian Lauszus
-    // See http://academic.csuohio.edu/simond/courses/eec644/kalman.pdf and http://academic.csuohio.edu/simond/courses/eec644/kalman.pdfhttp://www.cs.unc.edu/~welch/media/pdf/kalman_intro.pdf for more information
-    dt = dtime / 1000000; // Convert from microseconds to seconds
-
-    // Discrete Kalman filter time update equations - Time Update ("Predict")
-    // Update xhat - Project the state ahead
-    angle += dt * (newRate - bias);
-
-    // Update estimation error covariance - Project the error covariance ahead
-    P_00 += -dt * (P_10 + P_01) + Q_angle * dt;
-    P_01 += -dt * P_11;
-    P_10 += -dt * P_11;
-    P_11 += +Q_gyro * dt;
-
-    // Discrete Kalman filter measurement update equations - Measurement Update ("Correct")
-    // Calculate Kalman gain - Compute the Kalman gain
-    S = P_00 + R_angle;
-    K_0 = P_00 / S;
-    K_1 = P_10 / S;
-
-    // Calculate angle and resting rate - Update estimate with measurement zk
-    y = newAngle - angle;
-    angle += K_0 * y;
-    bias += K_1 * y;
-
-    // Calculate estimation error covariance - Update the error covariance
-    P_00 -= K_0 * P_00;
-    P_01 -= K_0 * P_01;
-    P_10 -= K_1 * P_00;
-    P_11 -= K_1 * P_01;
-
-    return angle;
-}
-double getGyroYrate() {
-    // (gyroAdc-gyroZero)/Sensitivity (In quids) - Sensitivity = 0.00333/3.3=0.001009091
-    double gyroRate = -((gyroY.read() - zeroValues[0]) / 0.001009091);
-    return gyroRate;
-}
-double getAccY() {
-    // (accAdc-accZero)/Sensitivity (In quids) - Sensitivity = 0.33/3.3=0.1    
-    double accXval = (accX.read() - zeroValues[1]) / 0.1;
-    double accYval = (accY.read() - zeroValues[2]) / 0.1;
-    accYval--;//-1g when lying down
-    double accZval = (accZ.read() - zeroValues[3]) / 0.1;
-
-    double R = sqrt(pow(accXval, 2) + pow(accYval, 2) + pow(accZval, 2)); // Calculate the force vector
-    double angleY = acos(accYval / R) * RAD_TO_DEG;
-
-    return angleY;
-}
-void calibrateSensors() {
-    LEDs = 0xF; // Turn all onboard LEDs on
-
-    double adc[4] = {0,0,0,0};
-    for (uint8_t i = 0; i < 100; i++) { // Take the average of 100 readings
-        /*
-        adc[0] += gyroY.read()*4095;
-        adc[1] += accX.read()*4095;
-        adc[2] += accY.read()*4095;
-        adc[3] += accZ.read()*4095;
-        */
-        adc[0] += gyroY.read();
-        adc[1] += accX.read();
-        adc[2] += accY.read();
-        adc[3] += accZ.read();
-        wait_ms(10);
-    }
-    zeroValues[0] = adc[0] / 100; // Gyro X-axis
-    zeroValues[1] = adc[1] / 100; // Accelerometer X-axis
-    zeroValues[2] = adc[2] / 100; // Accelerometer Y-axis
-    zeroValues[3] = adc[3] / 100; // Accelerometer Z-axis
-
-    LEDs = 0x0; // Turn all onboard LEDs off
-}
-void move(Motor motor, Direction direction, float speed) { // speed is a value in percentage (0.0f to 1.0f)
-    if (motor == right) {
-        leftPWM = speed;
-        if (direction == forward) {
-            leftA = 0;
-            leftB = 1;
-        } else if (direction == backward) {
-            leftA = 1;
-            leftB = 0;
-        }
-    } else if (motor == left) {
-        rightPWM = speed;
-        if (direction == forward) {
-            rightA = 0;
-            rightB = 1;
-        } else if (direction == backward) {
-            rightA = 1;
-            rightB = 0;
-        }
-    } else if (motor == both) {
-        leftPWM = speed;
-        rightPWM = speed;
-        if (direction == forward) {
-            leftA = 0;
-            leftB = 1;
-
-            rightA = 0;
-            rightB = 1;
-        } else if (direction == backward) {
-            leftA = 1;
-            leftB = 0;
-
-            rightA = 1;
-            rightB = 0;
-        }
-    }
-}
-void stop(Motor motor) {
-    if (motor == left) {
-        leftPWM = 1;
-        leftA = 1;
-        leftB = 1;
-    } else if (motor == right) {
-        rightPWM = 1;
-        rightA = 1;
-        rightB = 1;
-    } else if (motor == both) {
-        leftPWM = 1;
-        leftA = 1;
-        leftB = 1;
-
-        rightPWM = 1;
-        rightA = 1;
-        rightB = 1;
-    }
+/*
+ * The code is released under the GNU General Public License.
+ * Developed by Kristian Lauszus
+ * This is the algorithm for my balancing robot/segway.
+ * It is controlled by a PS3 Controller via bluetooth.
+ * The remote control code can be found at my other github repository: https://github.com/TKJElectronics/BalancingRobot
+ * For details, see http://blog.tkjelectronics.dk/2012/02/the-balancing-robot/
+ */
+
+#include "mbed.h"
+#include "BalancingRobot.h"
+#include "Encoder.h"
+
+/* Setup serial communication */
+Serial xbee(p13,p14); // For wireless debugging and setting PID constants
+Serial ps3(p9,p10); // For remote control
+Serial debug(USBTX, USBRX); // USB
+
+/* Setup encoders */
+Encoder leftEncoder(p29,p30);
+Encoder rightEncoder(p28,p27);
+
+/* Setup timer instance */
+Timer t;
+
+int main() {
+    /* Set baudrate */
+    xbee.baud(115200);
+    ps3.baud(115200);
+    debug.baud(115200);
+
+    /* Set PWM frequency */
+    leftPWM.period(0.00005); // The motor driver can handle a pwm frequency up to 20kHz (1/20000=0.00005)
+    rightPWM.period(0.00005);
+
+    /* Calibrate the gyro and accelerometer relative to ground */
+    calibrateSensors();
+
+    xbee.printf("Initialized\n");
+    processing(); // Send output to processing application
+
+    /* Setup timing */
+    t.start();
+    loopStartTime = t.read_us();
+    timer = loopStartTime;
+
+    while (1) {
+        /* Calculate pitch */
+        accYangle = getAccY();
+        gyroYrate = getGyroYrate();
+
+        // See my guide for more info about calculation the angles and the Kalman filter: http://arduino.cc/forum/index.php/topic,58048.0.html
+        pitch = kalman(accYangle, gyroYrate, t.read_us() - timer); // calculate the angle using a Kalman filter
+        timer = t.read_us();
+
+        //debug.printf("Pitch: %f, accYangle: %f\n",pitch,accYangle);
+
+        /* Drive motors */
+        if (pitch < 60 || pitch > 120) // Stop if falling or laying down
+            stopAndReset();
+        else
+            PID(targetAngle,targetOffset);
+
+        /* Update wheel velocity every 100ms */
+        loopCounter++;
+        if (loopCounter%10 == 0) { // If remainder is equal 0, it must be 10,20,30 etc.
+            //xbee.printf("Wheel - timer: %i\n",t.read_ms());
+            wheelPosition = leftEncoder.read() + rightEncoder.read();
+            wheelVelocity = wheelPosition - lastWheelPosition;
+            lastWheelPosition = wheelPosition;
+            //xbee.printf("WheelVelocity: %i\n",wheelVelocity);
+
+            if (abs(wheelVelocity) <= 20 && !stopped) { // Set new targetPosition if breaking
+                targetPosition = wheelPosition;
+                stopped = true;
+                //xbee.printf("Stopped\n");
+            }
+        }
+
+        /* Check for incoming serial data */
+        if (ps3.readable()) // Check if there's any incoming data
+            receivePS3();
+        if (xbee.readable()) // For setting the PID values
+            receiveXbee();
+
+        /* Read battery voltage every 1s */
+        if (loopCounter == 100) {
+            loopCounter = 0; // Reset loop counter
+            double analogVoltage = batteryVoltage.read()/1*3.3; // Convert to voltage
+            analogVoltage *= 6.6 // The analog pin is connected to a 56k-10k voltage divider
+            xbee.printf("analogVoltage: %f - timer: %i\n",analogVoltage,t.read_ms());
+            if (analogVoltage < 7.92 && pitch > 60 && pitch < 120) // Set buzzer on, if voltage gets critical low
+                buzzer = 1; // The mbed resets at aproximatly 1V           
+        }
+
+        /* Use a time fixed loop */
+        lastLoopUsefulTime = t.read_us() - loopStartTime;
+        if (lastLoopUsefulTime < STD_LOOP_TIME)
+            wait_us(STD_LOOP_TIME - lastLoopUsefulTime);
+        lastLoopTime = t.read_us() - loopStartTime; // only used for debugging
+        loopStartTime = t.read_us();
+
+        //debug.printf("%i,%i\n",lastLoopUsefulTime,lastLoopTime);
+    }
+}
+void PID(double restAngle, double offset) {
+    /* Steer robot */
+    if (steerForward) {
+        offset += (double)wheelVelocity/velocityScaleMove; // Scale down offset at high speed and scale up when reversing
+        restAngle -= offset;
+        //xbee.printf("Forward offset: %f\t WheelVelocity: %i\n",offset,wheelVelocity);
+    } else if (steerBackward) {
+        offset -= (double)wheelVelocity/velocityScaleMove; // Scale down offset at high speed and scale up when reversing
+        restAngle += offset;
+        //xbee.printf("Backward offset: %f\t WheelVelocity: %i\n",offset,wheelVelocity);
+    }
+    /* Break */
+    else if (steerStop) {
+        long positionError = wheelPosition - targetPosition;
+        if (abs(positionError) > zoneA) // Inside zone A
+            restAngle -= (double)positionError/positionScaleA;
+        else if (abs(positionError) > zoneB) // Inside zone B
+            restAngle -= (double)positionError/positionScaleB;
+        else // Inside zone C
+            restAngle -= (double)positionError/positionScaleC;
+
+        restAngle -= (double)wheelVelocity/velocityScaleStop;
+
+        if (restAngle < 80) // Limit rest Angle
+            restAngle = 80;
+        else if (restAngle > 100)
+            restAngle = 100;
+        //xbee.printf("restAngle: %f\t WheelVelocity: %i positionError: %i\n",restAngle,wheelVelocity,positionError);
+    }
+    /* Update PID values */
+    double error = (restAngle - pitch)/100;
+    double pTerm = Kp * error;
+    iTerm += Ki * error;
+    double dTerm = Kd * (error - lastError);
+    lastError = error;
+
+    double PIDValue = pTerm + iTerm + dTerm;
+
+    //debug.printf("Pitch: %5.2f\tPIDValue:  %5.2f\tpTerm: %5.2f\tiTerm: %5.2f\tdTerm: %5.2f\tKp: %5.2f\tKi: %5.2f\tKd: %5.2f\n",pitch,PIDValue,pTerm,iTerm,dTerm,Kp,Ki,Kd);
+
+    /* Steer robot sideways */
+    double PIDLeft;
+    double PIDRight;
+    if (steerLeft) {
+        PIDLeft = PIDValue-turnSpeed;
+        PIDRight = PIDValue+turnSpeed;
+    } else if (steerRotateLeft) {
+        PIDLeft = PIDValue-rotateSpeed;
+        PIDRight = PIDValue+rotateSpeed;
+    } else if (steerRight) {
+        PIDLeft = PIDValue+turnSpeed;
+        PIDRight = PIDValue-turnSpeed;
+    } else if (steerRotateRight) {
+        PIDLeft = PIDValue+rotateSpeed;
+        PIDRight = PIDValue-rotateSpeed;
+    } else {
+        PIDLeft = PIDValue;
+        PIDRight = PIDValue;
+    }
+    PIDLeft *= 0.95; // compensate for difference in the motors
+
+    /* Set PWM Values */
+    if (PIDLeft >= 0)
+        move(left, forward, PIDLeft);
+    else
+        move(left, backward, PIDLeft * -1);
+    if (PIDRight >= 0)
+        move(right, forward, PIDRight);
+    else
+        move(right, backward, PIDRight * -1);
+}
+void receivePS3() {
+    char input[16]; // The serial buffer is only 16 characters
+    int i = 0;
+    while (1) {
+        input[i] = ps3.getc();
+        if (input[i] == ';' || i == 15) // keep reading until it reads a semicolon or it exceeds the serial buffer
+            break;
+        i++;
+    }
+    //debug.printf("Input: %s\n",input);
+
+    // Set all false
+    steerForward = false;
+    steerBackward = false;
+    steerStop = false;
+    steerLeft = false;
+    steerRotateLeft = false;
+    steerRight = false;
+    steerRotateRight = false;
+
+    /* For remote control */
+    if (input[0] == 'F') { // Forward
+        strtok(input, ","); // Ignore 'F'
+        targetOffset = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+        //xbee.printf("%f\n",targetOffset); // Print targetOffset for debugging
+        steerForward = true;
+    } else if (input[0] == 'B') { // Backward
+        strtok(input, ","); // Ignore 'B'
+        targetOffset = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+        //xbee.printf("%f\n",targetOffset); // Print targetOffset for debugging
+        steerBackward = true;
+    } else if (input[0] == 'L') { // Left
+        if (input[1] == 'R') // Left Rotate
+            steerRotateLeft = true;
+        else
+            steerLeft = true;
+    } else if (input[0] == 'R') { // Right
+        if (input[1] == 'R') // Right Rotate
+            steerRotateRight = true;
+        else
+            steerRight = true;
+    } else if (input[0] == 'S') { // Stop
+        steerStop = true;
+        stopped = false;
+        targetPosition = wheelPosition;
+    }
+
+    else if (input[0] == 'T') { // Set the target angle
+        strtok(input, ","); // Ignore 'T'
+        targetAngle = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+        xbee.printf("%f\n",targetAngle); // Print targetAngle for debugging
+    } else if (input[0] == 'A') { // Abort
+        stopAndReset();
+        while (ps3.getc() != 'C'); // Wait until continue is send
+    }
+}
+void receiveXbee() {
+    char input[16]; // The serial buffer is only 16 characters
+    int i = 0;
+    while (1) {
+        input[i] = xbee.getc();
+        if (input[i] == ';' || i == 15) // keep reading until it reads a semicolon or it exceeds the serial buffer
+            break;
+        i++;
+    }
+    //debug.printf("Input: %s\n",input);
+
+    if (input[0] == 'T') { // Set the target angle
+        strtok(input, ","); // Ignore 'T'
+        targetAngle = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+    } else if (input[0] == 'P') {
+        strtok(input, ",");//Ignore 'P'
+        Kp = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+    } else if (input[0] == 'I') {
+        strtok(input, ",");//Ignore 'I'
+        Ki = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+    } else if (input[0] == 'D') {
+        strtok(input, ",");//Ignore 'D'
+        Kd = atof(strtok(NULL, ";")); // read until the end and then convert from string to double
+    } else if (input[0] == 'A') { // Abort
+        stopAndReset();
+        while (xbee.getc() != 'C'); // Wait until continue is send
+    } else if (input[0] == 'G') // The processing application sends this at startup
+        processing(); // Send output to processing application
+}
+void processing() {
+    /* Send output to processing application */
+    xbee.printf("Processing,%5.2f,%5.2f,%5.2f,%5.2f\n",Kp,Ki,Kd,targetAngle);
+}
+void stopAndReset() {
+    stop(both);
+    lastError = 0;
+    iTerm = 0;
+    targetPosition = wheelPosition;
+    buzzer= 0;
+}
+double kalman(double newAngle, double newRate, double dtime) {
+    // KasBot V2  -  Kalman filter module - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1284738418 - http://www.x-firm.com/?page_id=145
+    // with slightly modifications by Kristian Lauszus
+    // See http://academic.csuohio.edu/simond/courses/eec644/kalman.pdf and http://www.cs.unc.edu/~welch/media/pdf/kalman_intro.pdf for more information
+    dt = dtime / 1000000; // Convert from microseconds to seconds
+
+    // Discrete Kalman filter time update equations - Time Update ("Predict")
+    // Update xhat - Project the state ahead
+    angle += dt * (newRate - bias);
+
+    // Update estimation error covariance - Project the error covariance ahead
+    P_00 += -dt * (P_10 + P_01) + Q_angle * dt;
+    P_01 += -dt * P_11;
+    P_10 += -dt * P_11;
+    P_11 += +Q_gyro * dt;
+
+    // Discrete Kalman filter measurement update equations - Measurement Update ("Correct")
+    // Calculate Kalman gain - Compute the Kalman gain
+    S = P_00 + R_angle;
+    K_0 = P_00 / S;
+    K_1 = P_10 / S;
+
+    // Calculate angle and resting rate - Update estimate with measurement zk
+    y = newAngle - angle;
+    angle += K_0 * y;
+    bias += K_1 * y;
+
+    // Calculate estimation error covariance - Update the error covariance
+    P_00 -= K_0 * P_00;
+    P_01 -= K_0 * P_01;
+    P_10 -= K_1 * P_00;
+    P_11 -= K_1 * P_01;
+
+    return angle;
+}
+double getGyroYrate() {
+    // (gyroAdc-gyroZero)/Sensitivity (In quids) - Sensitivity = 0.00333/3.3=0.001009091
+    double gyroRate = -((gyroY.read() - zeroValues[0]) / 0.001009091);
+    return gyroRate;
+}
+double getAccY() {
+    // (accAdc-accZero)/Sensitivity (In quids) - Sensitivity = 0.33/3.3=0.1
+    double accXval = (accX.read() - zeroValues[1]) / 0.1;
+    double accYval = (accY.read() - zeroValues[2]) / 0.1;
+    accYval--;//-1g when lying down
+    double accZval = (accZ.read() - zeroValues[3]) / 0.1;
+
+    double R = sqrt(pow(accXval, 2) + pow(accYval, 2) + pow(accZval, 2)); // Calculate the force vector
+    double angleY = acos(accYval / R) * RAD_TO_DEG;
+
+    return angleY;
+}
+void calibrateSensors() {
+    LEDs = 0xF; // Turn all onboard LEDs on
+
+    double adc[4] = {0,0,0,0};
+    for (uint8_t i = 0; i < 100; i++) { // Take the average of 100 readings
+        adc[0] += gyroY.read();
+        adc[1] += accX.read();
+        adc[2] += accY.read();
+        adc[3] += accZ.read();
+        wait_ms(10);
+    }
+    zeroValues[0] = adc[0] / 100; // Gyro X-axis
+    zeroValues[1] = adc[1] / 100; // Accelerometer X-axis
+    zeroValues[2] = adc[2] / 100; // Accelerometer Y-axis
+    zeroValues[3] = adc[3] / 100; // Accelerometer Z-axis
+
+    LEDs = 0x0; // Turn all onboard LEDs off
+}
+void move(Motor motor, Direction direction, float speed) { // speed is a value in percentage (0.0f to 1.0f)
+    if (motor == left) {
+        leftPWM = speed;
+        if (direction == forward) {
+            leftA = 0;
+            leftB = 1;
+        } else if (direction == backward) {
+            leftA = 1;
+            leftB = 0;
+        }
+    } else if (motor == right) {
+        rightPWM = speed;
+        if (direction == forward) {
+            rightA = 0;
+            rightB = 1;
+        } else if (direction == backward) {
+            rightA = 1;
+            rightB = 0;
+        }
+    } else if (motor == both) {
+        leftPWM = speed;
+        rightPWM = speed;
+        if (direction == forward) {
+            leftA = 0;
+            leftB = 1;
+
+            rightA = 0;
+            rightB = 1;
+        } else if (direction == backward) {
+            leftA = 1;
+            leftB = 0;
+
+            rightA = 1;
+            rightB = 0;
+        }
+    }
+}
+void stop(Motor motor) {
+    if (motor == left) {
+        leftPWM = 1;
+        leftA = 1;
+        leftB = 1;
+    } else if (motor == right) {
+        rightPWM = 1;
+        rightA = 1;
+        rightB = 1;
+    } else if (motor == both) {
+        leftPWM = 1;
+        leftA = 1;
+        leftB = 1;
+
+        rightPWM = 1;
+        rightA = 1;
+        rightB = 1;
+    }
 }
\ No newline at end of file