1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-02 10:24:11 +01:00

AHRS: Split various update modes into individual functions

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2153 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
peabody124 2010-11-26 15:57:03 +00:00 committed by peabody124
parent 0c39ead89d
commit 444dd5c311

View File

@ -158,6 +158,13 @@ struct gps_sensor {
* @}
*/
/* INS functions */
void ins_outdoor_update();
void ins_indoor_update();
void simple_update();
/* Data accessors - prepare for */
/* Function Prototypes */
void downsample_data(void);
void calibrate_sensors(void);
@ -196,19 +203,166 @@ static uint8_t adc_oversampling = 20;
* @}
*/
/* INS functions */
/**
* @brief Update the EKF when in outdoor mode. The primary difference is using the GPS values.
*/
void ins_outdoor_update()
{
float gyro[3], accel[3], vel[3];
static uint8_t gps_dirty = 1;
static uint32_t last_gps_time = 0;
// format data for INS algo
gyro[0] = gyro_data.filtered.x;
gyro[1] = gyro_data.filtered.y;
gyro[2] = gyro_data.filtered.z;
accel[0] = accel_data.filtered.x,
accel[1] = accel_data.filtered.y,
accel[2] = accel_data.filtered.z,
INSStatePrediction(gyro, accel, 1 / (float)EKF_RATE);
attitude_data.quaternion.q1 = Nav.q[0];
attitude_data.quaternion.q2 = Nav.q[1];
attitude_data.quaternion.q3 = Nav.q[2];
attitude_data.quaternion.q4 = Nav.q[3];
send_attitude(); // get message out quickly
send_velocity();
send_position();
INSCovariancePrediction(1 / (float)EKF_RATE);
if (gps_data.updated) {
uint32_t this_gps_time = timer_count();
float gps_delay;
// Detect if greater than certain time since last gps update and if so
// reset EKF to that position since probably drifted too far for safe
// update
if (this_gps_time < last_gps_time)
gps_delay = ((0xFFFF - last_gps_time) - this_gps_time) / timer_rate();
else
gps_delay = (this_gps_time - last_gps_time) / timer_rate();
last_gps_time = this_gps_time;
gps_dirty = gps_delay > INSGPS_GPS_TIMEOUT;
// Compute velocity from Heading and groundspeed
vel[0] = gps_data.groundspeed * cos(gps_data.heading * M_PI / 180);
vel[1] = gps_data.groundspeed * sin(gps_data.heading * M_PI / 180);
vel[2] = 0;
if (mag_data.updated && !gps_dirty) {
//TOOD: add check for altitude updates
//FullCorrection(mag_data.scaled.axis, gps_data.NED, vel, altitude_data.altitude);
GpsMagCorrection(mag_data.scaled.axis, gps_data.NED, vel);
mag_data.updated = 0;
} else if (!gps_dirty) {
//GpsBaroCorrection(gps_data.NED, vel, altitude_data.altitude);
GpsBaroCorrection(gps_data.NED, vel, -gps_data.NED[2]);
} else { // GPS hasn't updated for a bit
INSPosVelReset(gps_data.NED,vel);
}
gps_data.updated = false;
} else if (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_OUTDOOR
&& mag_data.updated == 1) {
MagCorrection(mag_data.scaled.axis); // only trust mags if outdoors
mag_data.updated = 0;
}
}
/**
* @brief Update the EKF when in indoor mode
*/
void ins_indoor_update()
{
float gyro[3], accel[3], vel[3];
static uint8_t indoor_dirty = 1;
static uint32_t last_indoor_time = 0;
// format data for INS algo
gyro[0] = gyro_data.filtered.x;
gyro[1] = gyro_data.filtered.y;
gyro[2] = gyro_data.filtered.z;
accel[0] = accel_data.filtered.x,
accel[1] = accel_data.filtered.y,
accel[2] = accel_data.filtered.z,
INSStatePrediction(gyro, accel, 1 / (float)EKF_RATE);
attitude_data.quaternion.q1 = Nav.q[0];
attitude_data.quaternion.q2 = Nav.q[1];
attitude_data.quaternion.q3 = Nav.q[2];
attitude_data.quaternion.q4 = Nav.q[3];
send_attitude(); // get message out quickly
send_velocity();
send_position();
INSCovariancePrediction(1 / (float)EKF_RATE);
// Indoors, update with zero position and velocity and high covariance
vel[0] = 0;
vel[1] = 0;
vel[2] = 0;
uint32_t this_indoor_time = timer_count();
float indoor_delay;
// Detect if greater than certain time since last gps update and if so
// reset EKF to that position since probably drifted too far for safe
// update
if (this_indoor_time < last_indoor_time)
indoor_delay = ((0xFFFF - last_indoor_time) - this_indoor_time) / timer_rate();
else
indoor_delay = (this_indoor_time - last_indoor_time) / timer_rate();
last_indoor_time = this_indoor_time;
indoor_dirty = indoor_delay > INSGPS_GPS_TIMEOUT;
if(indoor_dirty)
INSPosVelReset(vel,vel);
if((mag_data.updated == 1) && (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_INDOOR)) {
MagVelBaroCorrection(mag_data.scaled.axis,vel,altitude_data.altitude); // only trust mags if outdoors
mag_data.updated = 0;
} else {
VelBaroCorrection(vel, altitude_data.altitude);
}
}
/**
* @brief Simple update using just mag and accel. Yaw biased and big attitude changes.
*/
void simple_update() {
float q[4];
float rpy[3];
/***************** SIMPLE ATTITUDE FROM NORTH AND ACCEL ************/
/* Very simple computation of the heading and attitude from accel. */
rpy[2] =
atan2((mag_data.raw.axis[0]),
(-1 * mag_data.raw.axis[1])) * 180 /
M_PI;
rpy[1] =
atan2(accel_data.filtered.x,
accel_data.filtered.z) * 180 / M_PI;
rpy[0] =
atan2(accel_data.filtered.y,
accel_data.filtered.z) * 180 / M_PI;
RPY2Quaternion(rpy, q);
attitude_data.quaternion.q1 = q[0];
attitude_data.quaternion.q2 = q[1];
attitude_data.quaternion.q3 = q[2];
attitude_data.quaternion.q4 = q[3];
send_attitude();
}
/**
* @brief AHRS Main function
*/
int main()
{
uint8_t spike=0;
float gyro[3], accel[3];
float vel[3] = { 0, 0, 0 };
uint8_t gps_dirty = 1;
uint8_t indoor_dirty = 1;
gps_data.quality = -1;
uint32_t last_gps_time = 0;
uint32_t last_indoor_time = 0;
uint32_t up_time_real = 0;
uint32_t up_time = 0;
uint32_t last_up_time = 0;
@ -319,10 +473,7 @@ for all data to be up to date before doing anything*/
AhrsStatusGet(&status);
status.CPULoad = ((float)running_counts /
(float)(idle_counts + running_counts)) * 100;
// status.IdleTimePerCyle = idle_counts / (timer_rate() / 10000);
// ***************************
status.IdleTimePerCyle=spike;
// ***************************
status.IdleTimePerCyle = idle_counts / (timer_rate() / 10000);
status.RunningTimePerCyle = running_counts / (timer_rate() / 10000);
status.DroppedUpdates = ekf_too_slow;
up_time = timer_count();
@ -416,132 +567,18 @@ status.IdleTimePerCyle=spike;
/******************** INS ALGORITHM **************************/
if (ahrs_algorithm != AHRSSETTINGS_ALGORITHM_SIMPLE) {
// format data for INS algo
gyro[0] = gyro_data.filtered.x;
gyro[1] = gyro_data.filtered.y;
gyro[2] = gyro_data.filtered.z;
accel[0] = accel_data.filtered.x,
accel[1] = accel_data.filtered.y,
accel[2] = accel_data.filtered.z,
INSStatePrediction(gyro, accel, 1 / (float)EKF_RATE);
send_attitude(); // get message out quickly
send_velocity();
send_position();
INSCovariancePrediction(1 / (float)EKF_RATE);
if (gps_data.updated && ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_OUTDOOR) {
uint32_t this_gps_time = timer_count();
float gps_delay;
// Detect if greater than certain time since last gps update and if so
// reset EKF to that position since probably drifted too far for safe
// update
if (this_gps_time < last_gps_time)
gps_delay = ((0xFFFF - last_gps_time) - this_gps_time) / timer_rate();
else
gps_delay = (this_gps_time - last_gps_time) / timer_rate();
last_gps_time = this_gps_time;
gps_dirty = gps_delay > INSGPS_GPS_TIMEOUT;
// Compute velocity from Heading and groundspeed
vel[0] = gps_data.groundspeed *
cos(gps_data.heading * M_PI / 180);
vel[1] = gps_data.groundspeed *
sin(gps_data.heading * M_PI / 180);
vel[2] = 0;
// INSSetPosVelVar(0.004);
INSSetPosVelVar(0.04);
if (mag_data.updated && !gps_dirty) {
//TOOD: add check for altitude updates
//FullCorrection(mag_data.scaled.axis, gps_data.NED, vel, altitude_data.altitude);
GpsMagCorrection(mag_data.scaled.axis, gps_data.NED, vel);
mag_data.updated = 0;
} else if (!gps_dirty) {
//GpsBaroCorrection(gps_data.NED, vel, altitude_data.altitude);
GpsBaroCorrection(gps_data.NED, vel, -gps_data.NED[2]);
} else { // GPS hasn't updated for a bit
INSPosVelReset(gps_data.NED,vel);
}
gps_data.updated = false;
} else if (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_OUTDOOR
&& mag_data.updated == 1) {
MagCorrection(mag_data.scaled.axis); // only trust mags if outdoors
mag_data.updated = 0;
}
else if (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_OUTDOOR){ //Do no update
} else {
// Indoors, update with zero position and velocity and high covariance
spike++;
AHRSSettingsData settings;
AHRSSettingsGet(&settings);
INSSetPosVelVar(settings.IndoorVelocityVariance);
vel[0] = 0;
vel[1] = 0;
vel[2] = 0;
uint32_t this_indoor_time = timer_count();
float indoor_delay;
// Detect if greater than certain time since last gps update and if so
// reset EKF to that position since probably drifted too far for safe
// update
if (this_indoor_time < last_indoor_time)
indoor_delay = ((0xFFFF - last_indoor_time) - this_indoor_time) / timer_rate();
else
indoor_delay = (this_indoor_time - last_indoor_time) / timer_rate();
last_indoor_time = this_indoor_time;
indoor_dirty = indoor_delay > INSGPS_GPS_TIMEOUT;
if(indoor_dirty)
INSPosVelReset(vel,vel);
if((mag_data.updated == 1) && (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_INSGPS_INDOOR)) {
MagVelBaroCorrection(mag_data.scaled.axis,vel,altitude_data.altitude); // only trust mags if outdoors
mag_data.updated = 0;
} else {
VelBaroCorrection(vel, altitude_data.altitude);
}
}
attitude_data.quaternion.q1 = Nav.q[0];
attitude_data.quaternion.q2 = Nav.q[1];
attitude_data.quaternion.q3 = Nav.q[2];
attitude_data.quaternion.q4 = Nav.q[3];
} else if (ahrs_algorithm == AHRSSETTINGS_ALGORITHM_SIMPLE) {
float q[4];
float rpy[3];
/***************** SIMPLE ATTITUDE FROM NORTH AND ACCEL ************/
/* Very simple computation of the heading and attitude from accel. */
rpy[2] =
atan2((mag_data.raw.axis[0]),
(-1 * mag_data.raw.axis[1])) * 180 /
M_PI;
rpy[1] =
atan2(accel_data.filtered.x,
accel_data.filtered.z) * 180 / M_PI;
rpy[0] =
atan2(accel_data.filtered.y,
accel_data.filtered.z) * 180 / M_PI;
RPY2Quaternion(rpy, q);
attitude_data.quaternion.q1 = q[0];
attitude_data.quaternion.q2 = q[1];
attitude_data.quaternion.q3 = q[2];
attitude_data.quaternion.q4 = q[3];
send_attitude();
switch(ahrs_algorithm) {
case AHRSSETTINGS_ALGORITHM_SIMPLE:
simple_update();
break;
case AHRSSETTINGS_ALGORITHM_INSGPS_OUTDOOR:
ins_outdoor_update();
break;
case AHRSSETTINGS_ALGORITHM_INSGPS_INDOOR:
case AHRSSETTINGS_ALGORITHM_INSGPS_INDOOR_NOMAG:
ins_indoor_update();
break;
}
ahrs_state = AHRS_IDLE;
#ifdef DUMP_FRIENDLY
@ -944,6 +981,9 @@ void settings_callback(AhrsObjHandle obj)
fir_coeffs[adc_oversampling] = adc_oversampling;
}
INSSetPosVelVar(settings.IndoorVelocityVariance);
}
void homelocation_callback(AhrsObjHandle obj)