Skip to content

CRSF telemetry: selectable altitude source for the GPS frame (ESTIMATED/MSL) - #11850

Open
raphaelhunziker1202-stack wants to merge 2 commits into
iNavFlight:masterfrom
raphaelhunziker1202-stack:crsf-gps-alt-msl
Open

CRSF telemetry: selectable altitude source for the GPS frame (ESTIMATED/MSL)#11850
raphaelhunziker1202-stack wants to merge 2 commits into
iNavFlight:masterfrom
raphaelhunziker1202-stack:crsf-gps-alt-msl

Conversation

@raphaelhunziker1202-stack

Copy link
Copy Markdown

Problem

The altitude field of the CRSF GPS frame (0x02) currently carries INAV's estimated altitude relative to the arming point (getEstimatedActualPosition(Z)). The CRSF specification intends this field to carry the GPS altitude — Betaflight sends gpsSol.llh.alt (MSL) here, and the GAlt sensor on EdgeTX/OpenTX radios is generally understood as "GPS altitude, sea level is zero" (which is exactly how INAV's own docs describe GAlt for SmartPort telemetry in docs/Telemetry.md).

As a result there is currently no way to see the aircraft's MSL altitude on the handset via CRSF, and the GPS frame duplicates information that is already sent in the barometer/vario frame (Alt sensor).

Solution

A new setting, kept deliberately minimal in scope (only the GPS frame altitude field is touched):

crsf_gps_alt_source = ESTIMATED | MSL
  • ESTIMATED (default): estimated altitude above the arming point — identical to the previous behaviour, nothing changes for existing users.
  • MSL: raw GNSS altitude above mean sea level (gpsSol.llh.alt).

The relative altitude remains available on the handset via the barometer/vario frame (Alt sensor) regardless of this setting, so no information is lost when selecting MSL.

This follows up on the discussion in #10934, where extending the CRSF telemetry to the TBS standard stalled — and where @MrD-RC asked for a CLI option to keep the legacy behaviour selectable. This PR implements only the altitude-source part of that, as an opt-in with the legacy behaviour as default.

Implementation notes

  • PG_TELEMETRY_CONFIG version bumped 8 → 9 (struct member added).
  • docs/Settings.md entry added to match the generated format.
  • Without a GPS fix, MSL reports 0 m (raw gpsSol.llh.alt), consistent with the other raw GPS fields in this frame.

Testing

  • Verified against the settings/PG patterns used by the surrounding code; CI build pending.
  • Bench/flight verification on a TBS LUCID H7 WING MINI with ELRS (EdgeTX TX16S) is planned and results will be reported here.

…s_alt_source)

The altitude field of the CRSF GPS frame (0x02) so far carried INAV's
estimated altitude relative to the arming point, while the CRSF
specification intends this field to carry the GPS altitude (MSL), which
is also what Betaflight sends and what the GAlt sensor on EdgeTX/OpenTX
radios is expected to show.

Add a new setting `crsf_gps_alt_source`:

- ESTIMATED (default): estimated altitude above the arming point,
  identical to the previous behaviour
- MSL: raw GNSS altitude above mean sea level

The relative altitude remains available via the barometer/vario frame
(Alt sensor) regardless of this setting.

PG_TELEMETRY_CONFIG version bumped 8 -> 9.
@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

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Branch Targeting Suggestion

You've targeted the master branch with this PR. Please consider if a version branch might be more appropriate:

  • maintenance-9.x - If your change is backward-compatible and won't create compatibility issues between INAV firmware and Configurator 9.x versions. This will allow your PR to be included in the next 9.x release.

  • maintenance-10.x - If your change introduces compatibility requirements between firmware and configurator that would break 9.x compatibility. This is for PRs which will be included in INAV 10.x

If master is the correct target for this change, no action is needed.


This is an automated suggestion to help route contributions to the appropriate branch.

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

Copy link
Copy Markdown

PR Summary by Qodo

Add selectable CRSF GPS altitude source

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Adds CRSF GPS altitude selection between legacy estimated altitude and GNSS MSL.
• Preserves ESTIMATED as the default to avoid changing existing handset behavior.
• Registers and documents the setting, including telemetry parameter-group migration to version 9.
Diagram

graph TD
  CLI["CLI setting"] --> CFG["Telemetry config"] --> PICK{"Altitude source"}
  EST["Estimated altitude"] --> PICK
  GPS["GNSS MSL altitude"] --> PICK
  PICK --> FRAME["GPS frame"] --> RADIO["Radio GAlt"]
Loading
High-Level Assessment

The selectable-source approach is appropriate because it adds CRSF-spec-compliant MSL reporting without silently breaking users who depend on legacy relative altitude. Unconditionally switching to MSL would be simpler but would introduce a behavioral compatibility change; keeping ESTIMATED as the default is the safer strategy.

Files changed (5) +36 / -2

Enhancement (2) +15 / -1
crsf.cSelect altitude source when serializing CRSF GPS frames +9/-1

Select altitude source when serializing CRSF GPS frames

• Chooses raw GNSS MSL altitude or estimated arming-relative altitude according to telemetry configuration. The selected centimeter value is converted to meters and encoded with the CRSF 1000-meter offset.

src/main/telemetry/crsf.c

telemetry.hDefine CRSF GPS altitude-source configuration types +6/-0

Define CRSF GPS altitude-source configuration types

• Adds the crsfGpsAltSource_e choices and stores the selected source in telemetryConfig_t.

src/main/telemetry/telemetry.h

Documentation (1) +10 / -0
Settings.mdDocument the CRSF GPS altitude-source setting +10/-0

Document the CRSF GPS altitude-source setting

• Adds generated-format documentation for crsf_gps_alt_source, including its ESTIMATED and MSL semantics and legacy-compatible default.

docs/Settings.md

Other (2) +11 / -1
settings.yamlRegister the CRSF altitude-source CLI setting +9/-0

Register the CRSF altitude-source CLI setting

• Defines the ESTIMATED/MSL lookup table and exposes crsf_gps_alt_source in the telemetry settings group. The setting maps to crsfGpsAltSource and defaults to ESTIMATED.

src/main/fc/settings.yaml

telemetry.cInitialize and migrate the new telemetry setting +2/-1

Initialize and migrate the new telemetry setting

• Bumps PG_TELEMETRY_CONFIG from version 8 to 9 and initializes crsfGpsAltSource from the generated ESTIMATED default.

src/main/telemetry/telemetry.c

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

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

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Remediation recommended

1. Negative altitude rounding changed ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new intermediate integer division truncates negative centimeters toward zero, whereas the
previous floating-point expression effectively rounded negative relative altitude down to the next
meter. In default ESTIMATED mode, values such as -150 cm now report -1 m instead of the legacy -2 m,
contradicting the promised unchanged behavior.
Code

src/main/telemetry/crsf.c[R248-250]

+        altitudeCm = lrintf(getEstimatedActualPosition(Z));
+    }
+    const uint16_t altitude = (altitudeCm / 100) + 1000;
Evidence
The CRSF field represents whole meters with a 1000 m offset, while getEstimatedActualPosition
returns a float. Rounding the float to centimeters and then applying signed integer division changes
how routine below-arming-point values are quantized compared with the removed expression.

src/main/telemetry/crsf.c[224-251]
src/main/navigation/navigation.c[5128-5136]

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

## Issue description
Preserve the previous CRSF conversion behavior for estimated negative altitudes. The new integer-centimeter intermediate causes signed integer division to round toward zero, changing the default telemetry output by one meter for negative, non-integral-meter positions.
## Issue Context
The ESTIMATED setting is intended to be behaviorally identical to the old implementation. Keep MSL selection separate while retaining the legacy floating-point conversion semantics or implementing an explicit equivalent rounding rule.
## Fix Focus Areas
- src/main/telemetry/crsf.c[242-251]

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


2. Synthetic altitude labeled raw 🐞 Bug ≡ Correctness
Description
The MSL branch reads the post-processed gpsSol.llh.alt, which GPS-fix estimation overwrites with
gpsOrigin.alt + baro.BaroAlt during an eligible GPS outage. Radios can therefore receive synthetic
barometric altitude despite the setting being documented as raw GNSS MSL.
Code

src/main/telemetry/crsf.c[R245-246]

+    if (telemetryConfig()->crsfGpsAltSource == CRSF_GPS_ALT_MSL) {
+        altitudeCm = gpsSol.llh.alt;
Evidence
The repository distinguishes raw gpsSolDRV from consumer-facing gpsSol, copies the former into
the latter, and then runs GPS-fix estimation. Under the supported fixed-wing estimation conditions,
that processing replaces gpsSol.llh.alt with GPS-origin altitude plus barometric relative altitude
before CRSF reads it.

src/main/telemetry/crsf.c[242-251]
src/main/io/gps.c[83-92]
src/main/io/gps.c[217-227]
src/main/io/gps.c[277-327]
src/main/io/gps.c[344-351]
src/main/fc/settings.yaml[2428-2433]

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

## Issue description
Ensure CRSF MSL telemetry uses a safely retained raw GNSS altitude rather than the processed GPS solution that fix estimation may overwrite.
## Issue Context
`gpsSolDRV` contains driver data but is explicitly unsafe to access asynchronously. Introduce or use a safe snapshot/accessor with clearly defined no-fix behavior rather than reading `gpsSolDRV` directly from telemetry code.
## Fix Focus Areas
- src/main/telemetry/crsf.c[242-251]
- src/main/io/gps.c[83-92]
- src/main/io/gps.c[264-327]
- src/main/io/gps.c[344-351]
- src/main/io/gps.h[124-160]

ⓘ 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 turn on the rule miner and Qodo learns your standards from review history

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/main/telemetry/crsf.c Outdated
Comment thread src/main/telemetry/crsf.c Outdated
Comment on lines +245 to +246
if (telemetryConfig()->crsfGpsAltSource == CRSF_GPS_ALT_MSL) {
altitudeCm = gpsSol.llh.alt;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Synthetic altitude labeled raw 🐞 Bug ≡ Correctness

The MSL branch reads the post-processed gpsSol.llh.alt, which GPS-fix estimation overwrites with
gpsOrigin.alt + baro.BaroAlt during an eligible GPS outage. Radios can therefore receive synthetic
barometric altitude despite the setting being documented as raw GNSS MSL.
Agent Prompt
## Issue description
Ensure CRSF MSL telemetry uses a safely retained raw GNSS altitude rather than the processed GPS solution that fix estimation may overwrite.

## Issue Context
`gpsSolDRV` contains driver data but is explicitly unsafe to access asynchronously. Introduce or use a safe snapshot/accessor with clearly defined no-fix behavior rather than reading `gpsSolDRV` directly from telemetry code.

## Fix Focus Areas
- src/main/telemetry/crsf.c[242-251]
- src/main/io/gps.c[83-92]
- src/main/io/gps.c[264-327]
- src/main/io/gps.c[344-351]
- src/main/io/gps.h[124-160]

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

The intermediate integer-centimeter step rounded negative estimated
altitudes differently than the previous float expression (by up to 1 m).
Use the original expression verbatim for the ESTIMATED path so the
default behaviour is unchanged, and drop raw from the MSL description
since gpsSol may carry the estimated fix when GPS fix estimation is
enabled.
@raphaelhunziker1202-stack

Copy link
Copy Markdown
Author

Addressed the automated review findings in 9eb30e9:

  • The ESTIMATED path now uses the exact legacy conversion expression again, so the default behaviour is bit-identical to before (the intermediate integer step could round negative altitudes differently by 1 m).
  • Dropped raw from the MSL wording: with GPS fix estimation enabled, gpsSol may carry the estimated fix during a GPS outage. Reading the processed gpsSol is intentional and consistent with the other fields of this frame (lat/lon/speed come from the same solution).

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