PX4 Firmware
PX4 Autopilot Software http://px4.io
AirspeedValidator.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2019 PX4 Development Team. 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 PX4 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 AirspeedValidator.cpp
36  * Estimates airspeed scale error (from indicated to equivalent airspeed), performes
37  * checks on airspeed measurement input and reports airspeed valid or invalid.
38  */
39 
40 #include "AirspeedValidator.hpp"
41 
42 
43 void
45 {
46  // get indicated airspeed from input data (raw airspeed)
47  _IAS = input_data.airspeed_indicated_raw;
48 
49  // to be able to detect missing data, save timestamp (used in data_missing check)
50  if (input_data.airspeed_timestamp != _previous_airspeed_timestamp && input_data.airspeed_timestamp > 0) {
51  _time_last_airspeed = input_data.timestamp;
53  }
54 
57  update_wind_estimator(input_data.timestamp, input_data.airspeed_true_raw, input_data.lpos_valid, input_data.lpos_vx,
58  input_data.lpos_vy,
59  input_data.lpos_vz, input_data.lpos_evh, input_data.lpos_evv, input_data.att_q);
61  check_airspeed_innovation(input_data.timestamp, input_data.vel_test_ratio, input_data.mag_test_ratio);
62  check_load_factor(input_data.accel_z);
64 }
65 
66 void
67 AirspeedValidator::update_wind_estimator(const uint64_t time_now_usec, float airspeed_true_raw, bool lpos_valid,
68  float lpos_vx, float lpos_vy,
69  float lpos_vz, float lpos_evh, float lpos_evv, const float att_q[4])
70 {
71  bool att_valid = true; // att_valid could also be a input_data state
72 
73  _wind_estimator.update(time_now_usec);
74 
75  if (lpos_valid && att_valid && _in_fixed_wing_flight) {
76 
77  Vector3f vI(lpos_vx, lpos_vy, lpos_vz);
78  Quatf q(att_q);
79 
80  // sideslip fusion
81  _wind_estimator.fuse_beta(time_now_usec, vI, q);
82 
83  // airspeed fusion (with raw TAS)
84  const Vector3f vel_var{Dcmf(q) *Vector3f{lpos_evh, lpos_evh, lpos_evv}};
85  _wind_estimator.fuse_airspeed(time_now_usec, airspeed_true_raw, vI, Vector2f{vel_var(0), vel_var(1)});
86  }
87 }
88 
89 // this function returns the current states of the wind estimator to be published in the airspeed module
92 {
93  wind_estimate_s wind_est = {};
94 
95  wind_est.timestamp = timestamp;
96  float wind[2];
98  wind_est.windspeed_north = wind[0];
99  wind_est.windspeed_east = wind[1];
100  float wind_cov[2];
101  _wind_estimator.get_wind_var(wind_cov);
102  wind_est.variance_north = wind_cov[0];
103  wind_est.variance_east = wind_cov[1];
109  return wind_est;
110 }
111 
112 void
114 {
115  _airspeed_scale_manual = airspeed_scale_manual;
116  _wind_estimator.enforce_airspeed_scale(1.0f / airspeed_scale_manual); // scale is inverted inside the wind estimator
117 }
118 
119 void
121 {
124 
125  } else {
127  }
128 
129 }
130 
131 void
132 AirspeedValidator::update_EAS_TAS(float air_pressure_pa, float air_temperature_celsius)
133 {
135  _TAS = calc_TAS_from_EAS(_EAS, air_pressure_pa, air_temperature_celsius);
136 }
137 
138 void
139 AirspeedValidator::check_airspeed_innovation(uint64_t time_now, float estimator_status_vel_test_ratio,
140  float estimator_status_mag_test_ratio)
141 {
142  // Check normalised innovation levels with requirement for continuous data and use of hysteresis
143  // to prevent false triggering.
144 
147  }
148 
149  /* Reset states if we are not flying */
150  if (!_in_fixed_wing_flight) {
151  // not in a flight condition that enables use of this check, thus pass check
153  _time_last_tas_pass = time_now;
155  _airspeed_valid = true;
156  _time_last_aspd_innov_check = time_now;
157 
158  } else {
159  float dt_s = math::max((time_now - _time_last_aspd_innov_check) / 1e6f, 0.01f); // limit to 100Hz
160 
161  if (dt_s < 1.0f) {
162  // Compute the ratio of innovation to gate size
163  float tas_test_ratio = _wind_estimator.get_tas_innov() * _wind_estimator.get_tas_innov()
164  / (fmaxf(_tas_gate, 1.0f) * fmaxf(_tas_gate, 1.0f) * _wind_estimator.get_tas_innov_var());
165 
166  if (tas_test_ratio <= _tas_innov_threshold) {
167  // record pass and reset integrator used to trigger
168  _time_last_tas_pass = time_now;
170 
171  } else {
172  // integrate exceedance
173  _apsd_innov_integ_state += dt_s * (tas_test_ratio - _tas_innov_threshold);
174  }
175 
176  if ((estimator_status_vel_test_ratio < 1.0f) && (estimator_status_mag_test_ratio < 1.0f)) {
177  // nav velocity data is likely good so airspeed innovations are able to be used
179  _time_last_tas_fail = time_now;
180  }
181  }
182 
185 
186  } else {
189  }
190  }
191 
192  _time_last_aspd_innov_check = time_now;
193  }
194 }
195 
196 
197 void
199 {
200  // Check if the airpeed reading is lower than physically possible given the load factor
201 
202  const bool bad_number_fail = false; // disable this for now
203 
204  if (_in_fixed_wing_flight) {
205 
206  if (!bad_number_fail) {
207  float max_lift_ratio = fmaxf(_EAS, 0.7f) / fmaxf(_airspeed_stall, 1.0f);
208  max_lift_ratio *= max_lift_ratio;
209 
210  _load_factor_ratio = 0.95f * _load_factor_ratio + 0.05f * (fabsf(accel_z) / 9.81f) / max_lift_ratio;
213 
214  } else {
215  _load_factor_check_failed = true; // bad number fail
216  }
217 
218  } else {
219 
220  _load_factor_ratio = 0.5f; // reset if not in fixed-wing flight (and not in takeoff condition)
221  }
222 
223 }
224 
225 
226 void
228 {
229 
230  const bool bad_number_fail = false; // disable this for now
231 
232  // Check if sensor data is missing - assume a minimum 5Hz data rate.
233  const bool data_missing = (timestamp - _time_last_airspeed) > 200_ms;
234 
235  // Declare data stopped if not received for longer than 1 second
236  _data_stopped_failed = (timestamp - _time_last_airspeed) > 1_s;
237 
238  if (_innovations_check_failed || _load_factor_check_failed || data_missing || bad_number_fail) {
239  // either innovation, load factor or data missing check failed, so declare airspeed failing and record timestamp
240  _time_checks_failed = timestamp;
241  _airspeed_failing = true;
242 
243  } else if (!_innovations_check_failed && !_load_factor_check_failed && !data_missing && !bad_number_fail) {
244  // All checks must pass to declare airspeed good
245  _time_checks_passed = timestamp;
246  _airspeed_failing = false;
247 
248  }
249 
250  if (_airspeed_valid) {
251  // A simultaneous load factor and innovaton check fail makes it more likely that a large
252  // airspeed measurement fault has developed, so a fault should be declared immediately
253  const bool both_checks_failed = (_innovations_check_failed && _load_factor_check_failed);
254 
255  // Because the innovation, load factor and data missing checks are subject to short duration false positives
256  // a timeout period is applied.
257  const bool single_check_fail_timeout = (timestamp - _time_checks_passed) > _checks_fail_delay * 1_s;
258 
259  if (_data_stopped_failed || both_checks_failed || single_check_fail_timeout || bad_number_fail) {
260 
261  _airspeed_valid = false;
262  }
263 
264  } else if ((timestamp - _time_checks_failed) > _checks_clear_delay * 1_s) {
265  _airspeed_valid = true;
266  }
267 }
float _tas_innov_threshold
innovation error threshold for triggering innovation check failure
uint64_t _time_last_airspeed
time last airspeed measurement was received (uSec)
float _tas_gate
gate size of airspeed innovation (to calculate tas_test_ratio)
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
float _load_factor_ratio
ratio of maximum load factor predicted by stall speed to measured load factor
void check_load_factor(float accel_z)
void update(uint64_t time_now)
uint64_t _time_checks_failed
time the checks have last not passed (uSec)
float calc_TAS_from_EAS(float speed_equivalent, float pressure_ambient, float temperature_celsius)
Calculate true airspeed (TAS) from equivalent airspeed (EAS).
Definition: airspeed.cpp:218
Dcm< float > Dcmf
Definition: Dcm.hpp:185
void update_airspeed_valid_status(const uint64_t timestamp)
int _checks_fail_delay
delay for airspeed invalid declaration after single check failure (Sec)
void get_wind(float wind[2])
bool _airspeed_valid
airspeed valid (pitot or groundspeed-windspeed)
uint64_t _time_last_aspd_innov_check
time airspeed innovation was last checked (uSec)
void check_airspeed_innovation(uint64_t timestamp, float estimator_status_vel_test_ratio, float estimator_status_mag_test_ratio)
void update_wind_estimator(const uint64_t timestamp, float airspeed_true_raw, bool lpos_valid, float lpos_vx, float lpos_vy, float lpos_vz, float lpos_evh, float lpos_evv, const float att_q[4])
static constexpr uint64_t TAS_INNOV_FAIL_DELAY
time required for innovation levels to pass or fail (usec)
WindEstimator _wind_estimator
wind estimator instance running in this particular airspeedValidator
float _EAS
equivalent airspeed in m/s
void get_wind_var(float wind_var[2])
float get_beta_innov_var()
float get_beta_innov()
void fuse_beta(uint64_t time_now, const matrix::Vector3f &velI, const matrix::Quatf &q_att)
float _tas_innov_integ_threshold
integrator innovation error threshold for triggering innovation check failure
Calculates airspeed from differential pressure and checks if this airspeed is valid.
bool _in_fixed_wing_flight
variable to bypass innovation and load factor checks
bool _airspeed_failing
airspeed sensor checks have detected failure, but not yet declared failed
wind_estimate_s get_wind_estimator_states(uint64_t timestamp)
uint64_t timestamp
Definition: wind_estimate.h:53
float _IAS
indicated airsped in m/s
float _airspeed_scale_manual
manually entered airspeed scale
void update_airspeed_validator(const airspeed_validator_update_data &input_data)
bool is_estimate_valid()
bool _data_stopped_failed
data_stopp check has detected failure
void update_in_fixed_wing_flight(bool in_fixed_wing_flight)
uint64_t _time_last_tas_fail
last time innovation checks failed
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Vector2< float > Vector2f
Definition: Vector2.hpp:69
float get_tas_scale()
void set_airspeed_scale_manual(float airspeed_scale_manual)
float _airspeed_stall
stall speed of aircraft used for load factor check
void update_EAS_TAS(float air_pressure_pa, float air_temperature_celsius)
int _checks_clear_delay
delay for airspeed valid declaration after all checks passed again (Sec)
float _apsd_innov_integ_state
inegral of excess normalised airspeed innovation (sec)
bool _load_factor_check_failed
load_factor check has detected failure
void fuse_airspeed(uint64_t time_now, float true_airspeed, const matrix::Vector3f &velI, const matrix::Vector2f &velIvar)
Vector3< float > Vector3f
Definition: Vector3.hpp:136
bool _innovations_check_failed
true when airspeed innovations have failed consistency checks
float get_tas_innov()
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
float _TAS
true airspeed in m/s
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
void enforce_airspeed_scale(float scale)
hrt_abstime _previous_airspeed_timestamp
timestamp from previous measurement input, to check validity of measurement
float _EAS_scale
scale factor from IAS to EAS
uint64_t _time_wind_estimator_initialized
time last time wind estimator was initialized (uSec)
float calc_EAS_from_IAS(float speed_indicated, float scale)
Calculate equivalent airspeed (EAS) from indicated airspeed (IAS).
Definition: airspeed.cpp:232
float get_tas_innov_var()
uint64_t _time_last_tas_pass
last time innovation checks passed
bool get_wind_estimator_reset()
uint64_t _time_checks_passed
time the checks have last passed (uSec)