LCOV - code coverage report
Current view: top level - AP_AHRS - AP_AHRS_NavEKF3.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 91 93 97.8 %
Date: 2026-09-09 11:02:08 Functions: 4 4 100.0 %

          Line data    Source code
       1             : #include "AP_AHRS_config.h"
       2             : 
       3             : #if AP_AHRS_NAVEKF3_ENABLED
       4             : 
       5             : #include "AP_AHRS_NavEKF3.h"
       6             : #include <AP_AHRS/AP_AHRS.h>
       7             : #include <AP_HAL/AP_HAL.h>
       8             : #include <AP_Logger/AP_Logger.h>
       9             : #include <GCS_MAVLink/GCS.h>
      10             : 
      11             : extern const AP_HAL::HAL& hal;
      12             : 
      13             : NavEKF3 AP_AHRS_NavEKF3::EKF3;
      14             : 
      15     2389898 : bool AP_AHRS_NavEKF3::start()
      16             : {
      17     2389898 :     const auto now_ms = AP_HAL::millis();
      18             : 
      19     2389898 :     if (start_time_ms == 0) {
      20        2086 :         start_time_ms = now_ms;
      21             :     }
      22             : 
      23             : #if HAL_LOGGING_ENABLED
      24             :     // if we're doing Replay logging then don't allow any data
      25             :     // into the EKF yet.  Don't allow it to block us for long.
      26     2389898 :     if (!hal.util->was_watchdog_reset()) {
      27     2389416 :         if (now_ms - start_time_ms < 5000) {
      28     1184019 :             if (!AP::logger().allow_start_ekf()) {
      29          43 :                 return false;
      30             :             }
      31             :         }
      32             :     }
      33             : #endif
      34             : 
      35             :     // wait 1 second for DCM to output a valid tilt error estimate
      36             :     // FIXME: work out whether this is still required!
      37     2389855 :     if (now_ms - start_time_ms <= 1000) {
      38      530414 :         return false;
      39             :     }
      40             : 
      41             :     // try to start the filter:
      42     1859441 :     return EKF3.InitialiseFilter();
      43             : }
      44             : 
      45    41686716 : void AP_AHRS_NavEKF3::update()
      46             : {
      47    41686716 :     if (!started) {
      48     2389898 :         started = start();
      49             :     }
      50    41686716 :     if (!started) {
      51     2388344 :         return;
      52             :     }
      53    39298372 :     EKF3.UpdateFilter();
      54             : 
      55             :     // check the current primary core; if it has changed then assume
      56             :     // our attitude is reset:
      57    39298372 :     const int8_t primary_core = EKF3.getPrimaryCoreIndex();
      58    39298372 :     if (attitude_reset_tracker.update(primary_core)) {
      59          68 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::EKF_PRIMARY, LogErrorCode(primary_core));
      60          68 :         GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "EKF3 primary changed:%d", (unsigned)primary_core);
      61             :     }
      62             : 
      63    39298372 :     yaw_reset_tracker.update(EKF3.getYawResetCount());
      64             : 
      65    39298372 :     position_NE_reset_tracker.update(EKF3.getPosNorthEastResetCount());
      66             : 
      67    39298372 :     position_D_reset_tracker.update(EKF3.getPosDownResetCount());
      68             : }
      69             : 
      70    41686716 : void AP_AHRS_NavEKF3::get_results(AP_AHRS_Backend::Estimates &results)
      71             : {
      72    41686716 :     const auto now_ms = AP_HAL::millis();
      73             : 
      74             :     // initialisation complete some time after ekf has started
      75    41686716 :     results.initialised = (started && (now_ms - start_time_ms > 20000));
      76             : 
      77    41686716 :     results.healthy = started && EKF3.healthy();
      78             : 
      79    41686716 :     const AP_InertialSensor &_ins = AP::ins();
      80             : 
      81             :     /*
      82             :      * rotational rate estimates:
      83             :      */
      84             :     // The backend should tell us what gyro it is using right now.
      85             :     // There's no API for that at the moment, so we assume the
      86             :     // gyro corresponds to the IMU index.
      87    41686716 :     const int8_t ek3_primary_gyro = EKF3.getPrimaryCoreIMUIndex();
      88    41686716 :     if (ek3_primary_gyro == -1) {
      89     1633697 :         results.primary_gyro = _ins.get_first_usable_gyro();
      90             :     } else {
      91    40053019 :         results.primary_gyro = ek3_primary_gyro;
      92             :     }
      93             : 
      94             :     // get gyro bias for primary EKF and change sign to give gyro drift
      95             :     // Note sign convention used by EKF is bias = measurement - truth
      96    41686716 :     Vector3f drift;
      97    41686716 :     EKF3.getGyroBias(-1, drift);
      98    41686716 :     results.gyro_drift = -drift;
      99             : 
     100             :     // use the same IMU as the primary EKF and correct for gyro drift
     101    41686716 :     results.gyro_estimate = _ins.get_gyro(results.primary_gyro) + results.gyro_drift;
     102             : 
     103             :     /*
     104             :      * attitude estimates:
     105             :      */
     106    41686716 :     EKF3.getRotationBodyToNED(results.dcm_matrix);
     107             : 
     108    41686716 :     Vector3f eulers;
     109    41686716 :     EKF3.getEulerAngles(eulers);
     110    41686716 :     results.roll_rad  = eulers.x;
     111    41686716 :     results.pitch_rad = eulers.y;
     112    41686716 :     results.yaw_rad   = eulers.z;
     113             : 
     114    41686716 :     EKF3.getQuaternion(results.quaternion);
     115    41686716 :     results.quaternion.rotate(-AP::ahrs().get_trim());
     116             : 
     117    41686716 :     results.attitude_valid = started;
     118             : 
     119    41686716 :     results.attitude_reset_count = attitude_reset_tracker.count();
     120             : 
     121    41686716 :     results.yaw_reset_count = yaw_reset_tracker.count();
     122             : 
     123    41686716 :     results.is_vibration_affected = EKF3.isVibrationAffected();
     124             : 
     125             :     /*
     126             :      * acceleration estimates
     127             :      */
     128             : 
     129             :     // The backend should tell us what accelerometer it is using
     130             :     // right now.  There's no API for that at the moment, so we assume
     131             :     // the accelerometer corresponds to the IMU index.
     132    41686716 :     const int8_t ek3_primary_accel = EKF3.getPrimaryCoreIMUIndex();
     133    41686716 :     if (ek3_primary_accel == -1) {
     134     1633697 :         results.primary_accel = _ins.get_first_usable_accel();
     135             :     } else {
     136    40053019 :         results.primary_accel = ek3_primary_accel;
     137             :     }
     138             : 
     139             :     // get 3-axis accel bias estimates for active EKF (this is usually
     140             :     // for the primary IMU)
     141    41686716 :     EKF3.getAccelBias(-1, results.accel_bias);
     142             : 
     143             :     // use the primary IMU for accel earth frame
     144    41686716 :     Vector3f accel = _ins.get_accel(results.primary_accel);
     145    41686716 :     accel -= results.accel_bias;
     146    41686716 :     results.accel_ef = results.dcm_matrix * AP::ahrs().get_rotation_autopilot_body_to_vehicle_body() * accel;
     147             : 
     148             :     /*
     149             :      * velocity estimates
     150             :      */
     151    41686716 :     EKF3.getVelNED(results.velocity_NED);
     152    41686716 :     results.velocity_NED_valid = true;
     153    41686716 :     results.vert_pos_rate_D = EKF3.getPosDownDerivative();
     154    41686716 :     results.vert_pos_rate_D_valid = true;
     155             : 
     156             :     // ground velocity estimate in meters/second, in North/East order
     157    41686716 :     results.velocity_NE = results.velocity_NED.xy();
     158             : 
     159             :     /*
     160             :      * position estimates
     161             :      */
     162    41686716 :     results.location_valid = EKF3.getLLH(results.location);
     163             : 
     164             :     // origin-relative functions
     165    41686716 :     results.provides_common_origin = true;
     166             : 
     167             :     // origin-relative position:
     168    41686716 :     results.position_NE_valid = EKF3.getPosNE(results.position_NE);
     169    41686716 :     results.position_NE_reset_count = position_NE_reset_tracker.count();
     170             : 
     171    41686716 :     results.position_D_valid = EKF3.getPosD(results.position_D);
     172    41686716 :     results.position_D_reset_count = position_D_reset_tracker.count();
     173             : 
     174    41686716 :     results.hagl_valid = EKF3.getHAGL(results.hagl);
     175             : 
     176             :     /*
     177             :      * air data estimates
     178             :      */
     179    41686716 :     results.wind_valid = EKF3.getWind(results.wind);
     180             : 
     181             :     /*
     182             :      * Sensor-related information
     183             :      */
     184             :     // true if the estimator will use GPS data in creating its
     185             :     // estimate when the data is good:
     186    41686716 :     results.configured_to_use_gps = EKF3.using_gps();
     187             :     // true if GPS is configured as the horizontal position source
     188             :     // for this estimator.  Used to decide whether GPS will set
     189             :     // the navigation origin:
     190    41686716 :     results.configured_to_use_gps_for_pos_XY = EKF3.configuredToUseGPSForPosXY();
     191             : 
     192             :     // are we consuming yaw from an external (e.g. vision-based) source?
     193    41686716 :     results.using_extnav_for_yaw = EKF3.using_extnav_for_yaw();
     194             : 
     195             :     // are we consuming yaw from a source which is *not* a compass
     196             :     // (e.g. the GSF)
     197    41686716 :     results.using_noncompass_for_yaw = EKF3.using_noncompass_for_yaw();
     198             : 
     199             : #if AP_AHRS_GET_MAG_DATA_ENABLED
     200             :     // estimators can provide their predicted magnetic fields:
     201    41686716 :     EKF3.getMagNED(results.mag_field_NED);
     202    41686716 :     results.mag_field_NED_valid = true;
     203    41686716 :     EKF3.getMagXYZ(results.mag_field_corrections);
     204    41686716 :     results.mag_field_corrections_valid = true;
     205             : #endif  // AP_AHRS_GET_MAG_DATA_ENABLED
     206             : 
     207             :     /*
     208             :      * filter status and estimates quality values:
     209             :      */
     210    41686716 :     EKF3.getFilterStatus(results.filter_status);
     211    41686716 :     results.filter_status_valid = true;
     212             : 
     213    41686716 :     EKF3.getFilterFaults(results.filter_faults);
     214             : 
     215             :     // provides the innovations normalised between 0 and 1:
     216    41686716 :     Vector2f offset;
     217    41686716 :     results.variances_valid = EKF3.getVariances(results.velVar, results.posVar, results.hgtVar, results.magVar, results.tasVar, offset);
     218             : 
     219    41686716 :     results.terrain_alt_variance_valid = EKF3.getTerrainAltVariance(results.terrain_alt_variance);
     220             : 
     221    41686716 :     EKF3.getEkfControlLimits(results.control_ground_speed_limit_ms, results.control_gain_scaler_XY);
     222    41686716 :     results.control_gain_scaler_Z = 1;
     223             : 
     224    41686716 :     results.control_height_limit_valid = EKF3.getHeightControlLimit(results.control_height_limit_m);
     225    41686716 : }
     226             : 
     227       31446 : bool AP_AHRS_NavEKF3::pre_arm_check(bool requires_position, char *failure_msg, uint8_t failure_msg_len) const
     228             : {
     229       31446 :     if (!started) {
     230           0 :         hal.util->snprintf(failure_msg, failure_msg_len, "EKF3 not started");
     231           0 :         return false;
     232             :     }
     233       31446 :     return EKF3.pre_arm_check(requires_position, failure_msg, failure_msg_len);
     234             : }
     235             : 
     236             : #endif  // AP_AHRS_NAVEKF3_ENABLED

Generated by: LCOV version 1.14