Skip to content

Reset FW throttle rate limit when switching to a non-limiting battery profile - #11980

Open
sensei-hacker wants to merge 1 commit into
iNavFlight:maintenance-10.xfrom
sensei-hacker:fix-throttle-rate-limit-profile-switch
Open

sensei-hacker wants to merge 1 commit into
iNavFlight:maintenance-10.xfrom
sensei-hacker:fix-throttle-rate-limit-profile-switch

Conversation

@sensei-hacker

Copy link
Copy Markdown
Member

Summary

Fixes a stale throttleRateLimit (fixed-wing throttle rate limiter) across an in-flight battery-profile switch.

Problem

mixerInit() only assigned throttleRateLimit when the active battery profile's motor.throttleRateLimiter was nonzero — there was no else branch to reset it. setBatteryProfile() swaps the active profile pointer but never re-derived the limit. Result: a pilot who arms on a limiting-enabled profile, then switches in-flight to a profile with limiting disabled (or a different rate), keeps the old limit applied for the rest of the flight.

Changes

  • Extracted the throttle-rate-limit derivation out of mixerInit() into mixerUpdateThrottleRateLimit() (declared in mixer.h), adding the missing reset-to-0.0f branch when the profile's limiter is disabled.
  • mixerInit() now calls this new function.
  • setBatteryProfile() (sensors/battery.c) now also calls it after swapping the active battery profile, so the limit is re-derived immediately on switch.
  • Added a UNIT_TEST-only accessor mixerGetThrottleRateLimit() for test verification.

Testing

  • Added src/test/unit/mixer_battery_profile_throttle_rate_limit_unittest.cc: reproduces the bug (confirmed failing against the pre-fix code — old profile's limit persisted after switching to a limiter-disabled profile) and passes with the fix.
  • Ran the full existing mixer/battery unit test suite (mixer_transition_logic_unittest, mixer_transition_policy_unittest, mixer_transition_scenarios_unittest, battery_ina226_unittest) — all pass, no regressions.
  • Built the MATEKF405 hardware target — links cleanly, no new warnings/errors.

Code Review

Reviewed with the inav-code-review agent — no critical/important issues found. Verified call-ordering at boot (via readEEPROM()) and on in-flight profile switch; both run in normal main-loop context with no reentrancy concern.

Addresses Qodo finding #2 from PR #11870.

… profile

mixerInit() only set throttleRateLimit when the active battery profile's
throttleRateLimiter was nonzero, and setBatteryProfile() never re-derived
it. Switching in-flight to a profile with limiting disabled (or a
different rate) left the previous profile's limit applied for the rest
of the flight. Extract the derivation into mixerUpdateThrottleRateLimit(),
add the missing reset-to-zero branch, and call it from setBatteryProfile()
as well as mixerInit().
@qodo-code-review

Copy link
Copy Markdown
Contributor

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Refresh FW throttle rate limit on battery profile changes

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Recomputes fixed-wing throttle limiting whenever the active battery profile changes.
• Clears stale limits when the selected profile disables throttle-rate limiting.
• Adds regression coverage using real mixer and battery profile entry points.
Diagram

sequenceDiagram
    participant Init as Mixer Init
    participant Battery as Battery Manager
    participant Profile as Active Profile
    participant Updater as Limit Updater
    participant Rate as Limit State
    participant Mix as Flight Mixing
    Init->>Updater: Refresh limit
    Battery->>Profile: Select profile
    Battery->>Updater: Refresh limit
    Updater->>Profile: Read limiter
    alt Limiter enabled
        Updater->>Rate: Store derived rate
    else Limiter disabled
        Updater->>Rate: Reset to zero
    end
    Mix->>Rate: Consume current limit
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Derive the limit inside mixTable
  • ➕ Always reflects the active profile without explicit synchronization calls
  • ➕ Eliminates separately maintained derived state
  • ➖ Adds repeated conversion work to the flight-control hot path
  • ➖ Couples motor mixing directly to battery-profile configuration
  • ➖ Makes the disabled-state behavior less explicit

Recommendation: Keep the PR's shared update function. It centralizes derivation, avoids repeated work in mixTable(), and refreshes state at both lifecycle points where the active profile can become relevant.

Files changed (6) +243 / -0

Bug fix (3) +23 / -0
mixer.cCentralize throttle rate limit derivation and reset +14/-0

Centralize throttle rate limit derivation and reset

• Extracts rate-limit calculation into mixerUpdateThrottleRateLimit() and calls it during mixer initialization. Disabled limiting now explicitly resets the cached value to zero, with a UNIT_TEST-only accessor added for verification.

src/main/flight/mixer.c

mixer.hExpose throttle rate limit refresh API +8/-0

Expose throttle rate limit refresh API

• Declares the shared refresh function for battery-profile changes. Also declares the test-only accessor for inspecting the file-static limit.

src/main/flight/mixer.h

battery.cRefresh mixer limit after battery profile switches +1/-0

Refresh mixer limit after battery profile switches

• Calls mixerUpdateThrottleRateLimit() after selecting the active battery profile and any associated control profile, ensuring in-flight switches immediately adopt the new limiter setting.

src/main/sensors/battery.c

Tests (3) +220 / -0
CMakeLists.txtConfigure the throttle rate limit regression test +4/-0

Configure the throttle rate limit regression test

• Links the new unit test against the real mixer and battery implementations plus their required common dependencies. Enables ADC code needed by the battery translation unit.

src/test/unit/CMakeLists.txt

battery_ina226_unittest.ccStub the new mixer refresh dependency +4/-0

Stub the new mixer refresh dependency

• Adds a no-op mixerUpdateThrottleRateLimit() stub so the existing battery test continues linking after setBatteryProfile() gains the new call.

src/test/unit/battery_ina226_unittest.cc

mixer_battery_profile_throttle_rate_limit_unittest.ccCover throttle limit initialization and profile switching +212/-0

Cover throttle limit initialization and profile switching

• Adds integration-style unit coverage using the real mixerInit() and setBatteryProfile() entry points. Verifies an enabled limiter produces a nonzero rate and switching to a disabled profile clears the stale rate.

src/test/unit/mixer_battery_profile_throttle_rate_limit_unittest.cc

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can turn on the rule miner and Qodo learns your standards from review history

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@sensei-hacker sensei-hacker added this to the 10.0 milestone Sep 20, 2026
@github-actions

Copy link
Copy Markdown

RAM / Flash usage vs. base commit b93fc4b — commit 60a3c3e

Target Flash Δ RAM Δ
MATEKF405 +196 B (+0.03%) CCM: ±0 B (±0.00%)
RAM: +12 B (+0.01%)
MATEKF722 +8 B (+0.00%) ITCM_RAM: -8 B (-0.06%)
RAM: ±0 B (±0.00%)
TCM: ±0 B (±0.00%)
MATEKF765 -240 B (-0.03%) DTCM_RAM: ±0 B (±0.00%)
SRAM1: -8 B (-0.01%)
MATEKH743 +128 B (+0.02%) D2_RAM: ±0 B (±0.00%)
DTCM_RAM: ±0 B (±0.00%)
ITCM_RAM: +48 B (+0.30%)
RAM: ±0 B (±0.00%)

See RAM/flash optimization guide for techniques to reduce usage.

@github-actions

Copy link
Copy Markdown

Test firmware build ready — commit 60a3c3e

Download firmware for PR #11980

249 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant