robot
Dependencies: MPU6050_Lab6_Part3 mbed
Fork of ESE519_Lab6_part3_skeleton by
main.cpp
- Committer:
- jliutang
- Date:
- 2016-11-16
- Revision:
- 9:d9776d8ce47c
- Parent:
- 6:ae3e6aefe908
File content as of revision 9:d9776d8ce47c:
//Balance Bot V4 //Author: Carter Sharer //Date: 10/13/2016 //ESE519 Lab 6 Part 3 Skeleton Code /******************************* 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 "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 #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 100 #define MAX_TARGET_ANGLE 12 //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; //Control Variables float target_angle; float throttle = 0; //From joystick float steering = 0; //From joystick float max_target_angle = MAX_TARGET_ANGLE; int robot_pos = 0; //Robots position bool fallen = true; float d_angle = 0; float d_anglemax = 0; float angle_old2 = 0; float angle_old3 = 0; float angle_correction = 0; float refAngle = 0; Timer timer; 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 DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); //Button bool button; #include "communication.h" // ================================================================ // === INITIAL SETUP === // ================================================================ void init_imu() { pc.printf("\r\r\n\n Start \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 10 seconds... \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(); } // ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ int main() { //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(); //timer timer_value = timer.read_us(); //Init Stepper Motors //Attach Timer Interupts (Tiker) timer_M1.attach_us(&ISR1, ZERO_SPEED); timer_M2.attach_us(&ISR2, ZERO_SPEED); step_M1 = 1; dir_M1 = 1; enable = DISABLE; //Disable Motors //Attach Interupt for IMU checkpin.rise(&dmpDataReady); //Used to set angle upon startup, filter bool FILTER_DISABLE = true; //Enable Motors enable = ENABLE; float integral1 = 0; float integral2 = 0; int16_t motor1Old = 0; int16_t motor2Old = 0; float lastError = 0; 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; //Reset position of Motor 1 pos_M2 = 0; //Reset position of motor 2 fallen = false; //Reset fallen flag } //This is the main while loop, all your code goes here while(!mpuInterrupt) { //Timer timer_value = timer.read_us(); //Set gainz with knobs Kp1 = knob1; Kd1 = knob2; Kp2 = knob3; Kd2 = knob4; //Joystick control throttle = jstick_v; steering = jstick_h; float error = 0; //STANDING: Motor Control Enabled if(((angle < 45) && (angle > -45)) && (fallen == false)) { //wait_ms(1); //Enable Motor enable = ENABLE; //controls error = angle - 0;//angle_correction; //should be balanced at 0 float Ki = 0.5; d_angle = angle-(angle_old+angle_old2+angle_old3)/3.0; /* if (d_angle > d_anglemax) d_anglemax = d_angle; if (d_angle > 2.0) d_angle = 2.0; if (d_angle < -2.0) d_angle = -2.0;*/ if (d_angle < 3.0 && d_angle > -3.0) d_angle = 0; motor1 = error * Kp1/10.0 + Kd1/25.0 * d_angle; motor2 = error * Kp2/10.0 + Kd2/25.0 * d_angle; /* if (d_angle == 0){ if (motor1 < -5) angle_correction += 0.002; else if (motor1 > 5) angle_correction -= 0.002; } */ /*long positionError = pos_M1 - 0; refAngle -= (double)positionError/500000.0; //initially 0 refAngle -= (double)motor1Old/500000.0; if (refAngle < -5) { refAngle = -5; } else if (refAngle > 5) { refAngle = 5; } error = (angle - refAngle)/10.0; double P = Kp1 * error; //I += 0.0001 * error; double D = Kd1 * (error - lastError); lastError = error; motor1 = error * P/10.0 + D/25.0 ; motor2 = error * P/10.0 + D/25.0 ; */ //Calculate motor inputs motor1 += 0.1 * int16_t(throttle/2 + steering/8); motor2 += 0.1 * int16_t(throttle/2 - steering/8); //Cap the max and min values [-100, 100] motor1 = CAP(motor1, MAX_CONTROL_OUTPUT); motor2 = CAP(motor2, MAX_CONTROL_OUTPUT); //Update speed if motor changes are above threshold int thresh = 1; if ((motor1 - motor1Old >= thresh) || (motor1-motor1Old <= -thresh)) { setMotor1Speed(motor1); motor1Old = motor1; } //motor1Old = motor1; if ((motor2 - motor2Old >= thresh) || (motor2-motor2Old <= -thresh)) { setMotor2Speed(motor2); motor2Old = motor2; } //motor2Old = motor2; //Set Motor Speed here //setMotor1Speed(motor1); //setMotor2Speed(motor2); } else { //FALLEN: Motor Control Disabled //Disable Motors enable = DISABLE; //Set fallen flag fallen = true; integral1 = 0; integral2 = 0; angle_correction = 0; lastError = 0; d_anglemax = 0; } /* 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:%0.3f Kp1:%0.3f Kd1:%0.2f Kp2:%0.2f Kd2:%0.3f pos_M1:%d pos_M2:%d dt:%0.2f, %0.2f\r\n", angle, Kp1, Kd1, Kp2, Kd2, pos_M1, pos_M2, robot_pos, throttle, steering); } //Meduim Loop: Good for sending and receiving if (medium_loop_counter >= 10) { medium_loop_counter = 0; // Read status //Recieve Data 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: Good for sending if speed is not an issue if(slow_loop_counter >= 99) { slow_loop_counter = 0; sprintf(txBuffer, "M1: %d, M2: %d, error: %0.2f, angle: %0.3f, dangle: %0.2f correction: %0.3f, Kp: %0.2f, Kd: %0.2f, motor1: %d", \ pos_M1, pos_M2, error, angle, d_angle, d_anglemax, Kp1, Kd1, motor1); rf_send(txBuffer, strlen(txBuffer)+1); } //End of Slow Loop //Reattach interupt checkpin.rise(&dmpDataReady); } //END WHILE /**** Update Values DO NOT MODIFY ********/ loop_counter++; slow_loop_counter++; medium_loop_counter++; dt = (timer_value - timer_old); timer_old = timer_value; angle_old3 = angle_old2; angle_old2 = angle_old; angle_old = angle; /*****************************************/ /********************* All IMU Handling DO NOT MODIFY *****************/ //Disable IRQ checkpin.rise(NULL); //reset interrupt flag and get INT_STATUS byte mpuInterrupt = false; 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("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 while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount(); //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 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 } } /********************* All IMU Handling DO NOT MODIFY *****************/ } //end main loop } //End Main()