LCOV - code coverage report
Current view: top level - AP_Airspeed - AP_Airspeed_Health.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 54 57 94.7 %
Date: 2026-09-09 11:02:08 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "AP_Airspeed_config.h"
       2             : 
       3             : #if AP_AIRSPEED_ENABLED
       4             : 
       5             : #include "AP_Airspeed.h"
       6             : 
       7             : #include <AP_Common/AP_Common.h>
       8             : #include <AP_GPS/AP_GPS.h>
       9             : #include <AP_Math/AP_Math.h>
      10             : #include <GCS_MAVLink/GCS.h>
      11             : #include <AP_AHRS/AP_AHRS.h>
      12             : #include <AP_Logger/AP_Logger.h>
      13             : 
      14      559330 : void AP_Airspeed::check_sensor_failures()
      15             : {
      16             : #ifndef HAL_BUILD_AP_PERIPH
      17     1677990 :     for (uint8_t i=0; i<AIRSPEED_MAX_SENSORS; i++) {
      18     1118660 :         check_sensor_ahrs_wind_max_failures(i);
      19             :     }
      20             : #endif
      21      559330 : }
      22             : 
      23     1118660 : void AP_Airspeed::check_sensor_ahrs_wind_max_failures(uint8_t i)
      24             : {
      25             : #ifndef HAL_BUILD_AP_PERIPH
      26     1118660 :     const uint32_t now_ms = AP_HAL::millis();
      27     1118660 :     if ((now_ms - state[i].failures.last_check_ms) <= 200) {
      28             :         // slow the checking rate
      29      940221 :         return;
      30             :     }
      31      379068 :     state[i].failures.last_check_ms = now_ms;
      32             : 
      33      379068 :     if (!is_positive(_wind_max) && !is_positive(_wind_gate)) {
      34             :         // nothing to do
      35        9878 :         return;
      36             :     }
      37             : 
      38      369190 :     if (state[i].airspeed <= 0) {
      39             :         // invalid estimate
      40      178078 :         return;
      41             :     }
      42             : 
      43      191112 :     const AP_GPS &gps = AP::gps();
      44      191112 :     if (gps.status() < AP_GPS_FixType::FIX_3D) {
      45             :         // GPS speed can't be trusted, re-enable airspeed as a fallback
      46       12673 :         if ((param[i].use == 0) && (state[i].failures.param_use_backup == 1)) {
      47           0 :             GCS_SEND_TEXT(MAV_SEVERITY_NOTICE, "Airspeed sensor %d, Re-enabled as GPS fall-back", i+1);
      48           0 :             param[i].use.set_and_notify(state[i].failures.param_use_backup); 
      49           0 :             state[i].failures.param_use_backup = -1;
      50             :         }
      51       12673 :         return;
      52             :     }
      53             : 
      54             :     // check for airspeed consistent with wind and vehicle velocity using the EKF
      55             :     uint32_t age_ms;
      56             :     float innovation, innovationVariance;
      57      178439 :     if (AP::ahrs().airspeed_health_data(i, innovation, innovationVariance, age_ms) && age_ms < 1000 && is_positive(innovationVariance)) {
      58      111141 :         state[i].failures.test_ratio = fabsf(innovation) / safe_sqrt(innovationVariance);
      59             :     } else {
      60       67298 :         state[i].failures.test_ratio = 0.0f;
      61             :     }
      62      178439 :     bool data_is_inconsistent = false;
      63      178439 :     if (is_positive(_wind_gate) && (AP_Airspeed::OptionsMask::USE_EKF_CONSISTENCY & _options) != 0) {
      64      178439 :         float gate_size = MAX(_wind_gate, 0.0f);
      65      178439 :         if (param[i].use == 0) {
      66             :             // require a smaller inconsistency for a disabled sensor to be declared consistent
      67       14228 :             gate_size *= 0.7f;
      68             :         }
      69      178439 :         data_is_inconsistent = state[i].failures.test_ratio > gate_size;
      70             :     }
      71             :     
      72      178439 :     const auto gps_speed = gps.velocity().length();
      73      178439 :     const float speed_diff = fabsf(state[i].airspeed-gps_speed);
      74      178439 :     const bool data_is_implausible = is_positive(_wind_max) && speed_diff > _wind_max;
      75             :     // update health_probability with LowPassFilter
      76      178439 :     if (data_is_implausible || data_is_inconsistent) {
      77             :         // bad, decay fast
      78         192 :         const float probability_coeff = 0.90f;
      79         192 :         state[i].failures.health_probability = probability_coeff*state[i].failures.health_probability;
      80             : 
      81      178439 :     } else if (!data_is_implausible && !data_is_inconsistent) {
      82             :         // good, grow slow
      83      178247 :         const float probability_coeff = 0.98f;
      84      178247 :         state[i].failures.health_probability = probability_coeff*state[i].failures.health_probability + (1.0f-probability_coeff)*1.0f;
      85             :     }
      86             : 
      87             :     // Now check if we need to disable or enable the sensor
      88             : 
      89             :     // here are some probability thresholds
      90             :     static const float DISABLE_PROB_THRESH_CRIT = 0.1f;
      91             :     static const float RE_ENABLE_PROB_THRESH_OK = 0.95f;
      92             : 
      93      178439 :     if (param[i].use > 0) {
      94      328422 :         if (((AP_Airspeed::OptionsMask::ON_FAILURE_AHRS_WIND_MAX_DO_DISABLE & _options) != 0) &&
      95      164211 :                 (state[i].failures.health_probability < DISABLE_PROB_THRESH_CRIT)) {
      96             :             // if "disable" option is allowed and sensor is enabled and is probably not healthy
      97           5 :             GCS_SEND_TEXT(MAV_SEVERITY_ERROR, "Airspeed sensor %d failure. Disabling", i+1);
      98           5 :             state[i].failures.param_use_backup = param[i].use;
      99           5 :             param[i].use.set_and_notify(0);
     100           5 :             state[i].healthy = false;
     101             :         }
     102             : 
     103             :         // Warn if necessary
     104             : 
     105             :         // set warn to max if not set or larger than max
     106      164211 :         float wind_warn = _wind_warn;
     107      164211 :         if ((!is_positive(wind_warn) || (wind_warn > _wind_max)) && is_positive(_wind_max)) {
     108         323 :             wind_warn = _wind_max;
     109             :         }
     110             : 
     111      164211 :         if (is_positive(wind_warn) && (speed_diff > wind_warn) && ((now_ms - state[i].failures.last_warn_ms) > 15000)) {
     112           1 :             state[i].failures.last_warn_ms = now_ms;
     113           1 :             GCS_SEND_TEXT(MAV_SEVERITY_WARNING, "Airspeed %d warning %0.1fm/s air to gnd speed diff", i+1, speed_diff);
     114             :         }
     115             : 
     116             :     // if Re-Enable options is allowed, and sensor is disabled but was previously enabled, and is probably healthy
     117       14228 :     } else if (((AP_Airspeed::OptionsMask::ON_FAILURE_AHRS_WIND_MAX_RECOVERY_DO_REENABLE & _options) != 0) &&
     118       15153 :                 (state[i].failures.param_use_backup > 0) && 
     119         925 :                 (state[i].failures.health_probability > RE_ENABLE_PROB_THRESH_OK)) {
     120             : 
     121           5 :         GCS_SEND_TEXT(MAV_SEVERITY_NOTICE, "Airspeed sensor %d now OK. Re-enabled", i+1);
     122           5 :         param[i].use.set_and_notify(state[i].failures.param_use_backup); // resume
     123           5 :         state[i].failures.param_use_backup = -1; // set to invalid so we don't use it
     124             :     }
     125             : #endif // HAL_BUILD_AP_PERIPH
     126             : }
     127             : 
     128             : #endif  // AP_AIRSPEED_ENABLED

Generated by: LCOV version 1.14