OP-1900 added deceleration check to autotakeoff failsafe
[librepilot.git] / flight / modules / StateEstimation / stateestimation.c
blob3ed9dfe02d3960fd1d64fc6af2f1c9970b242b99
1 /**
2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
4 * @{
5 * @addtogroup State Estimation
6 * @brief Acquires sensor data and computes state estimate
7 * @{
9 * @file stateestimation.c
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
11 * @brief Module to handle all comms to the AHRS on a periodic basis.
13 * @see The GNU Public License (GPL) Version 3
15 ******************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 * for more details.
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "inc/stateestimation.h"
34 #include <callbackinfo.h>
36 #include <gyrosensor.h>
37 #include <accelsensor.h>
38 #include <magsensor.h>
39 #include <barosensor.h>
40 #include <airspeedsensor.h>
41 #include <gpspositionsensor.h>
42 #include <gpsvelocitysensor.h>
43 #include <homelocation.h>
44 #include <auxmagsensor.h>
46 #include <gyrostate.h>
47 #include <accelstate.h>
48 #include <magstate.h>
49 #include <airspeedstate.h>
50 #include <attitudestate.h>
51 #include <positionstate.h>
52 #include <velocitystate.h>
54 #include "revosettings.h"
55 #include "flightstatus.h"
57 #include "CoordinateConversions.h"
59 // Private constants
60 #define STACK_SIZE_BYTES 256
61 #define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR
62 #define TASK_PRIORITY CALLBACK_TASK_FLIGHTCONTROL
63 #define TIMEOUT_MS 10
65 // Private filter init const
66 #define FILTER_INIT_FORCE -1
67 #define FILTER_INIT_IF_POSSIBLE -2
69 // local macros, ONLY to be used in the middle of StateEstimationCb in section RUNSTATE_LOAD after the update of states updated!
70 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(sensorname, shortname, a1, a2, a3) \
71 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
72 sensorname##Data s; \
73 sensorname##Get(&s); \
74 if (IS_REAL(s.a1) && IS_REAL(s.a2) && IS_REAL(s.a3)) { \
75 states.shortname[0] = s.a1; \
76 states.shortname[1] = s.a2; \
77 states.shortname[2] = s.a3; \
78 } \
79 else { \
80 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
81 } \
84 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_1_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(sensorname, shortname, a1, EXTRACHECK) \
85 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
86 sensorname##Data s; \
87 sensorname##Get(&s); \
88 if (IS_REAL(s.a1) && EXTRACHECK) { \
89 states.shortname[0] = s.a1; \
90 } \
91 else { \
92 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
93 } \
96 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_2_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(sensorname, shortname, a1, a2, EXTRACHECK) \
97 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
98 sensorname##Data s; \
99 sensorname##Get(&s); \
100 if (IS_REAL(s.a1) && IS_REAL(s.a2) && EXTRACHECK) { \
101 states.shortname[0] = s.a1; \
102 states.shortname[1] = s.a2; \
104 else { \
105 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
109 // local macros, ONLY to be used in the middle of StateEstimationCb in section RUNSTATE_SAVE before the check of alarms!
110 #define EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(statename, shortname, a1, a2, a3) \
111 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
112 statename##Data s; \
113 statename##Get(&s); \
114 s.a1 = states.shortname[0]; \
115 s.a2 = states.shortname[1]; \
116 s.a3 = states.shortname[2]; \
117 statename##Set(&s); \
120 #define EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_2_DIMENSIONS(statename, shortname, a1, a2) \
121 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
122 statename##Data s; \
123 statename##Get(&s); \
124 s.a1 = states.shortname[0]; \
125 s.a2 = states.shortname[1]; \
126 statename##Set(&s); \
130 // Private types
131 struct filterPipelineStruct;
133 typedef const struct filterPipelineStruct {
134 const stateFilter *filter;
135 const struct filterPipelineStruct *next;
136 } filterPipeline;
138 // Private variables
139 static DelayedCallbackInfo *stateEstimationCallback;
141 static volatile RevoSettingsData revoSettings;
142 static volatile sensorUpdates updatedSensors;
143 static volatile int32_t fusionAlgorithm = -1;
144 static const filterPipeline *filterChain = NULL;
146 // different filters available to state estimation
147 static stateFilter magFilter;
148 static stateFilter baroFilter;
149 static stateFilter baroiFilter;
150 static stateFilter velocityFilter;
151 static stateFilter altitudeFilter;
152 static stateFilter airFilter;
153 static stateFilter stationaryFilter;
154 static stateFilter llaFilter;
155 static stateFilter cfFilter;
156 static stateFilter cfmFilter;
157 static stateFilter ekf13iFilter;
158 static stateFilter ekf13Filter;
160 // this is a hack to provide a computational shortcut for faster gyro state progression
161 static float gyroRaw[3];
162 static float gyroDelta[3];
164 // preconfigured filter chains selectable via revoSettings.FusionAlgorithm
165 static const filterPipeline *cfQueue = &(filterPipeline) {
166 .filter = &airFilter,
167 .next = &(filterPipeline) {
168 .filter = &baroiFilter,
169 .next = &(filterPipeline) {
170 .filter = &altitudeFilter,
171 .next = &(filterPipeline) {
172 .filter = &cfFilter,
173 .next = NULL,
178 static const filterPipeline *cfmiQueue = &(filterPipeline) {
179 .filter = &magFilter,
180 .next = &(filterPipeline) {
181 .filter = &airFilter,
182 .next = &(filterPipeline) {
183 .filter = &baroiFilter,
184 .next = &(filterPipeline) {
185 .filter = &altitudeFilter,
186 .next = &(filterPipeline) {
187 .filter = &cfmFilter,
188 .next = NULL,
194 static const filterPipeline *cfmQueue = &(filterPipeline) {
195 .filter = &magFilter,
196 .next = &(filterPipeline) {
197 .filter = &airFilter,
198 .next = &(filterPipeline) {
199 .filter = &llaFilter,
200 .next = &(filterPipeline) {
201 .filter = &baroFilter,
202 .next = &(filterPipeline) {
203 .filter = &altitudeFilter,
204 .next = &(filterPipeline) {
205 .filter = &cfmFilter,
206 .next = NULL,
213 static const filterPipeline *ekf13iQueue = &(filterPipeline) {
214 .filter = &magFilter,
215 .next = &(filterPipeline) {
216 .filter = &airFilter,
217 .next = &(filterPipeline) {
218 .filter = &baroiFilter,
219 .next = &(filterPipeline) {
220 .filter = &stationaryFilter,
221 .next = &(filterPipeline) {
222 .filter = &ekf13iFilter,
223 .next = &(filterPipeline) {
224 .filter = &velocityFilter,
225 .next = NULL,
233 static const filterPipeline *ekf13Queue = &(filterPipeline) {
234 .filter = &magFilter,
235 .next = &(filterPipeline) {
236 .filter = &airFilter,
237 .next = &(filterPipeline) {
238 .filter = &llaFilter,
239 .next = &(filterPipeline) {
240 .filter = &baroFilter,
241 .next = &(filterPipeline) {
242 .filter = &ekf13Filter,
243 .next = &(filterPipeline) {
244 .filter = &velocityFilter,
245 .next = NULL,
253 // Private functions
255 static void settingsUpdatedCb(UAVObjEvent *objEv);
256 static void sensorUpdatedCb(UAVObjEvent *objEv);
257 static void homeLocationUpdatedCb(UAVObjEvent *objEv);
258 static void StateEstimationCb(void);
260 static inline int32_t maxint32_t(int32_t a, int32_t b)
262 if (a > b) {
263 return a;
265 return b;
269 * Initialise the module. Called before the start function
270 * \returns 0 on success or -1 if initialisation failed
272 int32_t StateEstimationInitialize(void)
274 RevoSettingsInitialize();
276 GyroSensorInitialize();
277 MagSensorInitialize();
278 AuxMagSensorInitialize();
279 BaroSensorInitialize();
280 AirspeedSensorInitialize();
281 GPSVelocitySensorInitialize();
282 GPSPositionSensorInitialize();
284 HomeLocationInitialize();
286 GyroStateInitialize();
287 AccelStateInitialize();
288 MagStateInitialize();
289 AirspeedStateInitialize();
290 PositionStateInitialize();
291 VelocityStateInitialize();
293 RevoSettingsConnectCallback(&settingsUpdatedCb);
295 HomeLocationConnectCallback(&homeLocationUpdatedCb);
297 GyroSensorConnectCallback(&sensorUpdatedCb);
298 AccelSensorConnectCallback(&sensorUpdatedCb);
299 MagSensorConnectCallback(&sensorUpdatedCb);
300 BaroSensorConnectCallback(&sensorUpdatedCb);
301 AirspeedSensorConnectCallback(&sensorUpdatedCb);
302 AuxMagSensorConnectCallback(&sensorUpdatedCb);
303 GPSVelocitySensorConnectCallback(&sensorUpdatedCb);
304 GPSPositionSensorConnectCallback(&sensorUpdatedCb);
306 uint32_t stack_required = STACK_SIZE_BYTES;
307 // Initialize Filters
308 stack_required = maxint32_t(stack_required, filterMagInitialize(&magFilter));
309 stack_required = maxint32_t(stack_required, filterBaroiInitialize(&baroiFilter));
310 stack_required = maxint32_t(stack_required, filterBaroInitialize(&baroFilter));
311 stack_required = maxint32_t(stack_required, filterVelocityInitialize(&velocityFilter));
312 stack_required = maxint32_t(stack_required, filterAltitudeInitialize(&altitudeFilter));
313 stack_required = maxint32_t(stack_required, filterAirInitialize(&airFilter));
314 stack_required = maxint32_t(stack_required, filterStationaryInitialize(&stationaryFilter));
315 stack_required = maxint32_t(stack_required, filterLLAInitialize(&llaFilter));
316 stack_required = maxint32_t(stack_required, filterCFInitialize(&cfFilter));
317 stack_required = maxint32_t(stack_required, filterCFMInitialize(&cfmFilter));
318 stack_required = maxint32_t(stack_required, filterEKF13iInitialize(&ekf13iFilter));
319 stack_required = maxint32_t(stack_required, filterEKF13Initialize(&ekf13Filter));
321 stateEstimationCallback = PIOS_CALLBACKSCHEDULER_Create(&StateEstimationCb, CALLBACK_PRIORITY, TASK_PRIORITY, CALLBACKINFO_RUNNING_STATEESTIMATION, stack_required);
323 return 0;
327 * Start the task. Expects all objects to be initialized by this point.
328 * \returns 0 on success or -1 if initialisation failed
330 int32_t StateEstimationStart(void)
332 RevoSettingsConnectCallback(&settingsUpdatedCb);
334 // Force settings update to make sure rotation loaded
335 settingsUpdatedCb(NULL);
337 return 0;
340 MODULE_INITCALL(StateEstimationInitialize, StateEstimationStart);
344 * Module callback
346 static void StateEstimationCb(void)
348 static filterResult alarm = FILTERRESULT_OK;
349 static filterResult lastAlarm = FILTERRESULT_UNINITIALISED;
350 static uint16_t alarmcounter = 0;
351 static const filterPipeline *current;
352 static stateEstimation states;
353 static uint32_t last_time;
354 static uint16_t bootDelay = 64;
356 // after system startup, first few sensor readings might be messed up, delay until everything has settled
357 if (bootDelay) {
358 bootDelay--;
359 PIOS_CALLBACKSCHEDULER_Schedule(stateEstimationCallback, TIMEOUT_MS, CALLBACK_UPDATEMODE_SOONER);
360 return;
363 alarm = FILTERRESULT_OK;
365 // set alarm to warning if called through timeout
366 if (updatedSensors == 0) {
367 if (PIOS_DELAY_DiffuS(last_time) > 1000 * TIMEOUT_MS) {
368 alarm = FILTERRESULT_WARNING;
370 } else {
371 last_time = PIOS_DELAY_GetRaw();
374 // check if a new filter chain should be initialized
375 if (fusionAlgorithm != revoSettings.FusionAlgorithm) {
376 FlightStatusData fs;
377 FlightStatusGet(&fs);
378 if (fs.Armed == FLIGHTSTATUS_ARMED_DISARMED || fusionAlgorithm == FILTER_INIT_FORCE) {
379 const filterPipeline *newFilterChain;
380 switch ((RevoSettingsFusionAlgorithmOptions)revoSettings.FusionAlgorithm) {
381 case REVOSETTINGS_FUSIONALGORITHM_BASICCOMPLEMENTARY:
382 newFilterChain = cfQueue;
383 break;
384 case REVOSETTINGS_FUSIONALGORITHM_COMPLEMENTARYMAG:
385 newFilterChain = cfmiQueue;
386 break;
387 case REVOSETTINGS_FUSIONALGORITHM_COMPLEMENTARYMAGGPSOUTDOOR:
388 newFilterChain = cfmQueue;
389 break;
390 case REVOSETTINGS_FUSIONALGORITHM_INS13INDOOR:
391 newFilterChain = ekf13iQueue;
392 break;
393 case REVOSETTINGS_FUSIONALGORITHM_GPSNAVIGATIONINS13:
394 newFilterChain = ekf13Queue;
395 break;
396 default:
397 newFilterChain = NULL;
399 // initialize filters in chain
400 current = newFilterChain;
401 bool error = 0;
402 while (current != NULL) {
403 int32_t result = current->filter->init((stateFilter *)current->filter);
404 if (result != 0) {
405 error = 1;
406 break;
408 current = current->next;
410 if (error) {
411 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR);
412 return;
413 } else {
414 // set new fusion algortithm
415 filterChain = newFilterChain;
416 fusionAlgorithm = revoSettings.FusionAlgorithm;
421 // read updated sensor UAVObjects and set initial state
422 states.updated = updatedSensors;
423 updatedSensors = 0;
425 // fetch sensors, check values, and load into state struct
426 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(GyroSensor, gyro, x, y, z);
427 if (IS_SET(states.updated, SENSORUPDATES_gyro)) {
428 gyroRaw[0] = states.gyro[0];
429 gyroRaw[1] = states.gyro[1];
430 gyroRaw[2] = states.gyro[2];
432 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(AccelSensor, accel, x, y, z);
433 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(MagSensor, boardMag, x, y, z);
434 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(AuxMagSensor, auxMag, x, y, z);
435 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(GPSVelocitySensor, vel, North, East, Down);
436 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_1_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(BaroSensor, baro, Altitude, true);
437 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_2_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(AirspeedSensor, airspeed, CalibratedAirspeed, TrueAirspeed, s.SensorConnected == AIRSPEEDSENSOR_SENSORCONNECTED_TRUE);
439 // GPS position data (LLA) is not fetched here since it does not contain floats. The filter must do all checks itself
441 // at this point sensor state is stored in "states" with some rudimentary filtering applied
443 // apply all filters in the current filter chain
444 current = filterChain;
446 // we are not done, re-dispatch self execution
448 while (current) {
449 filterResult result = current->filter->filter((stateFilter *)current->filter, &states);
450 if (result > alarm) {
451 alarm = result;
453 current = current->next;
456 // the final output of filters is saved in state variables
457 // EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(GyroState, gyro, x, y, z) // replaced by performance shortcut
458 if (IS_SET(states.updated, SENSORUPDATES_gyro)) {
459 gyroDelta[0] = states.gyro[0] - gyroRaw[0];
460 gyroDelta[1] = states.gyro[1] - gyroRaw[1];
461 gyroDelta[2] = states.gyro[2] - gyroRaw[2];
463 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(AccelState, accel, x, y, z);
464 if (IS_SET(states.updated, SENSORUPDATES_mag)) {
465 MagStateData s;
467 MagStateGet(&s);
468 s.x = states.mag[0];
469 s.y = states.mag[1];
470 s.z = states.mag[2];
471 switch (states.magStatus) {
472 case MAGSTATUS_OK:
473 s.Source = MAGSTATE_SOURCE_ONBOARD;
474 break;
475 case MAGSTATUS_AUX:
476 s.Source = MAGSTATE_SOURCE_AUX;
477 break;
478 default:
479 s.Source = MAGSTATE_SOURCE_INVALID;
481 MagStateSet(&s);
484 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(PositionState, pos, North, East, Down);
485 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(VelocityState, vel, North, East, Down);
486 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_2_DIMENSIONS(AirspeedState, airspeed, CalibratedAirspeed, TrueAirspeed);
487 // attitude nees manual conversion from quaternion to euler
488 if (IS_SET(states.updated, SENSORUPDATES_attitude)) { \
489 AttitudeStateData s;
490 AttitudeStateGet(&s);
491 s.q1 = states.attitude[0];
492 s.q2 = states.attitude[1];
493 s.q3 = states.attitude[2];
494 s.q4 = states.attitude[3];
495 Quaternion2RPY(&s.q1, &s.Roll);
496 AttitudeStateSet(&s);
498 // throttle alarms, raise alarm flags immediately
499 // but require system to run for a while before decreasing
500 // to prevent alarm flapping
501 if (alarm >= lastAlarm) {
502 lastAlarm = alarm;
503 alarmcounter = 0;
504 } else {
505 if (alarmcounter < 100) {
506 alarmcounter++;
507 } else {
508 lastAlarm = alarm;
509 alarmcounter = 0;
513 // clear alarms if everything is alright, then schedule callback execution after timeout
514 if (lastAlarm == FILTERRESULT_WARNING) {
515 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_WARNING);
516 } else if (lastAlarm == FILTERRESULT_CRITICAL) {
517 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_CRITICAL);
518 } else if (lastAlarm >= FILTERRESULT_ERROR) {
519 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE, SYSTEMALARMS_ALARM_ERROR);
520 } else {
521 AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE);
524 if (updatedSensors) {
525 PIOS_CALLBACKSCHEDULER_Dispatch(stateEstimationCallback);
526 } else {
527 PIOS_CALLBACKSCHEDULER_Schedule(stateEstimationCallback, TIMEOUT_MS, CALLBACK_UPDATEMODE_SOONER);
533 * Callback for eventdispatcher when RevoSettings has been updated
535 static void settingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
537 RevoSettingsGet((RevoSettingsData *)&revoSettings);
541 * Callback for eventdispatcher when HomeLocation has been updated
543 static void homeLocationUpdatedCb(__attribute__((unused)) UAVObjEvent *ev)
545 // Ask for a filter init (necessary for LLA filter)
546 // Only possible if disarmed
547 fusionAlgorithm = FILTER_INIT_IF_POSSIBLE;
552 * Callback for eventdispatcher when any sensor UAVObject has been updated
553 * updates the list of "recently updated UAVObjects" and dispatches the state estimator callback
555 static void sensorUpdatedCb(UAVObjEvent *ev)
557 if (!ev) {
558 return;
561 if (ev->obj == GyroSensorHandle()) {
562 updatedSensors |= SENSORUPDATES_gyro;
563 // shortcut - update GyroState right away
564 GyroSensorData s;
565 GyroStateData t;
566 GyroSensorGet(&s);
567 t.x = s.x + gyroDelta[0];
568 t.y = s.y + gyroDelta[1];
569 t.z = s.z + gyroDelta[2];
570 GyroStateSet(&t);
573 if (ev->obj == AccelSensorHandle()) {
574 updatedSensors |= SENSORUPDATES_accel;
577 if (ev->obj == MagSensorHandle()) {
578 updatedSensors |= SENSORUPDATES_boardMag;
581 if (ev->obj == AuxMagSensorHandle()) {
582 updatedSensors |= SENSORUPDATES_auxMag;
585 if (ev->obj == GPSPositionSensorHandle()) {
586 updatedSensors |= SENSORUPDATES_lla;
589 if (ev->obj == GPSVelocitySensorHandle()) {
590 updatedSensors |= SENSORUPDATES_vel;
593 if (ev->obj == BaroSensorHandle()) {
594 updatedSensors |= SENSORUPDATES_baro;
597 if (ev->obj == AirspeedSensorHandle()) {
598 updatedSensors |= SENSORUPDATES_airspeed;
601 PIOS_CALLBACKSCHEDULER_Dispatch(stateEstimationCallback);
606 * @}
607 * @}