Line data Source code
1 : #include "AP_NavEKF2_core.h"
2 :
3 : #include "AP_NavEKF2.h"
4 :
5 : #include <AP_DAL/AP_DAL.h>
6 : #include <AP_HAL/AP_HAL.h>
7 : #include <GCS_MAVLink/GCS.h>
8 : #include <AP_Logger/AP_Logger.h>
9 : #include <AP_Vehicle/AP_Vehicle_Type.h>
10 : #include <new>
11 :
12 : /*
13 : parameter defaults for different types of vehicle. The
14 : APM_BUILD_DIRECTORY is taken from the main vehicle directory name
15 : where the code is built.
16 : */
17 : #if APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_Replay)
18 : // copter defaults
19 : #define VELNE_M_NSE_DEFAULT 0.3f
20 : #define VELD_M_NSE_DEFAULT 0.5f
21 : #define POSNE_M_NSE_DEFAULT 1.0f
22 : #define ALT_M_NSE_DEFAULT 3.0f
23 : #define MAG_M_NSE_DEFAULT 0.05f
24 : #define GYRO_P_NSE_DEFAULT 3.0E-02f
25 : #define ACC_P_NSE_DEFAULT 6.0E-01f
26 : #define GBIAS_P_NSE_DEFAULT 1.0E-04f
27 : #define GSCALE_P_NSE_DEFAULT 5.0E-04f
28 : #define ABIAS_P_NSE_DEFAULT 5.0E-03f
29 : #define MAGB_P_NSE_DEFAULT 1.0E-04f
30 : #define MAGE_P_NSE_DEFAULT 1.0E-03f
31 : #define VEL_I_GATE_DEFAULT 500
32 : #define POS_I_GATE_DEFAULT 500
33 : #define HGT_I_GATE_DEFAULT 500
34 : #define MAG_I_GATE_DEFAULT 300
35 : #define MAG_CAL_DEFAULT 3
36 : #define GLITCH_RADIUS_DEFAULT 25
37 : #define FLOW_MEAS_DELAY 10
38 : #define FLOW_M_NSE_DEFAULT 0.25f
39 : #define FLOW_I_GATE_DEFAULT 300
40 : #define CHECK_SCALER_DEFAULT 100
41 : #define FLOW_USE_DEFAULT 1
42 :
43 : #elif APM_BUILD_TYPE(APM_BUILD_Rover)
44 : // rover defaults
45 : #define VELNE_M_NSE_DEFAULT 0.5f
46 : #define VELD_M_NSE_DEFAULT 0.7f
47 : #define POSNE_M_NSE_DEFAULT 1.0f
48 : #define ALT_M_NSE_DEFAULT 3.0f
49 : #define MAG_M_NSE_DEFAULT 0.05f
50 : #define GYRO_P_NSE_DEFAULT 3.0E-02f
51 : #define ACC_P_NSE_DEFAULT 6.0E-01f
52 : #define GBIAS_P_NSE_DEFAULT 1.0E-04f
53 : #define GSCALE_P_NSE_DEFAULT 5.0E-04f
54 : #define ABIAS_P_NSE_DEFAULT 5.0E-03f
55 : #define MAGB_P_NSE_DEFAULT 1.0E-04f
56 : #define MAGE_P_NSE_DEFAULT 1.0E-03f
57 : #define VEL_I_GATE_DEFAULT 500
58 : #define POS_I_GATE_DEFAULT 500
59 : #define HGT_I_GATE_DEFAULT 500
60 : #define MAG_I_GATE_DEFAULT 300
61 : #define MAG_CAL_DEFAULT 2
62 : #define GLITCH_RADIUS_DEFAULT 25
63 : #define FLOW_MEAS_DELAY 10
64 : #define FLOW_M_NSE_DEFAULT 0.25f
65 : #define FLOW_I_GATE_DEFAULT 300
66 : #define CHECK_SCALER_DEFAULT 100
67 : #define FLOW_USE_DEFAULT 1
68 :
69 : #elif APM_BUILD_TYPE(APM_BUILD_ArduPlane)
70 : // plane defaults
71 : #define VELNE_M_NSE_DEFAULT 0.5f
72 : #define VELD_M_NSE_DEFAULT 0.7f
73 : #define POSNE_M_NSE_DEFAULT 1.0f
74 : #define ALT_M_NSE_DEFAULT 3.0f
75 : #define MAG_M_NSE_DEFAULT 0.05f
76 : #define GYRO_P_NSE_DEFAULT 3.0E-02f
77 : #define ACC_P_NSE_DEFAULT 6.0E-01f
78 : #define GBIAS_P_NSE_DEFAULT 1.0E-04f
79 : #define GSCALE_P_NSE_DEFAULT 5.0E-04f
80 : #define ABIAS_P_NSE_DEFAULT 5.0E-03f
81 : #define MAGB_P_NSE_DEFAULT 1.0E-04f
82 : #define MAGE_P_NSE_DEFAULT 1.0E-03f
83 : #define VEL_I_GATE_DEFAULT 500
84 : #define POS_I_GATE_DEFAULT 500
85 : #define HGT_I_GATE_DEFAULT 500
86 : #define MAG_I_GATE_DEFAULT 300
87 : #define MAG_CAL_DEFAULT 0
88 : #define GLITCH_RADIUS_DEFAULT 25
89 : #define FLOW_MEAS_DELAY 10
90 : #define FLOW_M_NSE_DEFAULT 0.15f
91 : #define FLOW_I_GATE_DEFAULT 500
92 : #define CHECK_SCALER_DEFAULT 150
93 : #define FLOW_USE_DEFAULT 2
94 :
95 : #else
96 : // build type not specified, use copter defaults
97 : #define VELNE_M_NSE_DEFAULT 0.5f
98 : #define VELD_M_NSE_DEFAULT 0.7f
99 : #define POSNE_M_NSE_DEFAULT 1.0f
100 : #define ALT_M_NSE_DEFAULT 3.0f
101 : #define MAG_M_NSE_DEFAULT 0.05f
102 : #define GYRO_P_NSE_DEFAULT 3.0E-02f
103 : #define ACC_P_NSE_DEFAULT 6.0E-01f
104 : #define GBIAS_P_NSE_DEFAULT 1.0E-04f
105 : #define GSCALE_P_NSE_DEFAULT 5.0E-04f
106 : #define ABIAS_P_NSE_DEFAULT 5.0E-03f
107 : #define MAGB_P_NSE_DEFAULT 1.0E-04f
108 : #define MAGE_P_NSE_DEFAULT 1.0E-03f
109 : #define VEL_I_GATE_DEFAULT 500
110 : #define POS_I_GATE_DEFAULT 500
111 : #define HGT_I_GATE_DEFAULT 500
112 : #define MAG_I_GATE_DEFAULT 300
113 : #define MAG_CAL_DEFAULT 3
114 : #define GLITCH_RADIUS_DEFAULT 25
115 : #define FLOW_MEAS_DELAY 10
116 : #define FLOW_M_NSE_DEFAULT 0.25f
117 : #define FLOW_I_GATE_DEFAULT 300
118 : #define CHECK_SCALER_DEFAULT 100
119 : #define FLOW_USE_DEFAULT 1
120 :
121 : #endif // APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_Replay)
122 :
123 : // This allows boards to default to using a specified number of IMUs and EKF lanes
124 : #ifndef HAL_EKF_IMU_MASK_DEFAULT
125 : #define HAL_EKF_IMU_MASK_DEFAULT 3 // Default to using two IMUs
126 : #endif
127 :
128 : extern const AP_HAL::HAL& hal;
129 :
130 : // Define tuning parameters
131 : const AP_Param::GroupInfo NavEKF2::var_info[] = {
132 :
133 : // @Param: ENABLE
134 : // @DisplayName: Enable EKF2
135 : // @Description: This enables EKF2. Enabling EKF2 only makes the maths run, it does not mean it will be used for flight control. To use it for flight control set AHRS_EKF_TYPE=2. A reboot or restart will need to be performed after changing the value of EK2_ENABLE for it to take effect.
136 : // @Values: 0:Disabled, 1:Enabled
137 : // @User: Advanced
138 : // @RebootRequired: True
139 : AP_GROUPINFO_FLAGS("ENABLE", 0, NavEKF2, _enable, 0, AP_PARAM_FLAG_ENABLE),
140 :
141 : // GPS measurement parameters
142 :
143 : // @Param: GPS_TYPE
144 : // @DisplayName: GPS mode control
145 : // @Description: This controls use of GPS measurements : 0 = use 3D velocity & 2D position, 1 = use 2D velocity and 2D position, 2 = use 2D position, 3 = Inhibit GPS use - this can be useful when flying with an optical flow sensor in an environment where GPS quality is poor and subject to large multipath errors.
146 : // @Values: 0:GPS 3D Vel and 2D Pos, 1:GPS 2D vel and 2D pos, 2:GPS 2D pos, 3:No GPS
147 : // @User: Advanced
148 : AP_GROUPINFO("GPS_TYPE", 1, NavEKF2, _fusionModeGPS, 0),
149 :
150 : // @Param: VELNE_M_NSE
151 : // @DisplayName: GPS horizontal velocity measurement noise (m/s)
152 : // @Description: This sets a lower limit on the speed accuracy reported by the GPS receiver that is used to set horizontal velocity observation noise. If the model of receiver used does not provide a speed accurcy estimate, then the parameter value will be used. Increasing it reduces the weighting of the GPS horizontal velocity measurements.
153 : // @Range: 0.05 5.0
154 : // @Increment: 0.05
155 : // @User: Advanced
156 : // @Units: m/s
157 : AP_GROUPINFO("VELNE_M_NSE", 2, NavEKF2, _gpsHorizVelNoise, VELNE_M_NSE_DEFAULT),
158 :
159 : // @Param: VELD_M_NSE
160 : // @DisplayName: GPS vertical velocity measurement noise (m/s)
161 : // @Description: This sets a lower limit on the speed accuracy reported by the GPS receiver that is used to set vertical velocity observation noise. If the model of receiver used does not provide a speed accurcy estimate, then the parameter value will be used. Increasing it reduces the weighting of the GPS vertical velocity measurements.
162 : // @Range: 0.05 5.0
163 : // @Increment: 0.05
164 : // @User: Advanced
165 : // @Units: m/s
166 : AP_GROUPINFO("VELD_M_NSE", 3, NavEKF2, _gpsVertVelNoise, VELD_M_NSE_DEFAULT),
167 :
168 : // @Param: VEL_I_GATE
169 : // @DisplayName: GPS velocity innovation gate size
170 : // @Description: This sets the percentage number of standard deviations applied to the GPS velocity measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
171 : // @Range: 100 1000
172 : // @Increment: 25
173 : // @User: Advanced
174 : AP_GROUPINFO("VEL_I_GATE", 4, NavEKF2, _gpsVelInnovGate, VEL_I_GATE_DEFAULT),
175 :
176 : // @Param: POSNE_M_NSE
177 : // @DisplayName: GPS horizontal position measurement noise (m)
178 : // @Description: This sets the GPS horizontal position observation noise. Increasing it reduces the weighting of GPS horizontal position measurements.
179 : // @Range: 0.1 10.0
180 : // @Increment: 0.1
181 : // @User: Advanced
182 : // @Units: m
183 : AP_GROUPINFO("POSNE_M_NSE", 5, NavEKF2, _gpsHorizPosNoise, POSNE_M_NSE_DEFAULT),
184 :
185 : // @Param: POS_I_GATE
186 : // @DisplayName: GPS position measurement gate size
187 : // @Description: This sets the percentage number of standard deviations applied to the GPS position measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
188 : // @Range: 100 1000
189 : // @Increment: 25
190 : // @User: Advanced
191 : AP_GROUPINFO("POS_I_GATE", 6, NavEKF2, _gpsPosInnovGate, POS_I_GATE_DEFAULT),
192 :
193 : // @Param: GLITCH_RAD
194 : // @DisplayName: GPS glitch radius gate size (m)
195 : // @Description: This controls the maximum radial uncertainty in position between the value predicted by the filter and the value measured by the GPS before the filter position and velocity states are reset to the GPS. Making this value larger allows the filter to ignore larger GPS glitches but also means that non-GPS errors such as IMU and compass can create a larger error in position before the filter is forced back to the GPS position.
196 : // @Range: 10 100
197 : // @Increment: 5
198 : // @User: Advanced
199 : // @Units: m
200 : AP_GROUPINFO("GLITCH_RAD", 7, NavEKF2, _gpsGlitchRadiusMax, GLITCH_RADIUS_DEFAULT),
201 :
202 : // 8 was used for GPS_DELAY
203 :
204 : // Height measurement parameters
205 :
206 : // @Param: ALT_SOURCE
207 : // @DisplayName: Primary altitude sensor source
208 : // @Description: Primary height sensor used by the EKF. If a sensor other than Baro is selected and becomes unavailable, then the Baro sensor will be used as a fallback. NOTE: The EK2_RNG_USE_HGT parameter can be used to switch to range-finder when close to the ground in conjunction with EK2_ALT_SOURCE = 0 or 2 (Baro or GPS).
209 : // @Values: 0:Use Baro, 1:Use Range Finder, 2:Use GPS, 3:Use Range Beacon
210 : // @User: Advanced
211 : // @RebootRequired: True
212 : AP_GROUPINFO("ALT_SOURCE", 9, NavEKF2, _altSource, 0),
213 :
214 : // @Param: ALT_M_NSE
215 : // @DisplayName: Altitude measurement noise (m)
216 : // @Description: This is the RMS value of noise in the altitude measurement. Increasing it reduces the weighting of the baro measurement and will make the filter respond more slowly to baro measurement errors, but will make it more sensitive to GPS and accelerometer errors.
217 : // @Range: 0.1 10.0
218 : // @Increment: 0.1
219 : // @User: Advanced
220 : // @Units: m
221 : AP_GROUPINFO("ALT_M_NSE", 10, NavEKF2, _baroAltNoise, ALT_M_NSE_DEFAULT),
222 :
223 : // @Param: HGT_I_GATE
224 : // @DisplayName: Height measurement gate size
225 : // @Description: This sets the percentage number of standard deviations applied to the height measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
226 : // @Range: 100 1000
227 : // @Increment: 25
228 : // @User: Advanced
229 : AP_GROUPINFO("HGT_I_GATE", 11, NavEKF2, _hgtInnovGate, HGT_I_GATE_DEFAULT),
230 :
231 : // @Param: HGT_DELAY
232 : // @DisplayName: Height measurement delay (msec)
233 : // @Description: This is the number of msec that the Height measurements lag behind the inertial measurements.
234 : // @Range: 0 250
235 : // @Increment: 10
236 : // @User: Advanced
237 : // @Units: ms
238 : // @RebootRequired: True
239 : AP_GROUPINFO("HGT_DELAY", 12, NavEKF2, _hgtDelay_ms, 60),
240 :
241 : // Magnetometer measurement parameters
242 :
243 : // @Param: MAG_M_NSE
244 : // @DisplayName: Magnetometer measurement noise (Gauss)
245 : // @Description: This is the RMS value of noise in magnetometer measurements. Increasing it reduces the weighting on these measurements.
246 : // @Range: 0.01 0.5
247 : // @Increment: 0.01
248 : // @User: Advanced
249 : // @Units: Gauss
250 : AP_GROUPINFO("MAG_M_NSE", 13, NavEKF2, _magNoise, MAG_M_NSE_DEFAULT),
251 :
252 : // @Param: MAG_CAL
253 : // @DisplayName: Magnetometer default fusion mode
254 : // @Description: This determines when the filter will use the 3-axis magnetometer fusion model that estimates both earth and body fixed magnetic field states, when it will use a simpler magnetic heading fusion model that does not use magnetic field states and when it will use an alternative method of yaw determination to the magnetometer. The 3-axis magnetometer fusion is only suitable for use when the external magnetic field environment is stable. EK2_MAG_CAL = 0 uses heading fusion on ground, 3-axis fusion in-flight, and is the default setting for Plane users. EK2_MAG_CAL = 1 uses 3-axis fusion only when manoeuvring. EK2_MAG_CAL = 2 uses heading fusion at all times, is recommended if the external magnetic field is varying and is the default for rovers. EK2_MAG_CAL = 3 uses heading fusion on the ground and 3-axis fusion after the first in-air field and yaw reset has completed, and is the default for copters. EK2_MAG_CAL = 4 uses 3-axis fusion at all times. NOTE: The fusion mode can be forced to 2 for specific EKF cores using the EK2_MAG_MASK parameter. NOTE: limited operation without a magnetometer or any other yaw sensor is possible by setting all COMPASS_USE, COMPASS_USE2, COMPASS_USE3, etc parameters to 0 with COMPASS_ENABLE set to 1. If this is done, the EK2_GSF_RUN and EK2_GSF_USE masks must be set to the same as EK2_IMU_MASK.
255 : // @Values: 0:When flying,1:When manoeuvring,2:Never,3:After first climb yaw reset,4:Always
256 : // @User: Advanced
257 : AP_GROUPINFO("MAG_CAL", 14, NavEKF2, _magCal, MAG_CAL_DEFAULT),
258 :
259 : // @Param: MAG_I_GATE
260 : // @DisplayName: Magnetometer measurement gate size
261 : // @Description: This sets the percentage number of standard deviations applied to the magnetometer measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
262 : // @Range: 100 1000
263 : // @Increment: 25
264 : // @User: Advanced
265 : AP_GROUPINFO("MAG_I_GATE", 15, NavEKF2, _magInnovGate, MAG_I_GATE_DEFAULT),
266 :
267 : // Airspeed measurement parameters
268 :
269 : // @Param: EAS_M_NSE
270 : // @DisplayName: Equivalent airspeed measurement noise (m/s)
271 : // @Description: This is the RMS value of noise in equivalent airspeed measurements used by planes. Increasing it reduces the weighting of airspeed measurements and will make wind speed estimates less noisy and slower to converge. Increasing also increases navigation errors when dead-reckoning without GPS measurements.
272 : // @Range: 0.5 5.0
273 : // @Increment: 0.1
274 : // @User: Advanced
275 : // @Units: m/s
276 : AP_GROUPINFO("EAS_M_NSE", 16, NavEKF2, _easNoise, 1.4f),
277 :
278 : // @Param: EAS_I_GATE
279 : // @DisplayName: Airspeed measurement gate size
280 : // @Description: This sets the percentage number of standard deviations applied to the airspeed measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
281 : // @Range: 100 1000
282 : // @Increment: 25
283 : // @User: Advanced
284 : AP_GROUPINFO("EAS_I_GATE", 17, NavEKF2, _tasInnovGate, 400),
285 :
286 : // Rangefinder measurement parameters
287 :
288 : // @Param: RNG_M_NSE
289 : // @DisplayName: Range finder measurement noise (m)
290 : // @Description: This is the RMS value of noise in the range finder measurement. Increasing it reduces the weighting on this measurement.
291 : // @Range: 0.1 10.0
292 : // @Increment: 0.1
293 : // @User: Advanced
294 : // @Units: m
295 : AP_GROUPINFO("RNG_M_NSE", 18, NavEKF2, _rngNoise, 0.5f),
296 :
297 : // @Param: RNG_I_GATE
298 : // @DisplayName: Range finder measurement gate size
299 : // @Description: This sets the percentage number of standard deviations applied to the range finder innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
300 : // @Range: 100 1000
301 : // @Increment: 25
302 : // @User: Advanced
303 : AP_GROUPINFO("RNG_I_GATE", 19, NavEKF2, _rngInnovGate, 500),
304 :
305 : // Optical flow measurement parameters
306 :
307 : // @Param: MAX_FLOW
308 : // @DisplayName: Maximum valid optical flow rate
309 : // @Description: This sets the magnitude maximum optical flow rate in rad/sec that will be accepted by the filter
310 : // @Range: 1.0 4.0
311 : // @Increment: 0.1
312 : // @User: Advanced
313 : // @Units: rad/s
314 : AP_GROUPINFO("MAX_FLOW", 20, NavEKF2, _maxFlowRate, 2.5f),
315 :
316 : // @Param: FLOW_M_NSE
317 : // @DisplayName: Optical flow measurement noise (rad/s)
318 : // @Description: This is the RMS value of noise and errors in optical flow measurements. Increasing it reduces the weighting on these measurements.
319 : // @Range: 0.05 1.0
320 : // @Increment: 0.05
321 : // @User: Advanced
322 : // @Units: rad/s
323 : AP_GROUPINFO("FLOW_M_NSE", 21, NavEKF2, _flowNoise, FLOW_M_NSE_DEFAULT),
324 :
325 : // @Param: FLOW_I_GATE
326 : // @DisplayName: Optical Flow measurement gate size
327 : // @Description: This sets the percentage number of standard deviations applied to the optical flow innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
328 : // @Range: 100 1000
329 : // @Increment: 25
330 : // @User: Advanced
331 : AP_GROUPINFO("FLOW_I_GATE", 22, NavEKF2, _flowInnovGate, FLOW_I_GATE_DEFAULT),
332 :
333 : // @Param: FLOW_DELAY
334 : // @DisplayName: Optical Flow measurement delay (msec)
335 : // @Description: This is the number of msec that the optical flow measurements lag behind the inertial measurements. It is the time from the end of the optical flow averaging period and does not include the time delay due to the 100msec of averaging within the flow sensor.
336 : // @Range: 0 127
337 : // @Increment: 10
338 : // @User: Advanced
339 : // @Units: ms
340 : // @RebootRequired: True
341 : AP_GROUPINFO("FLOW_DELAY", 23, NavEKF2, _flowDelay_ms, FLOW_MEAS_DELAY),
342 :
343 : // State and Covariance Predition Parameters
344 :
345 : // @Param: GYRO_P_NSE
346 : // @DisplayName: Rate gyro noise (rad/s)
347 : // @Description: This control disturbance noise controls the growth of estimated error due to gyro measurement errors excluding bias. Increasing it makes the flter trust the gyro measurements less and other measurements more.
348 : // @Range: 0.0001 0.1
349 : // @Increment: 0.0001
350 : // @User: Advanced
351 : // @Units: rad/s
352 : AP_GROUPINFO("GYRO_P_NSE", 24, NavEKF2, _gyrNoise, GYRO_P_NSE_DEFAULT),
353 :
354 : // @Param: ACC_P_NSE
355 : // @DisplayName: Accelerometer noise (m/s^2)
356 : // @Description: This control disturbance noise controls the growth of estimated error due to accelerometer measurement errors excluding bias. Increasing it makes the flter trust the accelerometer measurements less and other measurements more.
357 : // @Range: 0.01 1.0
358 : // @Increment: 0.01
359 : // @User: Advanced
360 : // @Units: m/s/s
361 : AP_GROUPINFO("ACC_P_NSE", 25, NavEKF2, _accNoise, ACC_P_NSE_DEFAULT),
362 :
363 : // @Param: GBIAS_P_NSE
364 : // @DisplayName: Rate gyro bias stability (rad/s/s)
365 : // @Description: This state process noise controls growth of the gyro delta angle bias state error estimate. Increasing it makes rate gyro bias estimation faster and noisier.
366 : // @Range: 0.00001 0.001
367 : // @User: Advanced
368 : // @Units: rad/s/s
369 : AP_GROUPINFO("GBIAS_P_NSE", 26, NavEKF2, _gyroBiasProcessNoise, GBIAS_P_NSE_DEFAULT),
370 :
371 : // @Param: GSCL_P_NSE
372 : // @DisplayName: Rate gyro scale factor stability (1/s)
373 : // @Description: This noise controls the rate of gyro scale factor learning. Increasing it makes rate gyro scale factor estimation faster and noisier.
374 : // @Range: 0.000001 0.001
375 : // @User: Advanced
376 : // @Units: Hz
377 : AP_GROUPINFO("GSCL_P_NSE", 27, NavEKF2, _gyroScaleProcessNoise, GSCALE_P_NSE_DEFAULT),
378 :
379 : // @Param: ABIAS_P_NSE
380 : // @DisplayName: Accelerometer bias stability (m/s^3)
381 : // @Description: This noise controls the growth of the vertical accelerometer delta velocity bias state error estimate. Increasing it makes accelerometer bias estimation faster and noisier.
382 : // @Range: 0.00001 0.005
383 : // @User: Advanced
384 : // @Units: m/s/s/s
385 : AP_GROUPINFO("ABIAS_P_NSE", 28, NavEKF2, _accelBiasProcessNoise, ABIAS_P_NSE_DEFAULT),
386 :
387 : // 29 previously used for EK2_MAG_P_NSE parameter that has been replaced with EK2_MAGE_P_NSE and EK2_MAGB_P_NSE
388 :
389 : // @Param: WIND_P_NSE
390 : // @DisplayName: Wind velocity process noise (m/s^2)
391 : // @Description: This state process noise controls the growth of wind state error estimates. Increasing it makes wind estimation faster and noisier.
392 : // @Range: 0.01 1.0
393 : // @Increment: 0.1
394 : // @User: Advanced
395 : // @Units: m/s/s
396 : AP_GROUPINFO("WIND_P_NSE", 30, NavEKF2, _windVelProcessNoise, 0.1f),
397 :
398 : // @Param: WIND_PSCALE
399 : // @DisplayName: Height rate to wind process noise scaler
400 : // @Description: This controls how much the process noise on the wind states is increased when gaining or losing altitude to take into account changes in wind speed and direction with altitude. Increasing this parameter increases how rapidly the wind states adapt when changing altitude, but does make wind velocity estimation noiser.
401 : // @Range: 0.0 1.0
402 : // @Increment: 0.1
403 : // @User: Advanced
404 : AP_GROUPINFO("WIND_PSCALE", 31, NavEKF2, _wndVarHgtRateScale, 0.5f),
405 :
406 : // @Param: GPS_CHECK
407 : // @DisplayName: GPS preflight check
408 : // @Description: This is a 1 byte bitmap controlling which GPS preflight checks are performed. Set to 0 to bypass all checks. Set to 255 perform all checks. Set to 3 to check just the number of satellites and HDoP. Set to 31 for the most rigorous checks that will still allow checks to pass when the copter is moving, eg launch from a boat.
409 : // @Bitmask: 0:NSats,1:HDoP,2:speed error,3:position error,4:yaw error,5:pos drift,6:vert speed,7:horiz speed
410 : // @User: Advanced
411 : AP_GROUPINFO("GPS_CHECK", 32, NavEKF2, _gpsCheck, 31),
412 :
413 : // @Param: IMU_MASK
414 : // @DisplayName: Bitmask of active IMUs
415 : // @Description: 1 byte bitmap of IMUs to use in EKF2. A separate instance of EKF2 will be started for each IMU selected. Set to 1 to use the first IMU only (default), set to 2 to use the second IMU only, set to 3 to use the first and second IMU. Additional IMU's can be used up to a maximum of 6 if memory and processing resources permit. There may be insufficient memory and processing resources to run multiple instances. If this occurs EKF2 will fail to start.
416 : // @Bitmask: 0:FirstIMU,1:SecondIMU,2:ThirdIMU,3:FourthIMU,4:FifthIMU,5:SixthIMU
417 : // @User: Advanced
418 : // @RebootRequired: True
419 : AP_GROUPINFO("IMU_MASK", 33, NavEKF2, _imuMask, HAL_EKF_IMU_MASK_DEFAULT),
420 :
421 : // @Param: CHECK_SCALE
422 : // @DisplayName: GPS accuracy check scaler (%)
423 : // @Description: This scales the thresholds that are used to check GPS accuracy before it is used by the EKF. A value of 100 is the default. Values greater than 100 increase and values less than 100 reduce the maximum GPS error the EKF will accept. A value of 200 will double the allowable GPS error.
424 : // @Range: 50 200
425 : // @User: Advanced
426 : // @Units: %
427 : AP_GROUPINFO("CHECK_SCALE", 34, NavEKF2, _gpsCheckScaler, CHECK_SCALER_DEFAULT),
428 :
429 : // @Param: NOAID_M_NSE
430 : // @DisplayName: Non-GPS operation position uncertainty (m)
431 : // @Description: This sets the amount of position variation that the EKF allows for when operating without external measurements (eg GPS or optical flow). Increasing this parameter makes the EKF attitude estimate less sensitive to vehicle manoeuvres but more sensitive to IMU errors.
432 : // @Range: 0.5 50.0
433 : // @User: Advanced
434 : // @Units: m
435 : AP_GROUPINFO("NOAID_M_NSE", 35, NavEKF2, _noaidHorizNoise, 10.0f),
436 :
437 : // 36 was LOG_MASK, used for specifying which IMUs/cores to log
438 : // replay data for
439 :
440 : // control of magnetic yaw angle fusion
441 :
442 : // @Param: YAW_M_NSE
443 : // @DisplayName: Yaw measurement noise (rad)
444 : // @Description: This is the RMS value of noise in yaw measurements from the magnetometer. Increasing it reduces the weighting on these measurements.
445 : // @Range: 0.05 1.0
446 : // @Increment: 0.05
447 : // @User: Advanced
448 : // @Units: rad
449 : AP_GROUPINFO("YAW_M_NSE", 37, NavEKF2, _yawNoise, 0.5f),
450 :
451 : // @Param: YAW_I_GATE
452 : // @DisplayName: Yaw measurement gate size
453 : // @Description: This sets the percentage number of standard deviations applied to the magnetometer yaw measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
454 : // @Range: 100 1000
455 : // @Increment: 25
456 : // @User: Advanced
457 : AP_GROUPINFO("YAW_I_GATE", 38, NavEKF2, _yawInnovGate, 300),
458 :
459 : // @Param: TAU_OUTPUT
460 : // @DisplayName: Output complementary filter time constant (centi-sec)
461 : // @Description: Sets the time constant of the output complementary filter/predictor in centi-seconds.
462 : // @Range: 10 50
463 : // @Increment: 5
464 : // @User: Advanced
465 : // @Units: cs
466 : AP_GROUPINFO("TAU_OUTPUT", 39, NavEKF2, _tauVelPosOutput, 25),
467 :
468 : // @Param: MAGE_P_NSE
469 : // @DisplayName: Earth magnetic field process noise (gauss/s)
470 : // @Description: This state process noise controls the growth of earth magnetic field state error estimates. Increasing it makes earth magnetic field estimation faster and noisier.
471 : // @Range: 0.00001 0.01
472 : // @User: Advanced
473 : // @Units: Gauss/s
474 : AP_GROUPINFO("MAGE_P_NSE", 40, NavEKF2, _magEarthProcessNoise, MAGE_P_NSE_DEFAULT),
475 :
476 : // @Param: MAGB_P_NSE
477 : // @DisplayName: Body magnetic field process noise (gauss/s)
478 : // @Description: This state process noise controls the growth of body magnetic field state error estimates. Increasing it makes magnetometer bias error estimation faster and noisier.
479 : // @Range: 0.00001 0.01
480 : // @User: Advanced
481 : // @Units: Gauss/s
482 : AP_GROUPINFO("MAGB_P_NSE", 41, NavEKF2, _magBodyProcessNoise, MAGB_P_NSE_DEFAULT),
483 :
484 : // @Param: RNG_USE_HGT
485 : // @DisplayName: Range finder switch height percentage
486 : // @Description: Range finder can be used as the primary height source when below this percentage of its maximum range (see RNGFND*_MAX). This will not work unless Baro or GPS height is selected as the primary height source vis EK2_ALT_SOURCE = 0 or 2 respectively. This feature should not be used for terrain following as it is designed for vertical takeoff and landing with climb above the range finder use height before commencing the mission, and with horizontal position changes below that height being limited to a flat region around the takeoff and landing point.
487 : // @Range: -1 70
488 : // @Increment: 1
489 : // @User: Advanced
490 : // @Units: %
491 : AP_GROUPINFO("RNG_USE_HGT", 42, NavEKF2, _useRngSwHgt, -1),
492 :
493 : // @Param: TERR_GRAD
494 : // @DisplayName: Maximum terrain gradient
495 : // @Description: Specifies the maximum gradient of the terrain below the vehicle assumed when it is fusing range finder or optical flow to estimate terrain height.
496 : // @Range: 0 0.2
497 : // @Increment: 0.01
498 : // @User: Advanced
499 : AP_GROUPINFO("TERR_GRAD", 43, NavEKF2, _terrGradMax, 0.1f),
500 :
501 : // @Param: BCN_M_NSE
502 : // @DisplayName: Range beacon measurement noise (m)
503 : // @Description: This is the RMS value of noise in the range beacon measurement. Increasing it reduces the weighting on this measurement.
504 : // @Range: 0.1 10.0
505 : // @Increment: 0.1
506 : // @User: Advanced
507 : // @Units: m
508 : AP_GROUPINFO("BCN_M_NSE", 44, NavEKF2, _rngBcnNoise, 1.0f),
509 :
510 : // @Param: BCN_I_GTE
511 : // @DisplayName: Range beacon measurement gate size
512 : // @Description: This sets the percentage number of standard deviations applied to the range beacon measurement innovation consistency check. Decreasing it makes it more likely that good measurements will be rejected. Increasing it makes it more likely that bad measurements will be accepted.
513 : // @Range: 100 1000
514 : // @Increment: 25
515 : // @User: Advanced
516 : AP_GROUPINFO("BCN_I_GTE", 45, NavEKF2, _rngBcnInnovGate, 500),
517 :
518 : // @Param: BCN_DELAY
519 : // @DisplayName: Range beacon measurement delay (msec)
520 : // @Description: This is the number of msec that the range beacon measurements lag behind the inertial measurements. It is the time from the end of the optical flow averaging period and does not include the time delay due to the 100msec of averaging within the flow sensor.
521 : // @Range: 0 127
522 : // @Increment: 10
523 : // @User: Advanced
524 : // @Units: ms
525 : // @RebootRequired: True
526 : AP_GROUPINFO("BCN_DELAY", 46, NavEKF2, _rngBcnDelay_ms, 50),
527 :
528 : // @Param: RNG_USE_SPD
529 : // @DisplayName: Range finder max ground speed
530 : // @Description: The range finder will not be used as the primary height source when the horizontal ground speed is greater than this value.
531 : // @Range: 2.0 6.0
532 : // @Increment: 0.5
533 : // @User: Advanced
534 : // @Units: m/s
535 : AP_GROUPINFO("RNG_USE_SPD", 47, NavEKF2, _useRngSwSpd, 2.0f),
536 :
537 : // @Param: MAG_MASK
538 : // @DisplayName: Bitmask of active EKF cores that will always use heading fusion
539 : // @Description: 1 byte bitmap of EKF cores that will disable magnetic field states and use simple magnetic heading fusion at all times. This parameter enables specified cores to be used as a backup for flight into an environment with high levels of external magnetic interference which may degrade the EKF attitude estimate when using 3-axis magnetometer fusion. NOTE : Use of a different magnetometer fusion algorithm on different cores makes unwanted EKF core switches due to magnetometer errors more likely.
540 : // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
541 : // @User: Advanced
542 : // @RebootRequired: True
543 : AP_GROUPINFO("MAG_MASK", 48, NavEKF2, _magMask, 0),
544 :
545 : // @Param: OGN_HGT_MASK
546 : // @DisplayName: Bitmask control of EKF reference height correction
547 : // @Description: When a height sensor other than GPS is used as the primary height source by the EKF, the position of the zero height datum is defined by that sensor and its frame of reference. If a GPS height measurement is also available, then the height of the WGS-84 height datum used by the EKF can be corrected so that the height returned by the getLLH() function is compensated for primary height sensor drift and change in datum over time. The first two bit positions control when the height datum will be corrected. Correction is performed using a Bayes filter and only operates when GPS quality permits. The third bit position controls where the corrections to the GPS reference datum are applied. Corrections can be applied to the local vertical position or to the reported EKF origin height (default).
548 : // @Bitmask: 0:Correct when using Baro height,1:Correct when using range finder height,2:Apply corrections to local position
549 : // @User: Advanced
550 : // @RebootRequired: True
551 : AP_GROUPINFO("OGN_HGT_MASK", 49, NavEKF2, _originHgtMode, 0),
552 :
553 : // EXTNAV_DELAY was 50
554 :
555 : // @Param: FLOW_USE
556 : // @DisplayName: Optical flow use bitmask
557 : // @Description: Controls if the optical flow data is fused into the 24-state navigation estimator OR the 1-state terrain height estimator.
558 : // @User: Advanced
559 : // @Values: 0:None,1:Navigation,2:Terrain
560 : // @RebootRequired: True
561 : AP_GROUPINFO("FLOW_USE", 51, NavEKF2, _flowUse, FLOW_USE_DEFAULT),
562 :
563 : // @Param: MAG_EF_LIM
564 : // @DisplayName: EarthField error limit
565 : // @Description: This limits the difference between the learned earth magnetic field and the earth field from the world magnetic model tables. A value of zero means to disable the use of the WMM tables.
566 : // @User: Advanced
567 : // @Range: 0 500
568 : // @Units: mGauss
569 : AP_GROUPINFO("MAG_EF_LIM", 52, NavEKF2, _mag_ef_limit, 50),
570 :
571 : // @Param: HRT_FILT
572 : // @DisplayName: Height rate filter crossover frequency
573 : // @Description: Specifies the crossover frequency of the complementary filter used to calculate the output predictor height rate derivative.
574 : // @Range: 0.1 30.0
575 : // @Units: Hz
576 : AP_GROUPINFO("HRT_FILT", 53, NavEKF2, _hrt_filt_freq, 2.0f),
577 :
578 : // @Param: GSF_RUN_MASK
579 : // @DisplayName: Bitmask of which EKF-GSF yaw estimators run
580 : // @Description: A bitmask of which EKF2 instances run an independant EKF-GSF yaw estimator to provide a backup yaw estimate that doesn't rely on magnetometer data. This estimator uses IMU, GPS and, if available, airspeed data. EKF-GSF yaw estimator data for the primary EKF2 instance will be logged as GSF0 and GSF1 messages. Use of the yaw estimate generated by this algorithm is controlled by the EK2_GSF_USE_MASK and EK2_GSF_RST_MAX parameters. To run the EKF-GSF yaw estimator in ride-along and logging only, set EK2_GSF_USE_MASK to 0.
581 : // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
582 : // @User: Advanced
583 : // @RebootRequired: True
584 : AP_GROUPINFO("GSF_RUN_MASK", 54, NavEKF2, _gsfRunMask, 3),
585 :
586 : // @Param: GSF_USE_MASK
587 : // @DisplayName: Bitmask of which EKF-GSF yaw estimators are used
588 : // @Description: 1 byte bitmap of which EKF2 instances will use the output from the EKF-GSF yaw estimator that has been turned on by the EK2_GSF_RUN_MASK parameter. If the inertial navigation calculation stops following the GPS, then the vehicle code can request EKF2 to attempt to resolve the issue, either by performing a yaw reset if enabled by this parameter by switching to another EKF2 instance.
589 : // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
590 : // @User: Advanced
591 : // @RebootRequired: True
592 : AP_GROUPINFO("GSF_USE_MASK", 55, NavEKF2, _gsfUseMask, 3),
593 :
594 : // 56 was GSF_DELAY which was never released in a stable version
595 :
596 : // @Param: GSF_RST_MAX
597 : // @DisplayName: Maximum number of resets to the EKF-GSF yaw estimate allowed
598 : // @Description: Sets the maximum number of times the EKF2 will be allowed to reset its yaw to the estimate from the EKF-GSF yaw estimator. No resets will be allowed unless the use of the EKF-GSF yaw estimate is enabled via the EK2_GSF_USE_MASK parameter.
599 : // @Range: 1 10
600 : // @Increment: 1
601 : // @User: Advanced
602 : // @RebootRequired: True
603 : AP_GROUPINFO("GSF_RST_MAX", 57, NavEKF2, _gsfResetMaxCount, 2),
604 :
605 : // @Param: OPTIONS
606 : // @DisplayName: Optional EKF behaviour
607 : // @Description: optional EKF2 behaviour. Disabling external navigation prevents use of external vision data in the EKF2 solution
608 : // @Bitmask: 0:DisableExternalNavigation
609 : // @User: Advanced
610 : AP_GROUPINFO("OPTIONS", 58, NavEKF2, _options, 0),
611 :
612 : AP_GROUPEND
613 : };
614 :
615 2145 : NavEKF2::NavEKF2()
616 : {
617 2145 : AP_Param::setup_object_defaults(this, var_info);
618 2145 : }
619 :
620 :
621 : // Initialise the filter
622 39049668 : bool NavEKF2::InitialiseFilter(void)
623 : {
624 39049668 : AP::dal().start_frame(AP_DAL::FrameType::InitialiseFilterEKF2);
625 :
626 : // Return immediately if there is insufficient memory
627 39049668 : if (core_malloc_failed) {
628 : return false;
629 : }
630 :
631 39049668 : initFailure = InitFailures::UNKNOWN;
632 39049668 : if (_enable == 0) {
633 38945869 : if (AP::dal().configured_ekf_type() == 2) {
634 96405 : initFailure = InitFailures::NO_ENABLE;
635 : }
636 38945869 : return false;
637 : }
638 103799 : const auto &ins = AP::dal().ins();
639 :
640 103799 : imuSampleTime_us = AP::dal().micros64();
641 :
642 : // remember expected frame time
643 103799 : const float loop_rate = ins.get_loop_rate_hz();
644 103799 : if (!is_positive(loop_rate)) {
645 : return false;
646 : }
647 103799 : _frameTimeUsec = 1e6 / loop_rate;
648 :
649 : // expected number of IMU frames per prediction
650 103799 : _framesPerPrediction = uint8_t((EKF_TARGET_DT / (_frameTimeUsec * 1.0e-6) + 0.5));
651 :
652 103799 : if (core == nullptr) {
653 :
654 : // don't allow more filters than IMUs
655 511 : uint8_t mask = (1U<<ins.get_accel_count())-1;
656 511 : _imuMask.set_and_default(_imuMask.get() & mask);
657 :
658 : // count IMUs from mask
659 511 : num_cores = __builtin_popcount(_imuMask);
660 :
661 : // abort if num_cores is zero
662 511 : if (num_cores == 0) {
663 0 : if (ins.get_accel_count() == 0) {
664 0 : initFailure = InitFailures::NO_IMUS;
665 : } else {
666 0 : initFailure = InitFailures::NO_MASK;
667 : }
668 0 : return false;
669 : }
670 :
671 : // check if there is enough memory to create the EKF cores
672 511 : if (AP::dal().available_memory() < sizeof(NavEKF2_core)*num_cores + 4096) {
673 0 : initFailure = InitFailures::NO_MEM;
674 0 : core_malloc_failed = true;
675 0 : num_cores = 0;
676 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "NavEKF2: not enough memory available");
677 0 : return false;
678 : }
679 :
680 : // try to allocate from CCM RAM, fallback to Normal RAM if not available or full
681 511 : core = (NavEKF2_core*)AP::dal().malloc_type(sizeof(NavEKF2_core)*num_cores, AP_DAL::MemoryType::FAST);
682 511 : if (core == nullptr) {
683 0 : initFailure = InitFailures::NO_MEM;
684 0 : core_malloc_failed = true;
685 0 : num_cores = 0;
686 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "NavEKF2: memory allocation failed");
687 0 : return false;
688 : }
689 :
690 : //Call Constructors on all cores
691 1533 : for (uint8_t i = 0; i < num_cores; i++) {
692 1022 : new (&core[i]) NavEKF2_core(this);
693 : }
694 :
695 : // set the IMU index for the cores
696 511 : num_cores = 0;
697 4088 : for (uint8_t i=0; i<7; i++) {
698 3577 : if (_imuMask & (1U<<i)) {
699 1022 : if(!core[num_cores].setup_core(i, num_cores)) {
700 : // if any core setup fails, free memory, zero the core pointer and abort
701 0 : AP::dal().free_type(core, sizeof(NavEKF2_core)*num_cores, AP_DAL::MemoryType::FAST);
702 0 : core = nullptr;
703 0 : initFailure = InitFailures::NO_SETUP;
704 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "NavEKF2: core %d setup failed", num_cores);
705 0 : return false;
706 : }
707 1022 : num_cores++;
708 : }
709 : }
710 :
711 : // Set the primary initially to be the lowest index
712 511 : primary = 0;
713 : }
714 :
715 : // invalidate shared origin
716 103799 : common_origin_valid = false;
717 :
718 : // initialise the cores. We return success only if all cores
719 : // initialise successfully
720 : bool ret = true;
721 311397 : for (uint8_t i=0; i<num_cores; i++) {
722 207598 : ret &= core[i].InitialiseFilterBootstrap();
723 : }
724 :
725 : // zero the structs used capture reset events
726 103799 : memset(&yaw_reset_data, 0, sizeof(yaw_reset_data));
727 103799 : memset((void *)&pos_reset_data, 0, sizeof(pos_reset_data));
728 103799 : memset(&pos_down_reset_data, 0, sizeof(pos_down_reset_data));
729 :
730 103799 : return ret;
731 : }
732 :
733 : /*
734 : return true if a new core index has a better score than the current
735 : core
736 : */
737 40561 : bool NavEKF2::coreBetterScore(uint8_t new_core, uint8_t current_core) const
738 : {
739 40561 : const NavEKF2_core &oldCore = core[current_core];
740 40561 : const NavEKF2_core &newCore = core[new_core];
741 40561 : if (!newCore.healthy()) {
742 : // never consider a new core that isn't healthy
743 : return false;
744 : }
745 33357 : if (newCore.have_aligned_tilt() != oldCore.have_aligned_tilt()) {
746 : // tilt alignment is most critical, if one is tilt aligned and
747 : // the other isn't then use the tilt aligned lane
748 : return newCore.have_aligned_tilt();
749 : }
750 33357 : if (newCore.have_aligned_yaw() != oldCore.have_aligned_yaw()) {
751 : // yaw alignment is next most critical, if one is yaw aligned
752 : // and the other isn't then use the yaw aligned lane
753 : return newCore.have_aligned_yaw();
754 : }
755 : // if both cores are aligned then look at error scores
756 33357 : return newCore.errorScore() < oldCore.errorScore();
757 : }
758 :
759 : // Update Filter States - this should be called whenever new IMU data is available
760 2106892 : void NavEKF2::UpdateFilter(void)
761 : {
762 2106892 : AP::dal().start_frame(AP_DAL::FrameType::UpdateFilterEKF2);
763 :
764 2106892 : if (!core) {
765 0 : return;
766 : }
767 :
768 2106892 : imuSampleTime_us = AP::dal().micros64();
769 :
770 2106892 : bool statePredictEnabled[num_cores];
771 6320676 : for (uint8_t i=0; i<num_cores; i++) {
772 : // if we have not overrun by more than 3 IMU frames, and we
773 : // have already used more than 1/3 of the CPU budget for this
774 : // loop then suppress the prediction step. This allows
775 : // multiple EKF instances to cooperate on scheduling
776 8427568 : if (core[i].getFramesSincePredict() < (_framesPerPrediction+3) &&
777 4213784 : AP::dal().ekf_low_time_remaining(AP_DAL::EKFType::EKF2, i)) {
778 0 : statePredictEnabled[i] = false;
779 : } else {
780 4213784 : statePredictEnabled[i] = true;
781 : }
782 4213784 : core[i].UpdateFilter(statePredictEnabled[i]);
783 : }
784 :
785 : // If the current core selected has a bad error score or is unhealthy, switch to a healthy core with the lowest fault score
786 : // Don't start running the check until the primary core has started returned healthy for at least 10 seconds to avoid switching
787 : // due to initial alignment fluctuations and race conditions
788 2106892 : if (!runCoreSelection) {
789 : static uint64_t lastUnhealthyTime_us = 0;
790 172396 : if (!core[primary].healthy() || lastUnhealthyTime_us == 0) {
791 14594 : lastUnhealthyTime_us = imuSampleTime_us;
792 : }
793 172396 : runCoreSelection = (imuSampleTime_us - lastUnhealthyTime_us) > 1E7;
794 : }
795 2106892 : float primaryErrorScore = core[primary].errorScore();
796 2106892 : if ((primaryErrorScore > 1.0f || !core[primary].healthy()) && runCoreSelection) {
797 40560 : float lowestErrorScore = 0.67f * primaryErrorScore;
798 40560 : uint8_t newPrimaryIndex = primary; // index for new primary
799 121680 : for (uint8_t coreIndex=0; coreIndex<num_cores; coreIndex++) {
800 :
801 81120 : if (coreIndex != primary) {
802 : // an alternative core is available for selection only if healthy and if states have been updated on this time step
803 40560 : bool altCoreAvailable = statePredictEnabled[coreIndex] && coreBetterScore(coreIndex, newPrimaryIndex);
804 :
805 : // If the primary core is unhealthy and another core is available, then switch now
806 : // If the primary core is still healthy,then switching is optional and will only be done if
807 : // a core with a significantly lower error score can be found
808 40560 : float altErrorScore = core[coreIndex].errorScore();
809 40560 : if (altCoreAvailable && (!core[newPrimaryIndex].healthy() || altErrorScore < lowestErrorScore)) {
810 : newPrimaryIndex = coreIndex;
811 : lowestErrorScore = altErrorScore;
812 : }
813 : }
814 : }
815 : // update the yaw and position reset data to capture changes due to the lane switch
816 40560 : if (newPrimaryIndex != primary) {
817 6187 : updateLaneSwitchYawResetData(newPrimaryIndex);
818 6187 : updateLaneSwitchPosResetData(newPrimaryIndex);
819 6187 : updateLaneSwitchPosDownResetData(newPrimaryIndex);
820 6187 : primary = newPrimaryIndex;
821 6187 : lastLaneSwitch_ms = AP::dal().millis();
822 : }
823 : }
824 :
825 2106892 : if (primary != 0 && core[0].healthy() && !AP::dal().get_armed()) {
826 : // when on the ground and disarmed force the first lane. This
827 : // avoids us ending with with a lottery for which IMU is used
828 : // in each flight. Otherwise the alignment of the timing of
829 : // the lane updates with the timing of GPS updates can lead to
830 : // a lane other than the first one being used as primary for
831 : // some flights. As different IMUs may have quite different
832 : // noise characteristics this leads to inconsistent
833 : // performance
834 6183 : primary = 0;
835 : }
836 2106892 : }
837 :
838 : /*
839 : check if switching lanes will reduce the normalised
840 : innovations. This is called when the vehicle code is about to
841 : trigger an EKF failsafe, and it would like to avoid that by
842 : using a different EKF lane
843 : */
844 1 : void NavEKF2::checkLaneSwitch(void)
845 : {
846 1 : AP::dal().log_event2(AP_DAL::Event::checkLaneSwitch);
847 1 : const uint32_t now = AP::dal().millis();
848 1 : if (lastLaneSwitch_ms != 0 && now - lastLaneSwitch_ms < 5000) {
849 : // don't switch twice in 5 seconds
850 : return;
851 : }
852 1 : uint8_t newPrimaryIndex = primary;
853 3 : for (uint8_t coreIndex=0; coreIndex<num_cores; coreIndex++) {
854 2 : if (coreIndex != primary) {
855 1 : const NavEKF2_core &newCore = core[coreIndex];
856 : // an alternative core is available for selection only if healthy and if states have been updated on this time step
857 1 : bool altCoreAvailable = coreBetterScore(coreIndex, newPrimaryIndex);
858 1 : if (altCoreAvailable && newCore.errorScore() < 0.9) {
859 : newPrimaryIndex = coreIndex;
860 : }
861 : }
862 : }
863 :
864 : // update the yaw and position reset data to capture changes due to the lane switch
865 1 : if (newPrimaryIndex != primary) {
866 0 : updateLaneSwitchYawResetData(newPrimaryIndex);
867 0 : updateLaneSwitchPosResetData(newPrimaryIndex);
868 0 : updateLaneSwitchPosDownResetData(newPrimaryIndex);
869 0 : primary = newPrimaryIndex;
870 0 : lastLaneSwitch_ms = now;
871 0 : GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "NavEKF2: lane switch %u", primary);
872 : }
873 : }
874 :
875 : // Check basic filter health metrics and return a consolidated health status
876 2106892 : bool NavEKF2::healthy(void) const
877 : {
878 2106892 : if (!core) {
879 : return false;
880 : }
881 2106892 : return core[primary].healthy();
882 : }
883 :
884 : // returns false if we fail arming checks, in which case the buffer will be populated with a failure message
885 80 : bool NavEKF2::pre_arm_check(char *failure_msg, uint8_t failure_msg_len) const
886 : {
887 80 : if (!core) {
888 0 : AP::dal().snprintf(failure_msg, failure_msg_len, "no EKF2 cores");
889 0 : return false;
890 : }
891 240 : for (uint8_t i = 0; i < num_cores; i++) {
892 160 : if (!core[i].healthy()) {
893 0 : const char *failure = core[i].prearm_failure_reason();
894 0 : if (failure != nullptr) {
895 0 : AP::dal().snprintf(failure_msg, failure_msg_len, failure);
896 : } else {
897 0 : AP::dal().snprintf(failure_msg, failure_msg_len, "EKF2 core %d unhealthy", (int)i);
898 : }
899 0 : return false;
900 : }
901 : }
902 : return true;
903 : }
904 :
905 : // returns the index of the primary core
906 : // return -1 if no primary core selected
907 3673988 : int8_t NavEKF2::getPrimaryCoreIndex(void) const
908 : {
909 3673988 : if (!core) {
910 : return -1;
911 : }
912 3673988 : return primary;
913 : }
914 :
915 : // returns the index of the IMU of the primary core
916 : // return -1 if no primary core selected
917 83373432 : int8_t NavEKF2::getPrimaryCoreIMUIndex(void) const
918 : {
919 83373432 : if (!core) {
920 : return -1;
921 : }
922 4420898 : return core[primary].getIMUIndex();
923 : }
924 :
925 : // Write the last calculated NE position relative to the reference point (m).
926 : // If a calculated solution is not available, use the best available data and return false
927 : // If false returned, do not use for flight control
928 41686716 : bool NavEKF2::getPosNE(Vector2p &posNE) const
929 : {
930 41686716 : if (!core) {
931 : return false;
932 : }
933 2210449 : return core[primary].getPosNE(posNE);
934 : }
935 :
936 : // Write the last calculated D position relative to the reference point (m).
937 : // If a calculated solution is not available, use the best available data and return false
938 : // If false returned, do not use for flight control
939 41686716 : bool NavEKF2::getPosD(postype_t &posD) const
940 : {
941 41686716 : if (!core) {
942 : return false;
943 : }
944 2210449 : return core[primary].getPosD(posD);
945 : }
946 :
947 : // return NED velocity in m/s
948 41686716 : void NavEKF2::getVelNED(Vector3f &vel) const
949 : {
950 41686716 : if (core) {
951 2210449 : core[primary].getVelNED(vel);
952 : }
953 41686716 : }
954 :
955 : // return estimate of true airspeed vector in body frame in m/s for the specified instance
956 : // An out of range instance (eg -1) returns data for the primary instance
957 : // returns false if estimate is unavailable
958 135980 : bool NavEKF2::getAirSpdVec(Vector3f &vel) const
959 : {
960 135980 : if (core) {
961 135980 : return core[primary].getAirSpdVec(vel);
962 : }
963 : return false;
964 : }
965 :
966 : // Return the rate of change of vertical position in the down direction (dPosD/dt) in m/s
967 41686716 : float NavEKF2::getPosDownDerivative() const
968 : {
969 : // return the value calculated from a complementary filter applied to the EKF height and vertical acceleration
970 41686716 : if (core) {
971 2210449 : return core[primary].getPosDownDerivative();
972 : }
973 : return 0.0f;
974 : }
975 :
976 : // return body axis gyro bias estimates in rad/sec
977 41686716 : void NavEKF2::getGyroBias(Vector3f &gyroBias) const
978 : {
979 41686716 : if (core) {
980 2210449 : core[primary].getGyroBias(gyroBias);
981 : }
982 41686716 : }
983 :
984 : // reset body axis gyro bias estimates
985 7 : void NavEKF2::resetGyroBias(void)
986 : {
987 7 : AP::dal().log_event2(AP_DAL::Event::resetGyroBias);
988 :
989 7 : if (core) {
990 18 : for (uint8_t i=0; i<num_cores; i++) {
991 12 : core[i].resetGyroBias();
992 : }
993 : }
994 7 : }
995 :
996 : // Resets the baro so that it reads zero at the current height
997 : // Resets the EKF height to zero
998 : // Adjusts the EKf origin height so that the EKF height + origin height is the same as before
999 : // Returns true if the height datum reset has been performed
1000 : // If using a range finder for height no reset is performed and it returns false
1001 3121 : bool NavEKF2::resetHeightDatum(void)
1002 : {
1003 3121 : AP::dal().log_event2(AP_DAL::Event::resetHeightDatum);
1004 :
1005 : bool status = true;
1006 3121 : if (core) {
1007 4488 : for (uint8_t i=0; i<num_cores; i++) {
1008 2992 : if (!core[i].resetHeightDatum()) {
1009 : status = false;
1010 : }
1011 : }
1012 : } else {
1013 : status = false;
1014 : }
1015 3121 : return status;
1016 : }
1017 :
1018 : // return the horizontal speed limit in m/s set by optical flow sensor limits
1019 : // return the scale factor to be applied to navigation velocity gains to compensate for increase in velocity noise with height when using optical flow
1020 41686716 : void NavEKF2::getEkfControlLimits(float &ekfGndSpdLimit, float &ekfNavVelGainScaler) const
1021 : {
1022 41686716 : if (core) {
1023 2210449 : core[primary].getEkfControlLimits(ekfGndSpdLimit, ekfNavVelGainScaler);
1024 : } else {
1025 39476267 : ekfGndSpdLimit = 400.0f; //return 80% of max filter speed
1026 39476267 : ekfNavVelGainScaler = 1.0f;
1027 : }
1028 41686716 : }
1029 :
1030 : // return the individual Z-accel bias estimates in m/s^2
1031 41686716 : void NavEKF2::getAccelZBias(float &zbias) const
1032 : {
1033 41686716 : if (core) {
1034 2210449 : core[primary].getAccelZBias(zbias);
1035 : }
1036 41686716 : }
1037 :
1038 : // return the NED wind speed estimates in m/s (positive is air moving in the direction of the axis)
1039 41686716 : void NavEKF2::getWind(Vector3f &wind) const
1040 : {
1041 41686716 : if (core) {
1042 2210449 : core[primary].getWind(wind);
1043 : }
1044 41686716 : }
1045 :
1046 : // return earth magnetic field estimates in measurement units / 1000
1047 41686716 : void NavEKF2::getMagNED(Vector3f &magNED) const
1048 : {
1049 41686716 : if (core) {
1050 2210449 : core[primary].getMagNED(magNED);
1051 : }
1052 41686716 : }
1053 :
1054 : // return body magnetic field estimates in measurement units / 1000
1055 41686716 : void NavEKF2::getMagXYZ(Vector3f &magXYZ) const
1056 : {
1057 41686716 : if (core) {
1058 2210449 : core[primary].getMagXYZ(magXYZ);
1059 : }
1060 41686716 : }
1061 :
1062 : // Return estimated magnetometer offsets
1063 : // Return true if magnetometer offsets are valid
1064 0 : bool NavEKF2::getMagOffsets(uint8_t mag_idx, Vector3f &magOffsets) const
1065 : {
1066 0 : if (!core) {
1067 : return false;
1068 : }
1069 : // try the primary first, else loop through all of the cores and return when one has offsets for this mag instance
1070 0 : if (core[primary].getMagOffsets(mag_idx, magOffsets)) {
1071 : return true;
1072 : }
1073 0 : for (uint8_t i=0; i<num_cores; i++) {
1074 0 : if(core[i].getMagOffsets(mag_idx, magOffsets)) {
1075 : return true;
1076 : }
1077 : }
1078 : return false;
1079 : }
1080 :
1081 : // Return the last calculated latitude, longitude and height in WGS-84
1082 : // If a calculated location isn't available, return a raw GPS measurement
1083 : // The status will return true if a calculation or raw measurement is available
1084 : // The getFilterStatus() function provides a more detailed description of data health and must be checked if data is to be used for flight control
1085 41686716 : bool NavEKF2::getLLH(Location &loc) const
1086 : {
1087 41686716 : if (!core) {
1088 : return false;
1089 : }
1090 2210449 : return core[primary].getLLH(loc);
1091 : }
1092 :
1093 : // Return the latitude and longitude and height used to set the NED origin for the specified instance
1094 : // An out of range instance (eg -1) returns data for the primary instance
1095 : // All NED positions calculated by the filter are relative to this location
1096 : // Returns false if the origin has not been set
1097 6779639 : bool NavEKF2::getOriginLLH(Location &loc) const
1098 : {
1099 6779639 : if (!core) {
1100 : return false;
1101 : }
1102 431141 : if (common_origin_valid) {
1103 129125 : loc = common_EKF_origin;
1104 129125 : return true;
1105 : }
1106 302016 : return core[primary].getOriginLLH(loc);
1107 : }
1108 :
1109 : // set the latitude and longitude and height used to set the NED origin
1110 : // All NED positions calculated by the filter will be relative to this location
1111 : // The origin cannot be set if the filter is in a flight mode (eg vehicle armed)
1112 : // Returns false if the filter has rejected the attempt to set the origin
1113 750 : bool NavEKF2::setOriginLLH(const Location &loc)
1114 : {
1115 750 : AP::dal().log_SetOriginLLH2(loc);
1116 :
1117 750 : if (!core) {
1118 : return false;
1119 : }
1120 17 : if (common_origin_valid) {
1121 : // we don't allow setting of the EKF origin if the EKF origin
1122 : // has already been set.
1123 0 : GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "EKF2 refusing set origin");
1124 0 : return false;
1125 : }
1126 : bool ret = false;
1127 51 : for (uint8_t i=0; i<num_cores; i++) {
1128 34 : ret |= core[i].setOriginLLH(loc);
1129 : }
1130 : // return true if any core accepts the new origin
1131 : return ret;
1132 : }
1133 :
1134 : // return estimated height above ground level
1135 : // return false if ground height is not being estimated.
1136 41686716 : bool NavEKF2::getHAGL(float &HAGL) const
1137 : {
1138 41686716 : if (!core) {
1139 : return false;
1140 : }
1141 2210449 : return core[primary].getHAGL(HAGL);
1142 : }
1143 :
1144 : // return the Euler roll, pitch and yaw angle in radians for the specified instance
1145 41686716 : void NavEKF2::getEulerAngles(Vector3f &eulers) const
1146 : {
1147 41686716 : if (core) {
1148 2210449 : core[primary].getEulerAngles(eulers);
1149 : }
1150 41686716 : }
1151 :
1152 : // return the transformation matrix from XYZ (body) to NED axes
1153 41686716 : void NavEKF2::getRotationBodyToNED(Matrix3f &mat) const
1154 : {
1155 41686716 : if (core) {
1156 2210449 : core[primary].getRotationBodyToNED(mat);
1157 : }
1158 41686716 : }
1159 :
1160 : // return the quaternions defining the rotation from NED to XYZ (body) axes
1161 459 : void NavEKF2::getQuaternionBodyToNED(int8_t instance, Quaternion &quat) const
1162 : {
1163 459 : if (instance < 0 || instance >= num_cores) instance = primary;
1164 459 : if (core) {
1165 459 : Matrix3f mat;
1166 459 : core[instance].getRotationBodyToNED(mat);
1167 459 : quat.from_rotation_matrix(mat);
1168 : }
1169 459 : }
1170 :
1171 : // return the quaternions defining the rotation from NED to XYZ (autopilot) axes
1172 41686716 : void NavEKF2::getQuaternion(Quaternion &quat) const
1173 : {
1174 41686716 : if (core) {
1175 2210449 : core[primary].getQuaternion(quat);
1176 : }
1177 41686716 : }
1178 :
1179 : // return the innovations for the specified instance
1180 3439 : bool NavEKF2::getInnovations(Vector3f &velInnov, Vector3f &posInnov, Vector3f &magInnov, float &tasInnov, float &yawInnov) const
1181 : {
1182 3439 : if (core == nullptr) {
1183 : return false;
1184 : }
1185 :
1186 3408 : return core[primary].getInnovations(velInnov, posInnov, magInnov, tasInnov, yawInnov);
1187 : }
1188 :
1189 : // return the innovation consistency test ratios for the velocity, position, magnetometer and true airspeed measurements
1190 41686716 : bool NavEKF2::getVariances(float &velVar, float &posVar, float &hgtVar, Vector3f &magVar, float &tasVar, Vector2f &offset) const
1191 : {
1192 41686716 : if (core == nullptr) {
1193 : return false;
1194 : }
1195 :
1196 2210449 : return core[primary].getVariances(velVar, posVar, hgtVar, magVar, tasVar, offset);
1197 : }
1198 :
1199 : // should we use the compass? This is public so it can be used for
1200 : // reporting via ahrs.use_compass()
1201 129 : bool NavEKF2::use_compass(void) const
1202 : {
1203 129 : if (!core) {
1204 : return false;
1205 : }
1206 129 : return core[primary].use_compass();
1207 : }
1208 :
1209 : // are we using a gps?
1210 41686716 : bool NavEKF2::using_gps(void) const
1211 : {
1212 41686716 : return _fusionModeGPS != 3;
1213 : }
1214 :
1215 : // write the raw optical flow measurements
1216 : // rawFlowQuality is a measured of quality between 0 and 255, with 255 being the best quality
1217 : // rawFlowRates are the optical flow rates in rad/sec about the X and Y sensor axes.
1218 : // rawGyroRates are the sensor rotation rates in rad/sec measured by the sensors internal gyro
1219 : // The sign convention is that a RH physical rotation of the sensor about an axis produces both a positive flow and gyro rate
1220 : // msecFlowMeas is the scheduler time in msec when the optical flow data was received from the sensor.
1221 : // posOffset is the XYZ flow sensor position in the body frame in m
1222 : // heightOverride is the fixed height of the sensor above ground in m, when on rover vehicles. 0 if not used
1223 10128 : void NavEKF2::writeOptFlowMeas(const uint8_t rawFlowQuality, const Vector2f &rawFlowRates, const Vector2f &rawGyroRates, const uint32_t msecFlowMeas, const Vector3f &posOffset, float heightOverride)
1224 : {
1225 10128 : AP::dal().writeOptFlowMeas(rawFlowQuality, rawFlowRates, rawGyroRates, msecFlowMeas, posOffset, heightOverride);
1226 :
1227 10128 : if (core) {
1228 0 : for (uint8_t i=0; i<num_cores; i++) {
1229 0 : core[i].writeOptFlowMeas(rawFlowQuality, rawFlowRates, rawGyroRates, msecFlowMeas, posOffset, heightOverride);
1230 : }
1231 : }
1232 10128 : }
1233 :
1234 : // Set to true if the terrain underneath is stable enough to be used as a height reference
1235 : // in combination with a range finder. Set to false if the terrain underneath the vehicle
1236 : // cannot be used as a height reference. Use to prevent range finder operation otherwise
1237 : // enabled by the combination of EK2_RNG_AID_HGT and EK2_RNG_USE_SPD parameters.
1238 2339 : void NavEKF2::setTerrainHgtStable(bool val)
1239 : {
1240 2339 : if (val) {
1241 769 : AP::dal().log_event2(AP_DAL::Event::setTerrainHgtStable);
1242 : } else {
1243 1570 : AP::dal().log_event2(AP_DAL::Event::unsetTerrainHgtStable);
1244 : }
1245 2339 : if (core) {
1246 84 : for (uint8_t i=0; i<num_cores; i++) {
1247 56 : core[i].setTerrainHgtStable(val);
1248 : }
1249 : }
1250 :
1251 2339 : }
1252 :
1253 : /*
1254 : return the filter fault status as a bitmasked integer
1255 : 0 = quaternions are NaN
1256 : 1 = velocities are NaN
1257 : 2 = badly conditioned X magnetometer fusion
1258 : 3 = badly conditioned Y magnetometer fusion
1259 : 4 = badly conditioned Z magnetometer fusion
1260 : 5 = badly conditioned airspeed fusion
1261 : 6 = badly conditioned synthetic sideslip fusion
1262 : 7 = filter is not initialised
1263 : */
1264 41686716 : void NavEKF2::getFilterFaults(uint16_t &faults) const
1265 : {
1266 41686716 : if (core) {
1267 2210449 : core[primary].getFilterFaults(faults);
1268 : } else {
1269 39476267 : faults = 0;
1270 : }
1271 41686716 : }
1272 :
1273 : /*
1274 : return filter status flags
1275 : */
1276 41686716 : void NavEKF2::getFilterStatus(nav_filter_status &status) const
1277 : {
1278 41686716 : if (core) {
1279 2210449 : core[primary].getFilterStatus(status);
1280 : } else {
1281 39476267 : memset(&status, 0, sizeof(status));
1282 : }
1283 41686716 : }
1284 :
1285 : /*
1286 : return filter gps quality check status
1287 : */
1288 0 : void NavEKF2::getFilterGpsStatus(nav_gps_status &status) const
1289 : {
1290 0 : if (core) {
1291 0 : core[primary].getFilterGpsStatus(status);
1292 : } else {
1293 0 : memset(&status, 0, sizeof(status));
1294 : }
1295 0 : }
1296 :
1297 : // send an EKF_STATUS_REPORT message to GCS
1298 41686716 : bool NavEKF2::getTerrainAltVariance(float &terrainAltVar) const
1299 : {
1300 41686716 : if (core) {
1301 2210449 : return core[primary].getTerrainAltVariance(terrainAltVar);
1302 : }
1303 : return false;
1304 : }
1305 :
1306 : // provides the height limit to be observed by the control loops
1307 : // returns false if no height limiting is required
1308 : // this is needed to ensure the vehicle does not fly too high when using optical flow navigation
1309 41686716 : bool NavEKF2::getHeightControlLimit(float &height) const
1310 : {
1311 41686716 : if (!core) {
1312 : return false;
1313 : }
1314 2210449 : return core[primary].getHeightControlLimit(height);
1315 : }
1316 :
1317 : // Returns a count of NE position reset events; incremented when the primary
1318 : // core changes and when the primary core resets its NE position
1319 2106892 : uint16_t NavEKF2::getPosNorthEastResetCount(void)
1320 : {
1321 2106892 : if (!core) {
1322 : return 0;
1323 : }
1324 2106892 : const uint16_t core_count = core[primary].getPosNorthEastResetCount();
1325 2106892 : if (core_count != pos_reset_data.last_core_count) {
1326 450 : pos_reset_data.last_core_count = core_count;
1327 450 : pos_reset_data.count++;
1328 : }
1329 2106892 : return pos_reset_data.count;
1330 : }
1331 :
1332 : // Returns a count of D position reset events; incremented when the primary
1333 : // core changes and when the primary core resets its D position
1334 2106892 : uint16_t NavEKF2::getPosDownResetCount(void)
1335 : {
1336 2106892 : if (!core) {
1337 : return 0;
1338 : }
1339 2106892 : const uint16_t core_count = core[primary].getPosDownResetCount();
1340 2106892 : if (core_count != pos_down_reset_data.last_core_count) {
1341 305 : pos_down_reset_data.last_core_count = core_count;
1342 305 : pos_down_reset_data.count++;
1343 : }
1344 2106892 : return pos_down_reset_data.count;
1345 : }
1346 :
1347 : // Returns a count of yaw reset events; incremented when the primary core
1348 : // changes and when the primary core resets its yaw
1349 2106892 : uint16_t NavEKF2::getYawResetCount(void)
1350 : {
1351 2106892 : if (!core) {
1352 : return 0;
1353 : }
1354 2106892 : const uint16_t core_count = core[primary].getYawResetCount();
1355 2106892 : if (core_count != yaw_reset_data.last_core_count) {
1356 547 : yaw_reset_data.last_core_count = core_count;
1357 547 : yaw_reset_data.count++;
1358 : }
1359 2106892 : return yaw_reset_data.count;
1360 : }
1361 :
1362 : // update the yaw reset data to capture changes due to a lane switch
1363 6187 : void NavEKF2::updateLaneSwitchYawResetData(uint8_t new_primary)
1364 : {
1365 : // the new primary's historic in-core resets are not new events
1366 : // for consumers; re-seat the count and record a single event for
1367 : // the switch itself
1368 6187 : yaw_reset_data.last_core_count = core[new_primary].getYawResetCount();
1369 6187 : yaw_reset_data.count++;
1370 6187 : }
1371 :
1372 : // update the position reset data to capture changes due to a lane switch
1373 6187 : void NavEKF2::updateLaneSwitchPosResetData(uint8_t new_primary)
1374 : {
1375 : // the new primary's historic in-core resets are not new events
1376 : // for consumers; re-seat the count and record a single event for
1377 : // the switch itself
1378 6187 : pos_reset_data.last_core_count = core[new_primary].getPosNorthEastResetCount();
1379 6187 : pos_reset_data.count++;
1380 :
1381 6187 : }
1382 :
1383 : // Update the vertical position reset data to capture changes due to a core switch
1384 : // This should be called after the decision to switch cores has been made, but before the
1385 : // new primary EKF update has been run
1386 6187 : void NavEKF2::updateLaneSwitchPosDownResetData(uint8_t new_primary)
1387 : {
1388 : // the new primary's historic in-core resets are not new events
1389 : // for consumers; re-seat the count and record a single event for
1390 : // the switch itself
1391 6187 : pos_down_reset_data.last_core_count = core[new_primary].getPosDownResetCount();
1392 6187 : pos_down_reset_data.count++;
1393 :
1394 6187 : }
1395 :
1396 : /*
1397 : * Write position and quaternion data from an external navigation system
1398 : *
1399 : * pos : XYZ position (m) in a RH navigation frame with the Z axis pointing down and XY axes horizontal. Frame must be aligned with NED if the magnetomer is being used for yaw.
1400 : * quat : quaternion describing the rotation from navigation frame to body frame
1401 : * posErr : 1-sigma spherical position error (m)
1402 : * angErr : 1-sigma spherical angle error (rad)
1403 : * timeStamp_ms : system time the measurement was taken, not the time it was received (mSec)
1404 : * delay_ms : average delay of external nav system measurements relative to inertial measurements
1405 : * resetTime_ms : system time of the last position reset request (mSec)
1406 : *
1407 : * Sensor offsets are pulled directly from the AP_VisualOdom library
1408 : *
1409 : */
1410 10069 : void NavEKF2::writeExtNavData(const Vector3f &pos, const Quaternion &quat, float posErr, float angErr, uint32_t timeStamp_ms, uint16_t delay_ms, uint32_t resetTime_ms)
1411 : {
1412 10069 : AP::dal().writeExtNavData(pos, quat, posErr, angErr, timeStamp_ms, delay_ms, resetTime_ms);
1413 10069 : if (!option_is_set(Option::DisableExternalNav) && core) {
1414 0 : for (uint8_t i=0; i<num_cores; i++) {
1415 0 : core[i].writeExtNavData(pos, quat, posErr, angErr, timeStamp_ms, delay_ms, resetTime_ms);
1416 : }
1417 : }
1418 10069 : }
1419 :
1420 : // check if external navigation is being used for yaw observation
1421 83373432 : bool NavEKF2::isExtNavUsedForYaw() const
1422 : {
1423 83373432 : if (core) {
1424 4420898 : return core[primary].isExtNavUsedForYaw();
1425 : }
1426 : return false;
1427 : }
1428 :
1429 : // check if configured to use GPS for horizontal position estimation
1430 41691733 : bool NavEKF2::configuredToUseGPSForPosXY(void) const
1431 : {
1432 : // 0 = use 3D velocity, 1 = use 2D velocity, 2 = use no velocity, 3 = do not use GPS
1433 41691733 : return (_fusionModeGPS.get() != 3);
1434 : }
1435 :
1436 2 : void NavEKF2::requestYawReset(void)
1437 : {
1438 2 : AP::dal().log_event2(AP_DAL::Event::requestYawReset);
1439 :
1440 6 : for (uint8_t i = 0; i < num_cores; i++) {
1441 4 : core[i].EKFGSF_requestYawReset();
1442 : }
1443 2 : }
1444 :
1445 : // Writes the default equivalent airspeed in m/s to be used in forward flight if a measured airspeed is required and not available.
1446 0 : void NavEKF2::writeDefaultAirSpeed(float airspeed)
1447 : {
1448 0 : AP::dal().log_writeDefaultAirSpeed2(airspeed,0.0f);
1449 :
1450 0 : if (core) {
1451 0 : for (uint8_t i=0; i<num_cores; i++) {
1452 0 : core[i].writeDefaultAirSpeed(airspeed);
1453 : }
1454 : }
1455 0 : }
1456 :
1457 : /* Write velocity data from an external navigation system
1458 : * vel : velocity in NED (m)
1459 : * err : velocity error (m/s)
1460 : * timeStamp_ms : system time the measurement was taken, not the time it was received (mSec)
1461 : * delay_ms : average delay of external nav system measurements relative to inertial measurements
1462 : */
1463 4278 : void NavEKF2::writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms)
1464 : {
1465 4278 : AP::dal().writeExtNavVelData(vel, err, timeStamp_ms, delay_ms);
1466 4278 : if (!option_is_set(Option::DisableExternalNav) && core) {
1467 0 : for (uint8_t i=0; i<num_cores; i++) {
1468 0 : core[i].writeExtNavVelData(vel, err, timeStamp_ms, delay_ms);
1469 : }
1470 : }
1471 4278 : }
1472 :
1473 : // get yaw estimator instance
1474 0 : const EKFGSF_yaw *NavEKF2::get_yawEstimator(void) const
1475 : {
1476 0 : if (core) {
1477 0 : return core[primary].get_yawEstimator();
1478 : }
1479 : return nullptr;
1480 : }
|