Work in progress...
Dependencies: ESC FreeIMU mbed-rtos mbed
Experiment - work in progress...
main.cpp
- Committer:
- MatteoT
- Date:
- 2014-05-03
- Revision:
- 4:46f3c3dd5977
- Parent:
- 3:5e7476bca25f
- Child:
- 5:33abcc31b0aa
File content as of revision 4:46f3c3dd5977:
#include "math.h" #include "mbed.h" #include "rtos.h" #include "EthernetInterface.h" #include "esc.h" #include "PID.h" #include "MPU6050.h" #include "IMUfilter.h" #include <string> //Author: Matteo Terruzzi //Target differential of time in seconds, for the various program cycles: //timings as for main cycle: #define TARGET_IMU_DT 0.002 //every 1 step: 100% #define TARGET_MAIN_DT 0.016 //every 8 steps: 12.5% + 2 step start delay #define TARGET_TX_DT 0.040 //every 20 steps: 5% + 1 step start delay #define TARGET_RX_DT 0.040 //with previous //For the various dt, "average" is computed using a sort of low-pass filter of the actual value. //The formula (recurrence equation) is: // a(t) = x(t) * k - a(t-1) * k with a(0) = 0 //where: // x(t) is the actual value at the time t; // a(t) is the average at the timepoint t; // a(t-1) is the average at the previous timepoint; // k is AVERAGE_DT_K_GAIN (macro defined below). // //So, here is the meaning of AVERAGE_DT_K_GAIN, or k: the higher it is, the higher is the cut-frequency. //If k == 1, then a(t) == x(t). //If k == 0, then a(t) == target value (the actual value is totaly ignored). //A good value may be k = 1/8 = 0.125. #define AVERAGE_DT_K_GAIN 0.0125 //Blinking status leds #define LED_ESC LED1 #define LED_IMU LED2 #define LED_TXRX LED3 #define LED_RX LED4 #include "state.h" #include "IMU.h" #include "TXRX.h" int main() { Serial pc(USBTX,USBRX); //INITIALIZATION //------------------------------------------------------------------------------- //Setup ESCs ESC esc1(p23); ESC esc2(p24); ESC esc3(p25); ESC esc4(p26); //Setup status leds DigitalOut led_esc(LED_ESC); led_esc = 1; //flip at esc update (fixed 0 means that the ESCs was not been initiated--the program is stucked before this point) DigitalOut led_imu(LED_IMU); led_imu = 0; //flip at imu computations done (fixed 0 means that the imu sensors don't respond) DigitalOut led_txrx(LED_TXRX); led_txrx = 0; //flip at remote signal exchange done (fixed 0 means that the TXRX_thread has not been started) //Setup Ethernet EthernetInterface interface; interface.init("192.168.2.16","255.255.255.0","192.168.2.1"); interface.connect(); //Setup remote control Thread TXRX_thread (TXRX_thread_routine); led_txrx = 1; //Setup state QuadState mainQuadState; mainQuadState.reset(); QuadState rxQuadState; rxQuadState.reset(); QuadState txQuadState; txQuadState.reset(); //Setup FreeIMU IMUfilter IMU_filter(TARGET_IMU_DT,40); MPU6050 IMU_sensor(p28, p27); IMU_sensor.setGyroRange(MPU6050_GYRO_RANGE_250); IMU_sensor.setAcceleroRange(MPU6050_ACCELERO_RANGE_4G); led_imu = 1; //MAIN CONTROL CYCLE PREPARATION //------------------------------------------------------------------------------- unsigned short int step = 0; //Just a moment... Let the other threads begin! Thread::wait(2000 /*ms*/); Thread::yield(); //just made sure the other threads had time to begin. //Setup timers Timer IMU_dt_timer; IMU_dt_timer.reset(); IMU_dt_timer.start(); Timer dt_timer; dt_timer.reset(); dt_timer.start(); Thread::wait(1000.0 * min(mainQuadState.target_imu_dt,mainQuadState.target_main_dt)); //pid /*PID targetRoll_pid(0.1,0.0001,0.5, 0.020); targetRoll_pid.setInputLimits(-3.15/4,3.15/4); targetRoll_pid.setOutputLimits(0,0.5);*/ //MAIN CONTROL CYCLE //=================================================================================== while(1) { //IMU INPUT //------------------------------------------------------------------------------- //Measure the time and sleep to correct the interval QUAD_STATE_READ_ACTUAL_DT(mainQuadState,imu,IMU_dt_timer) QUAD_STATE_WAIT_DT_TARGET(mainQuadState.actual_imu_dt,mainQuadState.target_imu_dt) QUAD_STATE_UPDATE_DT(mainQuadState,imu,IMU_dt_timer) led_imu = 1; //Retrieve inertial values from sensors { float a[3], g[3]; IMU_sensor.getAccelero(a); IMU_sensor.getGyro(g); mainQuadState.sensor_accel_x += a[0]/4 - mainQuadState.sensor_accel_x/4; mainQuadState.sensor_accel_y += a[1]/4 - mainQuadState.sensor_accel_y/4; mainQuadState.sensor_accel_z += a[2]/4 - mainQuadState.sensor_accel_z/4; mainQuadState.sensor_gyro_r = g[0]; mainQuadState.sensor_gyro_p = g[1]; mainQuadState.sensor_gyro_y = g[2]; //Compute IMU filters IMU_filter.updateFilter(g[0], g[1], g[2], a[0], a[1], a[2]); } if(mainQuadState.actual_imu_dt >= 100.0 * mainQuadState.target_imu_dt) mainQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER = 0; //experiments only ////NOTE: FIXME: THAT'S ABSOLUTELY UNSAFE WHILE FLYING!!! led_imu = 0; if(step % 20 == 2){ //5% frequency; step%20==2 //REMOTE INPUT //------------------------------------------------------------------------------- led_txrx = 1; //Remote signal exchange txQuadState = mainQuadState; //send info back txQuadState.timestamp = time(NULL); if(TXRX_stateExchange(txQuadState,rxQuadState)){ mainQuadState.average_rx_dt = rxQuadState.average_rx_dt; mainQuadState.actual_rx_dt = rxQuadState.actual_rx_dt; mainQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER = rxQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER; if(mainQuadState.actual_rx_dt >= 100.0 * mainQuadState.target_rx_dt) mainQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER = 0; //experiments only ////NOTE: FIXME: THAT'S ABSOLUTELY UNSAFE WHILE FLYING!!! } /*if(step % 640 == 2){ //Other tasks if(pc.writeable()){ pc.printf("%s \r\n", mainQuadState.getJSON().c_str()); //the message is long => it slows down a lot! } }*/ led_txrx = 0; //end of 5% frequency; step%20==2 } if(step % 8 == 3){ //12.5% frequency; step%8==3 led_esc = 1; //ELABORATION //------------------------------------------------------------------------------- //Measure the time QUAD_STATE_UPDATE_DT(mainQuadState,main,dt_timer) //Get estimated rotation //IMU_filter.computeEuler(); //mainQuadState.estimated_rotation_y = IMU_filter.getYaw(); //mainQuadState.estimated_rotation_p = IMU_filter.getPitch(); //mainQuadState.estimated_rotation_r = IMU_filter.getRoll(); IMU_filter.getCorrectedEuler( mainQuadState.estimated_rotation_r, mainQuadState.estimated_rotation_p, mainQuadState.estimated_rotation_y ); IMU_filter.getQuaternion( mainQuadState.estimated_rotation_q1, mainQuadState.estimated_rotation_q2, mainQuadState.estimated_rotation_q3, mainQuadState.estimated_rotation_q4); //Elaborate inputs to determinate outputs {//Roll PID float previous = mainQuadState.pid_rotation_r_error; mainQuadState.pid_rotation_r_error = mainQuadState.target_rotation_r - mainQuadState.estimated_rotation_r; mainQuadState.pid_rotation_r_error_integrative += mainQuadState.pid_rotation_r_error; mainQuadState.pid_rotation_r_error_derivative = mainQuadState.pid_rotation_r_error - previous; mainQuadState.pid_rotation_r_out = mainQuadState.pid_rotation_r_kP * mainQuadState.pid_rotation_r_error + mainQuadState.pid_rotation_r_kI * mainQuadState.pid_rotation_r_error_integrative + mainQuadState.pid_rotation_r_kD * mainQuadState.pid_rotation_r_error_derivative; if(mainQuadState.pid_rotation_r_error_integrative > 100) mainQuadState.pid_rotation_r_error_integrative = 100; else if(mainQuadState.pid_rotation_r_error_integrative > -100) mainQuadState.pid_rotation_r_error_integrative = -100; }{//Pitch PID float previous = mainQuadState.pid_rotation_p_error; mainQuadState.pid_rotation_p_error = mainQuadState.target_rotation_p - mainQuadState.estimated_rotation_p; mainQuadState.pid_rotation_p_error_integrative += mainQuadState.pid_rotation_p_error; mainQuadState.pid_rotation_p_error_derivative = mainQuadState.pid_rotation_p_error - previous; mainQuadState.pid_rotation_p_out = mainQuadState.pid_rotation_p_kP * mainQuadState.pid_rotation_p_error + mainQuadState.pid_rotation_p_kI * mainQuadState.pid_rotation_p_error_integrative + mainQuadState.pid_rotation_p_kD * mainQuadState.pid_rotation_p_error_derivative; if(mainQuadState.pid_rotation_p_error_integrative > 100) mainQuadState.pid_rotation_p_error_integrative = 100; else if(mainQuadState.pid_rotation_p_error_integrative > -100) mainQuadState.pid_rotation_p_error_integrative = -100; }{//Yaw PID float previous = mainQuadState.pid_rotation_y_error; mainQuadState.pid_rotation_y_error = mainQuadState.target_rotation_y - mainQuadState.estimated_rotation_y; mainQuadState.pid_rotation_y_error_integrative += mainQuadState.pid_rotation_y_error; mainQuadState.pid_rotation_y_error_derivative = mainQuadState.pid_rotation_y_error - previous; mainQuadState.pid_rotation_y_out = mainQuadState.pid_rotation_y_kP * mainQuadState.pid_rotation_y_error + mainQuadState.pid_rotation_y_kI * mainQuadState.pid_rotation_y_error_integrative + mainQuadState.pid_rotation_y_kD * mainQuadState.pid_rotation_y_error_derivative; if(mainQuadState.pid_rotation_y_error_integrative > 100) mainQuadState.pid_rotation_y_error_integrative = 100; else if(mainQuadState.pid_rotation_y_error_integrative > -100) mainQuadState.pid_rotation_y_error_integrative = -100; } //Compute actual throttle values if(mainQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER == 0 || rxQuadState.ZERO_MEANS_ZERO_ALL_MOTORS_NOW__DANGER == 0){ mainQuadState.actual_throttle_1 = 0; mainQuadState.actual_throttle_2 = 0; mainQuadState.actual_throttle_3 = 0; mainQuadState.actual_throttle_4 = 0; }else{ mainQuadState.actual_rx_dt = rxQuadState.actual_rx_dt; mainQuadState.average_rx_dt = rxQuadState.average_rx_dt; mainQuadState.target_rotation_r = rxQuadState.target_rotation_r; mainQuadState.target_rotation_r_isRequired = rxQuadState.target_rotation_r_isRequired; mainQuadState.reference_throttle_1 = rxQuadState.reference_throttle_1; mainQuadState.reference_throttle_2 = rxQuadState.reference_throttle_2; mainQuadState.reference_throttle_3 = rxQuadState.reference_throttle_3; mainQuadState.reference_throttle_4 = rxQuadState.reference_throttle_4; /*float roll = 0; if(mainQuadState.target_rotation_r_isRequired){ targetRoll_pid.setSetPoint(mainQuadState.target_rotation_r); targetRoll_pid.setInterval(mainQuadState.average_main_dt); targetRoll_pid.setProcessValue(mainQuadState.estimated_rotation_r); roll = targetRoll_pid.compute(); }else{ targetRoll_pid.setSetPoint(mainQuadState.estimated_rotation_r); }*/ if(mainQuadState.reference_throttle_1 <= -1000) mainQuadState.actual_throttle_1 = 0; else{ float out = mainQuadState.reference_throttle_1; //NOTE: here we will have full throttle calcs.. out -= mainQuadState.pid_rotation_r_out; mainQuadState.actual_throttle_1 = out; } if(mainQuadState.reference_throttle_2 <= -1000) mainQuadState.actual_throttle_2 = 0; else{ float out = mainQuadState.reference_throttle_2; mainQuadState.actual_throttle_2 = out; } if(mainQuadState.reference_throttle_3 <= -1000) mainQuadState.actual_throttle_3 = 0; else{ float out = mainQuadState.reference_throttle_3; out += mainQuadState.pid_rotation_r_out; mainQuadState.actual_throttle_3 = out; } if(mainQuadState.reference_throttle_4 <= -1000) mainQuadState.actual_throttle_4 = 0; else{ float out = mainQuadState.reference_throttle_4; mainQuadState.actual_throttle_4 = out; } } //OUTPUT //------------------------------------------------------------------------------- //set new ESC values. esc1 = mainQuadState.actual_throttle_1; esc2 = mainQuadState.actual_throttle_2; esc3 = mainQuadState.actual_throttle_3; esc4 = mainQuadState.actual_throttle_4; //effectively output to ESCs esc1(); esc2(); esc3(); esc4(); led_esc = 0; //end of 12.5% frequency; step%8==3 } ++step; }//End of main control loop //It must not get here. return 0; }