PX4 Firmware
PX4 Autopilot Software http://px4.io
control.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015 Estimation and Control Library (ECL). All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name ECL nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file control.cpp
36  * Control functions for ekf attitude and position estimator.
37  *
38  * @author Paul Riseborough <p_riseborough@live.com.au>
39  *
40  */
41 
42 #include "../ecl.h"
43 #include "ekf.h"
44 #include <mathlib/mathlib.h>
45 
47 {
48  // Store the status to enable change detection
50 
51  // monitor the tilt alignment
53  // whilst we are aligning the tilt, monitor the variances
54  Vector3f angle_err_var_vec = calcRotVecVariances();
55 
56  // Once the tilt variances have reduced to equivalent of 3deg uncertainty, re-set the yaw and magnetic field states
57  // and declare the tilt alignment complete
58  if ((angle_err_var_vec(0) + angle_err_var_vec(1)) < sq(math::radians(3.0f))) {
61 
62  // send alignment status message to the console
64  ECL_INFO("EKF aligned, (pressure height, IMU buf: %i, OBS buf: %i)", (int)_imu_buffer_length, (int)_obs_buffer_length);
65 
66  } else if (_control_status.flags.ev_hgt) {
67  ECL_INFO("EKF aligned, (EV height, IMU buf: %i, OBS buf: %i)", (int)_imu_buffer_length, (int)_obs_buffer_length);
68 
69  } else if (_control_status.flags.gps_hgt) {
70  ECL_INFO("EKF aligned, (GPS height, IMU buf: %i, OBS buf: %i)", (int)_imu_buffer_length, (int)_obs_buffer_length);
71 
72  } else if (_control_status.flags.rng_hgt) {
73  ECL_INFO("EKF aligned, (range height, IMU buf: %i, OBS buf: %i)", (int)_imu_buffer_length, (int)_obs_buffer_length);
74  } else {
75  ECL_ERR("EKF aligned, (unknown height, IMU buf: %i, OBS buf: %i)", (int)_imu_buffer_length, (int)_obs_buffer_length);
76  }
77 
78  }
79 
80  }
81 
82  // check for intermittent data (before pop_first_older_than)
83  const baroSample &baro_init = _baro_buffer.get_newest();
85 
86  const gpsSample &gps_init = _gps_buffer.get_newest();
88 
89  // check for arrival of new sensor data at the fusion time horizon
92 
93  if (_mag_data_ready) {
94  // if enabled, use knowledge of theoretical magnetic field vector to calculate a synthetic magnetomter Z component value.
95  // this is useful if there is a lot of interference on the sensor measurement.
100  } else {
102  }
103  }
104 
107 
108  // if we have a new baro sample save the delta time between this sample and the last sample which is
109  // used below for baro offset calculations
110  if (_baro_data_ready) {
112  }
113 
114  // calculate 2,2 element of rotation matrix from sensor frame to earth frame
115  // this is required for use of range finder and flow data
117 
118  // Get range data from buffer and check validity
120 
122 
124  // correct the range data for position offset relative to the IMU
125  Vector3f pos_offset_body = _params.rng_pos_body - _params.imu_pos_body;
126  Vector3f pos_offset_earth = _R_to_earth * pos_offset_body;
127  _range_sample_delayed.rng += pos_offset_earth(2) / _R_rng_to_earth_2_2;
128  }
129 
130  // We don't fuse flow data immediately because we have to wait for the mid integration point to fall behind the fusion time horizon.
131  // This means we stop looking for new data until the old data has been fused.
132  if (!_flow_data_ready) {
135  }
136 
137  // check if we should fuse flow data for terrain estimation
139  // only fuse flow for terrain if range data hasn't been fused for 5 seconds
141  // only fuse flow for terrain if the main filter is not fusing flow and we are using gps
143  }
144 
147 
148  // check for height sensor timeouts and reset and change sensor if necessary
150 
151  // control use of observations for aiding
159 
160  // For efficiency, fusion of direct state observations for position and velocity is performed sequentially
161  // in a single function using sensor data from multiple sources (GPS, baro, range finder, etc)
163 
164  // Additional data from an external vision pose estimator can be fused.
166 
167  // Additional NE velocity data from an auxiliary sensor can be fused
169 
170  // check if we are no longer fusing measurements that directly constrain velocity drift
172 }
173 
175 {
176  // Check for new external vision data
177  if (_ev_data_ready) {
178 
179  // if the ev data is not in a NED reference frame, then the transformation between EV and EKF navigation frames
180  // needs to be calculated and the observations rotated into the EKF frame of reference
182  // rotate EV measurements into the EKF Navigation frame
184  }
185 
186  // external vision aiding selection logic
188 
189  // check for a external vision measurement that has fallen behind the fusion time horizon
191  // turn on use of external vision measurements for position
194  resetPosition();
195  ECL_INFO_TIMESTAMPED("EKF commencing external vision position fusion");
196  }
197 
198  // turn on use of external vision measurements for velocity
201  resetVelocity();
202  ECL_INFO_TIMESTAMPED("EKF commencing external vision velocity fusion");
203  }
204 
207  // Reset transformation between EV and EKF navigation frames when starting fusion
210  ECL_INFO_TIMESTAMPED("EKF external vision aligned");
211  }
212  }
213  }
214 
215  // external vision yaw aiding selection logic
217  // don't start using EV data unless daa is arriving frequently
219  // reset the yaw angle to the value from the observation quaternion
220  // get the roll, pitch, yaw estimates from the quaternion states
221  Quatf q_init(_state.quat_nominal);
222  Eulerf euler_init(q_init);
223 
224  // get initial yaw from the observation quaternion
225  const extVisionSample &ev_newest = _ext_vision_buffer.get_newest();
226  Quatf q_obs(ev_newest.quat);
227  Eulerf euler_obs(q_obs);
228  euler_init(2) = euler_obs(2);
229 
230  // save a copy of the quaternion state for later use in calculating the amount of reset change
231  Quatf quat_before_reset = _state.quat_nominal;
232 
233  // calculate initial quaternion states for the ekf
234  _state.quat_nominal = Quatf(euler_init);
236 
237  // adjust the quaternion covariances estimated yaw error
239 
240  // calculate the amount that the quaternion has changed by
241  _state_reset_status.quat_change = _state.quat_nominal * quat_before_reset.inversed();
242 
243  // add the reset amount to the output observer buffered data
244  for (uint8_t i = 0; i < _output_buffer.get_length(); i++) {
245  _output_buffer[i].quat_nominal = _state_reset_status.quat_change * _output_buffer[i].quat_nominal;
246  }
247 
248  // apply the change in attitude quaternion to our newest quaternion estimate
249  // which was already taken out from the output buffer
251 
252  // capture the reset event
253  _state_reset_status.quat_counter++;
254 
255  // flag the yaw as aligned
257 
258  // turn on fusion of external vision yaw measurements and disable all magnetometer fusion
260  _control_status.flags.mag_dec = false;
261 
263  stopMag3DFusion();
264 
265  ECL_INFO_TIMESTAMPED("EKF commencing external vision yaw fusion");
266  }
267  }
268 
269  // determine if we should start using the height observations
271  // don't start using EV data unless data is arriving frequently
274  resetHeight();
275  }
276  }
277 
278  // determine if we should use the vertical position observation
280  _fuse_height = true;
281  }
282 
283  // determine if we should use the horizontal position observations
285  _fuse_pos = true;
286 
287  // correct position and height for offset relative to IMU
288  Vector3f pos_offset_body = _params.ev_pos_body - _params.imu_pos_body;
289  Vector3f pos_offset_earth = _R_to_earth * pos_offset_body;
290  _ev_sample_delayed.pos(0) -= pos_offset_earth(0);
291  _ev_sample_delayed.pos(1) -= pos_offset_earth(1);
292  _ev_sample_delayed.pos(2) -= pos_offset_earth(2);
293 
294  // Use an incremental position fusion method for EV position data if GPS is also used
296  _fuse_hpos_as_odom = true;
297  } else {
298  _fuse_hpos_as_odom = false;
299  }
300 
301  if (_fuse_hpos_as_odom) {
302  if (!_hpos_prev_available) {
303  // no previous observation available to calculate position change
304  _fuse_pos = false;
305  _hpos_prev_available = true;
306 
307  } else {
308  // calculate the change in position since the last measurement
310 
311  // rotate measurement into body frame is required when fusing with GPS
312  ev_delta_pos = _ev_rot_mat * ev_delta_pos;
313 
314  // use the change in position since the last measurement
315  _vel_pos_innov[3] = _state.pos(0) - _hpos_pred_prev(0) - ev_delta_pos(0);
316  _vel_pos_innov[4] = _state.pos(1) - _hpos_pred_prev(1) - ev_delta_pos(1);
317 
318  // observation 1-STD error, incremental pos observation is expected to have more uncertainty
320  }
321 
322  // record observation and estimate for use next time
324  _hpos_pred_prev(0) = _state.pos(0);
325  _hpos_pred_prev(1) = _state.pos(1);
326 
327  } else {
328  // use the absolute position
329  Vector3f ev_pos_meas = _ev_sample_delayed.pos;
331  ev_pos_meas = _ev_rot_mat * ev_pos_meas;
332  }
333  _vel_pos_innov[3] = _state.pos(0) - ev_pos_meas(0);
334  _vel_pos_innov[4] = _state.pos(1) - ev_pos_meas(1);
335  // observation 1-STD error
336  _posObsNoiseNE = fmaxf(_ev_sample_delayed.posErr, 0.01f);
337 
338  // check if we have been deadreckoning too long
340  // don't reset velocity if we have another source of aiding constraining it
341  if (((_time_last_imu - _time_last_of_fuse) > (uint64_t)1E6) && ((_time_last_imu - _time_last_vel_fuse) > (uint64_t)1E6)) {
342  resetVelocity();
343  }
344 
345  resetPosition();
346  }
347  }
348 
349  // innovation gate size
351  }else{
352  _vel_pos_innov[3] = 0.0f;
353  _vel_pos_innov[4] = 0.0f;
354  }
355 
356  // determine if we should use the velocity observations
358  _fuse_hor_vel = true;
359  _fuse_vert_vel = true;
360 
361  Vector3f vel_aligned{_ev_sample_delayed.vel};
362 
363  // rotate measurement into correct earth frame if required
365  vel_aligned = _ev_rot_mat * _ev_sample_delayed.vel;
366  }
367 
368  // correct velocity for offset relative to IMU
370  Vector3f pos_offset_body = _params.ev_pos_body - _params.imu_pos_body;
371  Vector3f vel_offset_body = cross_product(ang_rate, pos_offset_body);
372  Vector3f vel_offset_earth = _R_to_earth * vel_offset_body;
373  vel_aligned -= vel_offset_earth;
374 
375  _vel_pos_innov[0] = _state.vel(0) - vel_aligned(0);
376  _vel_pos_innov[1] = _state.vel(1) - vel_aligned(1);
377  _vel_pos_innov[2] = _state.vel(2) - vel_aligned(2);
378 
379  // check if we have been deadreckoning too long
381  // don't reset velocity if we have another source of aiding constraining it
382  if (((_time_last_imu - _time_last_of_fuse) > (uint64_t)1E6) && ((_time_last_imu - _time_last_pos_fuse) > (uint64_t)1E6)) {
383  resetVelocity();
384  }
385  }
386 
387  // observation 1-STD error
389 
390  // innovation gate size
392  }
393 
394  // Fuse available NED position data into the main filter
397  _fuse_vert_vel = _fuse_hor_vel = false;
398  _fuse_pos = _fuse_height = false;
399  _fuse_hpos_as_odom = false;
400 
401  }
402 
403  // determine if we should use the yaw observation
405  fuseHeading();
406 
407  }
408 
412 
413  // Turn off EV fusion mode if no data has been received
414  _control_status.flags.ev_pos = false;
415  _control_status.flags.ev_vel = false;
416  _control_status.flags.ev_yaw = false;
417  ECL_INFO_TIMESTAMPED("EKF External Vision Data Stopped");
418 
419  }
420 }
421 
423 {
424  // Check if on ground motion is un-suitable for use of optical flow
426  // When on ground check if the vehicle is being shaken or moved in a way that could cause a loss of navigation
427  const float accel_norm = _accel_vec_filt.norm();
428 
429  const bool motion_is_excessive = ((accel_norm > (CONSTANTS_ONE_G * 1.5f)) // upper g limit
430  || (accel_norm < (CONSTANTS_ONE_G * 0.5f)) // lower g limit
431  || (_ang_rate_mag_filt > _flow_max_rate) // angular rate exceeds flow sensor limit
432  || (_R_to_earth(2,2) < cosf(math::radians(30.0f)))); // tilted excessively
433 
434  if (motion_is_excessive) {
436 
437  } else {
439  }
440 
441  } else {
444  }
445 
446  // Accumulate autopilot gyro data across the same time interval as the flow sensor
449 
450  // New optical flow data is available and is ready to be fused when the midpoint of the sample falls behind the fusion time horizon
451  if (_flow_data_ready) {
452  // Inhibit flow use if motion is un-suitable or we have good quality GPS
453  // Apply hysteresis to prevent rapid mode switching
454  float gps_err_norm_lim;
456  gps_err_norm_lim = 0.7f;
457  } else {
458  gps_err_norm_lim = 1.0f;
459  }
460 
461  // Check if we are in-air and require optical flow to control position drift
462  bool flow_required = _control_status.flags.in_air &&
463  (_is_dead_reckoning // is doing inertial dead-reckoning so must constrain drift urgently
464  || (_control_status.flags.opt_flow && !_control_status.flags.gps && !_control_status.flags.ev_pos && !_control_status.flags.ev_vel) // is completely reliant on optical flow
465  || (_control_status.flags.gps && (_gps_error_norm > gps_err_norm_lim))); // is using GPS, but GPS is bad
466 
468  // inhibit use of optical flow if motion is unsuitable and we are not reliant on it for flight navigation
469  bool preflight_motion_not_ok = !_control_status.flags.in_air && ((_imu_sample_delayed.time_us - _time_good_motion_us) > (uint64_t)1E5);
470  bool flight_motion_not_ok = _control_status.flags.in_air && !isRangeAidSuitable();
471  if ((preflight_motion_not_ok || flight_motion_not_ok) && !flow_required) {
472  _inhibit_flow_use = true;
473  }
475  // allow use of optical flow if motion is suitable or we are reliant on it for flight navigation
476  bool preflight_motion_ok = !_control_status.flags.in_air && ((_imu_sample_delayed.time_us - _time_bad_motion_us) > (uint64_t)5E6);
477  bool flight_motion_ok = _control_status.flags.in_air && isRangeAidSuitable();
478  if (preflight_motion_ok || flight_motion_ok || flow_required) {
479  _inhibit_flow_use = false;
480  }
481  }
482 
483  // Handle cases where we are using optical flow but are no longer able to because data is old
484  // or its use has been inhibited.
486  if (_inhibit_flow_use) {
488  _time_last_of_fuse = 0;
489 
490  } else if ((_time_last_imu - _time_last_of_fuse) > (uint64_t)_params.reset_timeout_max) {
492 
493  }
494  }
495 
496  // optical flow fusion mode selection logic
497  if ((_params.fusion_mode & MASK_USE_OF) // optical flow has been selected by the user
498  && !_control_status.flags.opt_flow // we are not yet using flow data
499  && _control_status.flags.tilt_align // we know our tilt attitude
502  {
503  // If the heading is not aligned, reset the yaw and magnetic field states
506  }
507 
508  // If the heading is valid and use is not inhibited , start using optical flow aiding
510  // set the flag and reset the fusion timeout
513 
514  // if we are not using GPS or external vision aiding, then the velocity and position states and covariances need to be set
515  const bool flow_aid_only = !(_control_status.flags.gps || _control_status.flags.ev_pos || _control_status.flags.ev_vel);
516  if (flow_aid_only) {
517  resetVelocity();
518  resetPosition();
519 
520  // align the output observer to the EKF states
522  }
523  }
524 
525  } else if (!(_params.fusion_mode & MASK_USE_OF)) {
527  }
528 
529  // handle the case when we have optical flow, are reliant on it, but have not been using it for an extended period
534 
536 
537  if (do_reset) {
538  resetVelocity();
539  resetPosition();
540  }
541  }
542 
543  // Only fuse optical flow if valid body rate compensation data is available
544  if (calcOptFlowBodyRateComp()) {
545 
546  bool flow_quality_good = (_flow_sample_delayed.quality >= _params.flow_qual_min);
547 
548  if (!flow_quality_good && !_control_status.flags.in_air) {
549  // when on the ground with poor flow quality, assume zero ground relative velocity and LOS rate
550  _flowRadXYcomp.zero();
551  } else {
552  // compensate for body motion to give a LOS rate
555  }
556  } else {
557  // don't use this flow data and wait for the next data to arrive
558  _flow_data_ready = false;
559  }
560  }
561 
562  // Wait until the midpoint of the flow sample has fallen behind the fusion time horizon
564  // Fuse optical flow LOS rate observations into the main filter only if height above ground has been updated recently
565  // but use a relaxed time criteria to enable it to coast through bad range finder data
566  if (_control_status.flags.opt_flow && ((_time_last_imu - _time_last_hagl_fuse) < (uint64_t)10e6)) {
567  fuseOptFlow();
568  _last_known_posNE(0) = _state.pos(0);
569  _last_known_posNE(1) = _state.pos(1);
570  }
571 
572  _flow_data_ready = false;
573  }
574 }
575 
577 {
578  // Check for new GPS data that has fallen behind the fusion time horizon
579  if (_gps_data_ready) {
580 
581  // GPS yaw aiding selection logic
587 
588  if (resetGpsAntYaw()) {
589  // flag the yaw as aligned
591 
592  // turn on fusion of external vision yaw measurements and disable all other yaw fusion
594  _control_status.flags.ev_yaw = false;
595  _control_status.flags.mag_dec = false;
596 
598  stopMag3DFusion();
599 
600  ECL_INFO_TIMESTAMPED("EKF commencing GPS yaw fusion");
601  }
602  }
603 
604  // fuse the yaw observation
606  fuseGpsAntYaw();
607  }
608 
609  // Determine if we should use GPS aiding for velocity and horizontal position
610  // To start using GPS we need angular alignment completed, the local NED origin set and GPS data that has not failed checks recently
611  bool gps_checks_passing = (_time_last_imu - _last_gps_fail_us > (uint64_t)5e6);
612  bool gps_checks_failing = (_time_last_imu - _last_gps_pass_us > (uint64_t)5e6);
614  if (_control_status.flags.tilt_align && _NED_origin_initialised && gps_checks_passing) {
615  // If the heading is not aligned, reset the yaw and magnetic field states
616  // Do not use external vision for yaw if using GPS because yaw needs to be
617  // defined relative to an NED reference frame
618  const bool want_to_reset_mag_heading = !_control_status.flags.yaw_align ||
621  if (want_to_reset_mag_heading && canResetMagHeading()) {
622  _control_status.flags.ev_yaw = false;
624  // Handle the special case where we have not been constraining yaw drift or learning yaw bias due
625  // to assumed invalid mag field associated with indoor operation with a downwards looking flow sensor.
628  // Zero the yaw bias covariance and set the variance to the initial alignment uncertainty
630  }
631  }
632 
633  // If the heading is valid start using gps aiding
635  // if we are not already aiding with optical flow, then we need to reset the position and velocity
636  // otherwise we only need to reset the position
637  _control_status.flags.gps = true;
638 
640  if (!resetPosition() || !resetVelocity()) {
641  _control_status.flags.gps = false;
642 
643  }
644 
645  } else if (!resetPosition()) {
646  _control_status.flags.gps = false;
647 
648  }
649 
650  if (_control_status.flags.gps) {
651  ECL_INFO_TIMESTAMPED("EKF commencing GPS fusion");
653  }
654  }
655  }
656 
657  } else if (!(_params.fusion_mode & MASK_USE_GPS)) {
658  _control_status.flags.gps = false;
659 
660  }
661 
662  // Handle the case where we are using GPS and another source of aiding and GPS is failing checks
664  _control_status.flags.gps = false;
665  // Reset position state to external vision if we are going to use absolute values
667  resetPosition();
668  }
669  ECL_WARN_TIMESTAMPED("EKF GPS data quality poor - stopping use");
670  }
671 
672  // handle the case when we now have GPS, but have not been using it for an extended period
673  if (_control_status.flags.gps) {
674  // We are relying on aiding to constrain drift so after a specified time
675  // with no aiding we need to do something
680 
681  // We haven't had an absolute position fix for a longer time so need to do something
682  do_reset = do_reset || ((_time_last_imu - _time_last_pos_fuse) > (2 * _params.reset_timeout_max));
683 
684  if (do_reset) {
685  // use GPS velocity data to check and correct yaw angle if a FW vehicle
687  // if flying a fixed wing aircraft, do a complete reset that includes yaw
689  }
690 
691  resetVelocity();
692  resetPosition();
693  _velpos_reset_request = false;
694  ECL_WARN_TIMESTAMPED("EKF GPS fusion timeout - reset to GPS");
695 
696  // Reset the timeout counters
699 
700  }
701  }
702 
703  // Only use GPS data for position and velocity aiding if enabled
704  if (_control_status.flags.gps) {
705  _fuse_pos = true;
706  _fuse_vert_vel = true;
707  _fuse_hor_vel = true;
708 
709  // correct velocity for offset relative to IMU
711  Vector3f pos_offset_body = _params.gps_pos_body - _params.imu_pos_body;
712  Vector3f vel_offset_body = cross_product(ang_rate, pos_offset_body);
713  Vector3f vel_offset_earth = _R_to_earth * vel_offset_body;
714  _gps_sample_delayed.vel -= vel_offset_earth;
715 
716  // correct position and height for offset relative to IMU
717  Vector3f pos_offset_earth = _R_to_earth * pos_offset_body;
718  _gps_sample_delayed.pos(0) -= pos_offset_earth(0);
719  _gps_sample_delayed.pos(1) -= pos_offset_earth(1);
720  _gps_sample_delayed.hgt += pos_offset_earth(2);
721 
722  // calculate observation process noise
723  float lower_limit = fmaxf(_params.gps_pos_noise, 0.01f);
724 
726  // if we are using other sources of aiding, then relax the upper observation
727  // noise limit which prevents bad GPS perturbing the position estimate
728  _posObsNoiseNE = fmaxf(_gps_sample_delayed.hacc, lower_limit);
729 
730  } else {
731  // if we are not using another source of aiding, then we are reliant on the GPS
732  // observations to constrain attitude errors and must limit the observation noise value.
733  float upper_limit = fmaxf(_params.pos_noaid_noise, lower_limit);
734  _posObsNoiseNE = math::constrain(_gps_sample_delayed.hacc, lower_limit, upper_limit);
735  }
736 
738 
739  // calculate innovations
745 
746  // set innovation gate size
749  }
750 
751  } else if (_control_status.flags.gps && (_imu_sample_delayed.time_us - _gps_sample_delayed.time_us > (uint64_t)10e6)) {
752  _control_status.flags.gps = false;
753  ECL_WARN_TIMESTAMPED("EKF GPS data stopped");
755  // Handle the case where we are fusing another position source along GPS,
756  // stop waiting for GPS after 1 s of lost signal
757  _control_status.flags.gps = false;
758  ECL_WARN_TIMESTAMPED("EKF GPS data stopped, using only EV or OF");
759  }
760 }
761 
763 {
764  /*
765  * Handle the case where we have not fused height measurements recently and
766  * uncertainty exceeds the max allowable. Reset using the best available height
767  * measurement source, continue using it after the reset and declare the current
768  * source failed if we have switched.
769  */
770 
771  // Check for IMU accelerometer vibration induced clipping as evidenced by the vertical innovations being positive and not stale.
772  // Clipping causes the average accel reading to move towards zero which makes the INS think it is falling and produces positive vertical innovations
773  float var_product_lim = sq(_params.vert_innov_test_lim) * sq(_params.vert_innov_test_lim);
774  bool bad_vert_accel = (_control_status.flags.baro_hgt && // we can only run this check if vertical position and velocity observations are independent
775  (sq(_vel_pos_innov[5] * _vel_pos_innov[2]) > var_product_lim * (_vel_pos_innov_var[5] * _vel_pos_innov_var[2])) && // vertical position and velocity sensors are in agreement that we have a significant error
776  (_vel_pos_innov[2] > 0.0f) && // positive innovation indicates that the inertial nav thinks it is falling
777  ((_imu_sample_delayed.time_us - _baro_sample_delayed.time_us) < 2 * BARO_MAX_INTERVAL) && // vertical position data is fresh
778  ((_imu_sample_delayed.time_us - _gps_sample_delayed.time_us) < 2 * GPS_MAX_INTERVAL)); // vertical velocity data is fresh
779 
780  // record time of last bad vert accel
781  if (bad_vert_accel) {
783 
784  } else {
786  }
787 
788  // declare a bad vertical acceleration measurement and make the declaration persist
789  // for a minimum of 10 seconds
792 
793  } else {
794  _bad_vert_accel_detected = bad_vert_accel;
795  }
796 
797  // check if height is continuously failing because of accel errors
798  bool continuous_bad_accel_hgt = ((_time_last_imu - _time_good_vert_accel) > (unsigned)_params.bad_acc_reset_delay_us);
799 
800  // check if height has been inertial deadreckoning for too long
801  bool hgt_fusion_timeout = ((_time_last_imu - _time_last_hgt_fuse) > (uint64_t)5e6);
802 
803  // reset the vertical position and velocity states
804  if (hgt_fusion_timeout || continuous_bad_accel_hgt) {
805  // boolean that indicates we will do a height reset
806  bool reset_height = false;
807 
808  // handle the case where we are using baro for height
810  // check if GPS height is available
811  const gpsSample &gps_init = _gps_buffer.get_newest();
812  bool gps_hgt_accurate = (gps_init.vacc < _params.req_vacc);
813 
814  const baroSample &baro_init = _baro_buffer.get_newest();
815  bool baro_hgt_available = ((_time_last_imu - baro_init.time_us) < 2 * BARO_MAX_INTERVAL);
816 
817  // check for inertial sensing errors in the last 10 seconds
818  bool prev_bad_vert_accel = (_time_last_imu - _time_bad_vert_accel < BADACC_PROBATION);
819 
820  // reset to GPS if adequate GPS data is available and the timeout cannot be blamed on IMU data
821  bool reset_to_gps = !_gps_hgt_intermittent && gps_hgt_accurate && !prev_bad_vert_accel;
822 
823  // reset to GPS if GPS data is available and there is no Baro data
824  reset_to_gps = reset_to_gps || (!_gps_hgt_intermittent && !baro_hgt_available);
825 
826  // reset to Baro if we are not doing a GPS reset and baro data is available
827  bool reset_to_baro = !reset_to_gps && baro_hgt_available;
828 
829  if (reset_to_gps) {
830  // set height sensor health
831  _baro_hgt_faulty = true;
832 
833  // reset the height mode
835 
836  // request a reset
837  reset_height = true;
838  ECL_WARN_TIMESTAMPED("EKF baro hgt timeout - reset to GPS");
839 
840  } else if (reset_to_baro) {
841  // set height sensor health
842  _baro_hgt_faulty = false;
843 
844  // reset the height mode
846 
847  // request a reset
848  reset_height = true;
849  ECL_WARN_TIMESTAMPED("EKF baro hgt timeout - reset to baro");
850 
851  } else {
852  // we have nothing we can reset to
853  // deny a reset
854  reset_height = false;
855 
856  }
857  }
858 
859  // handle the case we are using GPS for height
861  // check if GPS height is available
862  const gpsSample &gps_init = _gps_buffer.get_newest();
863  bool gps_hgt_accurate = (gps_init.vacc < _params.req_vacc);
864 
865  // check the baro height source for consistency and freshness
866  const baroSample &baro_init = _baro_buffer.get_newest();
867  bool baro_data_fresh = ((_time_last_imu - baro_init.time_us) < 2 * BARO_MAX_INTERVAL);
868  float baro_innov = _state.pos(2) - (_hgt_sensor_offset - baro_init.hgt + _baro_hgt_offset);
869  bool baro_data_consistent = fabsf(baro_innov) < (sq(_params.baro_noise) + P[9][9]) * sq(_params.baro_innov_gate);
870 
871  // if baro data is acceptable and GPS data is inaccurate, reset height to baro
872  bool reset_to_baro = baro_data_consistent && baro_data_fresh && !_baro_hgt_faulty && !gps_hgt_accurate;
873 
874  // if GPS height is unavailable and baro data is available, reset height to baro
875  reset_to_baro = reset_to_baro || (_gps_hgt_intermittent && baro_data_fresh);
876 
877  // if we cannot switch to baro and GPS data is available, reset height to GPS
878  bool reset_to_gps = !reset_to_baro && !_gps_hgt_intermittent;
879 
880  if (reset_to_baro) {
881  // set height sensor health
882  _baro_hgt_faulty = false;
883 
884  // reset the height mode
886 
887  // request a reset
888  reset_height = true;
889  ECL_WARN_TIMESTAMPED("EKF gps hgt timeout - reset to baro");
890 
891  } else if (reset_to_gps) {
892  // reset the height mode
894 
895  // request a reset
896  reset_height = true;
897  ECL_WARN_TIMESTAMPED("EKF gps hgt timeout - reset to GPS");
898 
899  } else {
900  // we have nothing to reset to
901  reset_height = false;
902 
903  }
904  }
905 
906  // handle the case we are using range finder for height
908 
909  // check if baro data is available
910  const baroSample &baro_init = _baro_buffer.get_newest();
911  bool baro_data_available = ((_time_last_imu - baro_init.time_us) < 2 * BARO_MAX_INTERVAL);
912 
913  // reset to baro if we have no range data and baro data is available
914  bool reset_to_baro = !_rng_hgt_valid && baro_data_available;
915 
916  if (_rng_hgt_valid) {
917 
918  // reset the height mode
920 
921  // request a reset
922  reset_height = true;
923  ECL_WARN_TIMESTAMPED("EKF rng hgt timeout - reset to rng hgt");
924 
925  } else if (reset_to_baro) {
926  // set height sensor health
927  _baro_hgt_faulty = false;
928 
929  // reset the height mode
931 
932  // request a reset
933  reset_height = true;
934  ECL_WARN_TIMESTAMPED("EKF rng hgt timeout - reset to baro");
935 
936  } else {
937  // we have nothing to reset to
938  reset_height = false;
939 
940  }
941  }
942 
943  // handle the case where we are using external vision data for height
945  // check if vision data is available
946  const extVisionSample &ev_init = _ext_vision_buffer.get_newest();
947  bool ev_data_available = ((_time_last_imu - ev_init.time_us) < 2 * EV_MAX_INTERVAL);
948 
949  // check if baro data is available
950  const baroSample &baro_init = _baro_buffer.get_newest();
951  bool baro_data_available = ((_time_last_imu - baro_init.time_us) < 2 * BARO_MAX_INTERVAL);
952 
953  // reset to baro if we have no vision data and baro data is available
954  bool reset_to_baro = !ev_data_available && baro_data_available;
955 
956  // reset to ev data if it is available
957  bool reset_to_ev = ev_data_available;
958 
959  if (reset_to_baro) {
960  // set height sensor health
961  _baro_hgt_faulty = false;
962 
963  // reset the height mode
965 
966  // request a reset
967  reset_height = true;
968  ECL_WARN_TIMESTAMPED("EKF ev hgt timeout - reset to baro");
969 
970  } else if (reset_to_ev) {
971  // reset the height mode
973 
974  // request a reset
975  reset_height = true;
976  ECL_WARN_TIMESTAMPED("EKF ev hgt timeout - reset to ev hgt");
977 
978  } else {
979  // we have nothing to reset to
980  reset_height = false;
981 
982  }
983  }
984 
985  // Reset vertical position and velocity states to the last measurement
986  if (reset_height) {
987  resetHeight();
988  // Reset the timout timer
990 
991  }
992 
993  }
994 }
995 
997 {
998  // set control flags for the desired primary height source
999 
1002 
1004 
1007  _fuse_height = true;
1008 
1009  // we have just switched to using range finder, calculate height sensor offset such that current
1010  // measurement matches our current height estimate
1012  if (isTerrainEstimateValid()) {
1014 
1015  } else {
1017  }
1018  }
1019 
1022  _fuse_height = true;
1023 
1024  // we have just switched to using baro height, we don't need to set a height sensor offset
1025  // since we track a separate _baro_hgt_offset
1027  _hgt_sensor_offset = 0.0f;
1028  }
1029 
1030  // Turn off ground effect compensation if it times out
1033 
1035  }
1036  }
1037 
1039  // switch to gps if there was a reset to gps
1040  _fuse_height = true;
1041 
1042  // we have just switched to using gps height, calculate height sensor offset such that current
1043  // measurement matches our current height estimate
1046  }
1047  }
1048  }
1049 
1050  // set the height data source to range if requested
1054 
1055  // we have just switched to using range finder, calculate height sensor offset such that current
1056  // measurement matches our current height estimate
1058  // use the parameter rng_gnd_clearance if on ground to avoid a noisy offset initialization (e.g. sonar)
1060 
1062 
1063  } else if (_control_status.flags.in_air) {
1064 
1066 
1067  } else {
1068 
1070  }
1071  }
1072 
1075  _fuse_height = true;
1076 
1077  // we have just switched to using baro height, we don't need to set a height sensor offset
1078  // since we track a separate _baro_hgt_offset
1080  _hgt_sensor_offset = 0.0f;
1081  }
1082  }
1083 
1084  // Determine if GPS should be used as the height source
1086 
1089  _fuse_height = true;
1090 
1091  // we have just switched to using range finder, calculate height sensor offset such that current
1092  // measurement matches our current height estimate
1094  if (isTerrainEstimateValid()) {
1096 
1097  } else {
1099  }
1100  }
1101 
1104  _fuse_height = true;
1105 
1106  // we have just switched to using gps height, calculate height sensor offset such that current
1107  // measurement matches our current height estimate
1110  }
1111 
1113  // switch to baro if there was a reset to baro
1114  _fuse_height = true;
1115 
1116  // we have just switched to using baro height, we don't need to set a height sensor offset
1117  // since we track a separate _baro_hgt_offset
1119  _hgt_sensor_offset = 0.0f;
1120  }
1121  }
1122  }
1123 
1124  // Determine if we rely on EV height but switched to baro
1127  // switch to baro if there was a reset to baro
1128  _fuse_height = true;
1129 
1130  // we have just switched to using baro height, we don't need to set a height sensor offset
1131  // since we track a separate _baro_hgt_offset
1133  _hgt_sensor_offset = 0.0f;
1134  }
1135  }
1136  }
1137 
1138  // calculate a filtered offset between the baro origin and local NED origin if we are not using the baro as a height reference
1140  float local_time_step = 1e-6f * _delta_time_baro_us;
1141  local_time_step = math::constrain(local_time_step, 0.0f, 1.0f);
1142 
1143  // apply a 10 second first order low pass filter to baro offset
1144  float offset_rate_correction = 0.1f * (_baro_sample_delayed.hgt + _state.pos(
1145  2) - _baro_hgt_offset);
1146  _baro_hgt_offset += local_time_step * math::constrain(offset_rate_correction, -0.1f, 0.1f);
1147  }
1148 
1150  && (!_range_data_ready || !_rng_hgt_valid)) {
1151 
1152  // If we are supposed to be using range finder data as the primary height sensor, have missed or rejected measurements
1153  // and are on the ground, then synthesise a measurement at the expected on ground value
1154  if (!_control_status.flags.in_air) {
1157 
1158  }
1159 
1160  _fuse_height = true;
1161  }
1162 
1163 
1164 }
1165 
1167 {
1168  const bool horz_vel_valid = _control_status.flags.gps
1172 
1174  && _rng_hgt_valid
1176  && horz_vel_valid) {
1177  // check if we can use range finder measurements to estimate height, use hysteresis to avoid rapid switching
1178  // Note that the 0.7 coefficients and the innovation check are arbitrary values but work well in practice
1179  const bool is_in_range = _is_range_aid_suitable
1182 
1183  const float ground_vel = sqrtf(_state.vel(0) * _state.vel(0) + _state.vel(1) * _state.vel(1));
1184  const bool is_below_max_speed = _is_range_aid_suitable
1185  ? ground_vel < _params.max_vel_for_range_aid
1186  : ground_vel < _params.max_vel_for_range_aid * 0.7f;
1187 
1188  const bool is_hagl_stable = _is_range_aid_suitable
1191 
1192  _is_range_aid_suitable = is_in_range && is_below_max_speed && is_hagl_stable;
1193 
1194  } else {
1195  _is_range_aid_suitable = false;
1196  }
1197 }
1198 
1200 {
1201  // control activation and initialisation/reset of wind states required for airspeed fusion
1202 
1203  // If both airspeed and sideslip fusion have timed out and we are not using a drag observation model then we no longer have valid wind estimates
1204  bool airspeed_timed_out = ((_time_last_imu - _time_last_arsp_fuse) > (uint64_t)10e6);
1205  bool sideslip_timed_out = ((_time_last_imu - _time_last_beta_fuse) > (uint64_t)10e6);
1206 
1207  if (_control_status.flags.wind && airspeed_timed_out && sideslip_timed_out && !(_params.fusion_mode & MASK_USE_DRAG)) {
1208  _control_status.flags.wind = false;
1209 
1210  }
1211 
1212  if (_control_status.flags.fuse_aspd && airspeed_timed_out) {
1214 
1215  }
1216 
1217  // Always try to fuse airspeed data if available and we are in flight
1219  // always fuse airsped data if we are flying and data is present
1222  }
1223 
1224  // If starting wind state estimation, reset the wind states and covariances before fusing any data
1225  if (!_control_status.flags.wind) {
1226  // activate the wind states
1227  _control_status.flags.wind = true;
1228  // reset the timout timer to prevent repeated resets
1231  // reset the wind speed states and corresponding covariances
1232  resetWindStates();
1234 
1235  }
1236 
1237  fuseAirspeed();
1238 
1239  }
1240 }
1241 
1243 {
1244  // control activation and initialisation/reset of wind states required for synthetic sideslip fusion fusion
1245 
1246  // If both airspeed and sideslip fusion have timed out and we are not using a drag observation model then we no longer have valid wind estimates
1247  bool sideslip_timed_out = ((_time_last_imu - _time_last_beta_fuse) > (uint64_t)10e6);
1248  bool airspeed_timed_out = ((_time_last_imu - _time_last_arsp_fuse) > (uint64_t)10e6);
1249 
1250  if (_control_status.flags.wind && airspeed_timed_out && sideslip_timed_out && !(_params.fusion_mode & MASK_USE_DRAG)) {
1251  _control_status.flags.wind = false;
1252  }
1253 
1254  // Perform synthetic sideslip fusion when in-air and sideslip fuson had been enabled externally in addition to the following criteria:
1255 
1256  // Sufficient time has lapsed sice the last fusion
1257  bool beta_fusion_time_triggered = ((_time_last_imu - _time_last_beta_fuse) > _params.beta_avg_ft_us);
1258 
1259  if (beta_fusion_time_triggered && _control_status.flags.fuse_beta && _control_status.flags.in_air) {
1260  // If starting wind state estimation, reset the wind states and covariances before fusing any data
1261  if (!_control_status.flags.wind) {
1262  // activate the wind states
1263  _control_status.flags.wind = true;
1264  // reset the timeout timers to prevent repeated resets
1267  // reset the wind speed states and corresponding covariances
1268  resetWindStates();
1270  }
1271 
1272  fuseSideslip();
1273  }
1274 }
1275 
1277 {
1281  if (!_control_status.flags.wind) {
1282  // reset the wind states and covariances when starting drag accel fusion
1283  _control_status.flags.wind = true;
1284  resetWindStates();
1286 
1288  fuseDrag();
1289 
1290  }
1291 
1292  } else {
1293  _control_status.flags.wind = false;
1294 
1295  }
1296  }
1297 }
1298 
1300 {
1301  // if we aren't doing any aiding, fake GPS measurements at the last known position to constrain drift
1302  // Coincide fake measurements with baro data for efficiency with a minimum fusion rate of 5Hz
1303  if (!(_params.fusion_mode & MASK_USE_GPS)) {
1304  _control_status.flags.gps = false;
1305  }
1306 
1307  if (!_control_status.flags.gps &&
1312 
1313  // We now need to use a synthetic position observation to prevent unconstrained drift of the INS states.
1315 
1316  // Fuse synthetic position observations every 200msec
1317  if (((_time_last_imu - _time_last_fake_gps) > (uint64_t)2e5) || _fuse_height) {
1318  // Reset position and velocity states if we re-commence this aiding method
1319  if ((_time_last_imu - _time_last_fake_gps) > (uint64_t)4e5) {
1320  resetPosition();
1321  resetVelocity();
1322  _fuse_hpos_as_odom = false;
1323 
1324  if (_time_last_fake_gps != 0) {
1325  ECL_WARN_TIMESTAMPED("EKF stopping navigation");
1326  }
1327 
1328  }
1329 
1330  _fuse_pos = true;
1331  _fuse_hor_vel = false;
1332  _fuse_vert_vel = false;
1334 
1337 
1338  } else {
1339  _posObsNoiseNE = 0.5f;
1340  }
1341 
1342  _vel_pos_innov[0] = 0.0f;
1343  _vel_pos_innov[1] = 0.0f;
1344  _vel_pos_innov[2] = 0.0f;
1347 
1348  // glitch protection is not required so set gate to a large value
1349  _posInnovGateNE = 100.0f;
1350 
1351  }
1352 
1353  } else {
1354  _using_synthetic_position = false;
1355  }
1356 
1357  // Fuse available NED velocity and position data into the main filter
1359  fuseVelPosHeight();
1360 
1361  }
1362 }
1363 
1365 {
1368 
1369  if (data_ready && primary_aiding) {
1371  _fuse_hor_vel_aux = true;
1377  fuseVelPosHeight();
1378  }
1379 }
float ev_pos_innov_gate
vision position fusion innovation consistency gate size (STD)
Definition: common.h:305
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
float _cos_tilt_rng
cosine of the range finder tilt rotation about the Y body axis
Definition: ekf.h:464
struct estimator::filter_control_status_u::@60 flags
#define VDIST_SENSOR_RANGE
Use range finder height.
Definition: common.h:180
uint64_t _time_bad_vert_accel
last time a bad vertical accel was detected (uSec)
Definition: ekf.h:477
void setControlBaroHeight()
float _posInnovGateNE
Number of standard deviations used for the NE position fusion innovation consistency check...
Definition: ekf.h:300
bool pop_first_older_than(const uint64_t &timestamp, data_type *sample)
Definition: RingBuffer.h:126
Vector3f delta_ang
delta angle in body frame (integrated gyro measurements) (rad)
Definition: common.h:107
float ev_vel_innov_gate
vision velocity fusion innovation consistency gate size (STD)
Definition: common.h:304
float switch_on_gyro_bias
1-sigma gyro bias uncertainty at switch on (rad/sec)
Definition: common.h:252
bool _fuse_height
true when baro height data should be fused
Definition: ekf.h:293
float hgt
gps height measurement (m)
Definition: common.h:116
uint32_t gps_yaw
22 - true when yaw (not ground course) data from a GPS receiver is being fused
Definition: common.h:463
stateSample _state
state struct of the ekf running at the delayed time horizon
Definition: ekf.h:288
float _vel_pos_innov_var[6]
NED velocity and position innovation variances: 0-2 vel ((m/sec)**2), 3-5 pos (m**2) ...
Definition: ekf.h:373
#define VDIST_SENSOR_GPS
Use GPS height.
Definition: common.h:179
uint32_t yaw_align
1 - true if the filter yaw alignment is complete
Definition: common.h:442
RingBuffer< outputSample > _output_buffer
bool resetGpsAntYaw()
void setControlGPSHeight()
bool resetMagHeading(const Vector3f &mag_init, bool increase_yaw_var=true, bool update_buffer=true)
Definition: ekf_helper.cpp:554
RingBuffer< extVisionSample > _ext_vision_buffer
float _vel_pos_innov[6]
NED velocity and position innovations: 0-2 vel (m/sec), 3-5 pos (m)
Definition: ekf.h:372
Vector3f ev_pos_body
xyz position of VI-sensor focal point in body frame (m)
Definition: common.h:329
float range_cos_max_tilt
cosine of the maximum tilt angle from the vertical that permits use of range finder and flow data ...
Definition: common.h:299
Dcm< float > Dcmf
Definition: Dcm.hpp:185
const data_type & get_newest()
Definition: RingBuffer.h:121
Vector2f _hpos_pred_prev
previous value of NE position state used by odometry fusion (m)
Definition: ekf.h:309
float _gps_alt_ref
WGS-84 height (m)
Definition: ekf.h:425
float gps_vel_innov_gate
GPS velocity innovation consistency gate size (STD)
Definition: common.h:264
void controlHeightSensorTimeouts()
Definition: control.cpp:762
uint32_t fuse_aspd
19 - true when airspeed measurements are being fused
Definition: common.h:460
Vector2f pos
NE earth frame gps horizontal position measurement (m)
Definition: common.h:115
uint32_t fixed_wing
17 - true when the vehicle is operating as a fixed wing vehicle
Definition: common.h:458
bool resetVelocity()
Definition: ekf_helper.cpp:50
Quatf quat
quaternion defining rotation from body to earth frame
Definition: common.h:158
Vector3f _imu_del_ang_of
bias corrected delta angle measurements accumulated across the same time frame as the optical flow ra...
Definition: ekf.h:395
void controlOpticalFlowFusion()
Definition: control.cpp:422
#define EV_MAX_INTERVAL
Maximum allowable time interval between external vision system measurements (uSec) ...
Definition: common.h:211
#define MASK_USE_EVYAW
set to true to use external vision quaternion data for yaw
Definition: common.h:193
bool _flow_for_terrain_data_ready
Definition: ekf.h:324
bool _ev_rot_mat_initialised
_ev_rot_mat should only be initialised once in the beginning through the reset function ...
Definition: ekf.h:314
uint64_t _last_gps_pass_us
last system time in usec that the GPS passed it&#39;s checks
Definition: ekf.h:418
float _hgt_sensor_offset
set as necessary if desired to maintain the same height after a height reset (m)
Definition: ekf.h:435
float gps_pos_noise
minimum allowed observation noise for gps position fusion (m)
Definition: common.h:259
void fuseSideslip()
void controlBetaFusion()
Definition: control.cpp:1242
uint32_t rng_hgt
10 - true when range finder height is being fused as a primary height reference
Definition: common.h:451
bool _fuse_hpos_as_odom
true when the NE position data is being fused using an odometry assumption
Definition: ekf.h:307
Vector3f cross_product(const Vector3f &vecIn1, const Vector3f &vecIn2)
uint64_t time_us
timestamp of the measurement (uSec)
Definition: common.h:122
void fuseAirspeed()
airspeedSample _airspeed_sample_delayed
uint32_t baro_hgt
9 - true when baro height is being fused as a primary height reference
Definition: common.h:450
void resetWindStates()
uint64_t _last_gps_fail_us
last system time in usec that the GPS failed it&#39;s checks
Definition: ekf.h:417
void controlDragFusion()
Definition: control.cpp:1276
bool _fuse_vert_vel
true when gps vertical velocity measurement should be fused
Definition: ekf.h:296
void fuseGpsAntYaw()
rangeSample _range_sample_delayed
void checkRangeAidSuitability()
Definition: control.cpp:1166
float vacc
1-std vertical position error (m)
Definition: common.h:120
Vector3f gyroXYZ
measured delta angle of the inertial frame about the body axes obtained from rate gyro measurements (...
Definition: common.h:150
float range_aid_innov_gate
gate size used for innovation consistency checks for range aid fusion
Definition: common.h:298
float _flow_max_rate
maximum angular flow rate that the optical flow sensor can measure (rad/s)
float gps_vel_noise
minimum allowed observation noise for gps velocity fusion (m/sec)
Definition: common.h:258
int32_t fusion_mode
bitmasked integer that selects which aiding sources will be used
Definition: common.h:222
int32_t vdist_sensor_type
selects the primary source for height data
Definition: common.h:223
bool _range_aid_mode_selected
true when range finder is being used as the height reference instead of the primary height sensor ...
Definition: ekf.h:483
float dt
amount of integration time (sec)
Definition: common.h:151
float P[_k_num_states][_k_num_states]
state covariance matrix
Definition: ekf.h:367
uint64_t _time_good_vert_accel
last time a good vertical accel was detected (uSec)
Definition: ekf.h:478
uint64_t _time_bad_motion_us
last system time that on-ground motion exceeded limits (uSec)
Definition: ekf.h:397
Vector3f pos
XYZ position in earth frame (m) - Z must be aligned with down axis.
Definition: common.h:156
static constexpr float CONSTANTS_ONE_G
Definition: geo.h:51
auxVelSample _auxvel_sample_delayed
bool _mag_inhibit_yaw_reset_req
true when magnetometer inhibit has been active for long enough to require a yaw reset when conditions...
Definition: ekf.h:361
const T & getState() const
Definition: AlphaFilter.hpp:67
float max_vel_for_range_aid
maximum ground velocity for which we allow to use the range finder as height source (if range_aid == ...
Definition: common.h:296
void calcExtVisRotMat()
float rng
range (distance to ground) measurement (m)
Definition: common.h:136
#define GPS_MAX_INTERVAL
Maximum allowable time interval between GPS measurements (uSec)
Definition: common.h:208
float _terrain_vpos
estimated vertical position of the terrain underneath the vehicle in local NED frame (m) ...
Definition: ekf.h:457
Vector2f velVarNE
estimated error variance of the NE velocity (m/sec)**2
Definition: common.h:173
uint64_t _time_last_of_fuse
time the last fusion of optical flow measurements were performed (uSec)
Definition: ekf.h:334
float yaw
yaw angle. NaN if not set (used for dual antenna GPS), (rad, [-PI, PI])
Definition: common.h:118
uint64_t _time_last_hgt_fuse
time the last fusion of height measurements was performed (uSec)
Definition: ekf.h:333
float _hagl_innov_var
innovation variance for the last height above terrain measurement (m**2)
Definition: ekf.h:460
#define MASK_USE_GEO_DECL
set to true to use the declination from the geo library when the GPS position becomes available...
Definition: common.h:184
#define ECL_ERR
Definition: ecl.h:92
float sacc
1-std speed error (m/sec)
Definition: common.h:121
#define BARO_MAX_INTERVAL
Maximum allowable time interval between pressure altitude measurements (uSec)
Definition: common.h:209
RingBuffer< gpsSample > _gps_buffer
bool _baro_data_ready
true when new baro height data has fallen behind the fusion time horizon and is available to be fused...
Definition: ekf.h:319
void resetExtVisRotMat()
void controlFusionModes()
Definition: control.cpp:46
uint32_t synthetic_mag_z
25 - true when we are using a synthesized measurement for the magnetometer Z component ...
Definition: common.h:466
bool _fuse_hor_vel
true when gps horizontal velocity measurement should be fused
Definition: ekf.h:295
AlphaFilterVector3f _mag_lpf
filtered magnetometer measurement (Gauss)
Definition: ekf.h:433
Dcmf _R_to_earth
transformation matrix from body frame to earth frame from last EKF prediction
Definition: ekf.h:348
float _hvelInnovGate
Number of standard deviations used for the horizontal velocity fusion innovation consistency check...
Definition: ekf.h:303
uint32_t ev_vel
24 - true when local earth frame velocity data from external vision measurements are being fused ...
Definition: common.h:465
Vector3f rng_pos_body
xyz position of range sensor in body frame (m)
Definition: common.h:327
void controlExternalVisionFusion()
Definition: control.cpp:174
uint64_t time_us
timestamp of the measurement (uSec)
Definition: common.h:163
float calculate_synthetic_mag_z_measurement(Vector3f mag_meas, Vector3f mag_earth_predicted)
#define RNG_MAX_INTERVAL
Maximum allowable time interval between range finder measurements (uSec)
Definition: common.h:210
void update_deadreckoning_status()
float baro_noise
observation noise for barometric height fusion (m)
Definition: common.h:261
bool _inhibit_flow_use
true when use of optical flow and range finder is being inhibited
Definition: ekf.h:399
void controlHeightFusion()
Definition: control.cpp:996
int32_t mag_declination_source
bitmask used to control the handling of declination data
Definition: common.h:274
bool realignYawGPS()
Definition: ekf_helper.cpp:405
bool _ev_data_ready
true when new external vision system data has fallen behind the fusion time horizon and is available ...
Definition: ekf.h:322
uint64_t _time_last_pos_fuse
time the last fusion of horizontal position measurements was performed (uSec)
Definition: ekf.h:330
float posErr
1-Sigma horizontal position accuracy (m)
Definition: common.h:159
bool _gps_checks_passed
Definition: ekf.h:421
uint32_t gnd_effect
20 - true when protection from ground effect induced static pressure rise is active ...
Definition: common.h:461
Vector3f calcRotVecVariances()
Vector3f vel
NED earth frame gps velocity measurement (m/sec)
Definition: common.h:117
int32_t synthesize_mag_z
Definition: common.h:363
float auxvel_gate
velocity fusion innovation consistency gate size (STD)
Definition: common.h:357
Vector2f _flowRadXYcomp
measured delta angle of the image about the X and Y body axes after removal of body rotation (rad)...
Definition: ekf.h:400
int bad_acc_reset_delay_us
Continuous time that the vertical position and velocity innovation test must fail before the states a...
Definition: common.h:353
bool canResetMagHeading() const
uint64_t time_us
timestamp of the measurement (uSec)
Definition: common.h:111
bool _baro_hgt_faulty
true if valid baro data is unavailable for use
Definition: ekf.h:470
int32_t range_aid
allow switching primary height source to range finder if certain conditions are met ...
Definition: common.h:297
bool _flow_data_ready
true when the leading edge of the optical flow integration period has fallen behind the fusion time h...
Definition: ekf.h:321
#define VDIST_SENSOR_EV
Use external vision.
Definition: common.h:181
Vector3f gps_pos_body
xyz position of the GPS antenna in body frame (m)
Definition: common.h:326
constexpr T radians(T degrees)
Definition: Limits.hpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
void stopMag3DFusion()
float rng_gnd_clearance
minimum valid value for range when on ground (m)
Definition: common.h:291
RingBuffer< dragSample > _drag_buffer
float req_vacc
maximum acceptable vertical position error (m)
Definition: common.h:317
#define MASK_USE_OF
set to true to use optical flow data
Definition: common.h:190
uint8_t quality
quality indicator between 0 and 255
Definition: common.h:148
filter_control_status_u _control_status
Euler< float > Eulerf
Definition: Euler.hpp:156
RingBuffer< baroSample > _baro_buffer
Vector3f vel
NED velocity in earth frame in m/s.
Definition: common.h:369
void setDiag(float(&cov_mat)[_k_num_states][_k_num_states], uint8_t first, uint8_t last, float variance)
float _aux_vel_innov[2]
NE auxiliary velocity innovations: (m/sec)
Definition: ekf.h:374
uint32_t ev_hgt
14 - true when height data from external vision measurements is being fused
Definition: common.h:455
void stopMagHdgFusion()
Vector2f flowRadXY
measured delta angle of the image about the X and Y body axes (rad), RH rotation is positive ...
Definition: common.h:149
static constexpr float sq(float var)
Definition: ekf.h:695
bool _tas_data_ready
true when new true airspeed data has fallen behind the fusion time horizon and is available to be fus...
Definition: ekf.h:323
void controlMagFusion()
Definition: mag_control.cpp:42
RingBuffer< magSample > _mag_buffer
uint32_t ev_yaw
13 - true when yaw data from external vision measurements is being fused
Definition: common.h:454
#define BADACC_PROBATION
Period of time that accel data declared bad must continuously pass checks to be declared good again (...
Definition: common.h:214
float baro_innov_gate
barometric and GPS height innovation consistency gate size (STD)
Definition: common.h:262
float _delta_time_of
time in sec that _imu_del_ang_of was accumulated over (sec)
Definition: ekf.h:396
bool _velpos_reset_request
true when a large yaw error has been fixed and a velocity and position state reset is required ...
Definition: ekf.h:445
uint64_t _time_last_fake_gps
same flag as "_flow_data_ready" but used for separate terrain estimator
Definition: ekf.h:326
float hgt
pressure altitude above sea level (m)
Definition: common.h:131
void increaseQuatYawErrVariance(float yaw_variance)
float _posObsNoiseNE
1-STD observation noise used for the fusion of NE position data (m)
Definition: ekf.h:299
void controlAuxVelFusion()
Definition: control.cpp:1364
bool _hpos_prev_available
true when previous values of the estimate and measurement are available for use
Definition: ekf.h:310
#define MASK_USE_EVPOS
set to true to use external vision position data
Definition: common.h:192
RingBuffer< auxVelSample > _auxvel_buffer
Vector2f velNE
measured NE velocity relative to the local origin (m/sec)
Definition: common.h:172
Dcmf _ev_rot_mat
transformation matrix that rotates observations from the EV to the EKF navigation frame...
Definition: ekf.h:312
uint32_t mag_aligned_in_flight
23 - true when the in-flight mag field alignment has been completed
Definition: common.h:464
#define ECL_WARN_TIMESTAMPED
Definition: ecl.h:94
#define MASK_USE_GPS
set to true to use GPS data
Definition: common.h:189
bool _rng_hgt_valid
true if range finder sample retrieved from buffer is valid
Definition: ekf.h:472
void setControlRangeHeight()
Quatf quat_nominal
quaternion defining the rotation from body to earth frame
Definition: common.h:368
void setControlEVHeight()
filter_control_status_u _control_status_prev
void resetHeight()
Definition: ekf_helper.cpp:214
void alignOutputFilter()
Definition: ekf_helper.cpp:378
void resetWindCovariance()
Definition: covariance.cpp:929
float max_hagl_for_range_aid
maximum height above ground for which we allow to use the range finder as height source (if range_aid...
Definition: common.h:295
Vector3f pos
NED position in earth frame in m.
Definition: common.h:370
void fuseVelPosHeight()
static int do_reset(const char *excludes[], int num_excludes)
Definition: param.cpp:802
uint32_t mag_dec
6 - true if synthetic magnetic declination measurements are being fused
Definition: common.h:447
#define MASK_USE_DRAG
set to true to use the multi-rotor drag model to estimate wind
Definition: common.h:194
Vector3< float > Vector3f
Definition: Vector3.hpp:136
float beta_avg_ft_us
The average time between synthetic sideslip measurements (uSec)
Definition: common.h:286
extVisionSample _ev_sample_delayed
uint32_t opt_flow
3 - true if optical flow measurements are being fused
Definition: common.h:444
float _R_rng_to_earth_2_2
2,2 element of the rotation matrix from sensor frame to earth frame
Definition: ekf.h:465
float _hagl_innov
innovation of the last height above terrain measurement (m)
Definition: ekf.h:459
float _vvelInnovGate
Number of standard deviations used for the vertical velocity fusion innovation consistency check...
Definition: ekf.h:304
#define VDIST_SENSOR_BARO
Use baro height.
Definition: common.h:178
uint64_t _time_last_arsp_fuse
time the last fusion of airspeed measurements were performed (uSec)
Definition: ekf.h:335
bool _gps_hgt_intermittent
true if gps height into the buffer is intermittent
Definition: ekf.h:471
float vert_innov_test_lim
Number of standard deviations allowed before the combined vertical velocity and position test is decl...
Definition: common.h:352
float _sin_tilt_rng
sine of the range finder tilt rotation about the Y body axis
Definition: ekf.h:463
#define MASK_ROTATE_EV
set to true to if the EV observations are in a non NED reference frame and need to be rotated before ...
Definition: common.h:195
uint64_t time_us
timestamp of the measurement (uSec)
Definition: common.h:132
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
void controlVelPosFusion()
Definition: control.cpp:1299
uint32_t in_air
7 - true when the vehicle is airborne
Definition: common.h:448
struct Ekf::@62 _state_reset_status
reset event monitoring structure containing velocity, position, height and yaw reset information ...
RingBuffer< rangeSample > _range_buffer
uint64_t _time_good_motion_us
last system time that on-ground motion was within limits (uSec)
Definition: ekf.h:398
void controlGpsFusion()
Definition: control.cpp:576
Vector3f _pos_meas_prev
previous value of NED position measurement fused using odometry assumption (m)
Definition: ekf.h:308
bool _fuse_pos
true when gps position data should be fused
Definition: ekf.h:294
Vector2f _last_known_posNE
last known local NE position vector (m)
Definition: ekf.h:338
#define ECL_INFO
Definition: ecl.h:90
Vector3f _velObsVarNED
1-STD observation noise variance used for the fusion of NED velocity data (m/sec)**2 ...
Definition: ekf.h:302
uint32_t wind
8 - true when wind velocity is being estimated
Definition: common.h:449
uint64_t _time_last_delpos_fuse
time the last fusion of incremental horizontal position measurements was performed (uSec) ...
Definition: ekf.h:331
uint32_t ev_pos
12 - true when local position data from external vision is being fused
Definition: common.h:453
RingBuffer< airspeedSample > _airspeed_buffer
Vector3f imu_pos_body
xyz position of IMU in body frame (m)
Definition: common.h:325
uint32_t fuse_beta
15 - true when synthetic sideslip measurements are being fused
Definition: common.h:456
float hacc
1-std horizontal position error (m)
Definition: common.h:119
void fuseDrag()
Definition: drag_fusion.cpp:46
uint64_t _delta_time_baro_us
delta time between two consecutive delayed baro samples from the buffer (uSec)
Definition: ekf.h:342
Vector3f vel
XYZ velocity in earth frame (m/sec) - Z must be aligned with down axis.
Definition: common.h:157
uint32_t gps_hgt
11 - true when GPS height is being fused as a primary height reference
Definition: common.h:452
float angErr
1-Sigma angular error (rad)
Definition: common.h:162
uint64_t _time_last_vel_fuse
time the last fusion of velocity measurements was performed (uSec)
Definition: ekf.h:332
float _ang_rate_mag_filt
angular rate magnitude after application of a decaying envelope filter (rad/sec)
Definition: ekf.h:453
bool isRangeAidSuitable()
Definition: ekf.h:686
void fuseHeading()
Definition: mag_fusion.cpp:438
int32_t flow_qual_min
minimum acceptable quality integer from the flow sensor
Definition: common.h:310
float _baro_hgt_offset
baro height reading at the local NED origin (m)
Definition: ekf.h:436
uint32_t gps
2 - true if GPS measurements are being fused
Definition: common.h:443
float pos_noaid_noise
observation noise for non-aiding position fusion (m)
Definition: common.h:260
uint32_t tilt_align
0 - true if the filter tilt alignment is complete
Definition: common.h:441
void controlAirDataFusion()
Definition: control.cpp:1199
static constexpr float FILTER_UPDATE_PERIOD_S
bool _bad_vert_accel_detected
true when bad vertical accelerometer data has been detected
Definition: ekf.h:479
void uncorrelateQuatStates()
RingBuffer< flowSample > _flow_buffer
#define GNDEFFECT_TIMEOUT
Maximum period of time that ground effect protection will be active after it was last turned on (uSec...
Definition: common.h:218
float velErr
1-Sigma velocity accuracy (m/sec)
Definition: common.h:161
Vector3f mag
NED magnetometer body frame measurements (Gauss)
Definition: common.h:126
void fuseOptFlow()
void updateRangeDataValidity()
uint64_t _time_last_beta_fuse
time the last fusion of synthetic sideslip measurements were performed (uSec)
Definition: ekf.h:336
Vector3f _accel_vec_filt
acceleration vector after application of a low pass filter (m/sec**2)
Definition: ekf.h:451
uint64_t _time_last_hagl_fuse
last system time that the hagl measurement failed it&#39;s checks (uSec)
Definition: ekf.h:461
Vector3f gyro_bias
delta angle bias estimate in rad
Definition: common.h:371
#define MASK_USE_GPSYAW
set to true to use GPS yaw data if available
Definition: common.h:196
Quatf quat_nominal
nominal quaternion describing vehicle attitude
Definition: common.h:93
bool _gps_data_ready
true when new GPS data has fallen behind the fusion time horizon and is available to be fused ...
Definition: ekf.h:317
bool resetPosition()
Definition: ekf_helper.cpp:139
bool calcOptFlowBodyRateComp()
float delta_ang_dt
delta angle integration period (sec)
Definition: common.h:109
Class for core functions for ekf attitude and position estimator.
uint64_t time_us
timestamp of the integration period leading edge (uSec)
Definition: common.h:152
bool isTerrainEstimateValid() const override
uint64_t time_us
timestamp of the measurement (uSec)
Definition: common.h:137
unsigned reset_timeout_max
maximum time we allow horizontal inertial dead reckoning before attempting to reset the states to the...
Definition: common.h:341
float gps_pos_innov_gate
GPS horizontal position innovation consistency gate size (STD)
Definition: common.h:263
#define ECL_INFO_TIMESTAMPED
Definition: ecl.h:93
bool _using_synthetic_position
true if we are using a synthetic position to constrain drift
Definition: ekf.h:328
bool _mag_data_ready
true when new magnetometer data has fallen behind the fusion time horizon and is available to be fuse...
Definition: ekf.h:318
float _gps_error_norm
normalised gps error
Definition: ekf.h:419
#define MASK_USE_EVVEL
sset to true to use external vision velocity data
Definition: common.h:197
bool _range_data_ready
true when new range finder data has fallen behind the fusion time horizon and is available to be fuse...
Definition: ekf.h:320
uint8_t get_length() const
Definition: RingBuffer.h:117
bool _fuse_hor_vel_aux
true when auxiliary horizontal velocity measurement should be fused
Definition: ekf.h:297
#define ISFINITE(x)
Definition: ecl.h:100
bool _is_range_aid_suitable
true when range finder can be used in flight as the height reference instead of the primary height se...
Definition: ekf.h:482