ESE519 Lab6 Part3

Dependencies:   MPU6050_Lab6_Part3 mbed

Fork of BroBot_v2 by Carter Sharer

Revision:
4:2512939c10f0
Parent:
3:2f76ffbc5cef
Child:
6:ae3e6aefe908
--- a/main.cpp	Wed Oct 12 05:04:10 2016 +0000
+++ b/main.cpp	Tue Oct 18 20:44:21 2016 +0000
@@ -1,13 +1,37 @@
-//BroBot V2
-//Author: Carter Sharer 
-//Date: 10/11/2016
+//BroBot V3
+//Author: Carter Sharer
+//Date: 10/13/2016
 
+//BroBot Begin
 #include "pin_assignments.h"
 #include "I2Cdev.h"
 #include "JJ_MPU6050_DMP_6Axis.h"
 #include "BroBot.h"
 #include "BroBot_IMU.h"
 #include "stepper_motors.h"
+#include "MRF24J40.h"
+
+//For RF Communication
+#define JSTICK_H 8
+#define JSTICK_V 9
+#define SPACE 10
+#define KNOB1 11
+#define KNOB2 12
+#define KNOB3 13
+#define KNOB4 14
+#define ANGLE 15
+#define BUTTON 16
+#define JSTICK_OFFSET 100
+#define TX_BUFFER_LEN 18
+#define TX_ANGLE_OFFSET 100
+//Knobs
+#define POT1 p17
+#define POT2 p18
+#define POT3 p16
+#define POT4 p15
+//JoyStick
+#define POTV p19
+#define POTH p20
 
 //PID
 #define MAX_THROTTLE 580
@@ -20,11 +44,29 @@
 #define ITERM_MAX_ERROR 25   // Iterm windup constants for PI control //40
 #define ITERM_MAX 8000       // 5000
 
+//MRF24J40
+PinName mosi(SDI); //SDI
+PinName miso(SDO); //SDO
+PinName sck(SCK);  //SCK
+PinName cs(CS); //CS
+PinName reset(RESET); //RESET
+// RF tranceiver to link with handheld.
+MRF24J40 mrf(mosi, miso, sck, cs, reset);
+uint8_t txBuffer[128]= {1, 8, 0, 0xA1, 0xB2, 0xC3, 0xD4, 0x00};
+uint8_t rxBuffer[128];
+uint8_t rxLen;
+
+//Controller Values
+uint8_t knob1, knob2, knob3, knob4;
+int8_t jstick_h, jstick_v;
+
+
 //PID Default control values from constant definitions
 float Kp = KP;
 float Kd = KD;
 float Kp_thr = KP_THROTTLE;
 float Ki_thr = KI_THROTTLE;
+float Kd_thr; //Added for CS Pos contorl
 float Kp_user = KP;
 float Kd_user = KD;
 float Kp_thr_user = KP_THROTTLE;
@@ -45,17 +87,29 @@
 int16_t actual_robot_speed;        // overall robot speed (measured from steppers speed)
 int16_t actual_robot_speed_old;
 float estimated_speed_filtered;    // Estimated robot speed
+int robot_pos = 0;
 
 Timer timer;
 int timer_value; //maybe make this a long
 int timer_old; //maybe make this a long
-float dt;
+int dt;
 
 uint8_t slow_loop_counter;
+uint8_t medium_loop_counter;
 uint8_t loop_counter;
 
+
 Serial pc(USBTX, USBRX);
 
+// LEDs
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+//Button
+bool button;
+
 // =============================================================================
 // ===      PD controller implementation(Proportional, derivative)           ===
 // =============================================================================
@@ -68,15 +122,18 @@
 
     error = setPoint - input;
 
+
     // Kd is implemented in two parts
     //    The biggest one using only the input (sensor) part not the SetPoint input-input(t-2)
     //    And the second using the setpoint to make it a bit more agressive   setPoint-setPoint(t-1)
-    output = Kp * error + (Kd * (setPoint - setPointOld) - Kd * (input - PID_errorOld2)) / DT;
-    //Serial.print(Kd*(error-PID_errorOld));Serial.print("\t");
-    //PID_errorOld2 = PID_errorOld;
-    //PID_errorOld = input;  // error for Kd is only the input component
-    //setPointOld = setPoint;
+    output = Kp * error; //+ (Kd * (setPoint - setPointOld) - Kd * (input - PID_errorOld2)) / DT;
+
+    PID_errorOld2 = PID_errorOld;
+    PID_errorOld = input;  // error for Kd is only the input component
+    setPointOld = setPoint;
     return output;
+
+
 }
 
 // PI controller implementation (Proportional, integral). DT is in miliseconds
@@ -106,7 +163,7 @@
     mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
     mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
     mpu.setDLPFMode(MPU6050_DLPF_BW_10);  //10,20,42,98,188  // Default factor for BROBOT:10
-    mpu.setRate(4);   // 0=1khz 1=500hz, 2=333hz, 3=250hz 4=200hz
+    mpu.setRate(4);   // 0=1khz 1=500hz, 2=333hz, 3=250hz [4=200hz]default
     mpu.setSleepEnabled(false);
     wait_ms(500);
 
@@ -116,7 +173,7 @@
         mpu.setDMPEnabled(true);
         mpuIntStatus = mpu.getIntStatus();
         dmpReady = true;
-    } else { 
+    } else {
         // 1 = initial memory load failed
         // 2 = DMP configuration updates failed
         pc.printf("DMP INIT error \r\n");
@@ -126,7 +183,7 @@
     wait_ms(500);
     pc.printf("Gyro calibration!!  Dont move the robot in 10 seconds... \r\n");
     wait_ms(500);
-    
+
     // verify connection
     pc.printf(mpu.testConnection() ? "Connection Good \r\n" : "Connection Failed\r\n");
 
@@ -140,14 +197,32 @@
 // ================================================================
 // ===                    MAIN PROGRAM LOOP                     ===
 // ================================================================
+//CS PID CONTROLLER TEST
+float target_angle_old = 0;
+float change_in_target_angle = 0;
+float change_in_angle = 0;
+float angle_old1 = 0;
+float angle_old2 = 0;
+float kp_term = 0;
+float kd_term = 0;
+float error;
+//For Position controller
+float pos_error = 0;
+float kp_pos_term = 0;
+float kd_pos_term = 0;
+float change_in_target_pos;
+float target_pos, target_pos_old;
+float change_in_pos;
+float robot_pos_old, robot_pos_old1, robot_pos_old2;
+
 int main()
 {
-    pc.baud(115200);
+    pc.baud(230400);
     pc.printf("Start\r\n");
     init_imu();
     timer.start();
     //timer
-    timer_value = timer.read_ms();
+    timer_value = timer.read_us();
 
     //Init Stepper Motors
     //Attach Timer Interupts (Tiker)
@@ -160,50 +235,174 @@
     //Set Gains
     Kp_thr = 0; //0.15;
     Ki_thr = 0; //0.15;
-    
+
+    //Attach Interupt for IMU
+    checkpin.rise(&dmpDataReady);
+
+    //Used to set angle upon startup, filter
+    bool FILTER_DISABLE = true;
+
     while(1) {
-        // New DMP Orientation solution?
-        fifoCount = mpu.getFIFOCount();
-        if (fifoCount >= 18) {
-            if (fifoCount > 18) { // If we have more than one packet we take the easy path: discard the buffer and wait for the next one
-                pc.printf("FIFO RESET!!\r\n");
-                mpu.resetFIFO();
-                return;
-            }
+
+        if(button) {
+            pos_M1 = 0;
+            pos_M2 = 0;
+            target_pos = 0;
+        }
+
+        while(!mpuInterrupt) { // && fifoCount < packetSize) {
+            //led4 = led4^1;
+            //pc.printf("In while comp loop \r\n");
+            timer_value = timer.read_us();
+
+            //Set Gainz with knobs
+            Kp = ((float)knob1) / 1000.0;
+            Kd = ((float)knob2) / 1.0;
+            Kp_thr = ((float)knob3) / 1000.0;
+            Kd_thr = ((float)knob4) / 100.0;
+
+            //Joystick control
+            throttle = (float)jstick_v  /10.0;
+            steering = (float)jstick_h / 10.0;
+
+            //Update Values
             loop_counter++;
             slow_loop_counter++;
+            medium_loop_counter++;
             dt = (timer_value - timer_old);
             timer_old = timer_value;
+            angle_old = angle;
 
-            angle_old = angle;
-            // Get new orientation angle from IMU (MPU6050)
-            angle = dmpGetPhi();
+            // Motor contorl
+            if((angle < 45) && (angle > -45)) {
 
-            mpu.resetFIFO();  // We always reset FIFO
-        } // End of new IMU data
+                //PID CONTROL MAGIC GOES HERE
+                // We calculate the estimated robot speed:
+                // Estimated_Speed = angular_velocity_of_stepper_motors(combined) - angular_velocity_of_robot(angle measured by IMU)
+                actual_robot_speed_old = actual_robot_speed;
+                actual_robot_speed = (speed_M1 + speed_M2) / 2; // Positive: forward
+                int16_t angular_velocity = (angle - angle_old) * 90.0; // 90 is an empirical extracted factor to adjust for real units
+                int16_t estimated_speed = -actual_robot_speed_old - angular_velocity;     // We use robot_speed(t-1) or (t-2) to compensate the delay
+                estimated_speed_filtered = estimated_speed_filtered * 0.95 + (float)estimated_speed * 0.05;  // low pass filter on estimated speed
+                // SPEED CONTROL: This is a PI controller.
+                //    input:user throttle, variable: estimated robot speed, output: target robot angle to get the desired speed
+                //CS target_angle = speedPIControl(dt, estimated_speed_filtered, throttle, Kp_thr, Ki_thr);
+                //CS target_angle = CAP(target_angle, max_target_angle); // limited output
+                //target_angle = 0;
+                // Stability control: This is a PD controller.
+                //    input: robot target angle(from SPEED CONTROL), variable: robot angle, output: Motor speed
+                //    We integrate the output (sumatory), so the output is really the motor acceleration, not motor speed.
 
-        if(loop_counter >= 5) {
-            loop_counter = 0;
-            int16_t offset = 
-            pc.printf("angle: %d \r\n", int16_t(angle-ANGLE_OFFSET));
-            setMotor1Speed(int16_t(angle-ANGLE_OFFSET));
-            setMotor2Speed(int16_t(angle-ANGLE_OFFSET));
-        }
-        if (slow_loop_counter >= 99) { // 2Hz
-            slow_loop_counter = 0; // Read  status
-        }  // End of slow loop
+                //pc.printf("dt: %f, angle: %f, target_angle: %f, Kp: %f, Kd: %f \r\n", dt, angle, target_angle, Kp, Kd);
+                //control_output = stabilityPDControl(dt, angle, target_angle, Kp, Kd);
+                
+                //CS Pd Target Angle Contoller Goes Here
+                target_pos += throttle;
+                robot_pos = (pos_M1 + pos_M2) / 2;
+                //KP Term
+                pos_error = robot_pos - target_pos; //robot_pos - target_pos;
+                kp_pos_term = -Kp_thr * pos_error;
+                
+                //KD Term
+                change_in_target_pos = target_pos - target_pos_old;
+                change_in_pos = robot_pos - robot_pos_old2;
+                kd_pos_term = ((-Kd_thr * change_in_target_pos) - (-Kd_thr*change_in_pos)) /dt;
+                target_angle = kp_pos_term + kd_pos_term;
+                target_angle = CAP(target_angle, MAX_TARGET_ANGLE);
+                
+                //Update values
+                target_pos_old = target_pos;
+                robot_pos_old2 = robot_pos_old1;
+                robot_pos_old1 = robot_pos_old;
+                
+                //CS PD Stability CONTROLLER HERE
+                error = target_angle - angle;
+                kp_term = Kp * error;
+
+                change_in_target_angle = target_angle - target_angle_old; //add
+                change_in_angle = angle - angle_old2; //add
+                kd_term = ((Kd * change_in_target_angle) - Kd*(change_in_angle)) / dt;
+
+                //Control Output
+                control_output += kp_term + kd_term;
+                control_output = CAP(control_output, MAX_CONTROL_OUTPUT); // Limit max output from control
+                motor1 = (int16_t)(control_output + (steering/4));
+                motor2 = (int16_t)(control_output - (steering/4));
+                motor1 = CAP(motor1, MAX_CONTROL_OUTPUT);
+                motor2 = CAP(motor2, MAX_CONTROL_OUTPUT);
+
+                //Update variables
+                target_angle_old = target_angle;
+                angle_old2 = angle_old1;
+                angle_old1 = angle;
+
+                //Enable Motors
+                enable = ENABLE;
+                setMotor1Speed(-motor1);
+                setMotor2Speed(-motor2);
+                robot_pos += (-motor1 + -motor2) / 2;
+                //pc.printf("m1: %d m2: %d angle: %0.1f, controlout: %f tAngle: %f dt: %f timer: %d \r\n", motor1, motor2, angle, control_output, target_angle, dt, timer_value);
+            } else {
+                //Disable Motors
+                enable = DISABLE;
+                //Set Motor Speed 0
+                PID_errorSum = 0;  // Reset PID I term
+            }
+
+            //Fast Loop
+            if(loop_counter >= 5) {
+                loop_counter = 0;
+                //pc.printf("angle: %d horz: %d verti: %d knob1: %d knob2: %d knob3: %d knob4: %d \r\n", int16_t(angle-ANGLE_OFFSET), jstick_h, jstick_v, knob1, knob2, knob3, knob4);
+                //setMotor1Speed(int16_t(angle));
+                //setMotor2Speed(int16_t(angle));
+                //pc.printf("horz: %d verti: %d knob1: %d angle: %d \r\n", jstick_h, jstick_v, knob1, (int)angle);
+                //pc.printf("angle: %d \r\n", (int)angle);
+                pc.printf("angle:%d Kp: %0.3f Kd: %0.2f  Kp_thr: %0.2f Kd_thr: %0.3f  tang: %0.2f dt:%d pos_M1:%d pos_M2:%d rob_pos: %d\r\n", (int)angle, Kp, Kd, Kp_thr, Ki_thr, target_angle, dt, pos_M1, pos_M2, robot_pos);
+            }
 
 
-        /*
-        //Set Gains
-        Kp = 0.02;
-        Kd = 0.01;
+            //Meduim Loop
+            if (medium_loop_counter >= 10) {
+                medium_loop_counter = 0; // Read  status
+                led2 = led2^1;
 
-        timer_value = timer.read_ms();
+                //Recieve Data
+                rxLen = mrf.Receive(rxBuffer, 128);
+                if(rxLen) {
+                    if((rxBuffer[0] == (uint8_t)1) && (rxBuffer[1] == (uint8_t)8) && (rxBuffer[2]==(uint8_t)0)) {
+                        jstick_h = (int8_t)rxBuffer[JSTICK_H] - JSTICK_OFFSET;
+                        jstick_v = (int8_t)rxBuffer[JSTICK_V] - JSTICK_OFFSET;
+                        knob1 = rxBuffer[KNOB1];
+                        knob2 = rxBuffer[KNOB2];
+                        knob3 = rxBuffer[KNOB3];
+                        knob4 = rxBuffer[KNOB4];
+                        button = rxBuffer[BUTTON];
+                        led1= led1^1;  //flash led for debuggin
+                        led4 = button;
+                    }
+                } else {
+                    mrf.Reset();
+                }
+            }  // End of medium loop
+            
+            //Slow Loop
+            if(slow_loop_counter >= 99) {
+                slow_loop_counter = 0;
 
-        // if programming failed, don't try to do anything
-        if (!dmpReady) return;
+                //Send Data
+                txBuffer[ANGLE] = (uint8_t)(angle + TX_ANGLE_OFFSET);
+                mrf.Send(txBuffer, TX_BUFFER_LEN);
+            } //End of Slow Loop
 
+            //Reattach interupt
+            checkpin.rise(&dmpDataReady);
+        } //END WHILE
+
+        //Disable IRQ
+        checkpin.rise(NULL);
+        led3 = led3^1;
+        //pc.printf("taking care of imu stuff angle: %f \r\n", angle);
+        //All IMU stuff
         // reset interrupt flag and get INT_STATUS byte
         mpuInterrupt = false;
         mpuIntStatus = mpu.getIntStatus();
@@ -215,90 +414,34 @@
         if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
             // reset so we can continue cleanly
             mpu.resetFIFO();
+            pc.printf("FIFO overflow!");
+
             // otherwise, check for DMP data ready interrupt (this should happen frequently)
         } else if (mpuIntStatus & 0x02) {
             // wait for correct available data length, should be a VERY short wait
-            //CS while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
+            while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
 
             // read a packet from FIFO
             mpu.getFIFOBytes(fifoBuffer, packetSize);
 
-            angle_old = angle; //Update old angle before reading new angle
-
             // track FIFO count here in case there is > 1 packet available
             // (this lets us immediately read more without waiting for an interrupt)
             fifoCount -= packetSize;
-            mpu.dmpGetQuaternion(&q, fifoBuffer);
-            angle = atan2(2 * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z) * RAD2GRAD;
-            angle = angle - ANGLE_OFFSET;
-            //pc.printf("angle: %f \r\n", angle);
 
-
-            //Update timer
-            dt = (timer_value - timer_old);
-            timer_old = timer_value;
-
-            //PID CONTROL MAGIC GOES HERE
-            // We calculate the estimated robot speed:
-            // Estimated_Speed = angular_velocity_of_stepper_motors(combined) - angular_velocity_of_robot(angle measured by IMU)
-            //CS actual_robot_speed_old = actual_robot_speed;
-            //CS actual_robot_speed = (speed_M1 + speed_M2) / 2; // Positive: forward
-            //CS int16_t angular_velocity = (angle - angle_old) * 90.0; // 90 is an empirical extracted factor to adjust for real units
-            //CS int16_t estimated_speed = -actual_robot_speed_old - angular_velocity;     // We use robot_speed(t-1) or (t-2) to compensate the delay
-            //CS estimated_speed_filtered = estimated_speed_filtered * 0.95 + (float)estimated_speed * 0.05;  // low pass filter on estimated speed
-            // SPEED CONTROL: This is a PI controller.
-            //    input:user throttle, variable: estimated robot speed, output: target robot angle to get the desired speed
-            //CS target_angle = speedPIControl(dt, estimated_speed_filtered, throttle, Kp_thr, Ki_thr);
-            //CD target_angle = constrain(target_angle, -max_target_angle, max_target_angle); // limited output
-            // Stability control: This is a PD controller.
-            //    input: robot target angle(from SPEED CONTROL), variable: robot angle, output: Motor speed
-            //    We integrate the output (sumatory), so the output is really the motor acceleration, not motor speed.
-
-            //pc.printf("dt: %f, angle: %f, target_angle: %f, Kp: %f, Kd: %f \r\n", dt, angle, target_angle, Kp, Kd);
-            control_output += stabilityPDControl(dt, angle, target_angle, Kp, Kd);
-            control_output = constrain(control_output, -MAX_CONTROL_OUTPUT, MAX_CONTROL_OUTPUT); // Limit max output from control
-            motor1 = control_output + steering;
-            motor2 = control_output - steering;
+            //Read new angle from IMU
+            new_angle = (float)(dmpGetPhi() - ANGLE_OFFSET);
+            dAngle = new_angle - angle;
 
 
-            //TEST P CONTROL
-            float gain = 1;
-            motor1 = angle * gain;
-            motor2 = angle * gain;
-            pc.printf("motor: %d control output: %f \r\n", motor1, control_output);
-
-            // Limit max speed (control output)
-            motor1 = constrain(motor1, -MAX_CONTROL_OUTPUT, MAX_CONTROL_OUTPUT);
-            motor2 = constrain(motor2, -MAX_CONTROL_OUTPUT, MAX_CONTROL_OUTPUT);
-
+            //Filter out angle readings larger then MAX_ANGLE_DELTA
+            if( ((dAngle < 15) && (dAngle > -15)) || FILTER_DISABLE) {
+                angle = new_angle;
+                FILTER_DISABLE = false; //turn of filter disabler
+            } else {
+                pc.printf("\t\t\t filtered angle \r\n");
+            }
+            //END IMU STUFF
 
         }
-
-
-        // Put all the pid loop stuff here
-        if((angle < 45) && (angle > -45)) {
-            //Enable Motors
-            if(motor1 == 0) {
-                enable = DISABLE;
-                setMotor1Speed(0);
-                setMotor2Speed(0);
-            } else {
-                enable = ENABLE;
-                setMotor1Speed(motor1);
-                setMotor2Speed(motor2);
-            }
-            //pc.printf("m1: %d m2: %d angle: %0.1f, controlout: %f tAngle: %f dt: %f timer: %d \r\n", motor1, motor2, angle, control_output, target_angle, dt, timer_value);
-        } else {
-            //Disable Motors
-            enable = DISABLE;
-            //Set Motor Speed 0
-            PID_errorSum = 0;  // Reset PID I term
-            Kp = 0;
-            Kd = 0;
-            Kp_thr = 0;
-            Ki_thr = 0;
-        }
-
-        *////////////
     } //end main loop
 } //End Main()
\ No newline at end of file