LCOV - code coverage report
Current view: top level - AP_NavEKF3 - AP_NavEKF3.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 409 445 91.9 %
Date: 2026-09-09 11:02:08 Functions: 70 75 93.3 %

          Line data    Source code
       1             : #include "AP_NavEKF3_core.h"
       2             : 
       3             : #include "AP_NavEKF3.h"
       4             : 
       5             : #include <AP_HAL/AP_HAL.h>
       6             : 
       7             : #include <GCS_MAVLink/GCS.h>
       8             : #include <AP_Logger/AP_Logger.h>
       9             : #include <AP_Vehicle/AP_Vehicle_Type.h>
      10             : #include <AP_BoardConfig/AP_BoardConfig.h>
      11             : 
      12             : #include "AP_DAL/AP_DAL.h"
      13             : 
      14             : #include <new>
      15             : 
      16             : /*
      17             :   parameter defaults for different types of vehicle. The
      18             :   APM_BUILD_DIRECTORY is taken from the main vehicle directory name
      19             :   where the code is built.
      20             :  */
      21             : #if APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_Replay)
      22             : // copter defaults
      23             : #define VELNE_M_NSE_DEFAULT     0.3f
      24             : #define VELD_M_NSE_DEFAULT      0.5f
      25             : #define POSNE_M_NSE_DEFAULT     0.5f
      26             : #define ALT_M_NSE_DEFAULT       2.0f
      27             : #define MAG_M_NSE_DEFAULT       0.05f
      28             : #define GYRO_P_NSE_DEFAULT      1.5E-02f
      29             : #define ACC_P_NSE_DEFAULT       3.5E-01f
      30             : #define GBIAS_P_NSE_DEFAULT     1.0E-03f
      31             : #define ABIAS_P_NSE_DEFAULT     2.0E-02f
      32             : #define MAGB_P_NSE_DEFAULT      1.0E-04f
      33             : #define MAGE_P_NSE_DEFAULT      1.0E-03f
      34             : #define VEL_I_GATE_DEFAULT      500
      35             : #define POS_I_GATE_DEFAULT      500
      36             : #define HGT_I_GATE_DEFAULT      500
      37             : #define MAG_I_GATE_DEFAULT      300
      38             : #define MAG_CAL_DEFAULT         3
      39             : #define GLITCH_RADIUS_DEFAULT   25
      40             : #define FLOW_MEAS_DELAY         10
      41             : #define FLOW_M_NSE_DEFAULT      0.25f
      42             : #define FLOW_I_GATE_DEFAULT     300
      43             : #define CHECK_SCALER_DEFAULT    100
      44             : #define FLOW_USE_DEFAULT        1
      45             : #define WIND_P_NSE_DEFAULT      0.2
      46             : 
      47             : #elif APM_BUILD_TYPE(APM_BUILD_Rover)
      48             : // rover defaults
      49             : #define VELNE_M_NSE_DEFAULT     0.5f
      50             : #define VELD_M_NSE_DEFAULT      0.7f
      51             : #define POSNE_M_NSE_DEFAULT     0.5f
      52             : #define ALT_M_NSE_DEFAULT       2.0f
      53             : #define MAG_M_NSE_DEFAULT       0.05f
      54             : #define GYRO_P_NSE_DEFAULT      1.5E-02f
      55             : #define ACC_P_NSE_DEFAULT       3.5E-01f
      56             : #define GBIAS_P_NSE_DEFAULT     1.0E-03f
      57             : #define ABIAS_P_NSE_DEFAULT     2.0E-02f
      58             : #define MAGB_P_NSE_DEFAULT      1.0E-04f
      59             : #define MAGE_P_NSE_DEFAULT      1.0E-03f
      60             : #define VEL_I_GATE_DEFAULT      500
      61             : #define POS_I_GATE_DEFAULT      500
      62             : #define HGT_I_GATE_DEFAULT      500
      63             : #define MAG_I_GATE_DEFAULT      300
      64             : #define MAG_CAL_DEFAULT         2
      65             : #define GLITCH_RADIUS_DEFAULT   25
      66             : #define FLOW_MEAS_DELAY         10
      67             : #define FLOW_M_NSE_DEFAULT      0.25f
      68             : #define FLOW_I_GATE_DEFAULT     300
      69             : #define CHECK_SCALER_DEFAULT    100
      70             : #define FLOW_USE_DEFAULT        1
      71             : #define WIND_P_NSE_DEFAULT      0.1
      72             : 
      73             : #elif APM_BUILD_TYPE(APM_BUILD_ArduPlane)
      74             : // plane defaults
      75             : #define VELNE_M_NSE_DEFAULT     0.5f
      76             : #define VELD_M_NSE_DEFAULT      0.7f
      77             : #define POSNE_M_NSE_DEFAULT     0.5f
      78             : #define ALT_M_NSE_DEFAULT       3.0f
      79             : #define MAG_M_NSE_DEFAULT       0.05f
      80             : #define GYRO_P_NSE_DEFAULT      1.5E-02f
      81             : #define ACC_P_NSE_DEFAULT       3.5E-01f
      82             : #define GBIAS_P_NSE_DEFAULT     1.0E-03f
      83             : #define ABIAS_P_NSE_DEFAULT     2.0E-02f
      84             : #define MAGB_P_NSE_DEFAULT      1.0E-04f
      85             : #define MAGE_P_NSE_DEFAULT      1.0E-03f
      86             : #define VEL_I_GATE_DEFAULT      500
      87             : #define POS_I_GATE_DEFAULT      500
      88             : #define HGT_I_GATE_DEFAULT      500
      89             : #define MAG_I_GATE_DEFAULT      300
      90             : #define MAG_CAL_DEFAULT         0
      91             : #define GLITCH_RADIUS_DEFAULT   25
      92             : #define FLOW_MEAS_DELAY         10
      93             : #define FLOW_M_NSE_DEFAULT      0.15f
      94             : #define FLOW_I_GATE_DEFAULT     500
      95             : #define CHECK_SCALER_DEFAULT    150
      96             : #define FLOW_USE_DEFAULT        2
      97             : #define WIND_P_NSE_DEFAULT      0.1
      98             : 
      99             : #elif APM_BUILD_TYPE(APM_BUILD_ArduSub)
     100             : // Sub defaults
     101             : #define VELNE_M_NSE_DEFAULT     0.5f
     102             : #define VELD_M_NSE_DEFAULT      0.7f
     103             : #define POSNE_M_NSE_DEFAULT     0.5f
     104             : #define ALT_M_NSE_DEFAULT       0.01f
     105             : #define MAG_M_NSE_DEFAULT       0.05f
     106             : #define GYRO_P_NSE_DEFAULT      1.5E-02f
     107             : #define ACC_P_NSE_DEFAULT       3.5E-01f
     108             : #define GBIAS_P_NSE_DEFAULT     1.0E-03f
     109             : #define ABIAS_P_NSE_DEFAULT     2.0E-02f
     110             : #define MAGB_P_NSE_DEFAULT      1.0E-04f
     111             : #define MAGE_P_NSE_DEFAULT      1.0E-03f
     112             : #define VEL_I_GATE_DEFAULT      500
     113             : #define POS_I_GATE_DEFAULT      500
     114             : #define HGT_I_GATE_DEFAULT      500
     115             : #define MAG_I_GATE_DEFAULT      300
     116             : #define MAG_CAL_DEFAULT         3
     117             : #define GLITCH_RADIUS_DEFAULT   25
     118             : #define FLOW_MEAS_DELAY         10
     119             : #define FLOW_M_NSE_DEFAULT      0.25f
     120             : #define FLOW_I_GATE_DEFAULT     300
     121             : #define CHECK_SCALER_DEFAULT    100
     122             : #define FLOW_USE_DEFAULT        1
     123             : #define WIND_P_NSE_DEFAULT      0.1
     124             : 
     125             : #else
     126             : // build type not specified, use copter defaults
     127             : #define VELNE_M_NSE_DEFAULT     0.5f
     128             : #define VELD_M_NSE_DEFAULT      0.7f
     129             : #define POSNE_M_NSE_DEFAULT     0.5f
     130             : #define ALT_M_NSE_DEFAULT       2.0f
     131             : #define MAG_M_NSE_DEFAULT       0.05f
     132             : #define GYRO_P_NSE_DEFAULT      1.5E-02f
     133             : #define ACC_P_NSE_DEFAULT       3.5E-01f
     134             : #define GBIAS_P_NSE_DEFAULT     1.0E-03f
     135             : #define ABIAS_P_NSE_DEFAULT     2.0E-02f
     136             : #define MAGB_P_NSE_DEFAULT      1.0E-04f
     137             : #define MAGE_P_NSE_DEFAULT      1.0E-03f
     138             : #define VEL_I_GATE_DEFAULT      500
     139             : #define POS_I_GATE_DEFAULT      500
     140             : #define HGT_I_GATE_DEFAULT      500
     141             : #define MAG_I_GATE_DEFAULT      300
     142             : #define MAG_CAL_DEFAULT         3
     143             : #define GLITCH_RADIUS_DEFAULT   25
     144             : #define FLOW_MEAS_DELAY         10
     145             : #define FLOW_M_NSE_DEFAULT      0.25f
     146             : #define FLOW_I_GATE_DEFAULT     300
     147             : #define CHECK_SCALER_DEFAULT    100
     148             : #define FLOW_USE_DEFAULT        1
     149             : #define WIND_P_NSE_DEFAULT      0.1
     150             : 
     151             : #endif // APM_BUILD_COPTER_OR_HELI || APM_BUILD_TYPE(APM_BUILD_Replay)
     152             : 
     153             : #ifndef EK3_PRIMARY_DEFAULT
     154             : #define EK3_PRIMARY_DEFAULT 0
     155             : #endif
     156             : 
     157             : // This allows boards to default to using a specified number of IMUs and EKF lanes
     158             : #ifndef HAL_EKF_IMU_MASK_DEFAULT
     159             : #define HAL_EKF_IMU_MASK_DEFAULT 3       // Default to using two IMUs
     160             : #endif
     161             : 
     162             : // Define tuning parameters
     163             : const AP_Param::GroupInfo NavEKF3::var_info[] = {
     164             : 
     165             :     // @Param: ENABLE
     166             :     // @DisplayName: Enable EKF3
     167             :     // @Description: This enables EKF3. Enabling EKF3 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=3. A reboot or restart will need to be performed after changing the value of EK3_ENABLE for it to take effect.
     168             :     // @Values: 0:Disabled, 1:Enabled
     169             :     // @User: Advanced
     170             :     // @RebootRequired: True
     171             :     AP_GROUPINFO_FLAGS("ENABLE", 0, NavEKF3, _enable, 1, AP_PARAM_FLAG_ENABLE),
     172             : 
     173             :     // GPS measurement parameters
     174             : 
     175             :     // 1 was GPS_TYPE
     176             : 
     177             :     // @Param: VELNE_M_NSE
     178             :     // @DisplayName: GPS horizontal velocity measurement noise (m/s)
     179             :     // @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.
     180             :     // @Range: 0.05 5.0
     181             :     // @Increment: 0.05
     182             :     // @User: Advanced
     183             :     // @Units: m/s
     184             :     AP_GROUPINFO("VELNE_M_NSE", 2, NavEKF3, _gpsHorizVelNoise, VELNE_M_NSE_DEFAULT),
     185             : 
     186             :     // @Param: VELD_M_NSE
     187             :     // @DisplayName: GPS vertical velocity measurement noise (m/s)
     188             :     // @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.
     189             :     // @Range: 0.05 5.0
     190             :     // @Increment: 0.05
     191             :     // @User: Advanced
     192             :     // @Units: m/s
     193             :     AP_GROUPINFO("VELD_M_NSE", 3, NavEKF3, _gpsVertVelNoise, VELD_M_NSE_DEFAULT),
     194             : 
     195             :     // @Param: VEL_I_GATE
     196             :     // @DisplayName: GPS velocity innovation gate size
     197             :     // @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. If EK3_GLITCH_RAD set to 0 the velocity innovations will be clipped instead of rejected if they exceed the gate size and a smaller value of EK3_VEL_I_GATE not exceeding 300 is recommended to limit the effect of GPS transient errors.
     198             :     // @Range: 100 1000
     199             :     // @Increment: 25
     200             :     // @User: Advanced
     201             :     AP_GROUPINFO("VEL_I_GATE", 4, NavEKF3, _gpsVelInnovGate, VEL_I_GATE_DEFAULT),
     202             : 
     203             :     // @Param: POSNE_M_NSE
     204             :     // @DisplayName: GPS horizontal position measurement noise (m)
     205             :     // @Description: This sets the GPS horizontal position observation noise. Increasing it reduces the weighting of GPS horizontal position measurements.
     206             :     // @Range: 0.1 10.0
     207             :     // @Increment: 0.1
     208             :     // @User: Advanced
     209             :     // @Units: m
     210             :     AP_GROUPINFO("POSNE_M_NSE", 5, NavEKF3, _gpsHorizPosNoise, POSNE_M_NSE_DEFAULT),
     211             : 
     212             :     // @Param: POS_I_GATE
     213             :     // @DisplayName: GPS position measurement gate size
     214             :     // @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. If EK3_GLITCH_RAD has been set to 0 the horizontal position innovations will be clipped instead of rejected if they exceed the gate size so a smaller value of EK3_POS_I_GATE not exceeding 300 is recommended to limit the effect of GPS transient errors.
     215             :     // @Range: 100 1000
     216             :     // @Increment: 25
     217             :     // @User: Advanced
     218             :     AP_GROUPINFO("POS_I_GATE", 6, NavEKF3, _gpsPosInnovGate, POS_I_GATE_DEFAULT),
     219             : 
     220             :     // @Param: GLITCH_RAD
     221             :     // @DisplayName: GPS glitch radius gate size (m)
     222             :     // @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. If EK3_GLITCH_RAD set to 0 the GPS innovations will be clipped instead of rejected if they exceed the gate size set by EK3_VEL_I_GATE and EK3_POS_I_GATE which can be useful if poor quality sensor data is causing GPS rejection and loss of navigation but does make the EKF more susceptible to GPS glitches. If setting EK3_GLITCH_RAD to 0 it is recommended to reduce EK3_VEL_I_GATE and EK3_POS_I_GATE to 300.
     223             :     // @Range: 10 100
     224             :     // @Increment: 5
     225             :     // @User: Advanced
     226             :     // @Units: m
     227             :     AP_GROUPINFO("GLITCH_RAD", 7, NavEKF3, _gpsGlitchRadiusMax, GLITCH_RADIUS_DEFAULT),
     228             : 
     229             :     // 8 previously used for EKF3_GPS_DELAY parameter that has been deprecated.
     230             :     // The EKF now takes its GPS delay form the GPS library with the default delays
     231             :     // specified by the GPS_DELAY and GPS_DELAY2 parameters.
     232             : 
     233             :     // Height measurement parameters
     234             : 
     235             :     // 9 was ALT_SOURCE
     236             : 
     237             :     // @Param: ALT_M_NSE
     238             :     // @DisplayName: Altitude measurement noise (m)
     239             :     // @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. A larger value for EK3_ALT_M_NSE may be required when operating with EK3_SRCx_POSZ = 0. This parameter also sets the noise for the 'synthetic' zero height measurement that is used when EK3_SRCx_POSZ = 0.
     240             :     // @Range: 0.01 100.0
     241             :     // @Increment: 0.1
     242             :     // @User: Advanced
     243             :     // @Units: m
     244             :     AP_GROUPINFO("ALT_M_NSE", 10, NavEKF3, _baroAltNoise, ALT_M_NSE_DEFAULT),
     245             : 
     246             :     // @Param: HGT_I_GATE
     247             :     // @DisplayName: Height measurement gate size
     248             :     // @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.  If EK3_GLITCH_RAD set to 0 the vertical position innovations will be clipped instead of rejected if they exceed the gate size and a smaller value of EK3_HGT_I_GATE not exceeding 300 is recommended to limit the effect of height sensor transient errors.
     249             :     // @Range: 100 1000
     250             :     // @Increment: 25
     251             :     // @User: Advanced
     252             :     AP_GROUPINFO("HGT_I_GATE", 11, NavEKF3, _hgtInnovGate, HGT_I_GATE_DEFAULT),
     253             : 
     254             :     // @Param: HGT_DELAY
     255             :     // @DisplayName: Height measurement delay (msec)
     256             :     // @Description: This is the number of msec that the Height measurements lag behind the inertial measurements.
     257             :     // @Range: 0 250
     258             :     // @Increment: 10
     259             :     // @User: Advanced
     260             :     // @Units: ms
     261             :     // @RebootRequired: True
     262             :     AP_GROUPINFO("HGT_DELAY", 12, NavEKF3, _hgtDelay_ms, 60),
     263             : 
     264             :     // Magnetometer measurement parameters
     265             : 
     266             :     // @Param: MAG_M_NSE
     267             :     // @DisplayName: Magnetometer measurement noise (Gauss)
     268             :     // @Description: This is the RMS value of noise in magnetometer measurements. Increasing it reduces the weighting on these measurements.
     269             :     // @Range: 0.01 0.5
     270             :     // @Increment: 0.01
     271             :     // @User: Advanced
     272             :     // @Units: Gauss
     273             :     AP_GROUPINFO("MAG_M_NSE", 13, NavEKF3, _magNoise, MAG_M_NSE_DEFAULT),
     274             : 
     275             :     // @Param: MAG_CAL
     276             :     // @DisplayName: Magnetometer default fusion mode
     277             :     // @Description: This determines when the filter will use the 3-axis magnetometer fusion model that estimates both earth and body fixed magnetic field states and when it will use a simpler magnetic heading fusion model that does not use magnetic field states. The 3-axis magnetometer fusion is only suitable for use when the external magnetic field environment is stable. EK3_MAG_CAL = 0 uses heading fusion on ground, 3-axis fusion in-flight, and is the default setting for Plane users. EK3_MAG_CAL = 1 uses 3-axis fusion only when manoeuvring. EK3_MAG_CAL = 2 uses heading fusion at all times, is recommended if the external magnetic field is varying and is the default for rovers. EK3_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. EK3_MAG_CAL = 4 uses 3-axis fusion at all times. EK3_MAG_CAL = 7 uses 3-axis fusion on the ground and after the first in-air field and yaw reset has completed. This allows the magnetic field to be learned on the ground before takeoff (useful when swapping batteries with different magnetic signatures) while inhibiting learning during the initial climb when motor magnetic interference is strongest. While disarmed and stationary the yaw is additionally anchored to the measured magnetic heading, since a stationary vehicle gives the 3-axis fusion no way to separate a yaw error from the body field states. A body field component perpendicular to the horizontal earth field is not separable from yaw by a heading measurement, so it appears as a heading offset rather than being learned. NOTE : Use of simple heading magnetometer fusion makes vehicle compass calibration and alignment errors harder for the EKF to detect which reduces the sensitivity of the Copter EKF failsafe algorithm. NOTE: The fusion mode can be forced to 2 for specific EKF cores using the EK3_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 and setting COMPASS_ENABLE to 0. If this is done, the EK3_GSF_RUN and EK3_GSF_USE masks must be set to the same as EK3_IMU_MASK. A yaw angle derived from IMU and GPS velocity data using a Gaussian Sum Filter (GSF) will then be used to align the yaw when flight commences and there is sufficient movement.
     278             :     // @Values: 0:When flying,1:When manoeuvring,2:Never,3:After first climb yaw reset,4:Always,5:Use external yaw sensor (Deprecated in 4.1+ see EK3_SRCn_YAW),6:External yaw sensor with compass fallback (Deprecated in 4.1+ see EK3_SRCn_YAW),7:On ground and after first climb yaw reset
     279             :     // @User: Advanced
     280             :     // @RebootRequired: True
     281             :     AP_GROUPINFO("MAG_CAL", 14, NavEKF3, _magCal, MAG_CAL_DEFAULT),
     282             : 
     283             :     // @Param: MAG_I_GATE
     284             :     // @DisplayName: Magnetometer measurement gate size
     285             :     // @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.
     286             :     // @Range: 100 1000
     287             :     // @Increment: 25
     288             :     // @User: Advanced
     289             :     AP_GROUPINFO("MAG_I_GATE", 15, NavEKF3, _magInnovGate, MAG_I_GATE_DEFAULT),
     290             : 
     291             :     // Airspeed measurement parameters
     292             : 
     293             :     // @Param: EAS_M_NSE
     294             :     // @DisplayName: Equivalent airspeed measurement noise (m/s)
     295             :     // @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.
     296             :     // @Range: 0.5 5.0
     297             :     // @Increment: 0.1
     298             :     // @User: Advanced
     299             :     // @Units: m/s
     300             :     AP_GROUPINFO("EAS_M_NSE", 16, NavEKF3, _easNoise, 1.4f),
     301             : 
     302             :     // @Param: EAS_I_GATE
     303             :     // @DisplayName: Airspeed measurement gate size
     304             :     // @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.
     305             :     // @Range: 100 1000
     306             :     // @Increment: 25
     307             :     // @User: Advanced
     308             :     AP_GROUPINFO("EAS_I_GATE", 17, NavEKF3, _tasInnovGate, 400),
     309             : 
     310             :     // Rangefinder measurement parameters
     311             : 
     312             :     // @Param: RNG_M_NSE
     313             :     // @DisplayName: Range finder measurement noise (m)
     314             :     // @Description: This is the RMS value of noise in the range finder measurement. Increasing it reduces the weighting on this measurement.
     315             :     // @Range: 0.1 10.0
     316             :     // @Increment: 0.1
     317             :     // @User: Advanced
     318             :     // @Units: m
     319             :     AP_GROUPINFO("RNG_M_NSE", 18, NavEKF3, _rngNoise, 0.5f),
     320             : 
     321             :     // @Param: RNG_I_GATE
     322             :     // @DisplayName: Range finder measurement gate size
     323             :     // @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.
     324             :     // @Range: 100 1000
     325             :     // @Increment: 25
     326             :     // @User: Advanced
     327             :     AP_GROUPINFO("RNG_I_GATE", 19, NavEKF3, _rngInnovGate, 500),
     328             : 
     329             :     // Optical flow measurement parameters
     330             : 
     331             :     // @Param: FLOW_MAX
     332             :     // @DisplayName: Optical flow rate maximum
     333             :     // @Description: The maximum optical flow rate in rad/sec that will be accepted by the filter.  Flow rates above this value will not be fused.
     334             :     // @Range: 1.0 4.0
     335             :     // @Increment: 0.1
     336             :     // @User: Advanced
     337             :     // @Units: rad/s
     338             :     AP_GROUPINFO("FLOW_MAX", 20, NavEKF3, _maxFlowRate, 2.5f),
     339             : 
     340             :     // @Param: FLOW_M_NSE
     341             :     // @DisplayName: Optical flow measurement noise (rad/s)
     342             :     // @Description: This is the RMS value of noise and errors in optical flow measurements. Increasing it reduces the weighting on these measurements.
     343             :     // @Range: 0.05 1.0
     344             :     // @Increment: 0.05
     345             :     // @User: Advanced
     346             :     // @Units: rad/s
     347             :     AP_GROUPINFO("FLOW_M_NSE", 21, NavEKF3, _flowNoise, FLOW_M_NSE_DEFAULT),
     348             : 
     349             :     // @Param: FLOW_I_GATE
     350             :     // @DisplayName: Optical Flow measurement gate size
     351             :     // @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.
     352             :     // @Range: 100 1000
     353             :     // @Increment: 25
     354             :     // @User: Advanced
     355             :     AP_GROUPINFO("FLOW_I_GATE", 22, NavEKF3, _flowInnovGate, FLOW_I_GATE_DEFAULT),
     356             : 
     357             :     // @Param: FLOW_DELAY
     358             :     // @DisplayName: Optical Flow measurement delay (msec)
     359             :     // @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.
     360             :     // @Range: 0 250
     361             :     // @Increment: 10
     362             :     // @User: Advanced
     363             :     // @Units: ms
     364             :     // @RebootRequired: True
     365             :     AP_GROUPINFO("FLOW_DELAY", 23, NavEKF3, _flowDelay_ms, FLOW_MEAS_DELAY),
     366             : 
     367             :     // State and Covariance Predition Parameters
     368             : 
     369             :     // @Param: GYRO_P_NSE
     370             :     // @DisplayName: Rate gyro noise (rad/s)
     371             :     // @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.
     372             :     // @Range: 0.0001 0.1
     373             :     // @Increment: 0.0001
     374             :     // @User: Advanced
     375             :     // @Units: rad/s
     376             :     AP_GROUPINFO("GYRO_P_NSE", 24, NavEKF3, _gyrNoise, GYRO_P_NSE_DEFAULT),
     377             : 
     378             :     // @Param: ACC_P_NSE
     379             :     // @DisplayName: Accelerometer noise (m/s^2)
     380             :     // @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.
     381             :     // @Range: 0.01 1.0
     382             :     // @Increment: 0.01
     383             :     // @User: Advanced
     384             :     // @Units: m/s/s
     385             :     AP_GROUPINFO("ACC_P_NSE", 25, NavEKF3, _accNoise, ACC_P_NSE_DEFAULT),
     386             : 
     387             :     // @Param: GBIAS_P_NSE
     388             :     // @DisplayName: Rate gyro bias stability (rad/s/s)
     389             :     // @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.
     390             :     // @Range: 0.00001 0.001
     391             :     // @User: Advanced
     392             :     // @Units: rad/s/s
     393             :     AP_GROUPINFO("GBIAS_P_NSE", 26, NavEKF3, _gyroBiasProcessNoise, GBIAS_P_NSE_DEFAULT),
     394             : 
     395             :     // 27 previously used for EK2_GSCL_P_NSE parameter that has been removed
     396             : 
     397             :     // @Param: ABIAS_P_NSE
     398             :     // @DisplayName: Accelerometer bias stability (m/s^3)
     399             :     // @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.
     400             :     // @Range: 0.00001 0.02
     401             :     // @User: Advanced
     402             :     // @Units: m/s/s/s
     403             :     AP_GROUPINFO("ABIAS_P_NSE", 28, NavEKF3, _accelBiasProcessNoise, ABIAS_P_NSE_DEFAULT),
     404             : 
     405             :     // 29 previously used for EK2_MAG_P_NSE parameter that has been replaced with EK3_MAGE_P_NSE and EK3_MAGB_P_NSE
     406             : 
     407             :     // @Param: WIND_P_NSE
     408             :     // @DisplayName: Wind velocity process noise (m/s^2)
     409             :     // @Description: This state process noise controls the growth of wind state error estimates. Increasing it makes wind estimation faster and noisier.
     410             :     // @Range: 0.01 2.0
     411             :     // @Increment: 0.1
     412             :     // @User: Advanced
     413             :     // @Units: m/s/s
     414             :     AP_GROUPINFO("WIND_P_NSE", 30, NavEKF3, _windVelProcessNoise, WIND_P_NSE_DEFAULT),
     415             : 
     416             :     // @Param: WIND_PSCALE
     417             :     // @DisplayName: Height rate to wind process noise scaler
     418             :     // @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.
     419             :     // @Range: 0.0 2.0
     420             :     // @Increment: 0.1
     421             :     // @User: Advanced
     422             :     AP_GROUPINFO("WIND_PSCALE", 31, NavEKF3, _wndVarHgtRateScale, 1.0f),
     423             : 
     424             :     // @Param: GPS_CHECK
     425             :     // @DisplayName: GPS preflight check
     426             :     // @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.
     427             :     // @Bitmask: 0:NSats,1:HDoP,2:speed error,3:position error,4:yaw error,5:pos drift,6:vert speed,7:horiz speed
     428             :     // @User: Advanced
     429             :     AP_GROUPINFO("GPS_CHECK",    32, NavEKF3, _gpsCheck, 31),
     430             : 
     431             :     // @Param: IMU_MASK
     432             :     // @DisplayName: Bitmask of active IMUs
     433             :     // @Description: 1 byte bitmap of IMUs to use in EKF3. A separate instance of EKF3 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 EKF3 will fail to start.
     434             :     // @Bitmask: 0:FirstIMU,1:SecondIMU,2:ThirdIMU,3:FourthIMU,4:FifthIMU,5:SixthIMU
     435             :     // @User: Advanced
     436             :     // @RebootRequired: True
     437             :     AP_GROUPINFO("IMU_MASK",     33, NavEKF3, _imuMask, HAL_EKF_IMU_MASK_DEFAULT),
     438             :     
     439             :     // @Param: CHECK_SCALE
     440             :     // @DisplayName: GPS accuracy check scaler (%)
     441             :     // @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.
     442             :     // @Range: 50 200
     443             :     // @User: Advanced
     444             :     // @Units: %
     445             :     AP_GROUPINFO("CHECK_SCALE", 34, NavEKF3, _gpsCheckScaler, CHECK_SCALER_DEFAULT),
     446             : 
     447             :     // @Param: NOAID_M_NSE
     448             :     // @DisplayName: Non-GPS operation position uncertainty (m)
     449             :     // @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.
     450             :     // @Range: 0.5 50.0
     451             :     // @User: Advanced
     452             :     // @Units: m
     453             :     AP_GROUPINFO("NOAID_M_NSE", 35, NavEKF3, _noaidHorizNoise, 10.0f),
     454             : 
     455             :     // @Param: BETA_MASK
     456             :     // @DisplayName: Bitmask controlling sidelip angle fusion
     457             :     // @Description: 1 byte bitmap controlling use of sideslip angle fusion for estimation of non wind states during operation of 'fly forward' vehicle types such as fixed wing planes. By assuming that the angle of sideslip is small, the wind velocity state estimates are corrected  whenever the EKF is not dead reckoning (e.g. has an independent velocity or position sensor such as GPS). This behaviour is on by default and cannot be disabled. When the EKF is dead reckoning, the wind states are used as a reference, enabling use of the small angle of sideslip assumption to correct non wind velocity states (eg attitude, velocity, position, etc) and improve navigation accuracy. This behaviour is on by default and cannot be disabled. The behaviour controlled by this parameter is the use of the small angle of sideslip assumption to correct non wind velocity states when the EKF is NOT dead reckoning. This is primarily of benefit to reduce the buildup of yaw angle errors during straight and level flight without a yaw sensor (e.g. magnetometer or dual antenna GPS yaw) provided aerobatic flight maneuvers with large sideslip angles are not performed. The 'always' option might be used where the yaw sensor is intentionally not fitted or disabled. The 'WhenNoYawSensor' option might be used if a yaw sensor is fitted, but protection against in-flight failure and continual rejection by the EKF is desired. For vehicles operated within visual range of the operator performing frequent turning maneuvers, setting this parameter is unnecessary.
     458             :     // @Bitmask: 0:Always,1:WhenNoYawSensor
     459             :     // @User: Advanced
     460             :     // @RebootRequired: True
     461             :     AP_GROUPINFO("BETA_MASK", 36, NavEKF3, _betaMask, 0),
     462             : 
     463             :     // control of magnetic yaw angle fusion
     464             : 
     465             :     // @Param: YAW_M_NSE
     466             :     // @DisplayName: Yaw measurement noise (rad)
     467             :     // @Description: This is the RMS value of noise in yaw measurements from the magnetometer. Increasing it reduces the weighting on these measurements.
     468             :     // @Range: 0.05 1.0
     469             :     // @Increment: 0.05
     470             :     // @User: Advanced
     471             :     // @Units: rad
     472             :     AP_GROUPINFO("YAW_M_NSE", 37, NavEKF3, _yawNoise, 0.5f),
     473             : 
     474             :     // @Param: YAW_I_GATE
     475             :     // @DisplayName: Yaw measurement gate size
     476             :     // @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.
     477             :     // @Range: 100 1000
     478             :     // @Increment: 25
     479             :     // @User: Advanced
     480             :     AP_GROUPINFO("YAW_I_GATE", 38, NavEKF3, _yawInnovGate, 300),
     481             : 
     482             :     // @Param: TAU_OUTPUT
     483             :     // @DisplayName: Output complementary filter time constant (centi-sec)
     484             :     // @Description: Sets the time constant of the output complementary filter/predictor in centi-seconds.
     485             :     // @Range: 10 50
     486             :     // @Increment: 5
     487             :     // @User: Advanced
     488             :     // @Units: cs
     489             :     AP_GROUPINFO("TAU_OUTPUT", 39, NavEKF3, _tauVelPosOutput, 25),
     490             : 
     491             :     // @Param: MAGE_P_NSE
     492             :     // @DisplayName: Earth magnetic field process noise (gauss/s)
     493             :     // @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.
     494             :     // @Range: 0.00001 0.01
     495             :     // @User: Advanced
     496             :     // @Units: Gauss/s
     497             :     AP_GROUPINFO("MAGE_P_NSE", 40, NavEKF3, _magEarthProcessNoise, MAGE_P_NSE_DEFAULT),
     498             : 
     499             :     // @Param: MAGB_P_NSE
     500             :     // @DisplayName: Body magnetic field process noise (gauss/s)
     501             :     // @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.
     502             :     // @Range: 0.00001 0.01
     503             :     // @User: Advanced
     504             :     // @Units: Gauss/s
     505             :     AP_GROUPINFO("MAGB_P_NSE", 41, NavEKF3, _magBodyProcessNoise, MAGB_P_NSE_DEFAULT),
     506             : 
     507             :     // @Param: RNG_USE_HGT
     508             :     // @DisplayName: Range finder switch height percentage
     509             :     // @Description: Range finder can be used as the primary height source when below this percentage of its maximum range (see RNGFNDx_MAX) and the primary height source is Baro or GPS (see EK3_SRCx_POSZ).  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.
     510             :     // @Range: -1 70
     511             :     // @Increment: 1
     512             :     // @User: Advanced
     513             :     // @Units: %
     514             :     AP_GROUPINFO("RNG_USE_HGT", 42, NavEKF3, _useRngSwHgt, -1),
     515             : 
     516             :     // @Param: TERR_GRAD
     517             :     // @DisplayName: Maximum terrain gradient
     518             :     // @Description: Specifies the maximum gradient of the terrain below the vehicle when it is using range finder as a height reference
     519             :     // @Range: 0 0.2
     520             :     // @Increment: 0.01
     521             :     // @User: Advanced
     522             :     AP_GROUPINFO("TERR_GRAD", 43, NavEKF3, _terrGradMax, 0.1f),
     523             : 
     524             :     // @Param: BCN_M_NSE
     525             :     // @DisplayName: Range beacon measurement noise (m)
     526             :     // @Description: This is the RMS value of noise in the range beacon measurement. Increasing it reduces the weighting on this measurement.
     527             :     // @Range: 0.1 10.0
     528             :     // @Increment: 0.1
     529             :     // @User: Advanced
     530             :     // @Units: m
     531             :     AP_GROUPINFO("BCN_M_NSE", 44, NavEKF3, _rngBcnNoise, 1.0f),
     532             : 
     533             :     // @Param: BCN_I_GTE
     534             :     // @DisplayName: Range beacon measurement gate size
     535             :     // @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.
     536             :     // @Range: 100 1000
     537             :     // @Increment: 25
     538             :     // @User: Advanced
     539             :     AP_GROUPINFO("BCN_I_GTE", 45, NavEKF3, _rngBcnInnovGate, 500),
     540             : 
     541             :     // @Param: BCN_DELAY
     542             :     // @DisplayName: Range beacon measurement delay (msec)
     543             :     // @Description: This is the number of msec that the range beacon measurements lag behind the inertial measurements.
     544             :     // @Range: 0 250
     545             :     // @Increment: 10
     546             :     // @User: Advanced
     547             :     // @Units: ms
     548             :     // @RebootRequired: True
     549             :     AP_GROUPINFO("BCN_DELAY", 46, NavEKF3, _rngBcnDelay_ms, 50),
     550             : 
     551             :     // @Param: RNG_USE_SPD
     552             :     // @DisplayName: Range finder max ground speed
     553             :     // @Description: The range finder will not be used as the primary height source when the horizontal ground speed is greater than this value.
     554             :     // @Range: 2.0 6.0
     555             :     // @Increment: 0.5
     556             :     // @User: Advanced
     557             :     // @Units: m/s
     558             :     AP_GROUPINFO("RNG_USE_SPD", 47, NavEKF3, _useRngSwSpd, 2.0f),
     559             : 
     560             :     // @Param: ACC_BIAS_LIM
     561             :     // @DisplayName: Accelerometer bias limit
     562             :     // @Description: The accelerometer bias state will be limited to +- this value
     563             :     // @Range: 0.5 2.5
     564             :     // @Increment: 0.1
     565             :     // @User: Advanced
     566             :     // @Units: m/s/s
     567             :     AP_GROUPINFO("ACC_BIAS_LIM", 48, NavEKF3, _accBiasLim, 1.0f),
     568             : 
     569             :     // @Param: MAG_MASK
     570             :     // @DisplayName: Bitmask of active EKF cores that will always use heading fusion
     571             :     // @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.
     572             :     // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
     573             :     // @User: Advanced
     574             :     // @RebootRequired: True
     575             :     AP_GROUPINFO("MAG_MASK", 49, NavEKF3, _magMask, 0),
     576             : 
     577             :     // @Param: OGN_HGT_MASK
     578             :     // @DisplayName: Bitmask control of EKF reference height correction
     579             :     // @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).
     580             :     // @Bitmask: 0:Correct when using Baro height,1:Correct when using range finder height,2:Apply corrections to local position
     581             :     // @User: Advanced
     582             :     // @RebootRequired: True
     583             :     AP_GROUPINFO("OGN_HGT_MASK", 50, NavEKF3, _originHgtMode, 0),
     584             : 
     585             :     // @Param: VIS_VERR_MIN
     586             :     // @DisplayName: Visual odometry minimum velocity error
     587             :     // @Description: This is the 1-STD odometry velocity observation error that will be assumed when maximum quality is reported by the sensor. When quality is between max and min, the error will be calculated using linear interpolation between VIS_VERR_MIN and VIS_VERR_MAX.
     588             :     // @Range: 0.05 0.5
     589             :     // @Increment: 0.05
     590             :     // @User: Advanced
     591             :     // @Units: m/s
     592             :     AP_GROUPINFO("VIS_VERR_MIN", 51, NavEKF3, _visOdmVelErrMin, 0.1f),
     593             : 
     594             :     // @Param: VIS_VERR_MAX
     595             :     // @DisplayName: Visual odometry maximum velocity error
     596             :     // @Description: This is the 1-STD odometry velocity observation error that will be assumed when minimum quality is reported by the sensor. When quality is between max and min, the error will be calculated using linear interpolation between VIS_VERR_MIN and VIS_VERR_MAX.
     597             :     // @Range: 0.5 5.0
     598             :     // @Increment: 0.1
     599             :     // @User: Advanced
     600             :     // @Units: m/s
     601             :     AP_GROUPINFO("VIS_VERR_MAX", 52, NavEKF3, _visOdmVelErrMax, 0.9f),
     602             : 
     603             :     // @Param: WENC_VERR
     604             :     // @DisplayName: Wheel odometry velocity error
     605             :     // @Description: This is the 1-STD odometry velocity observation error that will be assumed when wheel encoder data is being fused.
     606             :     // @Range: 0.01 1.0
     607             :     // @Increment: 0.1
     608             :     // @User: Advanced
     609             :     // @Units: m/s
     610             :     AP_GROUPINFO("WENC_VERR", 53, NavEKF3, _wencOdmVelErr, 0.1f),
     611             : 
     612             :     // @Param: FLOW_USE
     613             :     // @DisplayName: Optical flow use bitmask
     614             :     // @Description: Controls if the optical flow data is fused into the 24-state navigation estimator OR the 1-state terrain height estimator.
     615             :     // @User: Advanced
     616             :     // @Values: 0:None,1:Navigation,2:Terrain
     617             :     // @RebootRequired: True
     618             :     AP_GROUPINFO("FLOW_USE", 54, NavEKF3, _flowUse, FLOW_USE_DEFAULT),
     619             : 
     620             :     // @Param: HRT_FILT
     621             :     // @DisplayName: Height rate filter crossover frequency
     622             :     // @Description: Specifies the crossover frequency of the complementary filter used to calculate the output predictor height rate derivative.
     623             :     // @Range: 0.1 30.0
     624             :     // @Units: Hz
     625             :     AP_GROUPINFO("HRT_FILT", 55, NavEKF3, _hrt_filt_freq, 2.0f),
     626             : 
     627             :     // @Param: MAG_EF_LIM
     628             :     // @DisplayName: EarthField error limit
     629             :     // @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.
     630             :     // @User: Advanced
     631             :     // @Range: 0 500
     632             :     // @Units: mGauss
     633             :     AP_GROUPINFO("MAG_EF_LIM", 56, NavEKF3, _mag_ef_limit, 50),
     634             : 
     635             :     // @Param: GSF_RUN_MASK
     636             :     // @DisplayName: Bitmask of which EKF-GSF yaw estimators run
     637             :     // @Description: 1 byte bitmap of which EKF3 instances run an independent 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 EKF3 instance will be logged as GSF0 and GSF1 messages. Use of the yaw estimate generated by this algorithm is controlled by the EK3_GSF_USE_MASK and EK3_GSF_RST_MAX parameters. To run the EKF-GSF yaw estimator in ride-along and logging only, set EK3_GSF_USE to 0. 
     638             :     // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
     639             :     // @User: Advanced
     640             :     // @RebootRequired: True
     641             :     AP_GROUPINFO("GSF_RUN_MASK", 57, NavEKF3, _gsfRunMask, 3),
     642             : 
     643             :     // @Param: GSF_USE_MASK
     644             :     // @DisplayName: Bitmask of which EKF-GSF yaw estimators are used
     645             :     // @Description: A bitmask of which EKF3 instances will use the output from the EKF-GSF yaw estimator that has been turned on by the EK3_GSF_RUN_MASK parameter. If the inertial navigation calculation stops following the GPS, then the vehicle code can request EKF3 to attempt to resolve the issue, either by performing a yaw reset if enabled by this parameter by switching to another EKF3 instance.
     646             :     // @Bitmask: 0:FirstEKF,1:SecondEKF,2:ThirdEKF,3:FourthEKF,4:FifthEKF,5:SixthEKF
     647             :     // @User: Advanced
     648             :     // @RebootRequired: True
     649             :     AP_GROUPINFO("GSF_USE_MASK", 58, NavEKF3, _gsfUseMask, 3),
     650             : 
     651             :     // 59 was GSF_DELAY which was never released in a stable version
     652             : 
     653             :     // @Param: GSF_RST_MAX
     654             :     // @DisplayName: Maximum number of resets to the EKF-GSF yaw estimate allowed
     655             :     // @Description: Sets the maximum number of times the EKF3 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 EK3_GSF_USE_MASK parameter.
     656             :     // @Range: 1 10
     657             :     // @Increment: 1
     658             :     // @User: Advanced
     659             :     // @RebootRequired: True
     660             :     AP_GROUPINFO("GSF_RST_MAX", 60, NavEKF3, _gsfResetMaxCount, 2),
     661             : 
     662             :     // @Param: ERR_THRESH
     663             :     // @DisplayName: EKF3 Lane Relative Error Sensitivity Threshold
     664             :     // @Description: lanes have to be consistently better than the primary by at least this threshold to reduce their overall relativeCoreError, lowering this makes lane switching more sensitive to smaller error differences
     665             :     // @Range: 0.05 1
     666             :     // @Increment: 0.05
     667             :     // @User: Advanced
     668             :     AP_GROUPINFO("ERR_THRESH", 61, NavEKF3, _err_thresh, 0.2),
     669             : 
     670             :     // @Param: AFFINITY
     671             :     // @DisplayName: EKF3 Sensor Affinity Options
     672             :     // @Description: These options control the affinity between sensor instances and EKF cores
     673             :     // @User: Advanced
     674             :     // @Bitmask: 0:EnableGPSAffinity,1:EnableBaroAffinity,2:EnableCompassAffinity,3:EnableAirspeedAffinity
     675             :     // @RebootRequired: True
     676             : 
     677             :     AP_GROUPINFO("AFFINITY", 62, NavEKF3, _affinity, 0),
     678             : 
     679             :     AP_SUBGROUPEXTENSION("", 63, NavEKF3, var_info2),
     680             : 
     681             :     AP_GROUPEND
     682             : };
     683             : 
     684             : // second table of parameters. allows us to go beyond the 64 parameter limit
     685             : const AP_Param::GroupInfo NavEKF3::var_info2[] = {
     686             : 
     687             :     // @Group: SRC
     688             :     // @Path: ../AP_NavEKF/AP_NavEKF_Source.cpp
     689             :     AP_SUBGROUPINFO(sources, "SRC", 1, NavEKF3, AP_NavEKF_Source),
     690             : 
     691             :     // @Param: DRAG_BCOEF_X
     692             :     // @DisplayName: Ballistic coefficient for X axis drag
     693             :     // @Description: Ratio of mass to drag coefficient measured along the X body axis. This parameter enables estimation of wind drift for vehicles with bluff bodies and without propulsion forces in the X and Y direction (eg multicopters). The drag produced by this effect scales with speed squared. Set to a positive value > 1.0 to enable. A starting value is the mass in Kg divided by the frontal area. The predicted drag from the rotors is specified separately by the EK3_DRAG_MCOEF parameter.
     694             :     // @Range: 0.0 1000.0
     695             :     // @Units: kg/m/m
     696             :     // @User: Advanced
     697             :     AP_GROUPINFO("DRAG_BCOEF_X", 2, NavEKF3, _ballisticCoef_x, 0.0f),
     698             : 
     699             :     // @Param: DRAG_BCOEF_Y
     700             :     // @DisplayName: Ballistic coefficient for Y axis drag
     701             :     // @Description: Ratio of mass to drag coefficient measured along the Y body axis. This parameter enables estimation of wind drift for vehicles with bluff bodies and without propulsion forces in the X and Y direction (eg multicopters). The drag produced by this effect scales with speed squared. Set to a positive value > 1.0 to enable. A starting value is the mass in Kg divided by the side area. The predicted drag from the rotors is specified separately by the EK3_DRAG_MCOEF parameter.
     702             :     // @Range: 50.0 1000.0
     703             :     // @Units: kg/m/m
     704             :     // @User: Advanced
     705             :     AP_GROUPINFO("DRAG_BCOEF_Y", 3, NavEKF3, _ballisticCoef_y, 0.0f),
     706             : 
     707             :     // @Param: DRAG_M_NSE
     708             :     // @DisplayName: Observation noise for drag acceleration
     709             :     // @Description: This sets the amount of noise used when fusing X and Y acceleration as an observation that enables estimation of wind velocity for multi-rotor vehicles. This feature is enabled by the EK3_DRAG_BCOEF_X and EK3_DRAG_BCOEF_Y parameters
     710             :     // @Range: 0.1 2.0
     711             :     // @Increment: 0.1
     712             :     // @User: Advanced
     713             :     // @Units: m/s/s
     714             :     AP_GROUPINFO("DRAG_M_NSE", 4, NavEKF3, _dragObsNoise, 0.5f),
     715             : 
     716             :     // @Param: DRAG_MCOEF
     717             :     // @DisplayName: Momentum coefficient for propeller drag
     718             :     // @Description: This parameter is used to predict the drag produced by the rotors when flying a multi-copter, enabling estimation of wind drift. The drag produced by this effect scales with speed not speed squared and is produced because some of the air velocity normal to the rotors axis of rotation is lost when passing through the rotor disc which changes the momentum of the airflow causing drag. For unducted rotors the effect is roughly proportional to the area of the propeller blades when viewed side on and changes with different propellers. It is higher for ducted rotors. For example if flying at 15 m/s at sea level conditions produces a rotor induced drag acceleration of 1.5 m/s/s, then EK3_DRAG_MCOEF would be set to 0.1 = (1.5/15.0). Set EK3_MCOEF to a positive value to enable wind estimation using this drag effect. To account for the drag produced by the body which scales with speed squared, see documentation for the EK3_DRAG_BCOEF_X and EK3_DRAG_BCOEF_Y parameters.
     719             :     // @Range: 0.0 1.0
     720             :     // @Increment: 0.01
     721             :     // @Units: 1/s
     722             :     // @User: Advanced
     723             :     AP_GROUPINFO("DRAG_MCOEF", 5, NavEKF3, _momentumDragCoef, 0.0f),
     724             : 
     725             :     // @Param: OGNM_TEST_SF
     726             :     // @DisplayName: On ground not moving test scale factor
     727             :     // @Description: This parameter is adjust the sensitivity of the on ground not moving test which is used to assist with learning the yaw gyro bias and stopping yaw drift before flight when operating without a yaw sensor. Bigger values allow the detection of a not moving condition with noiser IMU data. Check the XKFM data logged when the vehicle is on ground not moving and adjust the value of OGNM_TEST_SF to be slightly higher than the maximum value of the XKFM.ADR, XKFM.ALR, XKFM.GDR and XKFM.GLR test levels.
     728             :     // @Range: 1.0 10.0
     729             :     // @Increment: 0.5
     730             :     // @User: Advanced
     731             :     AP_GROUPINFO("OGNM_TEST_SF", 6, NavEKF3, _ognmTestScaleFactor, 2.0f),
     732             : 
     733             :     // @Param: GND_EFF_DZ
     734             :     // @DisplayName: Baro height ground effect dead zone
     735             :     // @Description: This parameter sets the size of the dead zone that is applied to negative baro height spikes that can occur when taking off or landing when a vehicle with lift rotors is operating in ground effect ground effect. Set to about 0.5m less than the amount of negative offset in baro height that occurs just prior to takeoff when lift motors are spooling up. Set to 0 if no ground effect is present.
     736             :     // @Range: 0.0 10.0
     737             :     // @Increment: 0.5
     738             :     // @User: Advanced
     739             :     AP_GROUPINFO("GND_EFF_DZ", 7, NavEKF3, _baroGndEffectDeadZone, 4.0f),
     740             : 
     741             :     // @Param: PRIMARY
     742             :     // @DisplayName: Primary core number
     743             :     // @Description: The core number (index in IMU mask) that will be used as the primary EKF core on startup. While disarmed the EKF will force the use of this core. A value of 0 corresponds to the first IMU in EK3_IMU_MASK.
     744             :     // @Range: 0 2
     745             :     // @Increment: 1
     746             :     // @User: Advanced
     747             :     AP_GROUPINFO("PRIMARY", 8, NavEKF3, _primary_core, EK3_PRIMARY_DEFAULT),
     748             : 
     749             :     // @Param: LOG_LEVEL
     750             :     // @DisplayName: Logging Level
     751             :     // @Description: Determines how verbose the EKF3 streaming logging is. A value of 0 provides full logging(default), a value of 1 only XKF4 scaled innovations are logged, a value of 2 both XKF4 and GSF are logged, and a value of 3 disables all streaming logging of EKF3.
     752             :     // @Range: 0 3
     753             :     // @Increment: 1
     754             :     // @User: Advanced
     755             :     AP_GROUPINFO("LOG_LEVEL", 9, NavEKF3, _log_level, 0),
     756             :     
     757             :     // @Param: GPS_VACC_MAX
     758             :     // @DisplayName: GPS vertical accuracy threshold
     759             :     // @Description: Vertical accuracy threshold for GPS as the altitude source. The GPS will not be used as an altitude source if the reported vertical accuracy of the GPS is larger than this threshold, falling back to baro instead. Set to zero to deactivate the threshold check.
     760             :     // @Range: 0.0 10.0
     761             :     // @Increment: 0.1
     762             :     // @User: Advanced
     763             :     // @Units: m
     764             :     AP_GROUPINFO("GPS_VACC_MAX", 10, NavEKF3, _gpsVAccThreshold, 0.0f),
     765             : 
     766             :     // @Param: OPTIONS
     767             :     // @DisplayName: Optional EKF behaviour
     768             :     // @Description: EKF optional behaviour. Bit 0 (JammingExpected): Setting JammingExpected will change the EKF behaviour such that if dead reckoning navigation is possible it will require the preflight alignment GPS quality checks controlled by EK3_GPS_CHECK and EK3_CHECK_SCALE to pass before resuming GPS use if GPS lock is lost for more than 2 seconds to prevent bad position estimate. Bit 1 (Manual lane switching): DANGEROUS – If enabled, this disables automatic lane switching. If the active lane becomes unhealthy, no automatic switching will occur. Users must manually set EK3_PRIMARY to change lanes. No health checks will be performed on the selected lane. Use with extreme caution.  Bit 2 (Optflow may use terrain alt): Terrain SRTM data will be used if the vehicle climbs above the rangefinder's range allowing optical flow to be used at higher altitudes. Bit 3 (AGL KF for optflow scaling): Use a 2-state IMU-aided AGL Kalman filter (height + vertical velocity, fused with rangefinder) to compute the height-above-ground used for optical flow velocity scaling, instead of terrainState-pd. This decouples optical flow scaling from errors in the main filter's vertical position state.
     769             :     // @Bitmask: 0:JammingExpected, 1:ManualLaneSwitching, 2:Optflow may use terrain alt, 3:AGL KF for optflow scaling
     770             :     // @User: Advanced
     771             :     AP_GROUPINFO("OPTIONS",  11, NavEKF3, _options, 0),
     772             : 
     773             :     AP_GROUPEND
     774             : };
     775             : 
     776        2193 : NavEKF3::NavEKF3() :
     777        2193 :     dal{AP::dal()}
     778             : {
     779        2193 :     AP_Param::setup_object_defaults(this, var_info);
     780        2193 :     AP_Param::setup_object_defaults(this, var_info2);
     781        2193 : }
     782             : 
     783             : 
     784             : // Initialise the filter
     785     1859466 : bool NavEKF3::InitialiseFilter(void)
     786             : {
     787     1859466 :     if (_enable == 0 || _imuMask == 0) {
     788     1103649 :         return false;
     789             :     }
     790      755817 :     const auto &ins = dal.ins();
     791             : 
     792      755817 :     dal.start_frame(AP_DAL::FrameType::InitialiseFilterEKF3);
     793             : 
     794      755817 :     imuSampleTime_us = dal.micros64();
     795             : 
     796             :     // remember expected frame time
     797      755817 :     const float loop_rate = ins.get_loop_rate_hz();
     798      755817 :     if (!is_positive(loop_rate)) {
     799             :         return false;
     800             :     }
     801      755817 :     _frameTimeUsec = 1e6 / loop_rate;
     802             : 
     803             :     // expected number of IMU frames per prediction
     804      755817 :     _framesPerPrediction = uint8_t((EKF_TARGET_DT / (_frameTimeUsec * 1.0e-6) + 0.5));
     805             : 
     806             : #if APM_BUILD_TYPE(APM_BUILD_Replay)
     807             :     if (ins.get_accel_count() == 0) {
     808             :         return false;
     809             :     }
     810             : #endif
     811             : 
     812      755817 :     if (core == nullptr) {
     813             : 
     814             :         // don't run multiple filters for 1 IMU
     815        1995 :         uint8_t mask = (1U<<ins.get_accel_count())-1;
     816        1995 :         _imuMask.set_and_default(_imuMask.get() & mask);
     817             :         
     818             :         // initialise the setup variables
     819        7980 :         for (uint8_t i=0; i<MAX_EKF_CORES; i++) {
     820        5985 :             coreSetupRequired[i] = false;
     821        5985 :             coreImuIndex[i] = 0;
     822             :         }
     823        1995 :         num_cores = 0;
     824             : 
     825             :         // count IMUs from mask
     826        7980 :         for (uint8_t i=0; i<INS_MAX_INSTANCES; i++) {
     827        5985 :             if (_imuMask & (1U<<i)) {
     828        3989 :                 coreSetupRequired[num_cores] = true;
     829        3989 :                 coreImuIndex[num_cores] = i;
     830        3989 :                 num_cores++;
     831             :             }
     832             :         }
     833             : 
     834             :         // check if there is enough memory to create the EKF cores
     835        1995 :         if (dal.available_memory() < sizeof(NavEKF3_core)*num_cores + 4096) {
     836           0 :             GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "EKF3 not enough memory");
     837           0 :             _enable.set(0);
     838           0 :             num_cores = 0;
     839           0 :             return false;
     840             :         }
     841             : 
     842             :         //try to allocate from CCM RAM, fallback to Normal RAM if not available or full
     843        1995 :         core = (NavEKF3_core*)dal.malloc_type(sizeof(NavEKF3_core)*num_cores, AP_DAL::MemoryType::FAST);
     844        1995 :         if (core == nullptr) {
     845           0 :             _enable.set(0);
     846           0 :             num_cores = 0;
     847           0 :             GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "EKF3 allocation failed");
     848           0 :             return false;
     849             :         }
     850             : 
     851             :         // Call constructors on all cores
     852        5984 :         for (uint8_t i = 0; i < num_cores; i++) {
     853        3989 :             new (&core[i]) NavEKF3_core(this, dal);
     854             :         }
     855             :     }
     856             : 
     857             :     // Set up any cores that have been created
     858             :     // This specifies the IMU to be used and creates the data buffers
     859             :     // If we are unable to set up a core, return false and try again next time the function is called
     860             :     bool core_setup_success = true;
     861     2267085 :     for (uint8_t core_index=0; core_index<num_cores; core_index++) {
     862     1511268 :         if (coreSetupRequired[core_index]) {
     863       48273 :             coreSetupRequired[core_index] = !core[core_index].setup_core(coreImuIndex[core_index], core_index);
     864       48273 :             if (coreSetupRequired[core_index]) {
     865             :                 core_setup_success = false;
     866             :             }
     867             :         }
     868             :     }
     869             :     // exit with failure if any cores could not be setup
     870      755817 :     if (!core_setup_success) {
     871             :         return false;
     872             :     }
     873             : 
     874             :     // set relative error scores for all cores to 0
     875      733658 :     resetCoreErrors();
     876             : 
     877             :     // Set the primary initially to be users selected primary
     878      733658 :     primary = uint8_t(_primary_core) < num_cores? _primary_core : 0;
     879             : 
     880             :     // invalidate shared origin
     881      733658 :     common_origin_valid = false;
     882             : 
     883             :     // initialise the cores. We return success only if all cores
     884             :     // initialise successfully
     885             :     bool ret = true;
     886     2200608 :     for (uint8_t i=0; i<num_cores; i++) {
     887     1466950 :         ret &= core[i].InitialiseFilterBootstrap();
     888             :     }
     889             : 
     890             :     // set last time the cores were primary to 0
     891      733658 :     memset(coreLastTimePrimary_us, 0, sizeof(coreLastTimePrimary_us));
     892             : 
     893             :     // zero the structs used capture reset events
     894      733658 :     memset(&yaw_reset_data, 0, sizeof(yaw_reset_data));
     895      733658 :     memset((void *)&pos_reset_data, 0, sizeof(pos_reset_data));
     896      733658 :     memset(&pos_down_reset_data, 0, sizeof(pos_down_reset_data));
     897             : 
     898      733658 :     return ret;
     899             : }
     900             : 
     901             : /*
     902             :   return true if a new core index has a better score than the current
     903             :   core
     904             :  */
     905    26541991 : bool NavEKF3::coreBetterScore(uint8_t new_core, uint8_t current_core) const
     906             : {
     907    26541991 :     const NavEKF3_core &oldCore = core[current_core];
     908    26541991 :     const NavEKF3_core &newCore = core[new_core];
     909    26541991 :     if (!newCore.healthy()) {
     910             :         // never consider a new core that isn't healthy
     911             :         return false;
     912             :     }
     913    26541991 :     if (newCore.have_aligned_tilt() != oldCore.have_aligned_tilt()) {
     914             :         // tilt alignment is most critical, if one is tilt aligned and
     915             :         // the other isn't then use the tilt aligned lane
     916             :         return newCore.have_aligned_tilt();
     917             :     }
     918    26541991 :     if (newCore.have_aligned_yaw() != oldCore.have_aligned_yaw()) {
     919             :         // yaw alignment is next most critical, if one is yaw aligned
     920             :         // and the other isn't then use the yaw aligned lane
     921             :         return newCore.have_aligned_yaw();
     922             :     }
     923             :     // if both cores are aligned then look at relative error scores
     924    26541986 :     return coreRelativeErrors[new_core] < coreRelativeErrors[current_core];
     925             : }
     926             : 
     927             : /* 
     928             :   Update Filter States - this should be called whenever new IMU data is available
     929             :   Execution speed governed by SCHED_LOOP_RATE
     930             : */
     931    39298372 : void NavEKF3::UpdateFilter(void)
     932             : {
     933    39298372 :     dal.start_frame(AP_DAL::FrameType::UpdateFilterEKF3);
     934             : 
     935    39298372 :     if (!core) {
     936             :         return;
     937             :     }
     938             : 
     939    39298372 :     imuSampleTime_us = dal.micros64();
     940             : 
     941   117616322 :     for (uint8_t i=0; i<num_cores; i++) {
     942             :         // if we have not overrun by more than 3 IMU frames, and we
     943             :         // have already used more than 1/3 of the CPU budget for this
     944             :         // loop then suppress the prediction step. This allows
     945             :         // multiple EKF instances to cooperate on scheduling
     946             :         bool allow_state_prediction = true;
     947   156635900 :         if (core[i].getFramesSincePredict() < (_framesPerPrediction+3) &&
     948    78317950 :             dal.ekf_low_time_remaining(AP_DAL::EKFType::EKF3, i)) {
     949             :             allow_state_prediction = false;
     950             :         }
     951    78317950 :         core[i].UpdateFilter(allow_state_prediction);
     952             :     }
     953             : 
     954             :     // If the current core selected has a bad error score or is unhealthy, switch to a healthy core with the lowest fault score
     955             :     // Don't start running the check until the primary core has started returned healthy for at least 10 seconds to avoid switching
     956             :     // due to initial alignment fluctuations and race conditions
     957    39298372 :     if (!runCoreSelection) {
     958             :         static uint64_t lastUnhealthyTime_us = 0;
     959     3192867 :         if (!core[primary].healthy() || lastUnhealthyTime_us == 0) {
     960      421928 :             lastUnhealthyTime_us = imuSampleTime_us;
     961             :         }
     962     3192867 :         runCoreSelection = (imuSampleTime_us - lastUnhealthyTime_us) > 1E7;
     963             :     }
     964             : 
     965    39298372 :     const uint8_t user_primary = uint8_t(_primary_core) < num_cores? _primary_core : 0;
     966             :     bool lane_switching_enabled = true;
     967    39298372 :     if (option_is_enabled(Option::ManualLaneSwitch)) {
     968             :         lane_switching_enabled = false;
     969       62726 :         if (primary != user_primary) {
     970             :             // switch back to the user-selected core
     971           1 :             switchLane(user_primary);
     972             :         }
     973             :     }
     974             : 
     975    39298372 :     const bool armed  = dal.get_armed();
     976             : 
     977             :     // core selection is only available after the vehicle is armed, else forced to lane 0 if its healthy
     978    39298372 :     if (runCoreSelection && armed && lane_switching_enabled) {
     979             :         // update this instance's error scores for all active cores and get the primary core's error score
     980    26802485 :         float primaryErrorScore = updateCoreErrorScores();
     981             : 
     982             :         // update the accumulated relative error scores for all active cores
     983    26802485 :         updateCoreRelativeErrors();
     984             : 
     985             :         bool betterCore = false;
     986             :         bool altCoreAvailable = false;
     987    26802485 :         uint8_t newPrimaryIndex = primary;
     988             : 
     989             :         // loop through all available cores to find if an alternative core is available
     990    80146961 :         for (uint8_t coreIndex=0; coreIndex<num_cores; coreIndex++) {
     991    53344476 :             if (coreIndex != primary) {
     992    26541991 :                 float altCoreError = coreRelativeErrors[coreIndex];
     993             : 
     994             :                 // an alternative core is available for selection based on 2 conditions -
     995             :                 // 1. healthy and states have been updated on this time step
     996             :                 // 2. has relative error less than primary core error
     997             :                 // 3. not been the primary core for at least 10 seconds
     998    26541991 :                 altCoreAvailable = coreBetterScore(coreIndex, newPrimaryIndex) &&
     999       66373 :                     imuSampleTime_us - coreLastTimePrimary_us[coreIndex] > 1E7;
    1000             : 
    1001             :                 if (altCoreAvailable) {
    1002             :                     // if this core has a significantly lower relative error to the active primary, we consider it as a 
    1003             :                     // better core and would like to switch to it even if the current primary is healthy
    1004       62568 :                     betterCore = altCoreError <= -BETTER_THRESH; // a better core if its relative error is below a substantial level than the primary's
    1005             :                     // handle the case where the secondary core is faster to complete yaw alignment which can happen
    1006             :                     // in flight when oeprating without a magnetomer
    1007       62568 :                     const NavEKF3_core &newCore = core[coreIndex];
    1008       62568 :                     const NavEKF3_core &oldCore = core[primary];
    1009      125134 :                     betterCore |= newCore.have_aligned_yaw() && !oldCore.have_aligned_yaw();
    1010             :                     newPrimaryIndex = coreIndex;
    1011             :                 }
    1012             :             }
    1013             :         }
    1014    26802485 :         altCoreAvailable = newPrimaryIndex != primary;
    1015             : 
    1016             :         // Switch cores if another core is available and the active primary core meets one of the following conditions - 
    1017             :         // 1. has a bad error score
    1018             :         // 2. is unhealthy
    1019             :         // 3. is healthy, but a better core is available
    1020             :         // also update the yaw and position reset data to capture changes due to the lane switch
    1021    26802485 :         if (altCoreAvailable && (primaryErrorScore > 1.0f || !core[primary].healthy() || betterCore)) {
    1022          46 :             switchLane(newPrimaryIndex);
    1023          46 :             resetCoreErrors();
    1024          46 :             coreLastTimePrimary_us[primary] = imuSampleTime_us;
    1025             :         }
    1026             :     }
    1027             : 
    1028    39298372 :     if (primary != user_primary && core[user_primary].healthy() && !armed) {
    1029             :         // when on the ground and disarmed force the selected primary
    1030             :         // core. This avoids us ending with with a lottery for which
    1031             :         // IMU is used in each flight. Otherwise the alignment of the
    1032             :         // timing of the core selection updates with the timing of GPS
    1033             :         // updates can lead to a core other than the first one being
    1034             :         // used as primary for some flights. As different IMUs may
    1035             :         // have quite different noise characteristics this leads to
    1036             :         // inconsistent performance
    1037          23 :         primary = user_primary;
    1038             :     }
    1039             : 
    1040             :     // align position of inactive sources to ahrs
    1041    39298372 :     sources.align_inactive_sources();
    1042             : }
    1043             : 
    1044             : /*
    1045             :   check if switching lanes will reduce the normalised
    1046             :   innovations. This is called when the vehicle code is about to
    1047             :   trigger an EKF failsafe, and it would like to avoid that by
    1048             :   using a different EKF lane
    1049             : */
    1050          31 : void NavEKF3::checkLaneSwitch(void)
    1051             : {
    1052          31 :     dal.log_event3(AP_DAL::Event::checkLaneSwitch);
    1053             : 
    1054          31 :     if (option_is_enabled(Option::ManualLaneSwitch)) {
    1055             :         return;
    1056             :     }
    1057             : 
    1058          30 :     uint32_t now = dal.millis();
    1059          30 :     if (lastLaneSwitch_ms != 0 && now - lastLaneSwitch_ms < 5000) {
    1060             :         // don't switch twice in 5 seconds
    1061             :         return;
    1062             :     }
    1063             : 
    1064          30 :     float primaryErrorScore = core[primary].errorScore();
    1065             :     float lowestErrorScore = primaryErrorScore;
    1066          30 :     uint8_t newPrimaryIndex = primary;
    1067          90 :     for (uint8_t coreIndex=0; coreIndex<num_cores; coreIndex++) {
    1068          60 :         if (coreIndex != primary) {
    1069          30 :             const NavEKF3_core &newCore = core[coreIndex];
    1070             :             // an alternative core is available for selection only if healthy and if states have been updated on this time step
    1071          30 :             bool altCoreAvailable = newCore.healthy() && newCore.have_aligned_yaw() && newCore.have_aligned_tilt();
    1072          30 :             float altErrorScore = newCore.errorScore();
    1073          30 :             if (altCoreAvailable && altErrorScore < lowestErrorScore && altErrorScore < 0.9) {
    1074             :                 newPrimaryIndex = coreIndex;
    1075             :                 lowestErrorScore = altErrorScore;
    1076             :             }
    1077             :         }
    1078             :     }
    1079             : 
    1080             :     // update the yaw and position reset data to capture changes due to the lane switch
    1081          30 :     switchLane(newPrimaryIndex);
    1082             : }
    1083             : 
    1084             : // switch to a new lane
    1085          77 : void NavEKF3::switchLane(uint8_t new_lane_index)
    1086             : {
    1087          77 :     if (new_lane_index >= num_cores) {
    1088             :         return;
    1089             :     }
    1090             : 
    1091          77 :     if (new_lane_index != primary) {
    1092          57 :         updateLaneSwitchYawResetData(new_lane_index);
    1093          57 :         updateLaneSwitchPosResetData(new_lane_index);
    1094          57 :         updateLaneSwitchPosDownResetData(new_lane_index);
    1095          57 :         primary = new_lane_index;
    1096          57 :         lastLaneSwitch_ms = dal.millis();
    1097          57 :         GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "EKF3 lane switch %u", primary);
    1098             :     }
    1099             : }
    1100             : 
    1101           4 : void NavEKF3::requestYawReset(void)
    1102             : {
    1103           4 :     dal.log_event3(AP_DAL::Event::requestYawReset);
    1104             : 
    1105          12 :     for (uint8_t i = 0; i < num_cores; i++) {
    1106           8 :         core[i].EKFGSF_requestYawReset();
    1107             :     }
    1108           4 : }
    1109             : 
    1110             : /*
    1111             :   Update this instance error score value for all active cores
    1112             : */
    1113    26802485 : float NavEKF3::updateCoreErrorScores()
    1114             : {
    1115    80146961 :     for (uint8_t i = 0; i < num_cores; i++) {
    1116    53344476 :         coreErrorScores[i] = core[i].errorScore();
    1117             :     }
    1118    26802485 :     return coreErrorScores[primary];
    1119             : }
    1120             : 
    1121             : /*
    1122             :   Update the relative error for all alternate available cores with respect to primary core's error.
    1123             :   A positive relative error for a core means it has been more erroneous than the existing primary.
    1124             :   A negative relative error indicates a core which can be switched to.
    1125             : */
    1126    26802485 : void NavEKF3::updateCoreRelativeErrors()
    1127             : {
    1128             :     float error = 0;
    1129    80146961 :     for (uint8_t i = 0; i < num_cores; i++) {
    1130    53344476 :         if (i != primary) {
    1131    26541991 :             error = coreErrorScores[i] - coreErrorScores[primary];
    1132             :             // reduce error for a core only if its better than the primary lane by at least the Relative Error Threshold, this should prevent unnecessary lane changes
    1133    26541991 :             if (error > 0 || error < -MAX(_err_thresh, 0.05)) {
    1134    15460995 :                 coreRelativeErrors[i] += error;
    1135    15460995 :                 coreRelativeErrors[i] = constrain_ftype(coreRelativeErrors[i], -CORE_ERR_LIM, CORE_ERR_LIM);
    1136             :             }
    1137             :         }
    1138             :     }
    1139    26802485 : }
    1140             : 
    1141             : // Reset the relative error values
    1142      733704 : void NavEKF3::resetCoreErrors(void)
    1143             : {
    1144     2200746 :     for (uint8_t i = 0; i < num_cores; i++) {
    1145     1467042 :         coreRelativeErrors[i] = 0;
    1146             :     }
    1147      733704 : }
    1148             : 
    1149             : // set position, velocity and yaw sources to either 0=primary, 1=secondary, 2=tertiary
    1150          16 : void NavEKF3::setPosVelYawSourceSet(uint8_t source_set_idx)
    1151             : {
    1152          16 :     if (source_set_idx < AP_NAKEKF_SOURCE_SET_MAX) {
    1153          16 :         dal.log_event3(AP_DAL::Event(uint8_t(AP_DAL::Event::setSourceSet0)+source_set_idx));
    1154             :     }
    1155          16 :     sources.setPosVelYawSourceSet((AP_NavEKF_Source::SourceSetSelection)source_set_idx);
    1156          16 : }
    1157             : 
    1158             : // Check basic filter health metrics and return a consolidated health status
    1159    39298372 : bool NavEKF3::healthy(void) const
    1160             : {
    1161    39298372 :     if (!core) {
    1162             :         return false;
    1163             :     }
    1164    39298372 :     return core[primary].healthy();
    1165             : }
    1166             : 
    1167             : // returns false if we fail arming checks, in which case the buffer will be populated with a failure message
    1168             : // requires_position should be true if horizontal position configuration should be checked
    1169       31446 : bool NavEKF3::pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const
    1170             : {
    1171             :     // check source configuration
    1172       31446 :     if (!sources.pre_arm_check(requires_position, failure_msg, failure_msg_len)) {
    1173             :         return false;
    1174             :     }
    1175             : 
    1176             :     // check if using compass (i.e. EK3_SRCn_YAW) with deprecated MAG_CAL values (5 was EXTERNAL_YAW, 6 was EXTERNAL_YAW_FALLBACK)
    1177       31433 :     const int8_t magCalParamVal = _magCal.get();
    1178       94258 :     for (uint8_t i = 0; i < num_cores; i++) {
    1179       62825 :         const AP_NavEKF_Source::SourceYaw yaw_source = sources.getYawSource(i);
    1180       62825 :         if (((magCalParamVal == 5) || (magCalParamVal == 6)) && (yaw_source != AP_NavEKF_Source::SourceYaw::GPS)) {
    1181             :             // yaw source is configured to use compass but MAG_CAL valid is deprecated
    1182           0 :             dal.snprintf(failure_msg, failure_msg_len, "EK3_MAG_CAL and EK3_SRC1_YAW inconsistent");
    1183           0 :             return false;
    1184             :         }
    1185             :     }
    1186             : 
    1187       31433 :     if (!core) {
    1188           0 :         dal.snprintf(failure_msg, failure_msg_len, "no EKF3 cores");
    1189           0 :         return false;
    1190             :     }
    1191       92944 :     for (uint8_t i = 0; i < num_cores; i++) {
    1192       62177 :         if (!core[i].healthy()) {
    1193         662 :             const char *failure = core[i].prearm_failure_reason();
    1194         662 :             if (failure != nullptr) {
    1195         645 :                 dal.snprintf(failure_msg, failure_msg_len, failure);
    1196             :             } else {
    1197          17 :                 dal.snprintf(failure_msg, failure_msg_len, "EKF3 core %d unhealthy", (int)i);
    1198             :             }
    1199         662 :             return false;
    1200             :         }
    1201             :         // run per-core pre-arm checks
    1202       61515 :         if (!core[i].pre_arm_check(requires_position, failure_msg, failure_msg_len)) {
    1203             :             return false;
    1204             :         }
    1205             :     }
    1206             :     return true;
    1207             : }
    1208             : 
    1209             : // returns the index of the primary core
    1210             : // return -1 if no primary core selected
    1211    44047616 : int8_t NavEKF3::getPrimaryCoreIndex(void) const
    1212             : {
    1213    44047616 :     if (!core) {
    1214             :         return -1;
    1215             :     }
    1216    44047616 :     return primary;
    1217             : }
    1218             : 
    1219             : // returns the index of the IMU of the primary core
    1220             : // return -1 if no primary core selected
    1221    83373432 : int8_t NavEKF3::getPrimaryCoreIMUIndex(void) const
    1222             : {
    1223    83373432 :     if (!core) {
    1224             :         return -1;
    1225             :     }
    1226    80106038 :     return core[primary].getIMUIndex();
    1227             : }
    1228             : 
    1229             : // Write the last calculated NE position relative to the reference point (m).
    1230             : // If a calculated solution is not available, use the best available data and return false
    1231             : // If false returned, do not use for flight control
    1232    41686716 : bool NavEKF3::getPosNE(Vector2p &posNE) const
    1233             : {
    1234    41686716 :     if (!core) {
    1235             :         return false;
    1236             :     }
    1237    40053019 :     return core[primary].getPosNE(posNE);
    1238             : }
    1239             : 
    1240             : // Write the last calculated D position relative to the reference point (m).
    1241             : // If a calculated solution is not available, use the best available data and return false
    1242             : // If false returned, do not use for flight control
    1243    41686716 : bool NavEKF3::getPosD(postype_t &posD) const
    1244             : {
    1245    41686716 :     if (!core) {
    1246             :         return false;
    1247             :     }
    1248    40053019 :     return core[primary].getPosD(posD);
    1249             : }
    1250             : 
    1251             : // return NED velocity in m/s
    1252    41686716 : void NavEKF3::getVelNED(Vector3f &vel) const
    1253             : {
    1254    41686716 :     if (core) {
    1255    40053019 :         core[primary].getVelNED(vel);
    1256             :     }
    1257    41686716 : }
    1258             : 
    1259             : // return estimate of true airspeed vector in body frame in m/s
    1260             : // returns false if estimate is unavailable
    1261    36087486 : bool NavEKF3::getAirSpdVec(Vector3f &vel) const
    1262             : {
    1263    36087486 :     if (core) {
    1264    36087486 :         return core[primary].getAirSpdVec(vel);
    1265             :     }
    1266             :     return false;
    1267             : }
    1268             : 
    1269             : // return the innovation in m/s, innovation variance in (m/s)^2 and age in msec of the last TAS measurement processed for a given sensor instance
    1270      152265 : bool NavEKF3::getAirSpdHealthData(uint8_t instance, float &innovation, float &innovationVariance, uint32_t &age_ms) const
    1271             : {
    1272      152265 :     if (core == nullptr) {
    1273             :         return false;
    1274             :     }
    1275             : 
    1276             :     // Return primary if it is configured to use the given instance
    1277      152265 :     if (core[primary].getActiveAirspeed() == instance) {
    1278      146109 :         return core[primary].getAirSpdHealthData(innovation, innovationVariance, age_ms);
    1279             :     }
    1280             : 
    1281             :     // See if another core is using the given instance
    1282       17181 :     for (uint8_t i = 0; i < num_cores; i++) {
    1283       11895 :         if (core[i].getActiveAirspeed() == instance) {
    1284         870 :             return core[i].getAirSpdHealthData(innovation, innovationVariance, age_ms);
    1285             :         }
    1286             :     }
    1287             : 
    1288             :     return false;
    1289             : }
    1290             : 
    1291             : // Return the rate of change of vertical position in the down direction (dPosD/dt) in m/s
    1292    41686716 : float NavEKF3::getPosDownDerivative() const
    1293             : {
    1294             :     // return the value calculated from a complementary filter applied to the EKF height and vertical acceleration
    1295    41686716 :     if (core) {
    1296    40053019 :         return core[primary].getPosDownDerivative();
    1297             :     }
    1298             :     return 0.0f;
    1299             : }
    1300             : 
    1301             : // return body axis gyro bias estimates in rad/sec
    1302    41686716 : void NavEKF3::getGyroBias(int8_t instance, Vector3f &gyroBias) const
    1303             : {
    1304    41686716 :     if (instance < 0 || instance >= num_cores) instance = primary;
    1305    41686716 :     if (core) {
    1306    40053019 :         core[instance].getGyroBias(gyroBias);
    1307             :     }
    1308    41686716 : }
    1309             : 
    1310             : // return accelerometer bias estimate in m/s/s
    1311    41686716 : void NavEKF3::getAccelBias(int8_t instance, Vector3f &accelBias) const
    1312             : {
    1313    41686716 :     if (instance < 0 || instance >= num_cores) instance = primary;
    1314    41686716 :     if (core) {
    1315    40053019 :         core[instance].getAccelBias(accelBias);
    1316             :     }
    1317    41686716 : }
    1318             : 
    1319             : // returns active source set used by EKF3
    1320           0 : uint8_t NavEKF3::get_active_source_set() const
    1321             : {
    1322           0 :     return sources.get_active_source_set();
    1323             : }
    1324             : 
    1325             : // reset body axis gyro bias estimates
    1326           7 : void NavEKF3::resetGyroBias(void)
    1327             : {
    1328           7 :     dal.log_event3(AP_DAL::Event::resetGyroBias);
    1329             : 
    1330           7 :     if (core) {
    1331          21 :         for (uint8_t i=0; i<num_cores; i++) {
    1332          14 :             core[i].resetGyroBias();
    1333             :         }
    1334             :     }
    1335           7 : }
    1336             : 
    1337             : // Resets the baro so that it reads zero at the current height
    1338             : // Resets the EKF height to zero
    1339             : // Adjusts the EKF origin height so that the EKF height + origin height is the same as before
    1340             : // Returns true if the height datum reset has been performed
    1341             : // If using a range finder for height no reset is performed and it returns false
    1342        3121 : bool NavEKF3::resetHeightDatum(void)
    1343             : {
    1344        3121 :     dal.log_event3(AP_DAL::Event::resetHeightDatum);
    1345             : 
    1346             :     bool status = true;
    1347        3121 :     if (core) {
    1348        8828 :         for (uint8_t i=0; i<num_cores; i++) {
    1349        5885 :             if (!core[i].resetHeightDatum()) {
    1350             :                 status = false;
    1351             :             }
    1352             :         }
    1353             :     } else {
    1354             :         status = false;
    1355             :     }
    1356        3121 :     return status;
    1357             : }
    1358             : 
    1359             : // return the horizontal speed limit in m/s set by optical flow sensor limits
    1360             : // return the scale factor to be applied to navigation velocity gains to compensate for increase in velocity noise with height when using optical flow
    1361    41686716 : void NavEKF3::getEkfControlLimits(float &ekfGndSpdLimit, float &ekfNavVelGainScaler) const
    1362             : {
    1363    41686716 :     if (core) {
    1364    40053019 :         core[primary].getEkfControlLimits(ekfGndSpdLimit, ekfNavVelGainScaler);
    1365             :     } else {
    1366     1633697 :         ekfGndSpdLimit = 400.0f; //return 80% of max filter speed
    1367     1633697 :         ekfNavVelGainScaler = 1.0f;
    1368             :     }
    1369    41686716 : }
    1370             : 
    1371             : // return the NED wind speed estimates in m/s (positive is air moving in the direction of the axis)
    1372             : // returns true if wind state estimation is active
    1373    41686716 : bool NavEKF3::getWind(Vector3f &wind) const
    1374             : {
    1375    41686716 :     if (core == nullptr) {
    1376             :         return false;
    1377             :     }
    1378    40053019 :     return core[primary].getWind(wind);
    1379             : }
    1380             : 
    1381             : // return earth magnetic field estimates in measurement units / 1000
    1382    41686716 : void NavEKF3::getMagNED(Vector3f &magNED) const
    1383             : {
    1384    41686716 :     if (core) {
    1385    40053019 :         core[primary].getMagNED(magNED);
    1386             :     }
    1387    41686716 : }
    1388             : 
    1389             : // return body magnetic field estimates in measurement units / 1000
    1390    41686716 : void NavEKF3::getMagXYZ(Vector3f &magXYZ) const
    1391             : {
    1392    41686716 :     if (core) {
    1393    40053019 :         core[primary].getMagXYZ(magXYZ);
    1394             :     }
    1395    41686716 : }
    1396             : 
    1397             : // return the airspeed sensor in use
    1398    72438414 : uint8_t NavEKF3::getActiveAirspeed() const
    1399             : {
    1400    72438414 :     if (core) {
    1401    72438414 :         return core[primary].getActiveAirspeed();
    1402             :     } else {
    1403             :         return UINT8_MAX;
    1404             :     }
    1405             : }
    1406             : 
    1407             : // Return estimated magnetometer offsets
    1408             : // Return true if magnetometer offsets are valid
    1409           9 : bool NavEKF3::getMagOffsets(uint8_t mag_idx, Vector3f &magOffsets) const
    1410             : {
    1411           9 :     if (!core) {
    1412             :         return false;
    1413             :     }
    1414             :     // try the primary first, else loop through all of the cores and return when one has offsets for this mag instance
    1415           9 :     if (core[primary].getMagOffsets(mag_idx, magOffsets)) {
    1416             :         return true;
    1417             :     }
    1418          15 :     for (uint8_t i=0; i<num_cores; i++) {
    1419          11 :         if(core[i].getMagOffsets(mag_idx, magOffsets)) {
    1420             :             return true;
    1421             :         }
    1422             :     }
    1423             :     return false;
    1424             : }
    1425             : 
    1426             : // Return the last calculated latitude, longitude and height in WGS-84
    1427             : // If a calculated location isn't available, return a raw GPS measurement
    1428             : // The status will return true if a calculation or raw measurement is available
    1429             : // The getFilterStatus() function provides a more detailed description of data health and must be checked if data is to be used for flight control
    1430    41686716 : bool NavEKF3::getLLH(Location &loc) const
    1431             : {
    1432    41686716 :     if (!core) {
    1433             :         return false;
    1434             :     }
    1435    40053019 :     return core[primary].getLLH(loc);
    1436             : }
    1437             : 
    1438             : // Return the latitude and longitude and height used to set the NED origin
    1439             : // All NED positions calculated by the filter are relative to this location
    1440             : // Returns false if the origin has not been set
    1441    52093524 : bool NavEKF3::getOriginLLH(Location &loc) const
    1442             : {
    1443    52093524 :     if (!core) {
    1444             :         return false;
    1445             :     }
    1446    49962614 :     if (common_origin_valid) {
    1447    39910125 :         loc = common_EKF_origin;
    1448    39910125 :         return true;
    1449             :     }
    1450    10052489 :     return core[primary].getOriginLLH(loc);
    1451             : }
    1452             : 
    1453             : // set the latitude and longitude and height used to set the NED origin
    1454             : // All NED positions calculated by the filter will be relative to this location
    1455             : // The origin cannot be set if the filter is in a flight mode (eg vehicle armed)
    1456             : // Returns false if the filter has rejected the attempt to set the origin
    1457         219 : bool NavEKF3::setOriginLLH(const Location &loc)
    1458             : {
    1459         219 :     dal.log_SetOriginLLH3(loc);
    1460             : 
    1461         219 :     if (!core) {
    1462             :         return false;
    1463             :     }
    1464         159 :     if (common_origin_valid) {
    1465             :         // we don't allow setting the EKF origin if it has already been set
    1466             :         // this is to prevent causing upsets from a shifting origin.
    1467           0 :         GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "EKF3: origin already set");
    1468           0 :         return false;
    1469             :     }
    1470             :     bool ret = false;
    1471         477 :     for (uint8_t i=0; i<num_cores; i++) {
    1472         318 :         ret |= core[i].setOriginLLH(loc);
    1473             :     }
    1474             :     // return true if any core accepts the new origin
    1475             :     return ret;
    1476             : }
    1477             : 
    1478           2 : bool NavEKF3::setLatLng(const Location &loc, float posAccuracy, uint32_t timestamp_ms)
    1479             : {
    1480             : #if EK3_FEATURE_POSITION_RESET
    1481           2 :     dal.log_SetLatLng(loc, posAccuracy, timestamp_ms);
    1482             : 
    1483           2 :     if (!core) {
    1484             :         return false;
    1485             :     }
    1486             :     bool ret = false;
    1487           6 :     for (uint8_t i=0; i<num_cores; i++) {
    1488           4 :         ret |= core[i].setLatLng(loc, posAccuracy, timestamp_ms);
    1489             :     }
    1490             :     // return true if any core accepts the new origin
    1491             :     return ret;
    1492             : #else
    1493             :     return false;
    1494             : #endif // EK3_FEATURE_POSITION_RESET
    1495             : }
    1496             : 
    1497             : 
    1498             : // return estimated height above ground level
    1499             : // return false if ground height is not being estimated.
    1500    41686716 : bool NavEKF3::getHAGL(float &HAGL) const
    1501             : {
    1502    41686716 :     if (!core) {
    1503             :         return false;
    1504             :     }
    1505    40053019 :     return core[primary].getHAGL(HAGL);
    1506             : }
    1507             : 
    1508             : // return the Euler roll, pitch and yaw angle in radians
    1509    41686716 : void NavEKF3::getEulerAngles(Vector3f &eulers) const
    1510             : {
    1511    41686716 :     if (core) {
    1512    40053019 :         core[primary].getEulerAngles(eulers);
    1513             :     }
    1514    41686716 : }
    1515             : 
    1516             : // return the transformation matrix from XYZ (body) to NED axes
    1517    41686716 : void NavEKF3::getRotationBodyToNED(Matrix3f &mat) const
    1518             : {
    1519    41686716 :     if (core) {
    1520    40053019 :         core[primary].getRotationBodyToNED(mat);
    1521             :     }
    1522    41686716 : }
    1523             : 
    1524             : // return the quaternions defining the rotation from XYZ (body) to NED axes
    1525       73821 : void NavEKF3::getQuaternionBodyToNED(int8_t instance, Quaternion &quat) const
    1526             : {
    1527       73821 :     if (instance < 0 || instance >= num_cores) instance = primary;
    1528       73821 :     if (core) {
    1529       73821 :         Matrix3f mat;
    1530       73821 :         core[instance].getRotationBodyToNED(mat);
    1531       73821 :         quat.from_rotation_matrix(mat);
    1532             :     }
    1533       73821 : }
    1534             : 
    1535             : // return the quaternions defining the rotation from NED to XYZ (autopilot) axes
    1536    41686716 : void NavEKF3::getQuaternion(Quaternion &quat) const
    1537             : {
    1538    41686716 :     if (core) {
    1539    40053019 :         core[primary].getQuaternion(quat);
    1540             :     }
    1541    41686716 : }
    1542             : 
    1543             : // return the innovations
    1544      686586 : bool NavEKF3::getInnovations(Vector3f &velInnov, Vector3f &posInnov, Vector3f &magInnov, float &tasInnov, float &yawInnov) const
    1545             : {
    1546      686586 :     if (core == nullptr) {
    1547             :         return false;
    1548             :     }
    1549             : 
    1550      677201 :     return core[primary].getInnovations(velInnov, posInnov, magInnov, tasInnov, yawInnov);
    1551             : }
    1552             : 
    1553             : // return the innovation consistency test ratios for the velocity, position, magnetometer and true airspeed measurements
    1554    41686716 : bool NavEKF3::getVariances(float &velVar, float &posVar, float &hgtVar, Vector3f &magVar, float &tasVar, Vector2f &offset) const
    1555             : {
    1556    41686716 :     if (core == nullptr) {
    1557             :         return false;
    1558             :     }
    1559             : 
    1560    40053019 :     return core[primary].getVariances(velVar, posVar, hgtVar, magVar, tasVar, offset);
    1561             : }
    1562             : 
    1563             : // return 1-sigma position and velocity uncertainty from the EKF state error covariance matrix P
    1564          13 : bool NavEKF3::getPosVelUncertainty(float &pos_horiz_m, float &pos_vert_m, float &vel_m_s) const
    1565             : {
    1566          13 :     if (core == nullptr) {
    1567             :         return false;
    1568             :     }
    1569          13 :     return core[primary].getPosVelUncertainty(pos_horiz_m, pos_vert_m, vel_m_s);
    1570             : }
    1571             : 
    1572             : // get a source's velocity innovations
    1573             : // returns true on success and results are placed in innovations and variances arguments
    1574          39 : bool NavEKF3::getVelInnovationsAndVariancesForSource(AP_NavEKF_Source::SourceXY source, Vector3f &innovations, Vector3f &variances) const
    1575             : {
    1576          39 :     if (core) {
    1577          28 :         return core[primary].getVelInnovationsAndVariancesForSource(source, innovations, variances);
    1578             :     }
    1579             :     return false;
    1580             : }
    1581             : 
    1582             : // should we use the compass? This is public so it can be used for
    1583             : // reporting via ahrs.use_compass()
    1584       46313 : bool NavEKF3::use_compass(void) const
    1585             : {
    1586       46313 :     if (!core) {
    1587             :         return false;
    1588             :     }
    1589       46313 :     return core[primary].use_compass();
    1590             : }
    1591             : 
    1592             : // are we using (aka fusing) a non-compass yaw?
    1593    41704514 : bool NavEKF3::using_noncompass_for_yaw(void) const
    1594             : {
    1595    41704514 :     if (!core) {
    1596             :         return false;
    1597             :     }
    1598    40070817 :     return core[primary].using_noncompass_for_yaw();
    1599             : }
    1600             : 
    1601             : // are we using (aka fusing) external nav for yaw?
    1602    41686716 : bool NavEKF3::using_extnav_for_yaw() const
    1603             : {
    1604    41686716 :     if (!core) {
    1605             :         return false;
    1606             :     }
    1607    40053019 :     return core[primary].using_extnav_for_yaw();
    1608             : }
    1609             : 
    1610             : // are we using a gps?
    1611    41686716 : bool NavEKF3::using_gps(void) const
    1612             : {
    1613    41686716 :     if (!core) {
    1614             :         return false;
    1615             :     }
    1616    40053019 :     return core[primary].using_gps();
    1617             : }
    1618             : 
    1619             : // check if configured to use GPS for horizontal position estimation
    1620    49400439 : bool NavEKF3::configuredToUseGPSForPosXY(void) const
    1621             : {
    1622             :     // 0 = use 3D velocity, 1 = use 2D velocity, 2 = use no velocity, 3 = do not use GPS
    1623    49400439 :     if (sources.getPosXYSource(primary) == AP_NavEKF_Source::SourceXY::GPS) {
    1624    48959659 :         return true;
    1625             :     }
    1626             :     return false;
    1627             : }
    1628             : 
    1629             : // check if configured to use GPS for horizontal position estimation
    1630           0 : bool NavEKF3::configuredToUseGPSForPos(void) const
    1631             : {
    1632           0 :     if (configuredToUseGPSForPosXY() || sources.getPosZSource(primary) == AP_NavEKF_Source::SourceZ::GPS) {
    1633           0 :         return true;
    1634             :     }
    1635             :     return false;
    1636             : }
    1637             : 
    1638             : // write the raw optical flow measurements
    1639             : // rawFlowQuality is a measured of quality between 0 and 255, with 255 being the best quality
    1640             : // rawFlowRates are the optical flow rates in rad/sec about the X and Y sensor axes.
    1641             : // rawGyroRates are the sensor rotation rates in rad/sec measured by the sensors internal gyro
    1642             : // The sign convention is that a RH physical rotation of the sensor about an axis produces both a positive flow and gyro rate
    1643             : // msecFlowMeas is the scheduler time in msec when the optical flow data was received from the sensor.
    1644             : // posOffset is the XYZ flow sensor position in the body frame in m
    1645             : // heightOverride is the fixed height of the sensor above ground in m, when on rover vehicles. 0 if not used
    1646             : #if EK3_FEATURE_OPTFLOW_FUSION
    1647       10128 : void NavEKF3::writeOptFlowMeas(const uint8_t rawFlowQuality, const Vector2f &rawFlowRates, const Vector2f &rawGyroRates, const uint32_t msecFlowMeas, const Vector3f &posOffset, float heightOverride)
    1648             : {
    1649       10128 :     dal.writeOptFlowMeas(rawFlowQuality, rawFlowRates, rawGyroRates, msecFlowMeas, posOffset, heightOverride);
    1650             : 
    1651       10128 :     if (core) {
    1652       29964 :         for (uint8_t i=0; i<num_cores; i++) {
    1653       19976 :             core[i].writeOptFlowMeas(rawFlowQuality, rawFlowRates, rawGyroRates, msecFlowMeas, posOffset, heightOverride);
    1654             :         }
    1655             :     }
    1656       10128 : }
    1657             : 
    1658             : // retrieve latest corrected optical flow samples (used for calibration)
    1659       11051 : bool NavEKF3::getOptFlowSample(uint32_t& timeStamp_ms, Vector2f& flowRate, Vector2f& bodyRate, Vector2f& losPred) const
    1660             : {
    1661             :     // return optical flow samples from primary core
    1662       11051 :     if (core) {
    1663       11051 :         return core[primary].getOptFlowSample(timeStamp_ms, flowRate, bodyRate, losPred);
    1664             :     }
    1665             :     return false;
    1666             : }
    1667             : #endif  // EK3_FEATURE_OPTFLOW_FUSION
    1668             : 
    1669             : // write yaw angle sensor measurements
    1670           0 : void NavEKF3::writeEulerYawAngle(float yawAngle, float yawAngleErr, uint32_t timeStamp_ms, uint8_t type)
    1671             : {
    1672           0 :     dal.log_writeEulerYawAngle(yawAngle, yawAngleErr, timeStamp_ms, type);
    1673             : 
    1674           0 :     if (core) {
    1675           0 :         for (uint8_t i=0; i<num_cores; i++) {
    1676           0 :             core[i].writeEulerYawAngle(yawAngle, yawAngleErr, timeStamp_ms, type);
    1677             :         }
    1678             :     }
    1679           0 : }
    1680             : 
    1681             : /*
    1682             :  * Write position and quaternion data from an external navigation system
    1683             :  *
    1684             :  * 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.
    1685             :  * quat       : quaternion describing the rotation from navigation frame to body frame
    1686             :  * posErr     : 1-sigma spherical position error (m)
    1687             :  * angErr     : 1-sigma spherical angle error (rad)
    1688             :  * timeStamp_ms : system time the measurement was taken, not the time it was received (mSec)
    1689             :  * delay_ms   : average delay of external nav system measurements relative to inertial measurements
    1690             :  * resetTime_ms : system time of the last position reset request (mSec)
    1691             :  *
    1692             : */
    1693       10069 : void NavEKF3::writeExtNavData(const Vector3f &pos, const Quaternion &quat, float posErr, float angErr, uint32_t timeStamp_ms, uint16_t delay_ms, uint32_t resetTime_ms)
    1694             : {
    1695       10069 :     dal.writeExtNavData(pos, quat, posErr, angErr, timeStamp_ms, delay_ms, resetTime_ms);
    1696             : 
    1697       10069 :     if (core) {
    1698       29844 :         for (uint8_t i=0; i<num_cores; i++) {
    1699       19896 :             core[i].writeExtNavData(pos, quat, posErr, angErr, timeStamp_ms, delay_ms, resetTime_ms);
    1700             :         }
    1701             :     }
    1702       10069 : }
    1703             : 
    1704             : /* Write velocity data from an external navigation system
    1705             :  * vel : velocity in NED (m)
    1706             :  * err : velocity error (m/s)
    1707             :  * timeStamp_ms : system time the measurement was taken, not the time it was received (mSec)
    1708             :  * delay_ms : average delay of external nav system measurements relative to inertial measurements
    1709             : */
    1710        4278 : void NavEKF3::writeExtNavVelData(const Vector3f &vel, float err, uint32_t timeStamp_ms, uint16_t delay_ms)
    1711             : {
    1712        4278 :     dal.writeExtNavVelData(vel, err, timeStamp_ms, delay_ms);
    1713             : 
    1714        4278 :     if (core) {
    1715       12702 :         for (uint8_t i=0; i<num_cores; i++) {
    1716        8468 :             core[i].writeExtNavVelData(vel, err, timeStamp_ms, delay_ms);
    1717             :         }
    1718             :     }
    1719        4278 : }
    1720             : 
    1721             : // return data for debugging optical flow fusion
    1722             : /*
    1723             :  * Write body frame linear and angular displacement measurements from a visual odometry sensor
    1724             :  *
    1725             :  * quality is a normalised confidence value from 0 to 100
    1726             :  * delPos is the XYZ change in linear position measured in body frame and relative to the inertial reference at timeStamp_ms (m)
    1727             :  * delAng is the XYZ angular rotation measured in body frame and relative to the inertial reference at timeStamp_ms (rad)
    1728             :  * delTime is the time interval for the measurement of delPos and delAng (sec)
    1729             :  * timeStamp_ms is the timestamp of the last image used to calculate delPos and delAng (msec)
    1730             :  * delay_ms is the average delay of external nav system measurements relative to inertial measurements
    1731             :  * posOffset is the XYZ body frame position of the camera focal point (m)
    1732             : */
    1733        3633 : void NavEKF3::writeBodyFrameOdom(float quality, const Vector3f &delPos, const Vector3f &delAng, float delTime, uint32_t timeStamp_ms, uint16_t delay_ms, const Vector3f &posOffset)
    1734             : {
    1735        3633 :     dal.writeBodyFrameOdom(quality, delPos, delAng, delTime, timeStamp_ms, delay_ms, posOffset);
    1736             : 
    1737        3633 :     if (core) {
    1738       10743 :         for (uint8_t i=0; i<num_cores; i++) {
    1739        7162 :             core[i].writeBodyFrameOdom(quality, delPos, delAng, delTime, timeStamp_ms, delay_ms, posOffset);
    1740             :         }
    1741             :     }
    1742        3633 : }
    1743             : 
    1744             : /*
    1745             :  * Write odometry data from a wheel encoder. The axis of rotation is assumed to be parallel to the vehicle body axis
    1746             :  *
    1747             :  * delAng is the measured change in angular position from the previous measurement where a positive rotation is produced by forward motion of the vehicle (rad)
    1748             :  * delTime is the time interval for the measurement of delAng (sec)
    1749             :  * timeStamp_ms is the time when the rotation was last measured (msec)
    1750             :  * posOffset is the XYZ body frame position of the wheel hub (m)
    1751             : */
    1752        4353 : void NavEKF3::writeWheelOdom(float delAng, float delTime, uint32_t timeStamp_ms, const Vector3f &posOffset, float radius)
    1753             : {
    1754        4353 :     dal.writeWheelOdom(delAng, delTime, timeStamp_ms, posOffset, radius);
    1755             : 
    1756        4353 :     if (core) {
    1757       12459 :         for (uint8_t i=0; i<num_cores; i++) {
    1758        8306 :             core[i].writeWheelOdom(delAng, delTime, timeStamp_ms, posOffset, radius);
    1759             :         }
    1760             :     }
    1761        4353 : }
    1762             : 
    1763             : /* 
    1764             :  * Write terrain altitude (derived from SRTM) in meters above the origin
    1765             :  * only used by optical flow when out of rangefinder range
    1766             :  */
    1767     1064989 : void NavEKF3::writeTerrainData(float alt_m)
    1768             : {
    1769             : #if EK3_FEATURE_OPTFLOW_SRTM
    1770             :     // write altitude to DAL
    1771     1064989 :     dal.writeTerrainData(alt_m);
    1772             : 
    1773             :     // exit immediately if feature is not enabled
    1774     1064989 :     if (!option_is_enabled(Option::OptflowMayUseTerrainAlt)) {
    1775             :         return;
    1776             :     }
    1777             : 
    1778             :     // send to each core
    1779           0 :     if (core) {
    1780           0 :         for (uint8_t i=0; i<num_cores; i++) {
    1781           0 :             core[i].writeTerrainData(alt_m);
    1782             :         }
    1783             :     }
    1784             : #endif
    1785             : }
    1786             : 
    1787             : // Set to true if the terrain underneath is stable enough to be used as a height reference
    1788             : // in combination with a range finder. Set to false if the terrain underneath the vehicle
    1789             : // cannot be used as a height reference. Use to prevent range finder operation otherwise
    1790             : // enabled by the combination of EK3_RNG_USE_HGT and EK3_RNG_USE_SPD parameters.
    1791        2339 : void NavEKF3::setTerrainHgtStable(bool val)
    1792             : {
    1793        2339 :     if (val) {
    1794         769 :         dal.log_event3(AP_DAL::Event::setTerrainHgtStable);
    1795             :     } else {
    1796        1570 :         dal.log_event3(AP_DAL::Event::unsetTerrainHgtStable);
    1797             :     }
    1798             : 
    1799        2339 :     if (core) {
    1800        3837 :         for (uint8_t i=0; i<num_cores; i++) {
    1801        2559 :             core[i].setTerrainHgtStable(val);
    1802             :         }
    1803             :     }
    1804             : 
    1805        2339 : }
    1806             : 
    1807             : /*
    1808             :   return the filter fault status as a bitmasked integer
    1809             :   0 = quaternions are NaN
    1810             :   1 = velocities are NaN
    1811             :   2 = badly conditioned X magnetometer fusion
    1812             :   3 = badly conditioned Y magnetometer fusion
    1813             :   4 = badly conditioned Z magnetometer fusion
    1814             :   5 = badly conditioned airspeed fusion
    1815             :   6 = badly conditioned synthetic sideslip fusion
    1816             :   7 = filter is not initialised
    1817             : */
    1818    41686716 : void NavEKF3::getFilterFaults(uint16_t &faults) const
    1819             : {
    1820    41686716 :     if (core) {
    1821    40053019 :         core[primary].getFilterFaults(faults);
    1822             :     } else {
    1823     1633697 :         faults = 0;
    1824             :     }
    1825    41686716 : }
    1826             : 
    1827             : /*
    1828             :   return filter status flags
    1829             : */
    1830    41686716 : void NavEKF3::getFilterStatus(nav_filter_status &status) const
    1831             : {
    1832    41686716 :     if (core) {
    1833    40053019 :         core[primary].getFilterStatus(status);
    1834             :     } else {
    1835     1633697 :         memset(&status, 0, sizeof(status));
    1836             :     }
    1837    41686716 : }
    1838             : 
    1839             : // send an EKF_STATUS_REPORT message to GCS
    1840    41686716 : bool NavEKF3::getTerrainAltVariance(float &terrainAltVar) const
    1841             : {
    1842    41686716 :     if (core) {
    1843    40053019 :         return core[primary].getTerrainAltVariance(terrainAltVar);
    1844             :     }
    1845             :     return false;
    1846             : }
    1847             : 
    1848             : // provides the height limit to be observed by the control loops
    1849             : // returns false if no height limiting is required
    1850             : // this is needed to ensure the vehicle does not fly too high when using optical flow navigation
    1851    41686716 : bool NavEKF3::getHeightControlLimit(float &height) const
    1852             : {
    1853    41686716 :     if (!core) {
    1854             :         return false;
    1855             :     }
    1856    40053019 :     return core[primary].getHeightControlLimit(height);
    1857             : }
    1858             : 
    1859             : // Returns a count of NE position reset events; incremented when the primary
    1860             : // core changes and when the primary core resets its NE position
    1861    39298372 : uint16_t NavEKF3::getPosNorthEastResetCount(void)
    1862             : {
    1863    39298372 :     if (!core) {
    1864             :         return 0;
    1865             :     }
    1866    39298372 :     const uint16_t core_count = core[primary].getPosNorthEastResetCount();
    1867    39298372 :     if (core_count != pos_reset_data.last_core_count) {
    1868        2497 :         pos_reset_data.last_core_count = core_count;
    1869        2497 :         pos_reset_data.count++;
    1870             :     }
    1871    39298372 :     return pos_reset_data.count;
    1872             : }
    1873             : 
    1874             : // Returns a count of D position reset events; incremented when the primary
    1875             : // core changes and when the primary core resets its D position
    1876    39298372 : uint16_t NavEKF3::getPosDownResetCount(void)
    1877             : {
    1878    39298372 :     if (!core) {
    1879             :         return 0;
    1880             :     }
    1881    39298372 :     const uint16_t core_count = core[primary].getPosDownResetCount();
    1882    39298372 :     if (core_count != pos_down_reset_data.last_core_count) {
    1883        1619 :         pos_down_reset_data.last_core_count = core_count;
    1884        1619 :         pos_down_reset_data.count++;
    1885             :     }
    1886    39298372 :     return pos_down_reset_data.count;
    1887             : }
    1888             : 
    1889             : // Returns a count of yaw reset events; incremented when the primary core
    1890             : // changes and when the primary core resets its yaw
    1891    39298372 : uint16_t NavEKF3::getYawResetCount(void)
    1892             : {
    1893    39298372 :     if (!core) {
    1894             :         return 0;
    1895             :     }
    1896    39298372 :     const uint16_t core_count = core[primary].getYawResetCount();
    1897    39298372 :     if (core_count != yaw_reset_data.last_core_count) {
    1898        2140 :         yaw_reset_data.last_core_count = core_count;
    1899        2140 :         yaw_reset_data.count++;
    1900             :     }
    1901    39298372 :     return yaw_reset_data.count;
    1902             : }
    1903             : 
    1904             : // update the yaw reset data to capture changes due to a lane switch
    1905          57 : void NavEKF3::updateLaneSwitchYawResetData(uint8_t new_primary)
    1906             : {
    1907             :     // the new primary's historic in-core resets are not new events
    1908             :     // for consumers; re-seat the count and record a single event for
    1909             :     // the switch itself
    1910          57 :     yaw_reset_data.last_core_count = core[new_primary].getYawResetCount();
    1911          57 :     yaw_reset_data.count++;
    1912          57 : }
    1913             : 
    1914             : // update the position reset data to capture changes due to a lane switch
    1915          57 : void NavEKF3::updateLaneSwitchPosResetData(uint8_t new_primary)
    1916             : {
    1917             :     // the new primary's historic in-core resets are not new events
    1918             :     // for consumers; re-seat the count and record a single event for
    1919             :     // the switch itself
    1920          57 :     pos_reset_data.last_core_count = core[new_primary].getPosNorthEastResetCount();
    1921          57 :     pos_reset_data.count++;
    1922             : 
    1923          57 : }
    1924             : 
    1925             : // Update the vertical position reset data to capture changes due to a core switch
    1926             : // This should be called after the decision to switch cores has been made, but before the
    1927             : // new primary EKF update has been run
    1928          57 : void NavEKF3::updateLaneSwitchPosDownResetData(uint8_t new_primary)
    1929             : {
    1930             :     // the new primary's historic in-core resets are not new events
    1931             :     // for consumers; re-seat the count and record a single event for
    1932             :     // the switch itself
    1933          57 :     pos_down_reset_data.last_core_count = core[new_primary].getPosDownResetCount();
    1934          57 :     pos_down_reset_data.count++;
    1935             : 
    1936          57 : }
    1937             : 
    1938             : // Writes the default equivalent airspeed and 1-sigma uncertainty in m/s to be used in forward flight if a measured airspeed is required and not available.
    1939           0 : void NavEKF3::writeDefaultAirSpeed(float airspeed, float uncertainty)
    1940             : {
    1941             :     // ignore any data if the EKF is not started
    1942           0 :     if (!core) {
    1943             :         return;
    1944             :     }
    1945             : 
    1946           0 :     dal.log_writeDefaultAirSpeed3(airspeed, uncertainty);
    1947             : 
    1948           0 :     for (uint8_t i=0; i<num_cores; i++) {
    1949           0 :         core[i].writeDefaultAirSpeed(airspeed, uncertainty);
    1950             :     }
    1951             : }
    1952             : 
    1953             : // returns true when the yaw angle has been aligned
    1954           0 : bool NavEKF3::yawAlignmentComplete(void) const
    1955             : {
    1956           0 :     if (!core) {
    1957             :         return false;
    1958             :     }
    1959           0 :     return core[primary].have_aligned_yaw();
    1960             : }
    1961             : 
    1962             : // returns true when the state estimates are significantly degraded by vibration
    1963    41686716 : bool NavEKF3::isVibrationAffected() const
    1964             : {
    1965    41686716 :     if (core) {
    1966    40053019 :         return core[primary].isVibrationAffected();
    1967             :     }
    1968             :     return false;
    1969             : }
    1970             : 
    1971             : // get a yaw estimator instance
    1972         479 : const EKFGSF_yaw *NavEKF3::get_yawEstimator(void) const
    1973             : {
    1974         479 :     if (core) {
    1975         479 :         return core[primary].get_yawEstimator();
    1976             :     }
    1977             :     return nullptr;
    1978             : }
    1979             : 
    1980             : // Do a reset and bootstrap alignment of all EKF cores
    1981             : // return true if successful for all cores
    1982             : // When on the ground and stationary, gyros are recalibrated first so
    1983             : // the filter bootstraps with clean offsets.  In flight the gyro
    1984             : // calibration is skipped and the filter resets with existing biases.
    1985           1 : bool NavEKF3::InitialiseFilterBootstrap()
    1986             : {
    1987             :     // ignore any data if the EKF is not started
    1988           1 :     if (!core) {
    1989             :         return false;
    1990             :     }
    1991             : 
    1992             :     // initialise the cores. We return success only if all cores
    1993             :     // initialise successfully.  The per-core InitialiseFilterBootstrap()
    1994             :     // return value is false when the IMU delay buffer is not yet full,
    1995             :     // which is normal during a reset. Check statesInitialised directly
    1996             :     // to determine whether the bootstrap alignment succeeded.
    1997             :     bool ret = true;
    1998           3 :     for (uint8_t i=0; i<num_cores; i++) {
    1999             :         // clear the statesInitialised status to allow a bootstrap alignment
    2000           2 :         core[i].clearStatesInitialised();
    2001             :         // perform a bootstrap alignment
    2002           2 :         core[i].InitialiseFilterBootstrap();
    2003           2 :         if (!core[i].isStatesInitialised()) {
    2004             :             ret = false;
    2005             :         }
    2006             :     }
    2007             :     return ret;
    2008             : }

Generated by: LCOV version 1.14