void stateCalcAccelNed_f(void) { if (bit_is_set(state.accel_status, ACCEL_NED_F)) return; int errno = 0; if (state.ned_initialized_f) { if (bit_is_set(state.accel_status, ACCEL_NED_I)) { ACCELS_FLOAT_OF_BFP(state.ned_accel_f, state.ned_accel_i); } else if (bit_is_set(state.accel_status, ACCEL_ECEF_F)) { ned_of_ecef_vect_f(&state.ned_accel_f, &state.ned_origin_f, &state.ecef_accel_f); } else if (bit_is_set(state.accel_status, ACCEL_ECEF_I)) { /* transform ecef_i -> ecef_f -> ned_f , set status bits */ ACCELS_FLOAT_OF_BFP(state.ecef_accel_f, state.ecef_accel_i); SetBit(state.accel_status, ACCEL_ECEF_F); ned_of_ecef_vect_f(&state.ned_accel_f, &state.ned_origin_f, &state.ecef_accel_f); } else { /* could not get this representation, set errno */ errno = 1; } } else { /* ned coordinate system not initialized, set errno */ errno = 2; } if (errno) { //struct NedCoor_f _ned_zero = {0.0f}; //return _ned_zero; } /* set bit to indicate this representation is computed */ SetBit(state.accel_status, ACCEL_NED_F); }
static void send_accel(struct transport_tx *trans, struct link_device *dev) { struct FloatVect3 accel_float; ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); pprz_msg_send_IMU_ACCEL(trans, dev, AC_ID, &accel_float.x, &accel_float.y, &accel_float.z); }
void ahrs_dcm_update_accel(struct Int32Vect3 *accel) { ACCELS_FLOAT_OF_BFP(accel_float, *accel); // DCM filter uses g-force as positive // accelerometer measures [0 0 -g] in a static case accel_float.x = -accel_float.x; accel_float.y = -accel_float.y; accel_float.z = -accel_float.z; ahrs_dcm.gps_age ++; if (ahrs_dcm.gps_age < 50) { //Remove centrifugal acceleration and longitudinal acceleration #if USE_AHRS_GPS_ACCELERATIONS PRINT_CONFIG_MSG("AHRS_FLOAT_DCM uses GPS acceleration.") accel_float.x += ahrs_dcm.gps_acceleration; // Longitudinal acceleration #endif accel_float.y += ahrs_dcm.gps_speed * Omega[2]; // Centrifugal force on Acc_y = GPS_speed*GyroZ accel_float.z -= ahrs_dcm.gps_speed * Omega[1]; // Centrifugal force on Acc_z = GPS_speed*GyroY } else { ahrs_dcm.gps_speed = 0; ahrs_dcm.gps_acceleration = 0; ahrs_dcm.gps_age = 100; } Drift_correction(); }
static void dialog_with_io_proc() { struct AutopilotMessageCRCFrame msg_in; struct AutopilotMessageCRCFrame msg_out; uint8_t crc_valid; for (uint8_t i=0; i<6; i++) msg_out.payload.msg_down.pwm_outputs_usecs[i] = otp.servos_outputs_usecs[i]; // for (uint8_t i=0; i<4; i++) msg_out.payload.msg_down.csc_servo_cmd[i] = otp.csc_servo_outputs[i]; spi_link_send(&msg_out, sizeof(struct AutopilotMessageCRCFrame), &msg_in, &crc_valid); struct AutopilotMessagePTUp *in = &msg_in.payload.msg_up; RATES_FLOAT_OF_BFP(otp.imu.gyro, in->gyro); ACCELS_FLOAT_OF_BFP(otp.imu.accel, in->accel); MAGS_FLOAT_OF_BFP(otp.imu.mag, in->mag); otp.io_proc_msg_cnt = in->stm_msg_cnt; otp.io_proc_err_cnt = in->stm_crc_err_cnt; otp.rc_status = in->rc_status; otp.baro_abs = in->pressure_absolute; otp.baro_diff = in->pressure_differential; }
void ahrs_update_accel(void) { /* last column of roation matrix = ltp z-axis in imu-frame */ struct FloatVect3 c2 = { RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 0,2), RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 1,2), RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 2,2) }; struct FloatVect3 imu_accel_float; ACCELS_FLOAT_OF_BFP(imu_accel_float, imu.accel); struct FloatVect3 residual; if (ahrs_impl.correct_gravity && ahrs_impl.ltp_vel_norm_valid) { /* * centrifugal acceleration in body frame * a_c_body = omega x (omega x r) * (omega x r) = tangential velocity in body frame * a_c_body = omega x vel_tangential_body * assumption: tangential velocity only along body x-axis */ const struct FloatVect3 vel_tangential_body = {ahrs_impl.ltp_vel_norm, 0.0, 0.0}; struct FloatVect3 acc_c_body; VECT3_RATES_CROSS_VECT3(acc_c_body, *stateGetBodyRates_f(), vel_tangential_body); /* convert centrifugal acceleration from body to imu frame */ struct FloatVect3 acc_c_imu; FLOAT_RMAT_VECT3_MUL(acc_c_imu, ahrs_impl.body_to_imu_rmat, acc_c_body); /* and subtract it from imu measurement to get a corrected measurement of the gravitiy vector */ struct FloatVect3 corrected_gravity; VECT3_DIFF(corrected_gravity, imu_accel_float, acc_c_imu); /* compute the residual of gravity vector in imu frame */ FLOAT_VECT3_CROSS_PRODUCT(residual, corrected_gravity, c2); } else { FLOAT_VECT3_CROSS_PRODUCT(residual, imu_accel_float, c2); } #ifdef AHRS_GRAVITY_UPDATE_NORM_HEURISTIC /* heuristic on acceleration norm */ const float acc_norm = FLOAT_VECT3_NORM(imu_accel_float); const float weight = Chop(1.-6*fabs((9.81-acc_norm)/9.81), 0., 1.); #else const float weight = 1.; #endif /* compute correction */ const float gravity_rate_update_gain = -5e-2; // -5e-2 FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.rate_correction, residual, weight*gravity_rate_update_gain); const float gravity_bias_update_gain = 1e-5; // -5e-6 FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.gyro_bias, residual, weight*gravity_bias_update_gain); /* FIXME: saturate bias */ }
void ahrs_update_accel(void) { struct FloatVect3 imu_g; ACCELS_FLOAT_OF_BFP(imu_g, imu.accel); const float alpha = 0.92; ahrs_impl.lp_accel = alpha * ahrs_impl.lp_accel + (1. - alpha) *(FLOAT_VECT3_NORM(imu_g) - 9.81); const struct FloatVect3 earth_g = {0., 0., -9.81 }; const float dn = 250*fabs( ahrs_impl.lp_accel ); struct FloatVect3 g_noise = {1.+dn, 1.+dn, 1.+dn}; update_state(&earth_g, &imu_g, &g_noise); reset_state(); }
static inline void ahrs_lowpass_accel(void) { // get latest measurement ACCELS_FLOAT_OF_BFP(bafl_accel_last, imu.accel); // low pass it VECT3_ADD(bafl_accel_measure, bafl_accel_last); VECT3_SDIV(bafl_accel_measure, bafl_accel_measure, 2); #ifdef BAFL_DEBUG bafl_phi_accel = atan2f( -bafl_accel_measure.y, -bafl_accel_measure.z); bafl_theta_accel = atan2f(bafl_accel_measure.x, sqrtf(bafl_accel_measure.y*bafl_accel_measure.y + bafl_accel_measure.z*bafl_accel_measure.z)); #endif }
void stateCalcAccelEcef_f(void) { if (bit_is_set(state.accel_status, ACCEL_ECEF_F)) return; if (bit_is_set(state.accel_status, ACCEL_ECEF_I)) { ACCELS_FLOAT_OF_BFP(state.ecef_accel_f, state.ned_accel_i); } else if (bit_is_set(state.accel_status, ACCEL_NED_F)) { ecef_of_ned_vect_f(&state.ecef_accel_f, &state.ned_origin_f, &state.ned_accel_f); } else if (bit_is_set(state.accel_status, ACCEL_NED_I)) { /* transform ned_f -> ned_i -> ecef_i , set status bits */ ACCELS_FLOAT_OF_BFP(state.ned_accel_f, state.ned_accel_i); SetBit(state.accel_status, ACCEL_NED_F); ecef_of_ned_vect_f(&state.ecef_accel_f, &state.ned_origin_f, &state.ned_accel_f); } else { /* could not get this representation, set errno */ //struct EcefCoor_f _ecef_zero = {0.0f}; //return _ecef_zero; } /* set bit to indicate this representation is computed */ SetBit(state.accel_status, ACCEL_ECEF_F); }
void print_raw_log_entry(struct raw_log_entry* e){ struct DoubleVect3 tempvect; struct DoubleRates temprates; printf("%f\t", e->time); printf("%i\t", e->message.valid_sensors); RATES_FLOAT_OF_BFP(temprates, e->message.gyro); printf("% f % f % f\t", temprates.p, temprates.q, temprates.r); ACCELS_FLOAT_OF_BFP(tempvect, e->message.accel); printf("% f % f % f\t", tempvect.x, tempvect.y, tempvect.z); MAGS_FLOAT_OF_BFP(tempvect, e->message.mag); printf("% f % f % f\t", tempvect.x, tempvect.y, tempvect.z); printf("% i % i % i\t", e->message.ecef_pos.x, e->message.ecef_pos.y, e->message.ecef_pos.z); printf("% i % i % i\t", e->message.ecef_vel.x, e->message.ecef_vel.y, e->message.ecef_vel.z); double baro_scaled = (double)(e->message.pressure_absolute)/256; printf("%f", baro_scaled); }
void ahrs_update_accel(void) { struct FloatVect3 accel_float; ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); struct FloatVect3* r2 = (struct FloatVect3*)(&RMAT_ELMT(ahrs_float.ltp_to_imu_rmat, 2,0)); struct FloatVect3 residual; FLOAT_VECT3_CROSS_PRODUCT(residual, accel_float, (*r2)); /* heuristic on acceleration norm */ const float acc_norm = FLOAT_VECT3_NORM(accel_float); const float weight = Chop(1.-2*fabs(1-acc_norm/9.81), 0., 1.); //const float weight = 1.; /* compute correction */ const float gravity_rate_update_gain = 5e-2; FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.rate_correction, residual, weight*gravity_rate_update_gain); const float gravity_bias_update_gain = -5e-6; FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.gyro_bias, residual, weight*gravity_bias_update_gain); /* FIXME: saturate bias */ }
void ahrs_update_accel(void) { ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); // DCM filter uses g-force as positive // accelerometer measures [0 0 -g] in a static case accel_float.x = -accel_float.x; accel_float.y = -accel_float.y; accel_float.z = -accel_float.z; #ifdef USE_GPS if (gps.fix == GPS_FIX_3D) { //Remove centrifugal acceleration. accel_float.y += gps.speed_3d/100. * Omega[2]; // Centrifugal force on Acc_y = GPS_speed*GyroZ accel_float.z -= gps.speed_3d/100. * Omega[1]; // Centrifugal force on Acc_z = GPS_speed*GyroY } #endif Drift_correction(); }
void ahrs_update_accel(void) { ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); // scale accel adc raw to [m/s-2] FIXME // olri accel_float.x /= 10.19f; accel_float.y /= 10.5f; accel_float.z /= 10.4f; #ifdef USE_GPS // Remove centrifugal acceleration. if (gps_mode==3) { // Centrifugal force on Acc_y = GPS_speed*GyroZ accel_float.y += gps_speed_3d/100.f * Omega[2]; // Centrifugal force on Acc_z = GPS_speed*GyroY accel_float.z -= gps_speed_3d/100.f * Omega[1]; } #endif Drift_correction(); }
void ahrs_update_accel(void) { struct FloatVect3 accel_float; ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); #ifdef AHRS_GRAVITY_UPDATE_COORDINATED_TURN float v = FLOAT_VECT3_NORM(ahrs_impl.est_ltp_speed); accel_float.y -= v * ahrs_float.imu_rate.r; accel_float.z -= -v * ahrs_float.imu_rate.q; #endif struct FloatVect3 c2 = { RMAT_ELMT(ahrs_float.ltp_to_imu_rmat, 0,2), RMAT_ELMT(ahrs_float.ltp_to_imu_rmat, 1,2), RMAT_ELMT(ahrs_float.ltp_to_imu_rmat, 2,2)}; struct FloatVect3 residual; FLOAT_VECT3_CROSS_PRODUCT(residual, accel_float, c2); #ifdef AHRS_GRAVITY_UPDATE_NORM_HEURISTIC /* heuristic on acceleration norm */ const float acc_norm = FLOAT_VECT3_NORM(accel_float); const float weight = Chop(1.-6*fabs((9.81-acc_norm)/9.81), 0., 1.); #else const float weight = 1.; #endif /* compute correction */ const float gravity_rate_update_gain = -5e-2; // -5e-2 FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.rate_correction, residual, weight*gravity_rate_update_gain); #if 1 const float gravity_bias_update_gain = 1e-5; // -5e-6 FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.gyro_bias, residual, weight*gravity_bias_update_gain); #else const float alpha = 5e-4; FLOAT_RATES_SCALE(ahrs_impl.gyro_bias, 1.-alpha); FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.gyro_bias, residual, alpha); #endif /* FIXME: saturate bias */ }
void ahrs_propagate(void) { struct NedCoor_f accel; struct FloatRates body_rates; struct FloatEulers eulers; // realign all the filter if needed // a complete init cycle is required if (ins_impl.reset) { ins_impl.reset = FALSE; ins.status = INS_UNINIT; ahrs.status = AHRS_UNINIT; init_invariant_state(); } // fill command vector struct Int32Rates gyro_meas_body; INT32_RMAT_TRANSP_RATEMULT(gyro_meas_body, imu.body_to_imu_rmat, imu.gyro); RATES_FLOAT_OF_BFP(ins_impl.cmd.rates, gyro_meas_body); struct Int32Vect3 accel_meas_body; INT32_RMAT_TRANSP_VMULT(accel_meas_body, imu.body_to_imu_rmat, imu.accel); ACCELS_FLOAT_OF_BFP(ins_impl.cmd.accel, accel_meas_body); // update correction gains error_output(&ins_impl); // propagate model struct inv_state new_state; runge_kutta_4_float((float*)&new_state, (float*)&ins_impl.state, INV_STATE_DIM, (float*)&ins_impl.cmd, INV_COMMAND_DIM, invariant_model, dt); ins_impl.state = new_state; // normalize quaternion FLOAT_QUAT_NORMALIZE(ins_impl.state.quat); // set global state FLOAT_EULERS_OF_QUAT(eulers, ins_impl.state.quat); #if INS_UPDATE_FW_ESTIMATOR // Some stupid lines of code for neutrals eulers.phi -= ins_roll_neutral; eulers.theta -= ins_pitch_neutral; stateSetNedToBodyEulers_f(&eulers); #else stateSetNedToBodyQuat_f(&ins_impl.state.quat); #endif RATES_DIFF(body_rates, ins_impl.cmd.rates, ins_impl.state.bias); stateSetBodyRates_f(&body_rates); stateSetPositionNed_f(&ins_impl.state.pos); stateSetSpeedNed_f(&ins_impl.state.speed); // untilt accel and remove gravity FLOAT_QUAT_RMAT_B2N(accel, ins_impl.state.quat, ins_impl.cmd.accel); FLOAT_VECT3_SMUL(accel, accel, 1. / (ins_impl.state.as)); FLOAT_VECT3_ADD(accel, A); stateSetAccelNed_f(&accel); //------------------------------------------------------------// RunOnceEvery(3,{ DOWNLINK_SEND_INV_FILTER(DefaultChannel, DefaultDevice, &ins_impl.state.quat.qi, &eulers.phi, &eulers.theta, &eulers.psi, &ins_impl.state.speed.x, &ins_impl.state.speed.y, &ins_impl.state.speed.z, &ins_impl.state.pos.x, &ins_impl.state.pos.y, &ins_impl.state.pos.z, &ins_impl.state.bias.p, &ins_impl.state.bias.q, &ins_impl.state.bias.r, &ins_impl.state.as, &ins_impl.state.hb, &ins_impl.meas.baro_alt, &ins_impl.meas.pos_gps.z) }); #if LOG_INVARIANT_FILTER if (pprzLogFile.fs != NULL) { if (!log_started) { // log file header sdLogWriteLog(&pprzLogFile, "p q r ax ay az gx gy gz gvx gvy gvz mx my mz b qi qx qy qz bp bq br vx vy vz px py pz hb as\n"); log_started = TRUE; } else { sdLogWriteLog(&pprzLogFile, "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", ins_impl.cmd.rates.p, ins_impl.cmd.rates.q, ins_impl.cmd.rates.r, ins_impl.cmd.accel.x, ins_impl.cmd.accel.y, ins_impl.cmd.accel.z, ins_impl.meas.pos_gps.x, ins_impl.meas.pos_gps.y, ins_impl.meas.pos_gps.z, ins_impl.meas.speed_gps.x, ins_impl.meas.speed_gps.y, ins_impl.meas.speed_gps.z, ins_impl.meas.mag.x, ins_impl.meas.mag.y, ins_impl.meas.mag.z, ins_impl.meas.baro_alt, ins_impl.state.quat.qi, ins_impl.state.quat.qx, ins_impl.state.quat.qy, ins_impl.state.quat.qz, ins_impl.state.bias.p, ins_impl.state.bias.q, ins_impl.state.bias.r, ins_impl.state.speed.x, ins_impl.state.speed.y, ins_impl.state.speed.z, ins_impl.state.pos.x, ins_impl.state.pos.y, ins_impl.state.pos.z, ins_impl.state.hb, ins_impl.state.as); } } #endif }
void ahrs_fc_update_accel(struct Int32Vect3 *accel, float dt) { // check if we had at least one propagation since last update if (ahrs_fc.accel_cnt == 0) { return; } /* last column of roation matrix = ltp z-axis in imu-frame */ struct FloatVect3 c2 = { RMAT_ELMT(ahrs_fc.ltp_to_imu_rmat, 0, 2), RMAT_ELMT(ahrs_fc.ltp_to_imu_rmat, 1, 2), RMAT_ELMT(ahrs_fc.ltp_to_imu_rmat, 2, 2) }; struct FloatVect3 imu_accel_float; ACCELS_FLOAT_OF_BFP(imu_accel_float, *accel); struct FloatVect3 residual; struct FloatVect3 pseudo_gravity_measurement; if (ahrs_fc.correct_gravity && ahrs_fc.ltp_vel_norm_valid) { /* * centrifugal acceleration in body frame * a_c_body = omega x (omega x r) * (omega x r) = tangential velocity in body frame * a_c_body = omega x vel_tangential_body * assumption: tangential velocity only along body x-axis */ const struct FloatVect3 vel_tangential_body = {ahrs_fc.ltp_vel_norm, 0.0, 0.0}; struct FloatRMat *body_to_imu_rmat = orientationGetRMat_f(&ahrs_fc.body_to_imu); struct FloatRates body_rate; float_rmat_transp_ratemult(&body_rate, body_to_imu_rmat, &ahrs_fc.imu_rate); struct FloatVect3 acc_c_body; VECT3_RATES_CROSS_VECT3(acc_c_body, body_rate, vel_tangential_body); /* convert centrifugal acceleration from body to imu frame */ struct FloatVect3 acc_c_imu; float_rmat_vmult(&acc_c_imu, body_to_imu_rmat, &acc_c_body); /* and subtract it from imu measurement to get a corrected measurement of the gravity vector */ VECT3_DIFF(pseudo_gravity_measurement, imu_accel_float, acc_c_imu); } else { VECT3_COPY(pseudo_gravity_measurement, imu_accel_float); } VECT3_CROSS_PRODUCT(residual, pseudo_gravity_measurement, c2); /* FIR filtered pseudo_gravity_measurement */ #define FIR_FILTER_SIZE 8 static struct FloatVect3 filtered_gravity_measurement = {0., 0., 0.}; VECT3_SMUL(filtered_gravity_measurement, filtered_gravity_measurement, FIR_FILTER_SIZE - 1); VECT3_ADD(filtered_gravity_measurement, pseudo_gravity_measurement); VECT3_SDIV(filtered_gravity_measurement, filtered_gravity_measurement, FIR_FILTER_SIZE); if (ahrs_fc.gravity_heuristic_factor) { /* heuristic on acceleration (gravity estimate) norm */ /* Factor how strongly to change the weight. * e.g. for gravity_heuristic_factor 30: * <0.66G = 0, 1G = 1.0, >1.33G = 0 */ const float g_meas_norm = float_vect3_norm(&filtered_gravity_measurement) / 9.81; ahrs_fc.weight = 1.0 - ahrs_fc.gravity_heuristic_factor * fabs(1.0 - g_meas_norm) / 10.0; Bound(ahrs_fc.weight, 0.15, 1.0); } else { ahrs_fc.weight = 1.0; } /* Complementary filter proportional gain. * Kp = 2 * zeta * omega * weight * ahrs_fc.accel_cnt * with ahrs_fc.accel_cnt beeing the number of propagations since last update */ const float gravity_rate_update_gain = -2 * ahrs_fc.accel_zeta * ahrs_fc.accel_omega * ahrs_fc.weight * ahrs_fc.accel_cnt / 9.81; RATES_ADD_SCALED_VECT(ahrs_fc.rate_correction, residual, gravity_rate_update_gain); // reset accel propagation counter ahrs_fc.accel_cnt = 0; /* Complementary filter integral gain * Correct the gyro bias. * Ki = (omega*weight)^2 * dt */ const float gravity_bias_update_gain = ahrs_fc.accel_omega * ahrs_fc.accel_omega * ahrs_fc.weight * ahrs_fc.weight * dt / 9.81; RATES_ADD_SCALED_VECT(ahrs_fc.gyro_bias, residual, gravity_bias_update_gain); /* FIXME: saturate bias */ }
void ahrs_propagate(float dt) { struct FloatVect3 accel; struct FloatRates body_rates; // realign all the filter if needed // a complete init cycle is required if (ins_impl.reset) { ins_impl.reset = FALSE; ins.status = INS_UNINIT; ahrs.status = AHRS_UNINIT; init_invariant_state(); } // fill command vector struct Int32Rates gyro_meas_body; struct Int32RMat *body_to_imu_rmat = orientationGetRMat_i(&imu.body_to_imu); int32_rmat_transp_ratemult(&gyro_meas_body, body_to_imu_rmat, &imu.gyro); RATES_FLOAT_OF_BFP(ins_impl.cmd.rates, gyro_meas_body); struct Int32Vect3 accel_meas_body; int32_rmat_transp_vmult(&accel_meas_body, body_to_imu_rmat, &imu.accel); ACCELS_FLOAT_OF_BFP(ins_impl.cmd.accel, accel_meas_body); // update correction gains error_output(&ins_impl); // propagate model struct inv_state new_state; runge_kutta_4_float((float *)&new_state, (float *)&ins_impl.state, INV_STATE_DIM, (float *)&ins_impl.cmd, INV_COMMAND_DIM, invariant_model, dt); ins_impl.state = new_state; // normalize quaternion FLOAT_QUAT_NORMALIZE(ins_impl.state.quat); // set global state stateSetNedToBodyQuat_f(&ins_impl.state.quat); RATES_DIFF(body_rates, ins_impl.cmd.rates, ins_impl.state.bias); stateSetBodyRates_f(&body_rates); stateSetPositionNed_f(&ins_impl.state.pos); stateSetSpeedNed_f(&ins_impl.state.speed); // untilt accel and remove gravity struct FloatQuat q_b2n; float_quat_invert(&q_b2n, &ins_impl.state.quat); float_quat_vmult(&accel, &q_b2n, &ins_impl.cmd.accel); VECT3_SMUL(accel, accel, 1. / (ins_impl.state.as)); VECT3_ADD(accel, A); stateSetAccelNed_f((struct NedCoor_f *)&accel); //------------------------------------------------------------// #if SEND_INVARIANT_FILTER struct FloatEulers eulers; FLOAT_EULERS_OF_QUAT(eulers, ins_impl.state.quat); RunOnceEvery(3, { pprz_msg_send_INV_FILTER(trans, dev, AC_ID, &ins_impl.state.quat.qi, &eulers.phi, &eulers.theta, &eulers.psi, &ins_impl.state.speed.x, &ins_impl.state.speed.y, &ins_impl.state.speed.z, &ins_impl.state.pos.x, &ins_impl.state.pos.y, &ins_impl.state.pos.z, &ins_impl.state.bias.p, &ins_impl.state.bias.q, &ins_impl.state.bias.r, &ins_impl.state.as, &ins_impl.state.hb, &ins_impl.meas.baro_alt, &ins_impl.meas.pos_gps.z) }); #endif #if LOG_INVARIANT_FILTER if (pprzLogFile.fs != NULL) { if (!log_started) { // log file header sdLogWriteLog(&pprzLogFile, "p q r ax ay az gx gy gz gvx gvy gvz mx my mz b qi qx qy qz bp bq br vx vy vz px py pz hb as\n"); log_started = TRUE; } else { sdLogWriteLog(&pprzLogFile, "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", ins_impl.cmd.rates.p, ins_impl.cmd.rates.q, ins_impl.cmd.rates.r, ins_impl.cmd.accel.x, ins_impl.cmd.accel.y, ins_impl.cmd.accel.z, ins_impl.meas.pos_gps.x, ins_impl.meas.pos_gps.y, ins_impl.meas.pos_gps.z, ins_impl.meas.speed_gps.x, ins_impl.meas.speed_gps.y, ins_impl.meas.speed_gps.z, ins_impl.meas.mag.x, ins_impl.meas.mag.y, ins_impl.meas.mag.z, ins_impl.meas.baro_alt, ins_impl.state.quat.qi, ins_impl.state.quat.qx, ins_impl.state.quat.qy, ins_impl.state.quat.qz, ins_impl.state.bias.p, ins_impl.state.bias.q, ins_impl.state.bias.r, ins_impl.state.speed.x, ins_impl.state.speed.y, ins_impl.state.speed.z, ins_impl.state.pos.x, ins_impl.state.pos.y, ins_impl.state.pos.z, ins_impl.state.hb, ins_impl.state.as); } } #endif }
static void send_accel(void) { struct FloatVect3 accel_float; ACCELS_FLOAT_OF_BFP(accel_float, imu.accel); DOWNLINK_SEND_IMU_ACCEL(DefaultChannel, DefaultDevice, &accel_float.x, &accel_float.y, &accel_float.z); }
void ahrs_align(void) { RATES_FLOAT_OF_BFP(bafl_bias, ahrs_aligner.lp_gyro); ACCELS_FLOAT_OF_BFP(bafl_accel_measure, ahrs_aligner.lp_accel); ahrs.status = AHRS_RUNNING; }
void ahrs_update_accel(void) { /* last column of roation matrix = ltp z-axis in imu-frame */ struct FloatVect3 c2 = { RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 0,2), RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 1,2), RMAT_ELMT(ahrs_impl.ltp_to_imu_rmat, 2,2)}; struct FloatVect3 imu_accel_float; ACCELS_FLOAT_OF_BFP(imu_accel_float, imu.accel); struct FloatVect3 residual; struct FloatVect3 pseudo_gravity_measurement; if (ahrs_impl.correct_gravity && ahrs_impl.ltp_vel_norm_valid) { /* * centrifugal acceleration in body frame * a_c_body = omega x (omega x r) * (omega x r) = tangential velocity in body frame * a_c_body = omega x vel_tangential_body * assumption: tangential velocity only along body x-axis */ const struct FloatVect3 vel_tangential_body = {ahrs_impl.ltp_vel_norm, 0.0, 0.0}; struct FloatVect3 acc_c_body; VECT3_RATES_CROSS_VECT3(acc_c_body, *stateGetBodyRates_f(), vel_tangential_body); /* convert centrifugal acceleration from body to imu frame */ struct FloatVect3 acc_c_imu; FLOAT_RMAT_VECT3_MUL(acc_c_imu, ahrs_impl.body_to_imu_rmat, acc_c_body); /* and subtract it from imu measurement to get a corrected measurement of the gravity vector */ VECT3_DIFF(pseudo_gravity_measurement, imu_accel_float, acc_c_imu); } else { VECT3_COPY(pseudo_gravity_measurement, imu_accel_float); } FLOAT_VECT3_CROSS_PRODUCT(residual, pseudo_gravity_measurement, c2); /* FIR filtered pseudo_gravity_measurement */ #define FIR_FILTER_SIZE 8 static struct FloatVect3 filtered_gravity_measurement = {0., 0., 0.}; VECT3_SMUL(filtered_gravity_measurement, filtered_gravity_measurement, FIR_FILTER_SIZE-1); VECT3_ADD(filtered_gravity_measurement, pseudo_gravity_measurement); VECT3_SDIV(filtered_gravity_measurement, filtered_gravity_measurement, FIR_FILTER_SIZE); if (ahrs_impl.gravity_heuristic_factor) { /* heuristic on acceleration (gravity estimate) norm */ /* Factor how strongly to change the weight. * e.g. for gravity_heuristic_factor 30: * <0.66G = 0, 1G = 1.0, >1.33G = 0 */ const float g_meas_norm = FLOAT_VECT3_NORM(filtered_gravity_measurement) / 9.81; ahrs_impl.weight = 1.0 - ahrs_impl.gravity_heuristic_factor * fabs(1.0 - g_meas_norm) / 10.0; Bound(ahrs_impl.weight, 0.15, 1.0); } else { ahrs_impl.weight = 1.0; } /* Complementary filter proportional gain. * Kp = 2 * zeta * omega * weight * AHRS_PROPAGATE_FREQUENCY / AHRS_CORRECT_FREQUENCY */ const float gravity_rate_update_gain = -2 * ahrs_impl.accel_zeta * ahrs_impl.accel_omega * ahrs_impl.weight * AHRS_PROPAGATE_FREQUENCY / (AHRS_CORRECT_FREQUENCY * 9.81); FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.rate_correction, residual, gravity_rate_update_gain); /* Complementary filter integral gain * Correct the gyro bias. * Ki = (omega*weight)^2/AHRS_CORRECT_FREQUENCY */ const float gravity_bias_update_gain = ahrs_impl.accel_omega * ahrs_impl.accel_omega * ahrs_impl.weight * ahrs_impl.weight / (AHRS_CORRECT_FREQUENCY * 9.81); FLOAT_RATES_ADD_SCALED_VECT(ahrs_impl.gyro_bias, residual, gravity_bias_update_gain); /* FIXME: saturate bias */ }
/** * Auto-throttle inner loop * \brief */ void v_ctl_climb_loop(void) { // Airspeed setpoint rate limiter: // AIRSPEED_SETPOINT_SLEW in m/s/s - a change from 15m/s to 18m/s takes 3s with the default value of 1 float airspeed_incr = v_ctl_auto_airspeed_setpoint - v_ctl_auto_airspeed_setpoint_slew; BoundAbs(airspeed_incr, AIRSPEED_SETPOINT_SLEW * dt_attidude); v_ctl_auto_airspeed_setpoint_slew += airspeed_incr; #ifdef V_CTL_AUTO_GROUNDSPEED_SETPOINT // Ground speed control loop (input: groundspeed error, output: airspeed controlled) float err_groundspeed = (v_ctl_auto_groundspeed_setpoint - stateGetHorizontalSpeedNorm_f()); v_ctl_auto_groundspeed_sum_err += err_groundspeed; BoundAbs(v_ctl_auto_groundspeed_sum_err, V_CTL_AUTO_GROUNDSPEED_MAX_SUM_ERR); v_ctl_auto_airspeed_controlled = (err_groundspeed + v_ctl_auto_groundspeed_sum_err * v_ctl_auto_groundspeed_igain) * v_ctl_auto_groundspeed_pgain; // Do not allow controlled airspeed below the setpoint if (v_ctl_auto_airspeed_controlled < v_ctl_auto_airspeed_setpoint_slew) { v_ctl_auto_airspeed_controlled = v_ctl_auto_airspeed_setpoint_slew; // reset integrator of ground speed loop v_ctl_auto_groundspeed_sum_err = v_ctl_auto_airspeed_controlled / (v_ctl_auto_groundspeed_pgain * v_ctl_auto_groundspeed_igain); } #else v_ctl_auto_airspeed_controlled = v_ctl_auto_airspeed_setpoint_slew; #endif // Airspeed outerloop: positive means we need to accelerate float speed_error = v_ctl_auto_airspeed_controlled - stateGetAirspeed_f(); // Speed Controller to PseudoControl: gain 1 -> 5m/s error = 0.5g acceleration v_ctl_desired_acceleration = speed_error * v_ctl_airspeed_pgain / 9.81f; BoundAbs(v_ctl_desired_acceleration, v_ctl_max_acceleration); // Actual Acceleration from IMU: attempt to reconstruct the actual kinematic acceleration #ifndef SITL /* convert last imu accel measurement to float */ struct FloatVect3 accel_imu_f; ACCELS_FLOAT_OF_BFP(accel_imu_f, accel_imu_meas); /* rotate from imu to body frame */ struct FloatVect3 accel_meas_body; float_quat_vmult(&accel_meas_body, &imu_to_body_quat, &accel_imu_f); float vdot = accel_meas_body.x / 9.81f - sinf(stateGetNedToBodyEulers_f()->theta); #else float vdot = 0; #endif // Acceleration Error: positive means UAV needs to accelerate: needs extra energy float vdot_err = low_pass_vdot(v_ctl_desired_acceleration - vdot); // Flight Path Outerloop: positive means needs to climb more: needs extra energy float gamma_err = (v_ctl_climb_setpoint - stateGetSpeedEnu_f()->z) / v_ctl_auto_airspeed_controlled; // Total Energy Error: positive means energy should be added float en_tot_err = gamma_err + vdot_err; // Energy Distribution Error: positive means energy should go from overspeed to altitude = pitch up float en_dis_err = gamma_err - vdot_err; // Auto Cruise Throttle if (autopilot.launch && (v_ctl_mode >= V_CTL_MODE_AUTO_CLIMB)) { v_ctl_auto_throttle_nominal_cruise_throttle += v_ctl_auto_throttle_of_airspeed_igain * speed_error * dt_attidude + en_tot_err * v_ctl_energy_total_igain * dt_attidude; Bound(v_ctl_auto_throttle_nominal_cruise_throttle, 0.0f, 1.0f); } // Total Controller float controlled_throttle = v_ctl_auto_throttle_nominal_cruise_throttle + v_ctl_auto_throttle_climb_throttle_increment * v_ctl_climb_setpoint + v_ctl_auto_throttle_of_airspeed_pgain * speed_error + v_ctl_energy_total_pgain * en_tot_err; if ((controlled_throttle >= 1.0f) || (controlled_throttle <= 0.0f) || (autopilot_throttle_killed() == 1)) { // If your energy supply is not sufficient, then neglect the climb requirement en_dis_err = -vdot_err; // adjust climb_setpoint to maintain airspeed in case of an engine failure or an unrestriced climb if (v_ctl_climb_setpoint > 0) { v_ctl_climb_setpoint += - 30. * dt_attidude; } if (v_ctl_climb_setpoint < 0) { v_ctl_climb_setpoint += 30. * dt_attidude; } } /* pitch pre-command */ if (autopilot.launch && (v_ctl_mode >= V_CTL_MODE_AUTO_CLIMB)) { v_ctl_auto_throttle_nominal_cruise_pitch += v_ctl_auto_pitch_of_airspeed_igain * (-speed_error) * dt_attidude + v_ctl_energy_diff_igain * en_dis_err * dt_attidude; Bound(v_ctl_auto_throttle_nominal_cruise_pitch, H_CTL_PITCH_MIN_SETPOINT, H_CTL_PITCH_MAX_SETPOINT); } float v_ctl_pitch_of_vz = + (v_ctl_climb_setpoint /*+ d_err * v_ctl_auto_throttle_pitch_of_vz_dgain*/) * v_ctl_auto_throttle_pitch_of_vz_pgain - v_ctl_auto_pitch_of_airspeed_pgain * speed_error + v_ctl_auto_pitch_of_airspeed_dgain * vdot + v_ctl_energy_diff_pgain * en_dis_err + v_ctl_auto_throttle_nominal_cruise_pitch; if (autopilot_throttle_killed()) { v_ctl_pitch_of_vz = v_ctl_pitch_of_vz - 1 / V_CTL_GLIDE_RATIO; } v_ctl_pitch_setpoint = v_ctl_pitch_of_vz + nav_pitch; Bound(v_ctl_pitch_setpoint, H_CTL_PITCH_MIN_SETPOINT, H_CTL_PITCH_MAX_SETPOINT) ac_char_update(controlled_throttle, v_ctl_pitch_of_vz, v_ctl_climb_setpoint, v_ctl_desired_acceleration); v_ctl_throttle_setpoint = TRIM_UPPRZ(controlled_throttle * MAX_PPRZ); }
/** * Run the optical flow on a new image frame * @param[in] *opticflow The opticalflow structure that keeps track of previous images * @param[in] *state The state of the drone * @param[in] *img The image frame to calculate the optical flow from * @param[out] *result The optical flow result */ void opticflow_calc_frame(struct opticflow_t *opticflow, struct opticflow_state_t *state, struct image_t *img, struct opticflow_result_t *result) { // A switch counter that checks in the loop if the current method is similar, // to the previous (for reinitializing structs) static int8_t switch_counter = -1; if (switch_counter != opticflow->method) { opticflow->just_switched_method = true; switch_counter = opticflow->method; } else { opticflow->just_switched_method = false; } // Switch between methods (0 = fast9/lukas-kanade, 1 = EdgeFlow) if (opticflow->method == 0) { calc_fast9_lukas_kanade(opticflow, state, img, result); } else if (opticflow->method == 1) { calc_edgeflow_tot(opticflow, state, img, result); } /* Rotate velocities from camera frame coordinates to body coordinates for control * IMPORTANT!!! This frame to body orientation should be the case for the Parrot * ARdrone and Bebop, however this can be different for other quadcopters * ALWAYS double check! */ result->vel_body_x = result->vel_y; result->vel_body_y = - result->vel_x; // KALMAN filter on velocity float measurement_noise[2] = {result->noise_measurement, 1.0f}; static bool reinitialize_kalman = true; static uint8_t wait_filter_counter = 0; // When starting up the opticalflow module, or switching between methods, wait for a bit to prevent bias if (opticflow->kalman_filter == true) { if (opticflow->just_switched_method == true) { wait_filter_counter = 0; reinitialize_kalman = true; } if (wait_filter_counter > 50) { // Get accelerometer values rotated to body axis // TODO: use acceleration from the state ? struct FloatVect3 accel_imu_f; ACCELS_FLOAT_OF_BFP(accel_imu_f, state->accel_imu_meas); struct FloatVect3 accel_meas_body; float_quat_vmult(&accel_meas_body, &state->imu_to_body_quat, &accel_imu_f); float acceleration_measurement[2]; acceleration_measurement[0] = accel_meas_body.x; acceleration_measurement[1] = accel_meas_body.y; kalman_filter_opticflow_velocity(&result->vel_body_x, &result->vel_body_y, acceleration_measurement, result->fps, measurement_noise, opticflow->kalman_filter_process_noise, reinitialize_kalman); if (reinitialize_kalman) { reinitialize_kalman = false; } } else { wait_filter_counter++; } } else { reinitialize_kalman = true; } }
static struct raw_log_entry first_entry_after_initialisation(int file_descriptor){ int imu_measurements = 0, // => Gyro + Accel magnetometer_measurements = 0, baro_measurements = 0, gps_measurements = 0; // only the position struct DoubleMat33 attitude_profile_matrix, sigmaB; // the attitude profile matrix is often called "B" struct Orientation_Measurement gravity, magneto, fake; struct DoubleQuat q_ned2body, sigma_q; /* Prepare the attitude profile matrix */ FLOAT_MAT33_ZERO(attitude_profile_matrix); FLOAT_MAT33_ZERO(sigmaB); // for faster converging, but probably more rounding error #define MEASUREMENT_WEIGHT_SCALE 10 /* set the gravity measurement */ VECT3_ASSIGN(gravity.reference_direction, 0,0,-1); gravity.weight_of_the_measurement = MEASUREMENT_WEIGHT_SCALE/(double)(imu_frequency); // originally 1/(imu_frequency*gravity.norm() //gravity.weight_of_the_measurement = 1; /* set the magneto - measurement */ EARTHS_GEOMAGNETIC_FIELD_NORMED(magneto.reference_direction); magneto.weight_of_the_measurement = MEASUREMENT_WEIGHT_SCALE/(double)(mag_frequency); // originally 1/(mag_frequency*reference_direction.norm() //magneto.weight_of_the_measurement = 1; uint8_t read_ok; #if WITH_GPS struct raw_log_entry e = next_GPS(file_descriptor); #else /* WITH_GPS */ struct raw_log_entry e = read_raw_log_entry(file_descriptor, &read_ok); pos_0_ecef = Vector3d(4627578.56, 119659.25, 4373248.00); pos_cov_0 = Vector3d::Ones()*100; speed_0_ecef = Vector3d::Zero(); speed_cov_0 = Vector3d::Ones(); #endif /* WITH_GPS */ #ifdef EKNAV_FROM_LOG_DEBUG int imu_ready = 0, mag_ready = 0, baro_ready = 0, gps_ready = 0; #endif /* EKNAV_FROM_LOG_DEBUG */ for(read_ok = 1; (read_ok) && NOT_ENOUGH_MEASUREMENTS(imu_measurements, magnetometer_measurements, baro_measurements, gps_measurements); e = read_raw_log_entry(file_descriptor, &read_ok)){ if(IMU_READY(e.message.valid_sensors)){ imu_measurements++; // update the estimated bias bias_0 = NEW_MEAN(bias_0, RATES_BFP_AS_VECTOR3D(e.message.gyro), imu_measurements); // update the attitude profile matrix ACCELS_FLOAT_OF_BFP(gravity.measured_direction,e.message.accel); add_orientation_measurement(&attitude_profile_matrix, gravity); } if(MAG_READY(e.message.valid_sensors)){ magnetometer_measurements++; // update the attitude profile matrix MAGS_FLOAT_OF_BFP(magneto.measured_direction,e.message.mag); add_orientation_measurement(&attitude_profile_matrix, magneto); // now, generate fake measurement with the last gravity measurement fake = fake_orientation_measurement(gravity, magneto); add_orientation_measurement(&attitude_profile_matrix, fake); } if(BARO_READY(e.message.valid_sensors)){ baro_measurements++; // TODO: Fix it! //NEW_MEAN(baro_0_height, BARO_FLOAT_OF_BFP(e.message.pressure_absolute), baro_measurements); baro_0_height = (baro_0_height*(baro_measurements-1)+BARO_FLOAT_OF_BFP(e.message.pressure_absolute))/baro_measurements; } if(GPS_READY(e.message.valid_sensors)){ gps_measurements++; // update the estimated bias pos_0_ecef = NEW_MEAN(pos_0_ecef, VECT3_AS_VECTOR3D(e.message.ecef_pos)/100, gps_measurements); speed_0_ecef = NEW_MEAN(speed_0_ecef, VECT3_AS_VECTOR3D(e.message.ecef_vel)/100, gps_measurements); } #ifdef EKNAV_FROM_LOG_DEBUG if(imu_ready==0){ if(!NOT_ENOUGH_IMU_MEASUREMENTS(imu_measurements)){ printf("IMU READY %3i %3i %3i %3i\n", imu_measurements, magnetometer_measurements, baro_measurements, gps_measurements); imu_ready = 1; } } if(mag_ready==0){ if(!NOT_ENOUGH_MAGNETIC_FIELD_MEASUREMENTS(magnetometer_measurements)){ printf("MAG READY %3i %3i %3i %3i\n", imu_measurements, magnetometer_measurements, baro_measurements, gps_measurements); mag_ready = 1; } } if(baro_ready==0){ if(!NOT_ENOUGH_BARO_MEASUREMENTS(baro_measurements)){ printf("BARO READY %3i %3i %3i %3i\n", imu_measurements, magnetometer_measurements, baro_measurements, gps_measurements); baro_ready = 1; } } if(gps_ready==0){ if(!NOT_ENOUGH_GPS_MEASUREMENTS(gps_measurements)){ printf("GPS READY %3i %3i %3i %3i\n", imu_measurements, magnetometer_measurements, baro_measurements, gps_measurements); gps_ready = 1; } } #endif /* EKNAV_FROM_LOG_DEBUG */ } // setting the covariance gravity.weight_of_the_measurement *= imu_measurements; VECTOR_AS_VECT3(gravity.measured_direction, accelerometer_noise); magneto.weight_of_the_measurement *= magnetometer_measurements; VECTOR_AS_VECT3(magneto.measured_direction, magnetometer_noise); add_set_of_three_measurements(&sigmaB, gravity, magneto); #ifdef EKNAV_FROM_LOG_DEBUG DISPLAY_FLOAT_RMAT(" B", attitude_profile_matrix); DISPLAY_FLOAT_RMAT("sigmaB", sigmaB); #endif /* EKNAV_FROM_LOG_DEBUG */ // setting the initial orientation q_ned2body = estimated_attitude(attitude_profile_matrix, 1000, 1e-6, sigmaB, &sigma_q); orientation_0 = ecef2body_from_pprz_ned2body(pos_0_ecef,q_ned2body); baro_0_height += pos_0_ecef.norm(); struct DoubleEulers sigma_eu = sigma_euler_from_sigma_q(q_ned2body, sigma_q); orientation_cov_0 = EULER_AS_VECTOR3D(sigma_eu); #if WITH_GPS pos_cov_0 = 10*gps_pos_noise / gps_measurements; speed_cov_0 = 10*gps_speed_noise / gps_measurements; #endif // WITH_GPS return e; }