77 * @{
88 *
99 * @file filtercf.c
10- * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
10+ * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
11+ * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
1112 * @brief Complementary filter to calculate Attitude from Accels and Gyros
1213 * and optionally magnetometers:
1314 * WARNING: Will drift if the mean acceleration force doesn't point
4950
5051#define CALIBRATION_DELAY_MS 4000
5152#define CALIBRATION_DURATION_MS 6000
53+ #define RELOADSETTINGS_DELAY_MS 1000
54+ #define CONVERGENCE_MAGKP 20.0f
5255#define VARIANCE_WINDOW_SIZE 40
56+
57+ #define UNDONE 0
58+ #define DONE 1
59+ #define RUN 2
60+
5361// Private types
5462struct data {
5563 AttitudeSettingsData attitudeSettings ;
@@ -68,6 +76,7 @@ struct data {
6876 float rollPitchBiasRate ;
6977 int32_t timeval ;
7078 int32_t starttime ;
79+ int32_t inittime ;
7180 uint8_t init ;
7281 bool magCalibrated ;
7382 pw_variance_t gyro_var [3 ];
@@ -248,7 +257,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float
248257
249258 AttitudeStateData attitudeState ; // base on previous state
250259 AttitudeStateGet (& attitudeState );
251- this -> init = 0 ;
260+ this -> init = UNDONE ;
252261
253262 // Set initial attitude. Use accels to determine roll and pitch, rotate magnetic measurement accordingly,
254263 // so pseudo "north" vector can be estimated even if the board is not level
@@ -288,7 +297,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float
288297 return FILTERRESULT_OK ; // must return OK on initial initialization, so attitude will init with a valid quaternion
289298 }
290299 // check whether copter is steady
291- if (this -> init == 0 && this -> attitudeSettings .InitialZeroWhenBoardSteady == ATTITUDESETTINGS_INITIALZEROWHENBOARDSTEADY_TRUE ) {
300+ if (this -> init == UNDONE && this -> attitudeSettings .InitialZeroWhenBoardSteady == ATTITUDESETTINGS_INITIALZEROWHENBOARDSTEADY_TRUE ) {
292301 pseudo_windowed_variance_push_sample (& this -> gyro_var [0 ], gyro [0 ]);
293302 pseudo_windowed_variance_push_sample (& this -> gyro_var [1 ], gyro [1 ]);
294303 pseudo_windowed_variance_push_sample (& this -> gyro_var [2 ], gyro [2 ]);
@@ -304,36 +313,40 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float
304313 }
305314
306315
307- if (this -> init == 0 && xTaskGetTickCount () - this -> starttime < CALIBRATION_DELAY_MS / portTICK_RATE_MS ) {
316+ if (this -> init == UNDONE && xTaskGetTickCount () - this -> starttime < CALIBRATION_DELAY_MS / portTICK_RATE_MS ) {
308317 // wait 4 seconds for the user to get his hands off in case the board was just powered
309318 this -> timeval = PIOS_DELAY_GetRaw ();
310319 return FILTERRESULT_ERROR ;
311- } else if (this -> init == 0 && xTaskGetTickCount () - this -> starttime < (CALIBRATION_DELAY_MS + CALIBRATION_DURATION_MS ) / portTICK_RATE_MS ) {
320+ } else if (this -> init == UNDONE && xTaskGetTickCount () - this -> starttime < (CALIBRATION_DELAY_MS + CALIBRATION_DURATION_MS ) / portTICK_RATE_MS ) {
312321 // For first 6 seconds use accels to get gyro bias
313322 this -> attitudeSettings .AccelKp = 1.0f ;
314323 this -> attitudeSettings .AccelKi = 0.0f ;
315324 this -> attitudeSettings .YawBiasRate = 0.23f ;
316325 this -> accel_filter_enabled = false;
317326 this -> rollPitchBiasRate = 0.01f ;
318- this -> attitudeSettings .MagKp = this -> magCalibrated ? 1.0f : 0.0f ;
327+ this -> attitudeSettings .MagKp = this -> magCalibrated ? CONVERGENCE_MAGKP : 0.0f ;
319328 PIOS_NOTIFY_StartNotification (NOTIFY_DRAW_ATTENTION , NOTIFY_PRIORITY_REGULAR );
320329 } else if ((this -> attitudeSettings .ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE ) && (flightStatus .Armed == FLIGHTSTATUS_ARMED_ARMING )) {
321330 this -> attitudeSettings .AccelKp = 1.0f ;
322331 this -> attitudeSettings .AccelKi = 0.0f ;
323332 this -> attitudeSettings .YawBiasRate = 0.23f ;
324333 this -> accel_filter_enabled = false;
325334 this -> rollPitchBiasRate = 0.01f ;
326- this -> attitudeSettings .MagKp = this -> magCalibrated ? 1.0f : 0.0f ;
327- this -> init = 0 ;
335+ this -> attitudeSettings .MagKp = this -> magCalibrated ? CONVERGENCE_MAGKP : 0.0f ;
336+ this -> init = UNDONE ;
328337 PIOS_NOTIFY_StartNotification (NOTIFY_DRAW_ATTENTION , NOTIFY_PRIORITY_REGULAR );
329- } else if (this -> init == 0 ) {
330- // Reload settings (all the rates)
331- AttitudeSettingsGet (& this -> attitudeSettings );
338+ } else if (this -> init == UNDONE ) {
332339 this -> rollPitchBiasRate = 0.0f ;
333340 if (this -> accel_alpha > 0.0f ) {
334341 this -> accel_filter_enabled = true;
335342 }
336- this -> init = 1 ;
343+ this -> inittime = xTaskGetTickCount ();
344+ this -> init = DONE ;
345+ // Allow running filter with custom MagKp for some time before reload settings
346+ } else if (this -> init == DONE && (!this -> magCalibrated || (xTaskGetTickCount () - this -> inittime > RELOADSETTINGS_DELAY_MS / portTICK_RATE_MS ))) {
347+ // Reload settings (all the rates)
348+ AttitudeSettingsGet (& this -> attitudeSettings );
349+ this -> init = RUN ;
337350 }
338351
339352 // Compute the dT using the cpu clock
@@ -423,7 +436,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float
423436 this -> gyroBias [0 ] -= accel_err [0 ] * this -> attitudeSettings .AccelKi - gyro [0 ] * this -> rollPitchBiasRate ;
424437 this -> gyroBias [1 ] -= accel_err [1 ] * this -> attitudeSettings .AccelKi - gyro [1 ] * this -> rollPitchBiasRate ;
425438 if (this -> useMag ) {
426- this -> gyroBias [2 ] -= - mag_err [2 ] * this -> attitudeSettings .MagKi - gyro [2 ] * this -> rollPitchBiasRate ;
439+ this -> gyroBias [2 ] -= mag_err [2 ] * this -> attitudeSettings .MagKi - gyro [2 ] * this -> rollPitchBiasRate ;
427440 } else {
428441 this -> gyroBias [2 ] -= - gyro [2 ] * this -> rollPitchBiasRate ;
429442 }
@@ -473,7 +486,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float
473486 return FILTERRESULT_WARNING ;
474487 }
475488
476- if (this -> init ) {
489+ if (this -> init != UNDONE ) {
477490 return FILTERRESULT_OK ;
478491 } else {
479492 return FILTERRESULT_CRITICAL ; // return "critical" for now, so users can see the zeroing period, switch to more graceful notification later
0 commit comments