Terrain AGL Hold — terrain following for fixed wings (builds on #11438) - #11785
Draft
MartinovEm wants to merge 37 commits into
Draft
Terrain AGL Hold — terrain following for fixed wings (builds on #11438)#11785MartinovEm wants to merge 37 commits into
MartinovEm wants to merge 37 commits into
Conversation
…ature/inav_terrain # Conflicts: # docs/Settings.md
…ature/inav_terrain
…ature/inav_terrain # Conflicts: # .gitignore
…ature/inav_terrain
…rd is not in idle
…add new DEBUG LOG type "terrain"
Adds a third sdcardVTable_t implementation for the SITL target that reads/writes 512-byte blocks in a disk-image file on the host (--sdcard=<image>), following the SPI/SDIO drivers contract (deferred completion callbacks from poll()). Enables USE_SDCARD and USE_TERRAIN for SITL, so asyncfatfs and the terrain tile reader run unchanged in the simulator. Without --sdcard the virtual FC behaves like one with an empty card slot.
…es and climb lookahead
Adds terrain_nav.{c,h}: a strict wrapper around the terrain module for
future navigation consumers. Success is always an explicit boolean and
values are written only on success - no sentinel, stale or substituted
value ever reaches a caller. Provides current AGL, terrain height at an
arbitrary location (scheduling the block load on cache miss), terrain
height at the GPS origin, and a bounded climb-lookahead that walks the
grid along a bearing, accumulates achievable climb and reports the worst
height deficit together with an explicit count of unavailable samples.
Built entirely on the terrain module's public utilities; no existing
files changed apart from the build list. Nothing in flight code calls
this API yet - flight behavior is unchanged.
FW 3D Cruise only, opt-in RC box, health-gated, all commands through the single altitude-target funnel. Engage captures current AGL (below minimum: slew-limited climb to it); data loss freezes the target with an OSD warning, resume after 3 s healthy; pitch stick pauses the hold and re-captures on release; directional lookahead climbs early for rising terrain within the global per-cycle block budget (cache - 2); nav_max_altitude always wins with TERRAIN VS MAX ALT / TERRAIN PULL UP warnings. New settings: terrain_nav_min_agl (60 m default), terrain_nav_lookahead (1000 m, 0=off). SITL tile cache set to 5 to mirror the small-cache board tier.
…ning The climb lookahead scans along the course over ground; when the heading estimate is invalid the cog can be stale, so the lookahead now switches itself off (same skip as the config and low-speed gates) and the pilot gets a new lowest-priority OSD warning - the ceiling and data-loss warnings always override it. The reactive hold keeps tracking unchanged (the same degraded mode as terrain_nav_lookahead = 0). No new settings.
…LIMB info + TERR flymode indicator
…mand step, no deadband-edge writer flap)
…capped lookahead horizon
…d threat only, PULL UP survives below-min captures, pass-at-minimum clear rule, TAWS callout texts Below the minimum the escape-test shortfall now counts only the real terrain-relative deficit (the altitude term is clamped out there; above the minimum it keeps acting as the honest cushion), so the automatic climb shows TERRAIN AUTO CLIMB TO MIN instead of a false TERRAIN AHEAD. A capture below the minimum no longer extinguishes an active PULL UP - the alarm clears only at/above the minimum, as always. TERRAIN AHEAD clears when the escape test passes with the aircraft at/above the minimum, both sustained 2 s; a returning threat re-fires the series (the spare-margin clear could never be met riding exactly at the floor). OSD texts become "TERRAIN AHEAD!" and "TERRAIN! PULL UP!".
…-min capture hands over to the auto-climb info A capture below the minimum (low engagement or a deep stick release) starts a clean alarm phase again: the automatic climb shows TERRAIN AUTO CLIMB TO MIN, and TERRAIN! PULL UP! returns only when the climb is failing (losing height against the best achieved), when the pilot pushes below the margin, or when the floor is breached after having been reached.
… cap-uncover fast clear
…annel + auto-climb info alternation
At a 30 m floor the alarm point (floor - 5 m) minus the worst-case map error budget (30 m on steep slopes) minus the tracking band leaves no real clearance. 50 m is the lowest floor where the worst-case stack still clears with margin. Default unchanged at 6000.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
As an FPV pilot flying a field with hills around it, I kept coming back to the same worry: plain Cruise holds a fixed altitude — fine over flat ground, but around those hills it can quietly become a problem, since the aircraft holds its height above home, not above the ground rising ahead of it. The terrain data is already on the SD card — so I decided to work on a Cruise that follows it.
Terrain AGL Hold is basically CRUZ with a moving target — in 3D Cruise, one new mode box makes the altitude target follow the terrain data under the aircraft: you hold height above the ground, not above home. Downhill the plane descends with the valley, uphill it climbs with the ridge. Box off — instant stock CRUZ.
▶ Video — Flights 1–2: floor work and turns over the flat field (AtomRC Beluga, SpeedyBee F405 Wing, real SD terrain tiles).
▶ Video — Flight 3: crossing a ridge that rises ~150 m above the takeoff field — three passes, hands off the pitch stick, no warnings needed.
What it does
One navigation cycle — inputs, health gate, the moving target, the alarm ladder, and the single gate into the altitude target path (the stock controller, untouched).
TERRAIN AGL HOLD— fixed wing only, active only inside 3D Cruise (NAV COURSE HOLD + NAV ALTHOLD). It is a modifier: everything else stays stock Cruise.TERRAIN AUTO CLIMB TO MIN). Why 50 m is the lowest the firmware will accept: the floor has to absorb everything going wrong at once — worst-case map error on steep slopes (~±30 m; typical source agreement is ~6 m, measured against ICESat-2 and radar-altimeter data), the aircraft's natural ±5–8 m tracking breathing, and the alarm margin (the floor alarm fires 5 m below the floor). At a 50 m floor that worst-case stack still clears the ground with a few meters in hand.TERRAIN AHEAD!tens of seconds before any reactive alarm could fire.TERRAIN AUTO CLIMB TO MIN):TERRAIN NOT READYTERRAIN AUTO CLIMB TO MINTERRAIN AHEAD!TERRAIN! PULL UP!(blinks)TERRAIN! TURN AWAY!(blinks)TERRAIN VS MAX ALTnav_max_altitudeTERRAIN LOST - ALT FROZENTERRAIN LOOKAHEAD OFFSafety design
nav_max_altitudeclamp downstream. No PID or controller code is modified anywhere.nav_fw_auto_climb_rate— no separate terrain climb setting. Set it to what your aircraft can genuinely sustain: the terrain escape warning trusts that number.NB: set
nav_fw_manual_climb_rateequal tonav_fw_auto_climb_rate(they default to 300/500). Matched, an auto-climb stays smooth if you touch the pitch stick — and pulling won’t climb any faster, since the auto-climb is already at that rate. Left unmatched, you may see a small, harmless nose-ease.TERRAIN LOST - ALT FROZEN(it will not descend blindly), 3 s of healthy data resumes. Proven closed-loop on a deliberately corrupted card.Why a separate mode, and not SURFACE
A fair question: INAV already has "terrain following" — SURFACE mode. Why not extend it? Because under the same family name, the two do different jobs with different physics:
A pilot carrying SURFACE expectations into a map-based mode (or vice versa) would be carrying the wrong safety assumptions — that is exactly what a distinct name prevents. The two never stack: this mode refuses to engage while SURFACE is active. Converging the pilot-facing "terrain following" concept over both sources someday — happy to discuss (see the open question below); the safety rules stay per-source either way.
New settings (only two)
terrain_nav_min_aglterrain_nav_lookaheadHow to test (bench + first flight)
set terrain_enabled = ON(it defaults OFF), with terrain tiles on the SD card — you can generate tiles for your area with this map generator (usage explained in the repo).The two
terrain_nav_*settings themselves are CLI-only for now — a companion inav-configurator PR adding them to the GUI follows once the firmware side settles. Defaults are sane; for a first test you can skip bothsetlines entirely.OSD: the stock Altitude element shows height above your home point, not above the ground. To see the terrain height above ground (AGL) in flight, add the Rangefinder OSD element — with no rangefinder fitted, it shows the terrain-derived AGL. The flight-mode field shows TERR while the hold is engaged.
3. Important: set
nav_fw_manual_climb_rateequal tonav_fw_auto_climb_rate(defaults are 300/500 — unequal). If manual < auto, grabbing pitch during an auto-climb commands the lower rate and the nose visibly eases.4. Ground check outdoors: GPS fix ·
sd_info= Ready · the OSD height-above-ground element reads ≈ 0 on the ground.5. First flight: fly 3D Cruise as usual, get comfortably HIGH over FLAT ground, then flip TERRAIN AGL HOLD on — watch it hold height above the ground; flip it off and on; grab the pitch stick (it yields, release re-captures). Only when that is boring, go lower or toward terrain — and never dive at a hill on purpose; the message table above says what each warning wants from you. Panic rule: box off = stock cruise instantly; the pitch stick always wins.
Verification — honest levels
Flight 2: floor work, the push-dive ladders, the bank-vs-sag curve.
The SD timing proof: nav never blocks, the data layer’s lock does its job.
The campaign-wide alarm discipline: every fire below the floor, every clear at 60.
Tested on: SPI-SD F405 Wing + SITL. Not yet measured on SDIO-SD boards (H7 class) — the design is driver-independent (cache-only reads, async IO, health gating), but "at least as good on SDIO" is reasoning, not measurement. SDIO testers very welcome.
Integration notes
.TERtiles) is planned once that branch settles; the full test ladder will be re-run on 2 m tiles before this PR leaves draft.maintenance-10.xtook boxId 60 / permanentId 69 for AUTO SPEED — at the rebase this PR's box moves to boxId 61 / permanentId 70 (a two-file, known-resolution conflict until then).Roadmap (after this proves itself)
Terrain-relative waypoints · terrain-aware RTH · geozone awareness — deliberately later, on top of this foundation.
Credits: error414's terrain data layer made all of this possible — this PR only reads what #11438 provides. He saw the feature before anyone else and has been testing it since.
One personal note to close: I fly these hills every week. The flights above were the first time I crossed that ridge with my hands off the pitch stick — the plane just followed the ground, said nothing, and had nothing to say. That quiet is the feature.