Final project with problem

Dependencies:   mbed

Fork of Yusheng-final_project by Carter Sharer

Revision:
6:ae3e6aefe908
Parent:
4:2512939c10f0
Child:
9:a8fd0bd49279
--- a/main.cpp	Tue Oct 18 20:46:01 2016 +0000
+++ b/main.cpp	Thu Nov 10 19:20:55 2016 +0000
@@ -1,16 +1,30 @@
-//BroBot V3
+//Balance Bot V4
 //Author: Carter Sharer
 //Date: 10/13/2016
+//ESE519 Lab 6 Part 3 Skeleton Code
 
-//BroBot Begin
+/******************************* README USAGE *******************************
+* This robot must be powered on while it is laying down flat on a still table 
+* This allows the robot to calibrate the IMU (~5 seconds)
+* The motors are DISABLED when the robot tilts more then +-45 degrees from
+* vertical.  To ENABLE the motors you must lift the robot to < +- 45 degres and
+* press the joystick button.  
+* To reset the motor positions you must press the josystick button anytime.
+******************************************************************************/
+
+//Balance Bot Begin
 #include "pin_assignments.h"
 #include "I2Cdev.h"
 #include "JJ_MPU6050_DMP_6Axis.h"
-#include "BroBot.h"
-#include "BroBot_IMU.h"
+#include "balance_bot.h"
+#include "balance_bot_IMU.h"
 #include "stepper_motors.h"
 #include "MRF24J40.h"
 
+//Angle Offset is used to set the natural balance point of your robot.  
+//You should adjust this offset so that your robots balance point is near 0 
+#define ANGLE_OFFSET 107
+
 //For RF Communication
 #define JSTICK_H 8
 #define JSTICK_V 9
@@ -34,71 +48,36 @@
 #define POTH p20
 
 //PID
-#define MAX_THROTTLE 580
-#define MAX_STEERING 150
+#define MAX_THROTTLE 100
 #define MAX_TARGET_ANGLE 12
-#define KP 0.19
-#define KD 28
-#define KP_THROTTLE 0.01 //0.07    
-#define KI_THROTTLE 0//0.04
-#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;
+//PID Default control values from constant definitions
+float Kp1;
+float Kd1;
+float Kp2;
+float Kd2;
 
 //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;
-float Ki_thr_user = KI_THROTTLE;
-bool newControlParameters = false;
-bool modifing_control_parameters = false;
-float PID_errorSum;
-float PID_errorOld = 0;
-float PID_errorOld2 = 0;
-float setPointOld = 0;
+//Control Variables
 float target_angle;
-float throttle = 0;
-float steering = 0;
-float max_throttle = MAX_THROTTLE;
-float max_steering = MAX_STEERING;
+float throttle = 0; //From joystick
+float steering = 0; //From joystick
 float max_target_angle = MAX_TARGET_ANGLE;
-float control_output;
-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;
+int robot_pos = 0; //Robots position
+bool fallen = true;
 
 Timer timer;
-int timer_value; //maybe make this a long
-int timer_old; //maybe make this a long
+int timer_value; 
+int timer_old; 
 int dt;
 
+//Loop Counters 
 uint8_t slow_loop_counter;
 uint8_t medium_loop_counter;
 uint8_t loop_counter;
 
-
 Serial pc(USBTX, USBRX);
 
 // LEDs
@@ -109,48 +88,8 @@
 
 //Button
 bool button;
-
-// =============================================================================
-// ===      PD controller implementation(Proportional, derivative)           ===
-// =============================================================================
-// PD controller implementation(Proportional, derivative). DT is in miliseconds
-//    stabilityPDControl(      dt,       angle,   target_angle,        Kp,       Kd);
-float stabilityPDControl(float DT, float input, float setPoint,  float Kp, float Kd)
-{
-    float error;
-    float output;
-
-    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;
+#include "communication.h"
 
-    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
-float speedPIControl(float DT, float input, float setPoint,  float Kp, float Ki)
-{
-    float error;
-    float output;
-
-    error = setPoint - input;
-    PID_errorSum += CAP(error, ITERM_MAX_ERROR);
-    PID_errorSum = CAP(PID_errorSum, ITERM_MAX);
-
-    //Serial.println(PID_errorSum);
-
-    output = Kp * error + Ki * PID_errorSum * DT * 0.001; // DT is in miliseconds...
-    return (output);
-}
 // ================================================================
 // ===                      INITIAL SETUP                       ===
 // ================================================================
@@ -197,27 +136,13 @@
 // ================================================================
 // ===                    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(230400);
+    //Set the Channel. 0 is default, 15 is max
+    uint8_t channel = 2;
+    mrf.SetChannel(channel);
+
+    pc.baud(115200);
     pc.printf("Start\r\n");
     init_imu();
     timer.start();
@@ -230,11 +155,7 @@
     timer_M2.attach_us(&ISR2, ZERO_SPEED);
     step_M1 = 1;
     dir_M1 = 1;
-    enable = ENABLE; //Enable Motors
-
-    //Set Gains
-    Kp_thr = 0; //0.15;
-    Ki_thr = 0; //0.15;
+    enable = DISABLE; //Disable Motors
 
     //Attach Interupt for IMU
     checkpin.rise(&dmpDataReady);
@@ -242,172 +163,126 @@
     //Used to set angle upon startup, filter
     bool FILTER_DISABLE = true;
 
+    //Enable Motors
+    enable = ENABLE;
+
     while(1) {
+        //Led 4 to indicate if robot it STANDING or FALLEN
+        led4 = !fallen;
 
+        //Led 2 to indicate a button press
+        led2 = button;
+
+        //If button is pressed reset motor position
         if(button) {
-            pos_M1 = 0;
-            pos_M2 = 0;
-            target_pos = 0;
+            pos_M1 = 0; //Reset position of Motor 1
+            pos_M2 = 0; //Reset position of motor 2
+            fallen = false; //Reset fallen flag
         }
 
-        while(!mpuInterrupt) { // && fifoCount < packetSize) {
-            //led4 = led4^1;
-            //pc.printf("In while comp loop \r\n");
+        //This is the main while loop, all your code goes here
+        while(!mpuInterrupt) {
+            //Timer
             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;
+            //Set gainz with knobs
+            Kp1 = knob1;
+            Kd1 = knob2;
+            Kp2 = knob3;
+            Kd2 = knob4;
 
             //Joystick control
-            throttle = (float)jstick_v  /10.0;
-            steering = (float)jstick_h / 10.0;
+            throttle = jstick_v;
+            steering = jstick_h;
 
-            //Update Values
+            /**** Update Values DO NOT MODIFY ********/
             loop_counter++;
             slow_loop_counter++;
             medium_loop_counter++;
             dt = (timer_value - timer_old);
             timer_old = timer_value;
             angle_old = angle;
-
-            // Motor contorl
-            if((angle < 45) && (angle > -45)) {
+            /*****************************************/
 
-                //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.
+            //STANDING: Motor Control Enabled
+            if(((angle < 45) && (angle > -45)) && (fallen == false)) {
 
-                //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);
+                //Enable Motor
+                enable = ENABLE;
                 
-                //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);
+                /* This is where you want to impliment your controlers 
+                * Start off with a simple P controller.
+                *
+                * float error = angle - 0; //should be balanced at 0
+                * motor1 = error * Kp; 
+                * motor2 = error * Kp;        */
                 
-                //Update values
-                target_pos_old = target_pos;
-                robot_pos_old2 = robot_pos_old1;
-                robot_pos_old1 = robot_pos_old;
+                //Calculate motor inputs
+                motor1 = int16_t(throttle/2 + steering/8);
+                motor2 = int16_t(throttle/2 - steering/8);
                 
-                //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));
+                //Cap the max and min values [-100, 100]
                 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;
+                
+                //Set Motor Speed here
+                setMotor1Speed(motor1);
+                setMotor2Speed(motor2);
 
-                //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 {
+            } else { //FALLEN: Motor Control Disabled
                 //Disable Motors
                 enable = DISABLE;
-                //Set Motor Speed 0
-                PID_errorSum = 0;  // Reset PID I term
+
+                //Set fallen flag
+                fallen = true;
             }
-
-            //Fast Loop
+    
+            /* Here are some loops that trigger at different intervals, this 
+            * will allow you to do things at a slower rate, thus saving speed
+            * it is important to keep this fast so we dont miss IMU readings */
+            
+            //Fast Loop: Good for printing to serial monitor
             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);
+                pc.printf("angle:%d Kp1:%0.3f Kd1:%0.2f Kp2:%0.2f Kd2:%0.3f pos_M1:%d pos_M2:%d \r\n", (int)angle, Kp1, Kd1, Kp2, Kd2, pos_M1, pos_M2, robot_pos);
             }
 
-
-            //Meduim Loop
+            //Meduim Loop: Good for sending and receiving 
             if (medium_loop_counter >= 10) {
                 medium_loop_counter = 0; // Read  status
-                led2 = led2^1;
 
                 //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();
+                rxLen = rf_receive(rxBuffer, 128);
+                if(rxLen > 0) {
+                    led1 = led1^1;
+                    //Process data with our protocal
+                    communication_protocal(rxLen);
                 }
+
             }  // End of medium loop
-            
-            //Slow Loop
+
+            //Slow Loop: Good for sending if speed is not an issue 
             if(slow_loop_counter >= 99) {
                 slow_loop_counter = 0;
 
-                //Send Data
-                txBuffer[ANGLE] = (uint8_t)(angle + TX_ANGLE_OFFSET);
-                mrf.Send(txBuffer, TX_BUFFER_LEN);
+                /* Send Data To Controller goes here *
+                 *                                   */
             } //End of Slow Loop
 
             //Reattach interupt
             checkpin.rise(&dmpDataReady);
         } //END WHILE
 
+
+        /********************* All IMU Handling DO NOT MODIFY *****************/
         //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
+
+        //reset interrupt flag and get INT_STATUS byte
         mpuInterrupt = false;
         mpuIntStatus = mpu.getIntStatus();
 
-        // get current FIFO count
+        //get current FIFO count
         fifoCount = mpu.getFIFOCount();
 
         // check for overflow (this should never happen unless our code is too inefficient)
@@ -416,32 +291,29 @@
             mpu.resetFIFO();
             pc.printf("FIFO overflow!");
 
-            // otherwise, check for DMP data ready interrupt (this should happen frequently)
+            //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
+            //wait for correct available data length, should be a VERY short wait
             while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
 
-            // read a packet from FIFO
+            //read a packet from FIFO
             mpu.getFIFOBytes(fifoBuffer, packetSize);
 
-            // track FIFO count here in case there is > 1 packet available
-            // (this lets us immediately read more without waiting for an interrupt)
+            //track FIFO count here in case there is > 1 packet available
+            //(this lets us immediately read more without waiting for an interrupt)
             fifoCount -= packetSize;
 
             //Read new angle from IMU
             new_angle = (float)(dmpGetPhi() - ANGLE_OFFSET);
             dAngle = new_angle - angle;
 
-
             //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
+            } 
+        }
+        /********************* All IMU Handling DO NOT MODIFY *****************/
 
-        }
     } //end main loop
 } //End Main()
\ No newline at end of file