BroBot Code for ESE350 Lab6 part 3 (Skeleton)
Dependencies: MPU6050_V3 mbed-rtos mbed
Fork of BroBot_RTOS_ESE350 by
main.cpp
- Committer:
- csharer
- Date:
- 2017-03-22
- Revision:
- 19:19d72dc64b43
- Parent:
- 18:ee252b8f7430
- Child:
- 20:a7cba632d0b1
File content as of revision 19:19d72dc64b43:
/* BroBOT Running the mBed RTOS Authors: Arvind Ramesh and Carter Sharer */ /******************************* 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 0 degres and * press the joystick button. * To reset the motor positions you must press the josystick button anytime. ******************************************************************************/ //Controller Values float knob1, knob2, knob3, knob4; float jstick_h, jstick_v; //Button bool button; //BroBot Begin #include "cmsis_os.h" #include "rtos_definations.h" #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" #include "communication.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 //THIS NEEDS TO BE CHANGED FOR YOUR ROBOT #define THETA_OFFSET 0 //Set Channel to (Group Number - 1). Possible Channels are 0-15 #define MRF_CHANNEL 2 //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 #define MAX_STEERING 150 #define MAX_TARGET_ANGLE 12 //Joystick Control #define THROTTLE_DAMPNER 30 #define STREEING_DAMPNER 10 #define VELOCITY_SAMPLES 10 //*********** Local Function Definations BEGIN **************// void init_system(); void init_imu(); //*********** Local Function Definations END **************// Timer timer; int timer_value = 0; int timer_old = 0; float angle = 0; float theta = 0; float totalTheta = 0; float deltaTheta = 0; float velocitySamples[VELOCITY_SAMPLES + 1] = {0.0}; float target_pos = 0; float pos_error = 0; Serial pc(USBTX, USBRX); // LEDs DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); //Used to set angle upon startup bool initilizeAngle; bool initilizeTheta; // ================================================================ // === IMU Thread === // ================================================================ void imu_update_thread(void const *args) { float dAngle = 0; float dTheta = 0; float new_angle = 0; float new_theta = 0; long long timeOut = 0; pc.printf("Starting IMU Thread..\r\n"); while (1) { osSignalWait(IMU_UPDATE_SIGNAL,osWaitForever); if(mpuInterrupt) { mpuInterrupt = false; led3 = !led3; /********************* All IMU Handling DO NOT MODIFY *****************/ mpuIntStatus = mpu.getIntStatus(); //get current FIFO count fifoCount = mpu.getFIFOCount(); // check for overflow (this should never happen unless our code is too inefficient) if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // reset so we can continue cleanly mpu.resetFIFO(); pc.printf("MPU 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 timeOut = 0; while (fifoCount < packetSize) { timeOut++; fifoCount = mpu.getFIFOCount(); if(timeOut > 100000000){ break; } } //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) fifoCount -= packetSize; //Read new angle from IMU dmpGetReadings(&new_angle,&new_theta); new_angle = (float)(new_angle - ANGLE_OFFSET); new_theta = float(new_theta + THETA_OFFSET); //Calculate the delta angle dAngle = new_angle - angle; dTheta = new_theta - theta; //Filter out angle readings larger then MAX_ANGLE_DELTA if(initilizeAngle) { angle = new_angle; initilizeAngle = false; pc.printf("\t\t\t Setting Initial Value: %f\r\n",angle); } else if( ((dAngle < 15) && (dAngle > -15))) { angle = new_angle; theta = new_theta; } else { pc.printf("\t\t\t Delta Angle too Large: %f. Ignored \r\n",dAngle); pc.printf("\t\t\t New Angle: %f Old Angle: %f\r\n",new_angle,angle); } if(initilizeTheta) { theta = new_theta; initilizeTheta = false; } else if( ((dTheta < 15) && (dTheta > -15))) { theta = new_theta; } else { //pc.printf("\t\t\t Delta Theta too Large: %f. Ignored \r\n",dTheta); //pc.printf("\t\t\t New Theta: %f Old Theta: %f\r\n",new_theta,theta); theta = new_theta; dTheta = dTheta > 0 ? -1 : 1; dTheta = 1; } totalTheta += dTheta; } else{ pc.printf("\t\t\t IMU Error. MPU Status: %d!!\r\n",mpuIntStatus); } /********************* All IMU Handling DO NOT MODIFY *****************/ }//End of if(mpuInterrupt) loop osSignalClear(imu_update_thread_ID,IMU_UPDATE_SIGNAL); osSignalSet(pid_update_thread_ID,PID_UPDATE_SIGNAL); } } // ================================================================ // === PID Thread === // ================================================================ void pid_update_thread(void const *args) { float Kp1 = 0; float Kd1 = 0; float Kp2 = 0; float Kd2 = 0; float target_angle = 0; 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 throttle = 0; float steering = 0; float control_output = 0; int robot_pos = 0; //int loop_counter = 0; int velocitySamplesCounter = 0; int dt = 0; float error = 0; float velocity = 0; bool fallen = true; // --- For Position controller --- // float kp_pos_term = 0; float kd_pos_term = 0; float change_in_target_pos = 0; // -- For Velocity Controller --- // float target_pos_old = 0; float target_velocity = 0; float runningSumReplaceVal = 0; float newVelocity = 0; float velocitySum = 0; memset(velocitySamples,0,sizeof(velocitySamples)); pc.printf("Starting PID Thread..\r\n"); while(1) { osSignalWait(PID_UPDATE_SIGNAL,osWaitForever); //Button Press on the remote initilizes the robot position. if(button) { pos_M1 = 0; pos_M2 = 0; target_pos = 0; motor1 = 0; motor2 = 0; control_output = 0; fallen = false; } //Get the time stamp as soon as it enters the loop timer_value = timer.read_us(); led4 = !fallen; led2 = button; //Set Gainz With Knobs Kp1 = ((float)knob1); Kd1 = ((float)knob2); Kp2 = ((float)knob3); Kd2 = ((float)knob4); //Joystick Control throttle = (float)jstick_v / THROTTLE_DAMPNER; steering = (float)jstick_h / STREEING_DAMPNER; //Calculate the delta time dt = (timer_value - timer_old); timer_old = timer_value; //angle_old = angle; // STANDING: Motor Control Enabled //******************** PID Control BEGIN ********************** // if(((angle < 45) && (angle > -45)) && (fallen == false)) { //Robot Position robot_pos = (pos_M1 + pos_M2) / 2; //Target Position Incremented with Joystick target_pos += throttle; //*************** Velocity Computation ********************** velocitySamplesCounter++; if(velocitySamplesCounter == VELOCITY_SAMPLES){ velocitySamplesCounter = 0; } runningSumReplaceVal = velocitySamples[velocitySamplesCounter]; //value to replace newVelocity = (motor1 + motor2) / 2; velocitySamples[velocitySamplesCounter] = newVelocity; //replace value with velocitySum = velocitySum - runningSumReplaceVal + newVelocity; velocity = velocitySum/VELOCITY_SAMPLES; // ***************** Position Controller ********************* //Inputs: robot_position, target_pos //Error: distance from target position //Output: target_angle float Kp1P = Kp2/1000; float Kd1P = Kd2/100; //Calculate the Position Error using robot_pos and target_pos pos_error = robot_pos - target_pos; //robot_pos - target_pos; //Calculate the Proportional Term (P Term) Using The Error kp_pos_term = Kp1P * pos_error; //Calculate the Derivative Term (D Term) Using The Error change_in_target_pos = target_pos - target_pos_old; kd_pos_term = ((Kd1P * change_in_target_pos) + (Kd1P*velocity)); target_velocity = kp_pos_term + -kd_pos_term; target_velocity = CAP(target_velocity, 100); target_angle = -target_velocity; //************ PD Stability CONTROLLER HERE **************** //Inputs: angle, target_angle //Error: distance from target_angle //Output: control_output (motor speed) //Scale the Knob Values; float Kp1S = Kp1/100; float Kd1S = Kd1*100; //Calculate the Angle Error Using target_angle and angle error = target_angle - angle; //Calculate the Proportional Term (P term) Using the Error kp_term = Kp1S * error; //Calculate the Derivatve Term (D term) change_in_target_angle = target_angle - target_angle_old; //add change_in_angle = angle - angle_old2; //add kd_term = ((Kd1S * change_in_target_angle) - (Kd1S*change_in_angle)) / dt; //kd_term = ((Kd1 * change_in_target_angle) - (Kd1*velocity)); //Calculate the Control Output control_output += kp_term + kd_term; //-100 to 100 control_output = CAP(control_output, MAX_CONTROL_OUTPUT); // Limit max output from control //*************** Set Motor Speed ************************* motor1 = (int16_t)(control_output + (steering)); motor2 = (int16_t)(control_output - (steering)); motor1 = CAP(motor1, MAX_CONTROL_OUTPUT); motor2 = CAP(motor2, MAX_CONTROL_OUTPUT); setMotor1Speed(-motor1); setMotor2Speed(-motor2); //Update variables target_angle_old = target_angle; angle_old2 = angle_old1; angle_old1 = angle; //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); //Enable Motors enable = ENABLE; if(abs(motor1) == MAX_CONTROL_OUTPUT || abs(motor2) == MAX_CONTROL_OUTPUT) { pc.printf("Max Speed Reached. Killing the Robot\n"); enable = DISABLE; fallen = true; } } else { //[FALLEN} //Disable Motors enable = DISABLE; //Set fallen flag fallen = true; } osSignalClear(pid_update_thread_ID,PID_UPDATE_SIGNAL); } //end main loop } // ================================================================ // === Communication Thread === // ================================================================ void communication_update_thread(void const *args) { pc.printf("Starting Communication Thread..\r\n"); while(1) { //Recieve Data rxLen = rf_receive(rxBuffer, 128); if(rxLen > 0) { led1 = led1^1; //Process data with our protocal communication_protocal(rxLen); } } } // ================================================================ // === INITIAL SETUP === // ================================================================ void init_imu() { pc.printf("Start IMU Initilization.. \r\n"); // Manual MPU initialization... accel=2G, gyro=2000º/s, filter=20Hz BW, output=200Hz mpu.setClockSource(MPU6050_CLOCK_PLL_ZGYRO); 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]default mpu.setSleepEnabled(false); wait_ms(500); // load and configure the DMP devStatus = mpu.dmpInitialize(); if(devStatus == 0) { mpu.setDMPEnabled(true); mpuIntStatus = mpu.getIntStatus(); dmpReady = true; } else { // 1 = initial memory load failed // 2 = DMP configuration updates failed pc.printf("DMP INIT error \r\n"); } //Gyro Calibration wait_ms(500); pc.printf("Gyro calibration!! Dont move the robot in 1 second... \r\n"); wait_ms(500); // verify connection pc.printf(mpu.testConnection() ? "Connection Good \r\n" : "Connection Failed\r\n"); //Adjust Sensor Fusion Gain dmpSetSensorFusionAccelGain(0x20); wait_ms(200); mpu.resetFIFO(); } void init_system() { initilizeAngle = true; initilizeTheta = true; totalTheta = 0; target_pos = 0; pos_error = 0; //Set the Channel. 0 is default, 15 is max mrf.SetChannel(MRF_CHANNEL); enable = DISABLE; //Disable Motors pc.baud(115200); pc.printf("Booting BroBot mbed RTOS..\r\n"); //Initilize the IMU init_imu(); //Attach Interupt for IMU on rising edge of checkpin checkpin.rise(&dmpDataReady); pc.printf("IMU Initilized..\r\n"); //Init Stepper Motors //Attach Motor Control Timer Call Back Functions timer_M1.attach_us(&ISR1, ZERO_SPEED);//1s Period timer_M2.attach_us(&ISR2, ZERO_SPEED);//1s Period step_M1 = 1; dir_M1 = 1; pc.printf("Motors Initilized..\r\n"); //Timers initilized timer.start(); timer_value = timer.read_us(); enable = ENABLE; //Enable Motors } // ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ int main() { init_system(); //Create IMU Thread imu_update_thread_ID = osThreadCreate(osThread(imu_update_thread), NULL); //Create PID Thread pid_update_thread_ID = osThreadCreate(osThread(pid_update_thread), NULL); //Create Communication Thread communication_update_thread_ID = osThreadCreate(osThread(communication_update_thread), NULL); } //End Main()