Skip to content

Embed the stats decimal separator and damp the battery percentage - #11920

Open
Raffi1202 wants to merge 3 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:fix/osd-number-formatting
Open

Raffi1202 wants to merge 3 commits into
iNavFlight:maintenance-10.xfrom
Raffi1202:fix/osd-number-formatting

Conversation

@Raffi1202

@Raffi1202 Raffi1202 commented Sep 10, 2026

Copy link
Copy Markdown

Problem

Two OSD reports. #10420: on the post-flight stats screen, Flight Distance and Maximum Distance From Home use DJI number formatting on every video system, a separate . character that costs a column; the reporter notes it was never a regression, it always looked like this. #10053: the Battery Remaining Percentage element is sampled so often that its digits change constantly and the value never settles in flight (INAV 7.1.1, quadcopter).

Fixes #10420
Fixes #10053

Cause

src/main/io/osd.c:396, :408, :419 on maintenance-10.x: the three fractional branches of osdFormatDistanceStr() print "%d.%02d%c". osdFormatCoordinate() (osd.c:795) and osdFormatCentiNumber() only print an explicit dot on DJI systems and otherwise embed it with SYM_ZERO_HALF_TRAILING_DOT / SYM_ZERO_HALF_LEADING_DOT.
src/main/io/osd.c:1949: OSD_BATTERY_REMAINING_PERCENT prints calculateBatteryPercentage() raw on every osdRefresh() (TASK_OSD 250 Hz / DRAW_FREQ_DENOM 4 = 62.5 Hz), so every voltage dip reaches the digits.

Change

New osdFormatDistanceFractionStr() writes integer part, two-digit fraction and unit symbol; DJI-compatible systems get the same bytes as before, every other system gets the separator embedded in the two neighbouring digits. The km, mi and NM branches call it; the whole-number branches are unchanged. The battery percentage now runs through a 0.1 Hz pt1Filter_t in osdFilterData(), seeded on the first refresh and reset whenever getBatteryState() crosses BATTERY_NOT_PRESENT; the element prints lrintf() of the filtered value. Charge symbol, blink attributes and calculateBatteryPercentage() itself keep the raw value. One comment typo ("Embbed") fixed.

Test

Not run on hardware or SITL. Cause verified by reading osd.c:396-419 and osd.c:1949 on maintenance-10.x; the DJI branch reproduces the old format string byte for byte. Qodo review found that the filter carried the previous battery's value across a battery swap; commit 2860242 adds the presence-change reset. osd_unittest.cc builds only osd_utils.c, so osd.c has no unit coverage. (no run exists for fix/osd-number-formatting).

Flash / RAM

Not measured yet. The upstream firmware CI has not been released for this PR, so no size report exists.

Docs

No documentation change needed: docs/OSD.md lists the element and the stats rows but does not describe number formatting or smoothing for any element, and docs/DJI compatible OSD.md says nothing about the decimal separator.

Raphael Hunziker added 2 commits September 10, 2026 21:41
osdFormatDistanceStr() always printed an explicit '.' character, which is
the DJI number format. On every other system the decimal separator is
drawn into the digits around it, so the separate character wasted a
column on the post-flight stats screen.

Print the separator only for DJI compatible video systems and embed it
into the neighbouring digits otherwise, the way osdFormatCentiNumber()
and osdFormatCoordinate() already do.

Fixes iNavFlight#10420
osdRefresh() runs at 62.5Hz and the percentage was taken straight from
calculateBatteryPercentage(), so the digits followed every voltage dip
and were unreadable in flight.

Run the value through a pt1 filter in osdFilterData(), next to the other
noisy OSD values, and print the filtered result. The filter is seeded
with the current percentage on the first refresh so the element does not
have to ramp up from zero.

Only the digits are damped. The battery state, and with it the alarms,
the blinking and the charge symbol, still use the raw value.

Fixes iNavFlight#10053
@Raffi1202
Raffi1202 marked this pull request as ready for review September 11, 2026 15:40
@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

Fix OSD distance formatting and battery percentage jitter

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Embeds non-DJI distance decimals to reclaim one OSD column.
• Smooths battery percentage digits while preserving raw battery alarms and symbols.
Diagram

graph TD
  BAT["Battery percent"] --> FILTER["PT1 filter"] -->|rounded digits| OSD["OSD renderer"]
  BAT -->|raw alerts| OSD
  DIST["Distance values"] --> MODE{"DJI compatible?"}
  MODE -->|Yes| EXPLICIT["Explicit decimal"] --> OSD
  MODE -->|No| EMBED["Embedded decimal"] --> OSD
Loading
High-Level Assessment

The approach is appropriately scoped: distance formatting follows the established video-system-specific glyph convention, while battery smoothing remains inside the OSD filter stage so telemetry and alarm consumers retain raw values. Filtering at the battery source would affect unrelated consumers, and broadening the generic centi-number formatter would add unnecessary coupling for this fixed two-decimal distance format.

Files changed (1) +41 / -5

Bug fix (1) +41 / -5
osd.cCompact distance decimals and stabilize battery percentage digits +41/-5

Compact distance decimals and stabilize battery percentage digits

• Adds a video-system-aware distance fraction formatter that embeds decimal separators into adjacent glyphs on non-DJI displays while preserving DJI output. Introduces a seeded 0.1 Hz PT1 filter for displayed battery percentage digits without changing raw battery state, alarm, blink, or charge-symbol behavior. Also corrects a nearby comment typo.

src/main/io/osd.c

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

qodo-free-for-open-source-projects Bot commented Sep 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Reconnected batteries show stale charge ✓ Resolved 🐞 Bug ≡ Correctness
Description
osdFilterData() resets batteryRemainingFilterState only on its first invocation because the
reset is guarded by the function-static lastRefresh value. When a battery is disconnected or
replaced without rebooting, the 0.1 Hz filter carries the previous battery’s percentage into the new
session and the displayed digits take several seconds to converge.
Code

src/main/io/osd.c[5824]

+        batteryRemainingPercent = pt1FilterApply3(&batteryRemainingFilterState, calculateBatteryPercentage(), refresh_dT);
Evidence
The new assignment continuously interpolates from the filter’s prior output, while its only reset is
in the one-time initialization branch. Battery percentage becomes zero when the battery state
reaches not-present, but neither battery reinitialization nor OSD reinitialization clears this new
filter; the rounded retained value is then rendered directly.

src/main/io/osd.c[5811-5825]
src/main/io/osd.c[5832-5840]
src/main/io/osd.c[1979-1982]
src/main/sensors/battery.c[946-955]
src/main/common/filter.c[66-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The filtered OSD battery percentage retains state across battery disconnect and reconnect events, so a replacement battery initially displays charge from the previous battery.
## Fix Focus Areas
- src/main/io/osd.c[5819-5834]
## Recommended Fix
Track whether a battery is present and reset `batteryRemainingFilterState` to the current `calculateBatteryPercentage()` value whenever presence changes to or from `BATTERY_NOT_PRESENT`. Do not reset on warning or critical state transitions during a normal discharge.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can switch off images and animations for a plain-text comment

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/main/io/osd.c Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant