2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
5 * @addtogroup State Estimation
6 * @brief Acquires sensor data and computes state estimate
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
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>
45 #include <auxmagsettings.h>
47 #include <gyrostate.h>
48 #include <accelstate.h>
50 #include <airspeedstate.h>
51 #include <attitudestate.h>
52 #include <positionstate.h>
53 #include <velocitystate.h>
55 #include "revosettings.h"
56 #include "flightstatus.h"
58 #include "CoordinateConversions.h"
61 #define STACK_SIZE_BYTES 256
62 #define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR
63 #define TASK_PRIORITY CALLBACK_TASK_FLIGHTCONTROL
66 // Private filter init const
67 #define FILTER_INIT_FORCE -1
68 #define FILTER_INIT_IF_POSSIBLE -2
70 // local macros, ONLY to be used in the middle of StateEstimationCb in section RUNSTATE_LOAD after the update of states updated!
71 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(sensorname, shortname, a1, a2, a3) \
72 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
74 sensorname##Get(&s); \
75 if (IS_REAL(s.a1) && IS_REAL(s.a2) && IS_REAL(s.a3)) { \
76 states.shortname[0] = s.a1; \
77 states.shortname[1] = s.a2; \
78 states.shortname[2] = s.a3; \
81 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
85 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_1_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(sensorname, shortname, a1, EXTRACHECK) \
86 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
88 sensorname##Get(&s); \
89 if (IS_REAL(s.a1) && EXTRACHECK) { \
90 states.shortname[0] = s.a1; \
93 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
97 #define FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_2_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(sensorname, shortname, a1, a2, EXTRACHECK) \
98 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
100 sensorname##Get(&s); \
101 if (IS_REAL(s.a1) && IS_REAL(s.a2) && EXTRACHECK) { \
102 states.shortname[0] = s.a1; \
103 states.shortname[1] = s.a2; \
106 UNSET_MASK(states.updated, SENSORUPDATES_##shortname); \
110 // local macros, ONLY to be used in the middle of StateEstimationCb in section RUNSTATE_SAVE before the check of alarms!
111 #define EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(statename, shortname, a1, a2, a3) \
112 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
114 statename##Get(&s); \
115 s.a1 = states.shortname[0]; \
116 s.a2 = states.shortname[1]; \
117 s.a3 = states.shortname[2]; \
118 statename##Set(&s); \
121 #define EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_2_DIMENSIONS(statename, shortname, a1, a2) \
122 if (IS_SET(states.updated, SENSORUPDATES_##shortname)) { \
124 statename##Get(&s); \
125 s.a1 = states.shortname[0]; \
126 s.a2 = states.shortname[1]; \
127 statename##Set(&s); \
132 struct filterPipelineStruct
;
134 typedef const struct filterPipelineStruct
{
135 const stateFilter
*filter
;
136 const struct filterPipelineStruct
*next
;
140 static DelayedCallbackInfo
*stateEstimationCallback
;
142 static volatile RevoSettingsData revoSettings
;
143 static volatile sensorUpdates updatedSensors
;
144 static volatile int32_t fusionAlgorithm
= -1;
145 static const filterPipeline
*filterChain
= NULL
;
147 // different filters available to state estimation
148 static stateFilter magFilter
;
149 static stateFilter baroFilter
;
150 static stateFilter baroiFilter
;
151 static stateFilter velocityFilter
;
152 static stateFilter altitudeFilter
;
153 static stateFilter airFilter
;
154 static stateFilter stationaryFilter
;
155 static stateFilter llaFilter
;
156 static stateFilter cfFilter
;
157 static stateFilter cfmFilter
;
158 static stateFilter ekf13iFilter
;
159 static stateFilter ekf13Filter
;
160 static stateFilter ekf13iNavFilter
;
161 static stateFilter ekf13NavFilter
;
163 // this is a hack to provide a computational shortcut for faster gyro state progression
164 static float gyroRaw
[3];
165 static float gyroDelta
[3];
167 // preconfigured filter chains selectable via revoSettings.FusionAlgorithm
168 static const filterPipeline
*cfQueue
= &(filterPipeline
) {
169 .filter
= &airFilter
,
170 .next
= &(filterPipeline
) {
171 .filter
= &baroiFilter
,
172 .next
= &(filterPipeline
) {
173 .filter
= &altitudeFilter
,
174 .next
= &(filterPipeline
) {
181 static const filterPipeline
*cfmiQueue
= &(filterPipeline
) {
182 .filter
= &magFilter
,
183 .next
= &(filterPipeline
) {
184 .filter
= &airFilter
,
185 .next
= &(filterPipeline
) {
186 .filter
= &baroiFilter
,
187 .next
= &(filterPipeline
) {
188 .filter
= &altitudeFilter
,
189 .next
= &(filterPipeline
) {
190 .filter
= &cfmFilter
,
197 static const filterPipeline
*cfmQueue
= &(filterPipeline
) {
198 .filter
= &magFilter
,
199 .next
= &(filterPipeline
) {
200 .filter
= &airFilter
,
201 .next
= &(filterPipeline
) {
202 .filter
= &llaFilter
,
203 .next
= &(filterPipeline
) {
204 .filter
= &baroFilter
,
205 .next
= &(filterPipeline
) {
206 .filter
= &altitudeFilter
,
207 .next
= &(filterPipeline
) {
208 .filter
= &cfmFilter
,
216 static const filterPipeline
*ekf13iQueue
= &(filterPipeline
) {
217 .filter
= &magFilter
,
218 .next
= &(filterPipeline
) {
219 .filter
= &airFilter
,
220 .next
= &(filterPipeline
) {
221 .filter
= &baroiFilter
,
222 .next
= &(filterPipeline
) {
223 .filter
= &stationaryFilter
,
224 .next
= &(filterPipeline
) {
225 .filter
= &ekf13iFilter
,
226 .next
= &(filterPipeline
) {
227 .filter
= &velocityFilter
,
236 static const filterPipeline
*ekf13Queue
= &(filterPipeline
) {
237 .filter
= &magFilter
,
238 .next
= &(filterPipeline
) {
239 .filter
= &airFilter
,
240 .next
= &(filterPipeline
) {
241 .filter
= &llaFilter
,
242 .next
= &(filterPipeline
) {
243 .filter
= &baroFilter
,
244 .next
= &(filterPipeline
) {
245 .filter
= &ekf13Filter
,
246 .next
= &(filterPipeline
) {
247 .filter
= &velocityFilter
,
256 static const filterPipeline
*ekf13NavCFAttQueue
= &(filterPipeline
) {
257 .filter
= &magFilter
,
258 .next
= &(filterPipeline
) {
259 .filter
= &airFilter
,
260 .next
= &(filterPipeline
) {
261 .filter
= &llaFilter
,
262 .next
= &(filterPipeline
) {
263 .filter
= &baroFilter
,
264 .next
= &(filterPipeline
) {
265 .filter
= &ekf13NavFilter
,
266 .next
= &(filterPipeline
) {
267 .filter
= &velocityFilter
,
268 .next
= &(filterPipeline
) {
269 .filter
= &cfmFilter
,
279 static const filterPipeline
*ekf13iNavCFAttQueue
= &(filterPipeline
) {
280 .filter
= &magFilter
,
281 .next
= &(filterPipeline
) {
282 .filter
= &airFilter
,
283 .next
= &(filterPipeline
) {
284 .filter
= &baroiFilter
,
285 .next
= &(filterPipeline
) {
286 .filter
= &stationaryFilter
,
287 .next
= &(filterPipeline
) {
288 .filter
= &ekf13iNavFilter
,
289 .next
= &(filterPipeline
) {
290 .filter
= &velocityFilter
,
291 .next
= &(filterPipeline
) {
292 .filter
= &cfmFilter
,
304 static void settingsUpdatedCb(UAVObjEvent
*objEv
);
305 static void sensorUpdatedCb(UAVObjEvent
*objEv
);
306 static void criticalConfigUpdatedCb(UAVObjEvent
*objEv
);
307 static void StateEstimationCb(void);
309 static inline int32_t maxint32_t(int32_t a
, int32_t b
)
318 * Initialise the module. Called before the start function
319 * \returns 0 on success or -1 if initialisation failed
321 int32_t StateEstimationInitialize(void)
323 RevoSettingsInitialize();
325 GyroSensorInitialize();
326 MagSensorInitialize();
327 AuxMagSensorInitialize();
328 BaroSensorInitialize();
329 AirspeedSensorInitialize();
330 GPSVelocitySensorInitialize();
331 GPSPositionSensorInitialize();
333 HomeLocationInitialize();
335 GyroStateInitialize();
336 AccelStateInitialize();
337 MagStateInitialize();
338 AirspeedStateInitialize();
339 PositionStateInitialize();
340 VelocityStateInitialize();
341 AuxMagSettingsInitialize();
343 RevoSettingsConnectCallback(&settingsUpdatedCb
);
345 HomeLocationConnectCallback(&criticalConfigUpdatedCb
);
346 AuxMagSettingsConnectCallback(&criticalConfigUpdatedCb
);
348 GyroSensorConnectCallback(&sensorUpdatedCb
);
349 AccelSensorConnectCallback(&sensorUpdatedCb
);
350 MagSensorConnectCallback(&sensorUpdatedCb
);
351 BaroSensorConnectCallback(&sensorUpdatedCb
);
352 AirspeedSensorConnectCallback(&sensorUpdatedCb
);
353 AuxMagSensorConnectCallback(&sensorUpdatedCb
);
354 GPSVelocitySensorConnectCallback(&sensorUpdatedCb
);
355 GPSPositionSensorConnectCallback(&sensorUpdatedCb
);
357 uint32_t stack_required
= STACK_SIZE_BYTES
;
358 // Initialize Filters
359 stack_required
= maxint32_t(stack_required
, filterMagInitialize(&magFilter
));
360 stack_required
= maxint32_t(stack_required
, filterBaroiInitialize(&baroiFilter
));
361 stack_required
= maxint32_t(stack_required
, filterBaroInitialize(&baroFilter
));
362 stack_required
= maxint32_t(stack_required
, filterVelocityInitialize(&velocityFilter
));
363 stack_required
= maxint32_t(stack_required
, filterAltitudeInitialize(&altitudeFilter
));
364 stack_required
= maxint32_t(stack_required
, filterAirInitialize(&airFilter
));
365 stack_required
= maxint32_t(stack_required
, filterStationaryInitialize(&stationaryFilter
));
366 stack_required
= maxint32_t(stack_required
, filterLLAInitialize(&llaFilter
));
367 stack_required
= maxint32_t(stack_required
, filterCFInitialize(&cfFilter
));
368 stack_required
= maxint32_t(stack_required
, filterCFMInitialize(&cfmFilter
));
369 stack_required
= maxint32_t(stack_required
, filterEKF13iInitialize(&ekf13iFilter
));
370 stack_required
= maxint32_t(stack_required
, filterEKF13Initialize(&ekf13Filter
));
371 stack_required
= maxint32_t(stack_required
, filterEKF13NavOnlyInitialize(&ekf13NavFilter
));
372 stack_required
= maxint32_t(stack_required
, filterEKF13iNavOnlyInitialize(&ekf13iNavFilter
));
374 stateEstimationCallback
= PIOS_CALLBACKSCHEDULER_Create(&StateEstimationCb
, CALLBACK_PRIORITY
, TASK_PRIORITY
, CALLBACKINFO_RUNNING_STATEESTIMATION
, stack_required
);
380 * Start the task. Expects all objects to be initialized by this point.
381 * \returns 0 on success or -1 if initialisation failed
383 int32_t StateEstimationStart(void)
385 RevoSettingsConnectCallback(&settingsUpdatedCb
);
387 // Force settings update to make sure rotation loaded
388 settingsUpdatedCb(NULL
);
393 MODULE_INITCALL(StateEstimationInitialize
, StateEstimationStart
);
399 static void StateEstimationCb(void)
401 static filterResult alarm
= FILTERRESULT_OK
;
402 static filterResult lastAlarm
= FILTERRESULT_UNINITIALISED
;
403 static bool lastNavStatus
= false;
404 static uint16_t alarmcounter
= 0;
405 static uint16_t navstatuscounter
= 0;
406 static const filterPipeline
*current
;
407 static stateEstimation states
;
408 static uint32_t last_time
;
409 static uint16_t bootDelay
= 64;
411 // after system startup, first few sensor readings might be messed up, delay until everything has settled
414 PIOS_CALLBACKSCHEDULER_Schedule(stateEstimationCallback
, TIMEOUT_MS
, CALLBACK_UPDATEMODE_SOONER
);
418 alarm
= FILTERRESULT_OK
;
420 // set alarm to warning if called through timeout
421 if (updatedSensors
== 0) {
422 if (PIOS_DELAY_DiffuS(last_time
) > 1000 * TIMEOUT_MS
) {
423 alarm
= FILTERRESULT_WARNING
;
426 last_time
= PIOS_DELAY_GetRaw();
428 FlightStatusArmedOptions fsarmed
;
429 FlightStatusArmedGet(&fsarmed
);
430 states
.armed
= fsarmed
!= FLIGHTSTATUS_ARMED_DISARMED
;
432 // check if a new filter chain should be initialized
433 if (fusionAlgorithm
!= revoSettings
.FusionAlgorithm
) {
434 if (fsarmed
== FLIGHTSTATUS_ARMED_DISARMED
|| fusionAlgorithm
== FILTER_INIT_FORCE
) {
435 const filterPipeline
*newFilterChain
;
436 switch ((RevoSettingsFusionAlgorithmOptions
)revoSettings
.FusionAlgorithm
) {
437 case REVOSETTINGS_FUSIONALGORITHM_BASICCOMPLEMENTARY
:
438 newFilterChain
= cfQueue
;
440 AlarmsSet(SYSTEMALARMS_ALARM_MAGNETOMETER
, SYSTEMALARMS_ALARM_UNINITIALISED
);
442 case REVOSETTINGS_FUSIONALGORITHM_COMPLEMENTARYMAG
:
443 newFilterChain
= cfmiQueue
;
445 case REVOSETTINGS_FUSIONALGORITHM_COMPLEMENTARYMAGGPSOUTDOOR
:
446 newFilterChain
= cfmQueue
;
448 case REVOSETTINGS_FUSIONALGORITHM_INS13INDOOR
:
449 newFilterChain
= ekf13iQueue
;
451 case REVOSETTINGS_FUSIONALGORITHM_GPSNAVIGATIONINS13
:
452 newFilterChain
= ekf13Queue
;
454 case REVOSETTINGS_FUSIONALGORITHM_GPSNAVIGATIONINS13CF
:
455 newFilterChain
= ekf13NavCFAttQueue
;
457 case REVOSETTINGS_FUSIONALGORITHM_TESTINGINSINDOORCF
:
458 newFilterChain
= ekf13iNavCFAttQueue
;
461 newFilterChain
= NULL
;
463 // initialize filters in chain
464 current
= newFilterChain
;
466 states
.debugNavYaw
= 0;
467 states
.navOk
= false;
468 states
.navUsed
= false;
469 while (current
!= NULL
) {
470 int32_t result
= current
->filter
->init((stateFilter
*)current
->filter
);
475 current
= current
->next
;
478 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE
, SYSTEMALARMS_ALARM_ERROR
);
481 // set new fusion algorithm
482 filterChain
= newFilterChain
;
483 fusionAlgorithm
= revoSettings
.FusionAlgorithm
;
488 // read updated sensor UAVObjects and set initial state
489 states
.updated
= updatedSensors
;
492 // fetch sensors, check values, and load into state struct
493 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(GyroSensor
, gyro
, x
, y
, z
);
494 if (IS_SET(states
.updated
, SENSORUPDATES_gyro
)) {
495 gyroRaw
[0] = states
.gyro
[0];
496 gyroRaw
[1] = states
.gyro
[1];
497 gyroRaw
[2] = states
.gyro
[2];
499 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(AccelSensor
, accel
, x
, y
, z
);
500 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(MagSensor
, boardMag
, x
, y
, z
);
501 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(AuxMagSensor
, auxMag
, x
, y
, z
);
502 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_3_DIMENSIONS(GPSVelocitySensor
, vel
, North
, East
, Down
);
503 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_1_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(BaroSensor
, baro
, Altitude
, true);
504 FETCH_SENSOR_FROM_UAVOBJECT_CHECK_AND_LOAD_TO_STATE_2_DIMENSION_WITH_CUSTOM_EXTRA_CHECK(AirspeedSensor
, airspeed
, CalibratedAirspeed
, TrueAirspeed
, s
.SensorConnected
== AIRSPEEDSENSOR_SENSORCONNECTED_TRUE
);
506 // GPS position data (LLA) is not fetched here since it does not contain floats. The filter must do all checks itself
508 // at this point sensor state is stored in "states" with some rudimentary filtering applied
510 // apply all filters in the current filter chain
511 current
= filterChain
;
513 // we are not done, re-dispatch self execution
516 filterResult result
= current
->filter
->filter((stateFilter
*)current
->filter
, &states
);
517 if (result
> alarm
) {
520 current
= current
->next
;
523 // the final output of filters is saved in state variables
524 // EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(GyroState, gyro, x, y, z) // replaced by performance shortcut
525 if (IS_SET(states
.updated
, SENSORUPDATES_gyro
)) {
526 gyroDelta
[0] = states
.gyro
[0] - gyroRaw
[0];
527 gyroDelta
[1] = states
.gyro
[1] - gyroRaw
[1];
528 gyroDelta
[2] = states
.gyro
[2] - gyroRaw
[2];
530 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(AccelState
, accel
, x
, y
, z
);
531 if (IS_SET(states
.updated
, SENSORUPDATES_mag
)) {
538 switch (states
.magStatus
) {
540 s
.Source
= MAGSTATE_SOURCE_ONBOARD
;
543 s
.Source
= MAGSTATE_SOURCE_AUX
;
546 s
.Source
= MAGSTATE_SOURCE_INVALID
;
551 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(PositionState
, pos
, North
, East
, Down
);
552 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_3_DIMENSIONS(VelocityState
, vel
, North
, East
, Down
);
553 EXPORT_STATE_TO_UAVOBJECT_IF_UPDATED_2_DIMENSIONS(AirspeedState
, airspeed
, CalibratedAirspeed
, TrueAirspeed
);
554 // attitude nees manual conversion from quaternion to euler
555 if (IS_SET(states
.updated
, SENSORUPDATES_attitude
)) { \
557 AttitudeStateGet(&s
);
558 s
.q1
= states
.attitude
[0];
559 s
.q2
= states
.attitude
[1];
560 s
.q3
= states
.attitude
[2];
561 s
.q4
= states
.attitude
[3];
562 Quaternion2RPY(&s
.q1
, &s
.Roll
);
563 s
.NavYaw
= states
.debugNavYaw
;
564 AttitudeStateSet(&s
);
566 // throttle alarms, raise alarm flags immediately
567 // but require system to run for a while before decreasing
568 // to prevent alarm flapping
569 if (alarm
>= lastAlarm
) {
573 if (alarmcounter
< 100) {
581 if (lastNavStatus
< states
.navOk
) {
582 lastNavStatus
= states
.navOk
;
583 navstatuscounter
= 0;
585 if (navstatuscounter
< 100) {
588 lastNavStatus
= states
.navOk
;
589 navstatuscounter
= 0;
593 // clear alarms if everything is alright, then schedule callback execution after timeout
594 if (lastAlarm
== FILTERRESULT_WARNING
) {
595 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE
, SYSTEMALARMS_ALARM_WARNING
);
596 } else if (lastAlarm
== FILTERRESULT_CRITICAL
) {
597 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE
, SYSTEMALARMS_ALARM_CRITICAL
);
598 } else if (lastAlarm
>= FILTERRESULT_ERROR
) {
599 AlarmsSet(SYSTEMALARMS_ALARM_ATTITUDE
, SYSTEMALARMS_ALARM_ERROR
);
601 AlarmsClear(SYSTEMALARMS_ALARM_ATTITUDE
);
604 if (!states
.navUsed
) {
605 AlarmsSet(SYSTEMALARMS_ALARM_NAV
, SYSTEMALARMS_ALARM_UNINITIALISED
);
608 AlarmsClear(SYSTEMALARMS_ALARM_NAV
);
610 AlarmsSet(SYSTEMALARMS_ALARM_NAV
, SYSTEMALARMS_ALARM_CRITICAL
);
614 if (updatedSensors
) {
615 PIOS_CALLBACKSCHEDULER_Dispatch(stateEstimationCallback
);
617 PIOS_CALLBACKSCHEDULER_Schedule(stateEstimationCallback
, TIMEOUT_MS
, CALLBACK_UPDATEMODE_SOONER
);
623 * Callback for eventdispatcher when RevoSettings has been updated
625 static void settingsUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
627 RevoSettingsGet((RevoSettingsData
*)&revoSettings
);
631 * Callback for eventdispatcher when HomeLocation or other critical configs (auxmagsettings, ...) has been updated
633 static void criticalConfigUpdatedCb(__attribute__((unused
)) UAVObjEvent
*ev
)
635 // Ask for a filter init (necessary for LLA filter)
636 // Only possible if disarmed
637 fusionAlgorithm
= FILTER_INIT_IF_POSSIBLE
;
642 * Callback for eventdispatcher when any sensor UAVObject has been updated
643 * updates the list of "recently updated UAVObjects" and dispatches the state estimator callback
645 static void sensorUpdatedCb(UAVObjEvent
*ev
)
651 if (ev
->obj
== GyroSensorHandle()) {
652 updatedSensors
|= SENSORUPDATES_gyro
;
653 // shortcut - update GyroState right away
657 t
.x
= s
.x
+ gyroDelta
[0];
658 t
.y
= s
.y
+ gyroDelta
[1];
659 t
.z
= s
.z
+ gyroDelta
[2];
660 t
.SensorReadTimestamp
= s
.SensorReadTimestamp
;
664 if (ev
->obj
== AccelSensorHandle()) {
665 updatedSensors
|= SENSORUPDATES_accel
;
668 if (ev
->obj
== MagSensorHandle()) {
669 updatedSensors
|= SENSORUPDATES_boardMag
;
672 if (ev
->obj
== AuxMagSensorHandle()) {
673 updatedSensors
|= SENSORUPDATES_auxMag
;
676 if (ev
->obj
== GPSPositionSensorHandle()) {
677 updatedSensors
|= SENSORUPDATES_lla
;
680 if (ev
->obj
== GPSVelocitySensorHandle()) {
681 updatedSensors
|= SENSORUPDATES_vel
;
684 if (ev
->obj
== BaroSensorHandle()) {
685 updatedSensors
|= SENSORUPDATES_baro
;
688 if (ev
->obj
== AirspeedSensorHandle()) {
689 updatedSensors
|= SENSORUPDATES_airspeed
;
692 PIOS_CALLBACKSCHEDULER_Dispatch(stateEstimationCallback
);