From aecabf40d2ab354c130f6cfde24be7065810581c Mon Sep 17 00:00:00 2001 From: Nicolas Michel Date: Thu, 1 Oct 2026 17:01:09 -0700 Subject: [PATCH 1/3] Fix/AS-1603: Land detector overrides a stuck rangefinder after 30 s A downward rangefinder can report a healthy but false distance while the vehicle is on the ground (NCT-3495: radar reported 6.55 m / Good for 400+ s after touchdown; same pattern in NCT-3311, NCT-2885, NCT-2781), which blocks land detection and therefore disarm indefinitely. Add a secondary path to the land detector: if the throttle, acceleration and descent-rate criteria have all held continuously for LAND_DETECTOR_RNGFND_TIMEOUT_SEC (30 s) while only the rangefinder check fails, send a warning and declare the landing anyway. The primary path and all downstream disarm behaviour are unchanged. Verified in SITL with a MAVLink rangefinder stuck at 650 cm after touchdown: unpatched build never disarms; patched build disarms 30 s after the inertial criteria are met; a normal landing still completes at the 0.5 s trigger. Co-Authored-By: Claude Fable 5.1 --- ArduCopter/config.h | 3 +++ ArduCopter/land_detector.cpp | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ArduCopter/config.h b/ArduCopter/config.h index 7aa6d154b1..7aaaa9513c 100644 --- a/ArduCopter/config.h +++ b/ArduCopter/config.h @@ -478,6 +478,9 @@ #ifndef LAND_DETECTOR_ACCEL_MAX # define LAND_DETECTOR_ACCEL_MAX 1.0f // vehicle acceleration must be under 1m/s/s #endif +#ifndef LAND_DETECTOR_RNGFND_TIMEOUT_SEC +# define LAND_DETECTOR_RNGFND_TIMEOUT_SEC 30.0f // number of seconds the non-rangefinder landing criteria must hold before a healthy-but-wrong rangefinder is overridden +#endif ////////////////////////////////////////////////////////////////////////////// // CAMERA TRIGGER AND CONTROL diff --git a/ArduCopter/land_detector.cpp b/ArduCopter/land_detector.cpp index 9271e5e9e5..e92e2c0709 100644 --- a/ArduCopter/land_detector.cpp +++ b/ArduCopter/land_detector.cpp @@ -10,6 +10,9 @@ // counter to verify landings static uint32_t land_detector_count = 0; +// counter of consecutive loops in which every landing criterion except the rangefinder check has held +static uint32_t land_detector_rngfnd_timeout_count = 0; + // run land and crash detectors // called at MAIN_LOOP_RATE void Copter::update_land_and_crash_detectors() @@ -58,6 +61,7 @@ void Copter::update_land_detector() } else if (standby_active) { // land detector will not run in standby mode land_detector_count = 0; + land_detector_rngfnd_timeout_count = 0; } else { #if FRAME_CONFIG == HELI_FRAME @@ -95,7 +99,10 @@ void Copter::update_land_detector() rangefinder_check = true; } - if (motor_at_lower_limit && accel_stationary && descent_rate_low && rangefinder_check) { + // landing criteria that do not depend on the rangefinder + const bool inertial_landed = motor_at_lower_limit && accel_stationary && descent_rate_low; + + if (inertial_landed && rangefinder_check) { // landed criteria met - increment the counter and check if we've triggered if( land_detector_count < ((float)LAND_DETECTOR_TRIGGER_SEC)*scheduler.get_loop_rate_hz()) { land_detector_count++; @@ -106,6 +113,21 @@ void Copter::update_land_detector() // we've sensed movement up or down so reset land_detector land_detector_count = 0; } + + // a rangefinder can report a healthy but false distance while the vehicle is on the + // ground (NCT-3495), which would block landing detection indefinitely. If every + // other criterion has held for LAND_DETECTOR_RNGFND_TIMEOUT_SEC, override the + // rangefinder check and declare the landing. + if (inertial_landed && !ap.land_complete) { + if (land_detector_rngfnd_timeout_count < ((float)LAND_DETECTOR_RNGFND_TIMEOUT_SEC)*scheduler.get_loop_rate_hz()) { + land_detector_rngfnd_timeout_count++; + } else { + gcs().send_text(MAV_SEVERITY_WARNING, "Land detect: rangefinder overridden"); + set_land_complete(true); + } + } else { + land_detector_rngfnd_timeout_count = 0; + } } set_land_complete_maybe(ap.land_complete || (land_detector_count >= LAND_DETECTOR_MAYBE_TRIGGER_SEC*scheduler.get_loop_rate_hz())); @@ -119,6 +141,7 @@ void Copter::set_land_complete(bool b) return; land_detector_count = 0; + land_detector_rngfnd_timeout_count = 0; if(b){ Log_Write_Event(DATA_LAND_COMPLETE); From 1b3365be1d2b2bdbc9653e9f7225f570cdae0dda Mon Sep 17 00:00:00 2001 From: Nicolas Michel Date: Wed, 7 Oct 2026 15:35:20 -0700 Subject: [PATCH 2/3] Fix/AS-1603: Reduce stuck-rangefinder timeout to 15 s --- ArduCopter/land_detector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArduCopter/land_detector.cpp b/ArduCopter/land_detector.cpp index e92e2c0709..4571553efa 100644 --- a/ArduCopter/land_detector.cpp +++ b/ArduCopter/land_detector.cpp @@ -2,7 +2,7 @@ #include // Code to detect a crash main ArduCopter code -#define LAND_CHECK_ANGLE_ERROR_DEG 30.0f // maximum angle error to be considered landing +#define LAND_CHECK_ANGLE_ERROR_DEG 15.0f // maximum angle error to be considered landing #define LAND_CHECK_LARGE_ANGLE_CD 1500.0f // maximum angle target to be considered landing #define LAND_CHECK_ACCEL_MOVING 3.0f // maximum acceleration after subtracting gravity From 45f7dfc19a05b3f854616569e7473cff2c40a786 Mon Sep 17 00:00:00 2001 From: Nicolas Michel Date: Wed, 7 Oct 2026 15:49:11 -0700 Subject: [PATCH 3/3] Fix/AS-1603: Correct the 15 s timeout change 1b3365be1d changed LAND_CHECK_ANGLE_ERROR_DEG (a throttle-mix / crash-check angle threshold) instead of the timeout. Restore it to 30 deg and set LAND_DETECTOR_RNGFND_TIMEOUT_SEC to 15 s in config.h as intended. Co-Authored-By: Claude Fable 5.1 --- ArduCopter/config.h | 2 +- ArduCopter/land_detector.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ArduCopter/config.h b/ArduCopter/config.h index 7aaaa9513c..a86fd37213 100644 --- a/ArduCopter/config.h +++ b/ArduCopter/config.h @@ -479,7 +479,7 @@ # define LAND_DETECTOR_ACCEL_MAX 1.0f // vehicle acceleration must be under 1m/s/s #endif #ifndef LAND_DETECTOR_RNGFND_TIMEOUT_SEC -# define LAND_DETECTOR_RNGFND_TIMEOUT_SEC 30.0f // number of seconds the non-rangefinder landing criteria must hold before a healthy-but-wrong rangefinder is overridden +# define LAND_DETECTOR_RNGFND_TIMEOUT_SEC 15.0f // number of seconds the non-rangefinder landing criteria must hold before a healthy-but-wrong rangefinder is overridden #endif ////////////////////////////////////////////////////////////////////////////// diff --git a/ArduCopter/land_detector.cpp b/ArduCopter/land_detector.cpp index 4571553efa..e92e2c0709 100644 --- a/ArduCopter/land_detector.cpp +++ b/ArduCopter/land_detector.cpp @@ -2,7 +2,7 @@ #include // Code to detect a crash main ArduCopter code -#define LAND_CHECK_ANGLE_ERROR_DEG 15.0f // maximum angle error to be considered landing +#define LAND_CHECK_ANGLE_ERROR_DEG 30.0f // maximum angle error to be considered landing #define LAND_CHECK_LARGE_ANGLE_CD 1500.0f // maximum angle target to be considered landing #define LAND_CHECK_ACCEL_MOVING 3.0f // maximum acceleration after subtracting gravity