From 3efba8995a95d6c29f1cb83161c25a770b907e78 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Sun, 11 Jan 2026 14:34:00 -0600 Subject: [PATCH 1/2] Fix altitude hold climb rate calculation deadband issue Remove double application of RC deadband in multicopter altitude hold climb rate calculation. Previously, deadband was applied to both the stick input (rcThrottleAdjustment) and the scaling limit (limitValue), causing the actual climb rate to not match the configured value. Now deadband is only applied once to the stick input, and the limit value uses the raw throttle range for proper scaling. Fixes #10660 --- src/main/navigation/navigation_multicopter.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/navigation/navigation_multicopter.c b/src/main/navigation/navigation_multicopter.c index bb8f15dc8ba..4efc7bf0483 100644 --- a/src/main/navigation/navigation_multicopter.c +++ b/src/main/navigation/navigation_multicopter.c @@ -143,9 +143,10 @@ bool adjustMulticopterAltitudeFromRCInput(void) /* Set velocity proportional to stick movement * Scale from altHoldThrottleRCZero to maxthrottle or minthrottle to altHoldThrottleRCZero */ - // Calculate max up or min down limit value scaled for deadband - int16_t limitValue = rcThrottleAdjustment > 0 ? getMaxThrottle() : getThrottleIdleValue(); - limitValue = applyDeadbandRescaled(limitValue - altHoldThrottleRCZero, rcControlsConfig()->alt_hold_deadband, -500, 500); + // Calculate max up or min down limit value (raw range, deadband already applied to rcThrottleAdjustment) + int16_t limitValue = rcThrottleAdjustment > 0 ? + (getMaxThrottle() - altHoldThrottleRCZero) : + (altHoldThrottleRCZero - getThrottleIdleValue()); int16_t rcClimbRate = ABS(rcThrottleAdjustment) * navConfig()->mc.max_manual_climb_rate / limitValue; updateClimbRateToAltitudeController(rcClimbRate, 0, ROC_TO_ALT_CONSTANT); From da05284915a962fd95a8324fdcee4e3b55924892 Mon Sep 17 00:00:00 2001 From: Ray Morris Date: Sun, 11 Jan 2026 16:29:54 -0600 Subject: [PATCH 2/2] Add defensive check against division by zero Adds safety check for limitValue to prevent potential division by zero in climb rate calculation. While the existing constraint on altHoldThrottleRCZero should prevent this condition under normal operation, this defensive check protects against: - Configuration corruption or invalid EEPROM values - Extremely narrow throttle range configurations - Future code changes that might affect the constraint behavior Addresses code review feedback on PR #11241. --- src/main/navigation/navigation_multicopter.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/navigation/navigation_multicopter.c b/src/main/navigation/navigation_multicopter.c index 4efc7bf0483..00a10d06a61 100644 --- a/src/main/navigation/navigation_multicopter.c +++ b/src/main/navigation/navigation_multicopter.c @@ -148,6 +148,11 @@ bool adjustMulticopterAltitudeFromRCInput(void) (getMaxThrottle() - altHoldThrottleRCZero) : (altHoldThrottleRCZero - getThrottleIdleValue()); + // Defensive check - should never trigger with valid configuration + if (limitValue <= 0) { + limitValue = 1; // Prevent division by zero/negative + } + int16_t rcClimbRate = ABS(rcThrottleAdjustment) * navConfig()->mc.max_manual_climb_rate / limitValue; updateClimbRateToAltitudeController(rcClimbRate, 0, ROC_TO_ALT_CONSTANT);