diff --git a/src/lib/systemlib/system_params.yaml b/src/lib/systemlib/system_params.yaml index ac8547325c..177b44adf8 100644 --- a/src/lib/systemlib/system_params.yaml +++ b/src/lib/systemlib/system_params.yaml @@ -138,11 +138,14 @@ parameters: reboot_required: true SYS_HAS_NUM_GNSS: description: - short: Control if and how many GNSS receivers are expected + short: Control if and how many GNSS receivers are required long: |- - 0: Disable GNSS redundancy check (any number of GNSS receivers is acceptable). + 0: No minimum receiver count required. Position divergence between two receivers + and loss of a GNSS receiver still produce a warning but never trigger the + COM_GPS_LOSS_ACT failsafe action. 1-N: Require the presence of N GNSS receivers for arming and during flight. If the active count drops below this value in flight, COM_GPS_LOSS_ACT is triggered. + When set to 2, position divergence between the two receivers also triggers COM_GPS_LOSS_ACT. type: int32 default: 0 min: 0 diff --git a/src/modules/commander/HealthAndArmingChecks/GpsRedundancyCheckTest.cpp b/src/modules/commander/HealthAndArmingChecks/GpsRedundancyCheckTest.cpp index a4bcb9b5ba..d9ecc33405 100644 --- a/src/modules/commander/HealthAndArmingChecks/GpsRedundancyCheckTest.cpp +++ b/src/modules/commander/HealthAndArmingChecks/GpsRedundancyCheckTest.cpp @@ -136,6 +136,20 @@ public: & (uint64_t)events::px4::enums::health_component_t::gps) != 0; } + // Runs one check cycle and returns true if gnss_lost was set (failsafe would trigger) + bool hasGnssLost(bool armed) + { + vehicle_status_s status{}; + status.arming_state = armed + ? vehicle_status_s::ARMING_STATE_ARMED + : vehicle_status_s::ARMING_STATE_DISARMED; + Context context{status}; + failsafe_flags_s failsafe_flags{}; + Report reporter{failsafe_flags, 0_s}; + _check->checkAndReport(context, reporter); + return failsafe_flags.gnss_lost; + } + static orb_advert_t _pub0; static orb_advert_t _pub1; GpsRedundancyChecks *_check{nullptr}; @@ -198,6 +212,41 @@ TEST_F(GpsRedundancyCheckTest, FixTypeBelow3TreatedAsInactive) EXPECT_FALSE(hasDivergenceWarning(false)); } +// Divergence with SYS_HAS_NUM_GNSS=2 and COM_GPS_LOSS_ACT>0 → gnss_lost set (failsafe fires) +TEST_F(GpsRedundancyCheckTest, DivergenceWithRedundancyRequiredSetsGnssLost) +{ + int i = 2; + param_set(param_find("SYS_HAS_NUM_GNSS"), &i); + i = 1; // Return + param_set(param_find("COM_GPS_LOSS_ACT"), &i); + delete _check; + _check = new GpsRedundancyChecks(); + + sensor_gps_s gps0 = makeGps(BASE_LAT, BASE_LON); + sensor_gps_s gps1 = makeGps(DIVERGING_LAT, BASE_LON); + orb_publish(ORB_ID(sensor_gps), _pub0, &gps0); + orb_publish(ORB_ID(sensor_gps), _pub1, &gps1); + EXPECT_TRUE(hasGnssLost(false)); +} + +// Divergence with SYS_HAS_NUM_GNSS=0 and COM_GPS_LOSS_ACT>0 → warning only, gnss_lost not set +TEST_F(GpsRedundancyCheckTest, DivergenceWithoutRedundancyRequiredWarnsOnly) +{ + int i = 0; + param_set(param_find("SYS_HAS_NUM_GNSS"), &i); + i = 1; // Return + param_set(param_find("COM_GPS_LOSS_ACT"), &i); + delete _check; + _check = new GpsRedundancyChecks(); + + sensor_gps_s gps0 = makeGps(BASE_LAT, BASE_LON); + sensor_gps_s gps1 = makeGps(DIVERGING_LAT, BASE_LON); + orb_publish(ORB_ID(sensor_gps), _pub0, &gps0); + orb_publish(ORB_ID(sensor_gps), _pub1, &gps1); + EXPECT_FALSE(hasGnssLost(false)); + EXPECT_TRUE(hasDivergenceWarning(false)); +} + // Divergence then recovery: timer resets and warning stops TEST_F(GpsRedundancyCheckTest, DivergenceClearsAfterRecovery) { diff --git a/src/modules/commander/HealthAndArmingChecks/checks/gpsRedundancyCheck.cpp b/src/modules/commander/HealthAndArmingChecks/checks/gpsRedundancyCheck.cpp index 243b4f1c9e..4375f3e15a 100644 --- a/src/modules/commander/HealthAndArmingChecks/checks/gpsRedundancyCheck.cpp +++ b/src/modules/commander/HealthAndArmingChecks/checks/gpsRedundancyCheck.cpp @@ -75,12 +75,16 @@ void GpsRedundancyChecks::checkAndReport(const Context &context, Report &reporte } } + const int required = _param_sys_has_num_gnss.get(); + // Position divergence check: warn if two fixed receivers disagree beyond their combined // uncertainty. The gate is: lever-arm separation + GNSS_DIVERGENCE_SIGMA * RMS(eph0, eph1). // Using RMS(eph) means the gate tightens when both receivers are accurate and widens // automatically when one degrades, avoiding false alarms without a hard-coded threshold. // Pre-arm: warn immediately. In-flight: require GPS_DIVERGENCE_SUSTAIN to suppress // transient multipath spikes. + // The failsafe action is only triggered when SYS_HAS_NUM_GNSS >= 2; otherwise divergence + // is reported as a warning only. bool divergence_active = false; if (fixed_count >= 2) { @@ -106,8 +110,8 @@ void GpsRedundancyChecks::checkAndReport(const Context &context, Report &reporte } if (hrt_elapsed_time(&_divergence_since) >= sustain) { - divergence_active = true; - const bool act = (_param_com_gnss_loss_act.get() > 0); + const bool act = (_param_com_gnss_loss_act.get() > 0) && (required >= 2); + divergence_active = act; /* EVENT * @description @@ -115,6 +119,7 @@ void GpsRedundancyChecks::checkAndReport(const Context &context, Report &reporte * * * Configure the failsafe action with COM_GPS_LOSS_ACT. + * The failsafe action is only triggered when SYS_HAS_NUM_GNSS is set to 2. * */ reporter.healthFailure(act ? NavModes::All : NavModes::None, @@ -135,7 +140,6 @@ void GpsRedundancyChecks::checkAndReport(const Context &context, Report &reporte _peak_fixed_count = fixed_count; } - const int required = _param_sys_has_num_gnss.get(); const bool below_required = (required > 0 && fixed_count < required); const bool dropped_below_peak = (_peak_fixed_count > 1 && fixed_count < _peak_fixed_count); diff --git a/src/modules/commander/commander_params.yaml b/src/modules/commander/commander_params.yaml index d24873fe3c..3bd7b96e35 100644 --- a/src/modules/commander/commander_params.yaml +++ b/src/modules/commander/commander_params.yaml @@ -136,8 +136,9 @@ parameters: short: GNSS loss failsafe mode long: |- Action the system takes when a GNSS failure is detected during flight. - Triggers when the active GNSS count drops below SYS_HAS_NUM_GNSS or when - two receivers report positions inconsistent with their reported accuracy. + Triggers when the active GNSS count drops below SYS_HAS_NUM_GNSS (disabled + when SYS_HAS_NUM_GNSS=0), or when two receivers report positions inconsistent + with their reported accuracy and SYS_HAS_NUM_GNSS=2 (otherwise warning only). Any value above Warning also blocks arming. type: enum values: