diff --git a/quad/src/quad_app/control_algorithm.c b/quad/src/quad_app/control_algorithm.c index 05e4b4b74e09383f94d6e7a6683179aa00f856db..77f1c5771345210e8a2f41a8d655be909c838134 100644 --- a/quad/src/quad_app/control_algorithm.c +++ b/quad/src/quad_app/control_algorithm.c @@ -15,7 +15,7 @@ #define USE_LIDAR #define USE_OF -#define USE_FAKE_YAW +#define USE_MAG_YAW #define MAX_VALID_LIDAR (10.0) // Maximum valid distance to read from LiDAR to update //10 degrees @@ -128,6 +128,9 @@ int control_algorithm_init(parameter_t * ps) // gyroscope z integrator ps->gyro_yaw = graph_add_defined_block(graph, BLOCK_INTEGRATOR, "Integrated gyro z"); + //Complementary yaw + ps->mag_yaw = graph_add_defined_block(graph, BLOCK_CONSTANT, "Mag Yaw"); + ps->mixer = graph_add_defined_block(graph, BLOCK_MIXER, "Signal Mixer"); ps->angle_time = graph_add_defined_block(graph, BLOCK_CONSTANT, "Ts_IMU"); @@ -154,7 +157,7 @@ int control_algorithm_init(parameter_t * ps) graph_set_source(graph, ps->roll_r_pid, PID_CUR_POINT, ps->gyro_x, CONST_VAL); graph_set_source(graph, ps->roll_r_pid, PID_DT, ps->angle_time, CONST_VAL); graph_set_source(graph, ps->roll_pid, PID_CUR_POINT, ps->cur_roll, CONST_VAL); - //graph_set_source(graph, ps->roll_pid, PID_CUR_POINT, ps->vrpn_roll, CONST_VAL); + //graph_set_source(graph, ps->roll_pid, PID_CUR_POINT, ps->vrpn_roll, CONST_VAL);USE_FAKE_YAW graph_set_source(graph, ps->roll_pid, PID_DT, ps->angle_time, CONST_VAL); // Connect yaw PID chain @@ -179,8 +182,8 @@ int control_algorithm_init(parameter_t * ps) graph_set_source(graph, ps->x_vel_clamp, BOUNDS_IN, ps->x_pos_pid, PID_CORRECTION); // X/Y global to local conversion -#ifdef USE_FAKE_YAW - graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->gyro_yaw, CONST_VAL); +#ifdef USE_MAG_YAW + graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->mag_yaw, CONST_VAL); #else graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->cur_yaw, CONST_VAL); #endif @@ -230,8 +233,8 @@ int control_algorithm_init(parameter_t * ps) // X/Y global to local conversion -#ifdef USE_FAKE_YAW - graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->gyro_yaw, CONST_VAL); +#ifdef USE_MAG_YAW + graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->mag_yaw, CONST_VAL); #else graph_set_source(graph, ps->yaw_correction, ROT_YAW, ps->cur_yaw, CONST_VAL); #endif @@ -251,9 +254,9 @@ int control_algorithm_init(parameter_t * ps) graph_set_source(graph, ps->throttle_trim_add, ADD_SUMMAND1, ps->alt_pid, PID_CORRECTION); graph_set_source(graph, ps->throttle_trim_add, ADD_SUMMAND2, ps->throttle_trim, CONST_VAL); // Yaw angle -#ifdef USE_FAKE_YAW +#ifdef USE_MAG_YAW graph_set_source(graph, ps->yaw_pid, PID_DT, ps->angle_time, CONST_VAL); - graph_set_source(graph, ps->yaw_pid, PID_CUR_POINT, ps->gyro_yaw, CONST_VAL); + graph_set_source(graph, ps->yaw_pid, PID_CUR_POINT, ps->mag_yaw, CONST_VAL); #else graph_set_source(graph, ps->yaw_pid, PID_DT, ps->pos_time, CONST_VAL); graph_set_source(graph, ps->yaw_pid, PID_CUR_POINT, ps->cur_yaw, CONST_VAL); @@ -272,8 +275,8 @@ int control_algorithm_init(parameter_t * ps) graph_set_source(graph, ps->mixer, MIXER_YAW, ps->clamp_d_pwmY, BOUNDS_OUT); // Connect optical flow -#ifdef USE_FAKE_YAW - graph_set_source(graph, ps->of_angle_corr, ROT_YAW, ps->gyro_yaw, ADD_SUM); +#ifdef USE_MAG_YAW + graph_set_source(graph, ps->of_angle_corr, ROT_YAW, ps->mag_yaw, ADD_SUM); #else graph_set_source(graph, ps->of_angle_corr, ROT_YAW, ps->cur_yaw, ADD_SUM); #endif @@ -464,6 +467,7 @@ int control_algorithm_init(parameter_t * ps) // Sensor values graph_set_param_val(graph, ps->cur_pitch, CONST_SET, sensor_struct->pitch_angle_filtered); graph_set_param_val(graph, ps->cur_roll, CONST_SET, sensor_struct->roll_angle_filtered); + graph_set_param_val(graph, ps->mag_yaw, CONST_SET, sensor_struct->yaw_angle_filtered); graph_set_param_val(graph, ps->gyro_y, CONST_SET, sensor_struct->gyr_y); graph_set_param_val(graph, ps->gyro_x, CONST_SET, sensor_struct->gyr_x); graph_set_param_val(graph, ps->gyro_z, CONST_SET, sensor_struct->gyr_z); diff --git a/quad/src/quad_app/log_data.c b/quad/src/quad_app/log_data.c index dadb8194d29a6c6c677f4aea810ae9cfed1e32a2..94566042e3ddc79352fe1d2ba89b49780ceacfa0 100644 --- a/quad/src/quad_app/log_data.c +++ b/quad/src/quad_app/log_data.c @@ -119,6 +119,7 @@ void initialize_logging(log_t* log_struct, parameter_t* ps) { addOutputToLog(log_struct, ps->of_integ_x, INTEGRATED, m); addOutputToLog(log_struct, ps->of_integ_y, INTEGRATED, m); addOutputToLog(log_struct, ps->gyro_yaw, INTEGRATED, rad); + addOutputToLog(log_struct, ps->mag_yaw, CONST_VAL, rad); addParamToLog(log_struct, ps->cur_roll, CONST_VAL, rad); addParamToLog(log_struct, ps->cur_yaw, CONST_VAL, rad); @@ -135,7 +136,7 @@ void initialize_logging(log_t* log_struct, parameter_t* ps) { addParamToLog(log_struct, ps->flow_quality, CONST_VAL, "none"); // TODO: Make this not stupid. Adding 6 for IMU and 1 for timestamp - row_size = n_outputs + n_params + 6 + 1; + row_size = n_outputs + n_params + 9 + 1; size_t needed_memory = sizeof(float) * row_size * LOG_STARTING_SIZE; logArray = malloc(needed_memory); if (!logArray) { // malloc failed @@ -161,6 +162,10 @@ int log_data(log_t* log_struct, parameter_t* ps) thisRow[offset++] = log_struct->gam.gyro_xVel_p; thisRow[offset++] = log_struct->gam.gyro_yVel_q; thisRow[offset++] = log_struct->gam.gyro_zVel_r; + thisRow[offset++] = log_struct->gam.mag_x; + thisRow[offset++] = log_struct->gam.mag_y; + thisRow[offset++] = log_struct->gam.mag_z; + int i; for (i = 0; i < n_params; i++) { @@ -218,7 +223,7 @@ void printLogging(struct CommDriver *comm, log_t* log_struct, parameter_t* ps, r } // Header names for the pre-defined values - safe_sprintf_cat(&buf, "%%Time\taccel_x\taccel_y\taccel_z\tgyro_x\tgyro_y\tgyro_z"); + safe_sprintf_cat(&buf, "%%Time\taccel_x\taccel_y\taccel_z\tgyro_x\tgyro_y\tgyro_z\tmag_x\tmag_y\tmag_z"); // Print all the recorded block parameters for (i = 0; i < n_params; i++) { @@ -239,7 +244,7 @@ void printLogging(struct CommDriver *comm, log_t* log_struct, parameter_t* ps, r // Send units header buf.size = 0; - safe_sprintf_cat(&buf, "&s\tG\tG\tG\trad/s\trad/s\trad/s"); // The pre-defined ones + safe_sprintf_cat(&buf, "&s\tG\tG\tG\trad/s\trad/s\trad/s\tuT\tuT\tuT"); // The pre-defined ones safe_sprintf_cat(&buf, units_output.str); safe_sprintf_cat(&buf, units_param.str); safe_sprintf_cat(&buf, "\n"); diff --git a/quad/src/quad_app/sensor_processing.c b/quad/src/quad_app/sensor_processing.c index 59511fa9d349d6b274d5d5c32f183b85f05e8417..7e23bfbd0fb1ceb104537003d2dd70155e1594e3 100644 --- a/quad/src/quad_app/sensor_processing.c +++ b/quad/src/quad_app/sensor_processing.c @@ -14,9 +14,15 @@ #include <math.h> #define ALPHA 0.99 +#define YAW_ALPHA (0.995) #define PX4FLOW_QUAL_MIN (100) #define PX4FLOW_VEL_DECAY (0.99) +#define MAG_OFFSET_X (-33.9844) +#define MAG_OFFSET_Y (40.4922) + +#define GYRO_Z_OFFSET (0.0073) + int sensor_processing_init(sensor_t* sensor_struct) { float a0 = 0.0200833310260; float a1 = 0.0401666620520; @@ -33,6 +39,15 @@ int sensor_processing_init(sensor_t* sensor_struct) { float vel_b2 = 0.6853; sensor_struct->flow_x_filt = filter_make_state(vel_a0, vel_a1, vel_a2, vel_b1, vel_b2); sensor_struct->flow_y_filt = filter_make_state(vel_a0, vel_a1, vel_a2, vel_b1, vel_b2); + + float mag_a0 = 2.3921e-4; + float mag_a1 = 4.7841e-4; + float mag_a2 = 2.3921e-4; + float mag_b1 = -1.9281; + float mag_b2 = 0.9391; + sensor_struct->mag_x_filt = filter_make_state(mag_a0, mag_a1, mag_a2, mag_b1, mag_b2); + sensor_struct->mag_y_filt = filter_make_state(mag_a0, mag_a1, mag_a2, mag_b1, mag_b2); + return 0; } @@ -155,6 +170,15 @@ int sensor_processing(log_t* log_struct, user_input_t *user_input_struct, raw_se last_lidar = this_lidar; sensor_struct->lidar_altitude = filtered_alt; + //Magnetometer filter + float magX_filt = biquad_execute(&sensor_struct->mag_x_filt, gam->mag_x - MAG_OFFSET_X); + float magY_filt = biquad_execute(&sensor_struct->mag_y_filt, gam->mag_y - MAG_OFFSET_Y); + float mag_yaw = atan2(-magY_filt, -magX_filt); + + //Heading complementary filter + sensor_struct->yaw_angle_filtered = YAW_ALPHA * (sensor_struct->yaw_angle_filtered + + (sensor_struct->psi_dot)*get_last_loop_time()) + (1. - YAW_ALPHA) * mag_yaw; + return 0; } diff --git a/quad/src/quad_app/type_def.h b/quad/src/quad_app/type_def.h index c424869c4574c8445259bc3a1713178cae0ba898..7a5e2cb0de7060144035971061677feb0a1451b8 100644 --- a/quad/src/quad_app/type_def.h +++ b/quad/src/quad_app/type_def.h @@ -102,15 +102,18 @@ typedef struct gam { float accel_roll; float accel_pitch; - // MAG - //Xint16 raw_mag_x, raw_mag_y, raw_mag_z; - - float heading; // In degrees + //float heading; // In degrees float mag_x; //Magnetic north: ~50 uT float mag_y; float mag_z; + float magX_correction; + float magY_correction; + float magZ_correction; + + int magDRDYCount; + SensorError_t error; } gam_t; @@ -303,6 +306,7 @@ typedef struct sensor { // Complementary filter outputs float pitch_angle_filtered; float roll_angle_filtered; + float yaw_angle_filtered; // Z-axis value obtained from LiDAR // Note that this is not distance, as our Z-axis points upwards. @@ -319,6 +323,8 @@ typedef struct sensor { struct biquadState accel_z_filt; struct biquadState flow_x_filt; struct biquadState flow_y_filt; + struct biquadState mag_x_filt; + struct biquadState mag_y_filt; // Information obtained from optical flow sensor px4flow_t optical_flow; @@ -411,6 +417,7 @@ typedef struct parameter_t { int of_trimmed_x; // Trimmed optical flow integrated value (of_integ_x + of_trim_x) int of_trimmed_y; int gyro_yaw; // Integrates the gyro z value + int mag_yaw; //Complementary filtered magnetometer/gyro yaw } parameter_t; /** diff --git a/quad/xsdk_workspace/real_quad/.cproject b/quad/xsdk_workspace/real_quad/.cproject index eff70df8bb1fb6819d306f20afe048666440a183..57f76856b0208ef5824dd1bc3f413b84b8f3c3cf 100644 --- a/quad/xsdk_workspace/real_quad/.cproject +++ b/quad/xsdk_workspace/real_quad/.cproject @@ -109,7 +109,7 @@ </tool> <tool id="xilinx.gnu.arm.c.toolchain.compiler.release.85270120" name="ARM gcc compiler" superClass="xilinx.gnu.arm.c.toolchain.compiler.release"> <option defaultValue="gnu.c.optimization.level.more" id="xilinx.gnu.compiler.option.optimization.level.515686013" name="Optimization Level" superClass="xilinx.gnu.compiler.option.optimization.level" valueType="enumerated"/> - <option id="xilinx.gnu.compiler.option.debugging.level.1121150517" name="Debug Level" superClass="xilinx.gnu.compiler.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/> + <option id="xilinx.gnu.compiler.option.debugging.level.1121150517" name="Debug Level" superClass="xilinx.gnu.compiler.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> <option id="xilinx.gnu.compiler.inferred.swplatform.includes.687694973" name="Software Platform Include Path" superClass="xilinx.gnu.compiler.inferred.swplatform.includes" valueType="includePath"> <listOptionValue builtIn="false" value="../../system_bsp/ps7_cortexa9_0/include"/> </option> diff --git a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_imu.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_imu.c index bf94f23894fcebfc6b76d97b49b9e4d869426226..c7f2bfff3b7751ebf40346d52431eca8e15352f3 100644 --- a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_imu.c +++ b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_imu.c @@ -13,6 +13,8 @@ #define MAG_READ_SIZE 6 #define MAG_BASE_ADDR 0x03 +#define MAG_DRDY_TIMEOUT (10) + #define RAD_TO_DEG 57.29578 #define DEG_TO_RAD 0.0174533 @@ -44,7 +46,7 @@ #define GYRO_X_BIAS 0.005f #define GYRO_Y_BIAS -0.014f -#define GYRO_Z_BIAS 0.0541f +#define GYRO_Z_BIAS 0.0614//0.0541f #define ACCEL_X_BIAS 0.023f #define ACCEL_Y_BIAS 0.009f @@ -53,6 +55,7 @@ int mpu9150_write(struct I2CDriver *i2c, u8 register_addr, u8 data); int mpu9150_read(struct I2CDriver *i2c, u8* recv_buffer, u8 register_addr, int size); +int mpu9150_calc_mag_sensitivity(struct IMUDriver *self, gam_t *gam); int mpu9150_read_mag(struct IMUDriver *self, gam_t* gam); int mpu9150_read_gyro_accel(gam_t* gam); @@ -77,23 +80,57 @@ int zybo_imu_reset(struct IMUDriver *self, gam_t *gam) { // Enable I2C bypass for AUX I2C (Magnetometer) mpu9150_write(i2c, 0x37, 0x02); - // Setup Mag - mpu9150_write(i2c, 0x37, 0x02); //INT_PIN_CFG -- INT_LEVEL=0 ; INT_OPEN=0 ; LATCH_INT_EN=0 ; INT_RD_CLEAR=0 ; FSYNC_INT_LEVEL=0 ; FSYNC_INT_EN=0 ; I2C_BYPASS_EN=0 ; CLKOUT_EN=0 - usleep(100000); + //Calculate magnetometer sensitivities + mpu9150_calc_mag_sensitivity(self, gam); + + usleep(10000); + + //Enable single measurement mode + mpu9150_write(i2c, 0x0A, 0x00); + mpu9150_write(i2c, 0x0A, 0x01); + int i; - gam_t temp_gam; // Do about 20 reads to warm up the device for(i=0; i < 20; ++i){ - self->read(self, &temp_gam); + self->read(self, gam); usleep(1000); } return 0; } +int mpu9150_calc_mag_sensitivity(struct IMUDriver *self, gam_t *gam) { + u8 buf[3]; + u8 ASAX, ASAY, ASAZ; + + // Quickly read from the factory ROM to get correction coefficents + int status = mpu9150_write(self->i2c, 0x0A, 0x0F); + if(status != 0) { + return status; + } + + usleep(10000); + + // Read raw adjustment values + status = mpu9150_read(self->i2c, buf, 0x10,3); + if(status != 0) { + return status; + } + ASAX = buf[0]; + ASAY = buf[1]; + ASAZ = buf[2]; + + // Set the correction coefficients + gam->magX_correction = (ASAX-128)*0.5/128 + 1; + gam->magY_correction = (ASAY-128)*0.5/128 + 1; + gam->magZ_correction = (ASAZ-128)*0.5/128 + 1; + + return 0; +} + int zybo_imu_read(struct IMUDriver *self, gam_t *gam) { struct I2CDriver *i2c = self->i2c; i16 raw_accel_x, raw_accel_y, raw_accel_z; @@ -126,7 +163,7 @@ int zybo_imu_read(struct IMUDriver *self, gam_t *gam) { gam->gyro_zVel_r = ((gyro_z / GYRO_SENS) * DEG_TO_RAD) + GYRO_Z_BIAS; // Magnometer - //mpu9150_read_mag(self, gam); + mpu9150_read_mag(self, gam); return error; } @@ -174,56 +211,55 @@ int mpu9150_read(struct I2CDriver *i2c, u8* recv_buffer, u8 register_addr, int s int mpu9150_read_mag(struct IMUDriver *self, gam_t* gam){ - - static double magX_correction = -1, magY_correction, magZ_correction; - - struct I2CDriver *i2c = self->i2c; - - u8 mag_data[6]; - i16 raw_magX, raw_magY, raw_magZ; - - // Grab calibrations if not done already - if(magX_correction == -1){ - u8 buf[3]; - u8 ASAX, ASAY, ASAZ; - - // Quickly read from the factory ROM to get correction coefficents - mpu9150_write(i2c, 0x0A, 0x0F); - usleep(10000); - - // Read raw adjustment values - mpu9150_read(i2c, buf, 0x10,3); - ASAX = buf[0]; - ASAY = buf[1]; - ASAZ = buf[2]; - - // Set the correction coefficients - magX_correction = (ASAX-128)*0.5/128 + 1; - magY_correction = (ASAY-128)*0.5/128 + 1; - magZ_correction = (ASAZ-128)*0.5/128 + 1; - } - - // Set Mag to single read mode - mpu9150_write(i2c, 0x0A, 0x01); - usleep(10000); - mag_data[0] = 0; - - // Keep checking if data is ready before reading new mag data - while(mag_data[0] == 0x00){ - mpu9150_read(i2c, mag_data, 0x02, 1); - } - - // Get mag data - mpu9150_read(i2c, mag_data, 0x03, 6); - - raw_magX = (mag_data[1] << 8) | mag_data[0]; - raw_magY = (mag_data[3] << 8) | mag_data[2]; - raw_magZ = (mag_data[5] << 8) | mag_data[4]; - - // Set magnetometer data to output - gam->mag_x = raw_magX * magX_correction; - gam->mag_y = raw_magY * magY_correction; - gam->mag_z = raw_magZ * magZ_correction; - - return 0; + u8 mag_data[6]; + u8 mag_status; + i16 raw_magX, raw_magY, raw_magZ; + + int trigger = 0; + + int status = mpu9150_read(self->i2c, mag_data, 0x02, 1); + if(status != 0) { + return status; + } + + if(mag_data[0] & 0x01) { + // Get mag data + status = mpu9150_read(self->i2c, mag_data, 0x03, 6); + if(status != 0) { + return status; + } + + status = mpu9150_read(self->i2c, &mag_status, 0x09, 1); + if(status != 0) { + return status; + } + + raw_magX = (mag_data[1] << 8) | mag_data[0]; + raw_magY = (mag_data[3] << 8) | mag_data[2]; + raw_magZ = (mag_data[5] << 8) | mag_data[4]; + + // Set magnetometer data to output + gam->mag_x = raw_magX * gam->magX_correction; + gam->mag_y = raw_magY * gam->magY_correction; + gam->mag_z = raw_magZ * gam->magZ_correction; + + trigger = 1; + } + else { + gam->magDRDYCount++; + + if(gam->magDRDYCount > MAG_DRDY_TIMEOUT) { + gam->magDRDYCount = 0; + + trigger = 1; + } + } + + if(trigger) { + //Start next reading + mpu9150_write(self->i2c, 0x0A, 0x00); + mpu9150_write(self->i2c, 0x0A, 0x01); + } + + return 0; } diff --git a/quad/xsdk_workspace/real_quad/src/main.c b/quad/xsdk_workspace/real_quad/src/main.c index d715d8e6538906b99b38f21f50260d801540c4cf..198b48d057c468db94336fad51a42d6a5d7682ab 100644 --- a/quad/xsdk_workspace/real_quad/src/main.c +++ b/quad/xsdk_workspace/real_quad/src/main.c @@ -48,7 +48,7 @@ int main() #ifdef RUN_TESTS //test_zybo_mio7_led_and_system(); //test_zybo_i2c(); - //test_zybo_i2c_imu(); + test_zybo_i2c_imu(); //test_zybo_i2c_px4flow(); //test_zybo_i2c_lidar(); //test_zybo_i2c_all();