Conversation
Replace static-radius nav_fw_wp_turn_smoothing with nav_fw_wp_turn_mode. FLY_BY anticipates the turn from the real coordinated-turn radius R = V^2/(g*tan(bank)) at d = R*tan(angle/2), so the turn starts at the correct distance at any speed; FLY_OVER flies over the WP then turns. Landing approach always uses FLY_BY. PG_NAV_CONFIG 7->8.
…curve roll-in Builds on the FLY_BY/FLY_OVER turn predictor: - Energy/altitude bank guard (always-on): reduce the effective nav bank limit when a commanded climb cannot be sustained near the pitch/throttle limit while banked, from target-vs-actual vertical speed (filtered + Schmitt deadband + bank-entry baseline). Widens the turn/loiter so the climb recovers. - Loiter-radius floor: never demand a circle tighter than the effective bank allows. - Coordinated-turn feed-forward (nav_fw_turn_ff_gain, dev/experimental, default 100): command the geometric bank for the active turn/loiter radius so the PID only trims. - Roll-in S-curve replacing the control_smoothness PT1 (roll axis only): step-triggered, control_smoothness*50ms time constant, smoothstep then 1:1. Pitch PT1 retained. - DEBUG_FW_TURN channel for tuning. PG_NAV_CONFIG 8->9. (Includes minor comment trims to the B1 turn-predictor code per AGENT.md.)
…iter-only headroom Refinements on the B2 feed-forward/guard work (navigation_fixedwing.c): - Loiter-radius floor -> stabilised per-revolution peak hold with 1 m/s gradual decay (getFwStableLoiterRadius): ratchet up at once, hold the peak over a full revolution (orbital azimuth net 360deg), ease down at <=1 m/s. Stops the commanded circle thrashing with wind-driven ground-speed swings. - Bank-limit semantics: nav_fw_bank_angle is the planning TARGET; control output may use reserve up to the hard ceiling max_angle_inclination_rll to hold the radius (getFwBankCeilingDeg / getFwEffectiveBankLimit / getFwPlanningBankDeg). Energy guard reduces the ceiling and snaps straight to the target on trigger. - Headroom is loiter-only (getFwControlBankLimit): WP turns/cruise clamp to the planning target so coordinated turns fly a clean arc, not the hard ceiling. - Roll-in S-curve time constant -> control_smoothness*100ms (cap 1000ms).
Replace the heading-PID corner turn with an explicit coordinated arc on real WP-to-WP turns (>30 deg). New nav_fw_wp_turn_coordination = COORDINATED (default) / DIRECT (legacy fallback). The turn is a variable-radius spline driven directly on the roll axis: - RAMP_IN: smoothstep bank 0->phi_nom (no servo slam; control_smoothness folded into the ramp time and bypassed during the arc). - STEADY: direct radius control (nominal + radial pull-back + tangent alignment) against an inscribed circle placed tangent to BOTH legs, so the exit lands on the out-leg instead of offset. - CAPTURE: closed-loop roll-out, bank proportional to the heading still to go -> levels exactly on the out-leg, cannot overshoot the heading. Roll-aware easing: ease time = 1.5*phi/roll_rate + control_smoothness + the new nav_fw_wp_turn_control_ease (servo/inertia margin); the FLY_BY turn-start lead is sized from it so the longer eased path still starts in time. PG_NAV_CONFIG 10 -> 11. Settings: nav_fw_wp_turn_coordination, nav_fw_wp_turn_handback_angle, nav_fw_wp_turn_max_lead_time, nav_fw_wp_turn_control_ease (all dev/experimental).
Two state-handling fixes in the arc turn coordinator (found in code review): - The coordinator's engage latch and leg-bearing memory were function-local statics that survived resetFixedWingPositionController(). Interrupting nav mid-arc (switch to ANGLE/ALTHOLD/COURSE_HOLD) and re-entering WP mode resumed the arc with stale geometry, banking toward an outdated out-leg. State is now file-scope (fwArcEngaged, fwArcPrevLegBearing) and cleared on controller reset; the roll S-curve smoother is re-seeded the same way (fwRollSmoothReseed) so stale filter state cannot fire a spurious ramp. - A leg change while an arc was still active (short legs: FLY_BY early-reach advances the mission mid-turn) was silently consumed: the arc completed onto the stale out-bearing and the new corner got no coordination at all. Now the closed-loop capture is retargeted onto the new leg (bounded +/-phi_nom, hands back once aligned), so quick consecutive corners degrade gracefully instead of being skipped.
…ual throttle Maintainer decisions 2026-08-20 after the resume code review: nav_fw_wp_turn_max_lead_time: min 0 -> 1000ms (0 silently disabled the FLY_BY anticipation: lead distance 0 -> WP reached by proximity radius, arc engages uncapped at the corner - an undesigned mode). Stays a permanent user setting instead of being hardcoded before release; DEV note dropped, Settings.md regenerated. Energy bank guard: evaluate the near-throttle-limit branch against the AUTO throttle demand (before allow_manual_thr_increase is added). Pilot-held full throttle permanently armed the branch even though the autopilot still had throttle authority; the throttle branch now cleanly means 'auto-throttle authority exhausted'. A genuine energy crisis is still caught by the OR-connected pitch branch (climb pitch saturates).
The arc coordinator's original exit (design v1) handed control back to the heading PID at a fixed heading error (nav_fw_wp_turn_handback_angle, 15 deg) with a 300ms progress guard against premature handback on cog noise (NAV_FW_ARC_HANDBACK_GUARD_MS). Both became obsolete when the exit was replaced by the closed-loop capture phase (bank proportional to remaining heading, cannot hand back early or overshoot) but survived as dead code: the guard define was never referenced, the setting was stored but never read. Remove both (PG_NAV_CONFIG 11 -> 12 for the struct change) and skip the turn feed-forward computation entirely while the arc coordinator drives the roll: its result was discarded (the arc bank command already is the coordinated bank), and its arc branch only fed a debug channel with values that were never applied. fwArcDir is unused after that and removed.
…edictive roll-out lead - loiter FF only once established on the circle: fed during the (much larger) approach cone it fought the approach carrot and slewed the entry across the circle - capped and >150 deg corners fly the bounded closed-loop capture instead of the reactive PID / a degenerate tangent circle (flutter) - capture leads the roll-out by omega*(tau + control_ease), tau from the angle-P gain: the airframe sheds bank slower than the command falls, the residual turn rate was overshooting the out-leg - keep the roll smoother's reseed baseline current while the arc drives (a stale reset-time seed caused a brief roll twitch at arc handback) - nav_fw_wp_turn_max_lead_time bounds/default now 3000/6000/12000 (the 3 s ceiling capped nearly every cruise-speed corner) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- FLY_OVER now engages the arc coordinator as a reverse FLY_BY: the turn circle is pinned at the overfly point (led by the roll-in drift) and the exit course is the tangent from that circle through the next waypoint, so the roll-out lands exactly on a straight line to it. Handles any turn angle including full reversals; HITL: exit course within 2 deg of the direct line at all tested corners - shaped roll-out for all arc exits: the capture command's collapse is rate-limited to the entry ramp's build-up rate (phiNom/tEase) with the no-overshoot envelope kept on top; the lead gains the ramp's heading share (0.5*omega*tEase) and STEADY hands over early enough for the ramp to fit; handback waits until nearly level - debug: ch2 = active exit course while the arc runs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nt S Third wp_turn_mode: turn away onto a counter arc first, then cross the WP already aligned on the outbound course. The two equal-radius circles are spaced sqrt((2R)^2 + Ls^2) so an internal-tangent gap (Ls = 2 ease times of travel) gives the roll reversal room; the away arc rolls out onto the tangent course through the shared capture predictor and the main arc is picked up at the touch point with a standard ramp. Scales itself with the corner angle and degenerates cleanly to a teardrop at a full 180 reversal - no fallback needed. ARC_STEADY feed-forward now tracks current groundspeed (phi = atan(v^2/gR)) so wind-driven speed change along the arc is commanded immediately instead of recovered through the radial error term. Mission legs only (NAV_AUTO_WP) - the landing approach keeps FLY_BY. Debug ch1 shows the FLY_INTO sequencer stage (energy-guard bank-limit write muted in that mode). PG_NAV_CONFIG 12 -> 13: the restack onto the updated fw-roll-smoothing head pulled in the cruise_lock_on_level field, changing the struct layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… onto the leg With nav_fw_wp_tracking_accuracy enabled, FLY_OVER now rolls out ON the new leg instead of on the direct course to the next WP: the main arc exits onto a bounded intercept course (gamma = half the turn, capped at 45 deg), a short straight gives the bank reversal room, and a standard corner-cut arc rolls out tangentially on the line. At the pickup the second circle is re-solved from CURRENT groundspeed (the arming radius may be unflyable downwind) and anchored along the leg line through the actual position, so wind drift becomes an along-track shift instead of a parallel roll-out offset. Robustness from the same HITL campaign: the arc bank command is clamped to the effective ceiling (wind can drive the radial term arbitrarily large, and rate limits, handoff checks and the smoother seed must not run on a command the airframe cannot reach); no hand-back mid-S (path tracking must not see the transient offset); ramp duration scales with the commanded bank span; the cross-track rate estimator is seeded from the geometric closing speed on hand-back so path tracking re-engages without commanding a full-error kick; comments trimmed to project style. HITL (X-Plane, 15 km/h wind): all corners incl. the 180 reversal and the sharpest downwind corner roll out within 3-9 m of the line, hand-back course within 2 deg; wind-free within 0.5-6.5 m. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e debug layout - nav_fw_wp_turn_coordination merged into nav_fw_wp_turn_mode (DIRECT / COORD_FLYBY / COORD_FLYOVER / COORD_FLYINTO), PG_NAV_CONFIG -> 14 - DEBUG_FW_TURN: one owner per channel, documented in docs/development/fw-turn-debugging.md for the official docs - remove unreachable not-engaged S pickup branch (superseded by the engaged pickup; defensive stale release on controller reset mid-S) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n path tracking is on Reversal/capped fallbacks ended parallel to the leg a full turn-diameter off (logged: 116 m after the 180 at WP1, 46 deg tracker cut). The capture target now tracks a live intercept course onto the leg line, tapering 1 cd/cm and capped at nav_fw_wp_tracking_max_angle. Sim: handoff on ~50 deg intercept, on the line within 0.4-4 m. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The arc coordinator followed the global nav_fw_wp_turn_mode on the landing approach legs; clean transitions between the approach tracks are mandatory, so the effective mode is forced to COORD_FLYBY there (from DIRECT too). Landing doc updated - approach turning points come from the coordinated turn radius, not nav_wp_radius; turn-mode setting description shortened. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ve FF assist Additive FF on the carrot PID settles inside the commanded circle (HITL: 86-92 m flown at 120 m set) and its binary engage gate sat exactly in that error band, toggling the full circulation bank (POSHOLD bank flapping). Once established on the hold circle the steady arc law now takes over as a latch and regulates the radius directly; approach stays on stock guidance, loiter PID limit back to the planning bank. HITL: round circles at 30 km/h wind across a 65-145 km/h speed sweep, clean adaptive radius migration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lags from turn tuning settings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- corner-cut anticipation gated to FLY_BY legs (landing approach still forces it in every mode); DIRECT no longer advances waypoints early - turn feed-forward returns 0 in DIRECT outside the landing approach - PG_NAV_CONFIG collapsed to a single increment vs maintenance-10.x (8 -> 9) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-predictor Sync with maintenance-10.x after the MAVLink guided-mode work landed (iNavFlight#11717, iNavFlight#11731 et al.). Conflict in src/main/navigation/navigation_fixedwing.c, calculateVirtualPositionTarget_FW(): upstream iNavFlight#11717 changed the loiter radius source to navigationGetLoiterRadius(), which adds a GCS loiter radius override (POSHOLD states only); this branch wraps the same spot with the stable-loiter-radius peak hold. Resolved by keeping the stable-radius block and feeding it navigationGetLoiterRadius() as the base radius, so the GCS override is honored underneath the peak hold. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review request: both circle-line intersection solves in updateFwTurnArc() called raw sqrtf(); navigation/ convention is fast_fsqrtf(), which maps to the CMSIS VSQRT path on ARM targets. No behavior change - both discriminants are checked > 0 before the call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HITL logs at 495 Hz showed the roll shudder was not in the arc phases but at the transitions between them, where a shaped command was replaced by an unshaped one in a single nav update. - Arc hand-back: the arc releases with the wings near level while the PID and turn FF still see the full carrot error (measured 21 deg while the arc's own exit error was 1.7 deg), so their command was adopted as a step of -1818 cd. Crossfade from the arc's last command over the turn ease time, edge-triggered so every release path is covered, and independent of nav_fw_control_smoothness - that defaults to 0, which makes the S-curve smoother a pass-through. - ARC_RAMP_IN -> ARC_STEADY: the ramp ends on phiNom while the steady law recomputes from phiLive plus the accumulated eR/eH. Measured steps of +453 to +2000 cd. The steady law now blends from the ramp's final command. - ARC_STEADY had no slew limit at all, unlike the other two phases. On a tight arc the tangent bearing is ill-conditioned near the centre and eH inverted between two updates, commanding +8140 cd into the bank limit and saturating rcCommand(roll). Two-sided rate limit added. - Turn FF: heading error and velXY arrive at GPS rate (5 Hz in HITL) while the controller runs at 50 Hz, so the FF was a staircase stepping 250-600 cd every 200 ms. Slew limited rather than filtered, so a settled command is not lagged. The taper now also starts at the deadband edge instead of at zero, removing the step at the gate. - The away arc of the S sequencer blocks the hand-back and stranded the aircraft for 39 s with path tracking suppressed when the second-arc pickup never triggered. Bounded by the time to fly half the away circle. - nav_fw_land/turn hand-off threshold raised from 1.5 to 3 deg: over 13 logged turns the 1.5 deg gate was never satisfied before release, and the residual bank is bounded by the separate bank gate, not by this one. - Debug: clear the phase and heading-error channels on release, and show the pickup along-track distance while the away arc runs. Stale channels previously read as arc episodes minutes after the arc had ended. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nav_cruise_lock_on_level makes the roll-out gate optional, so with it off the course locks immediately while the aircraft is still turning - the case the 'cog - gyroRateDps(YAW)' lead was there for. Restore it for that path; the gated path locks after the roll-out and the forced timeout lock does not need it either (2.5 s of level command means level or already in trouble). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The missed-waypoint bearing check compares the bearing to the waypoint against the inbound leg bearing. Once the aircraft is established on the outbound leg that angle settles at (180 - turn angle), so beyond a ~80 deg turn it can never reach the 100 deg limit - it can only fire on the brief swing right next to the waypoint. In a HITL log of a 114 deg turn that swing peaked at 99.4 deg and missed by 0.6 deg. The waypoint then stayed active behind the aircraft, which correctly steered back to it: a full reversal 81 m past the waypoint before the check finally tripped. With nav_wp_radius small (3 m there) the radius path cannot cover this either, and FLY_OVER/FLY_INTO never set wpTurnSmoothingActive, so the anticipated-turn path does not apply. Treat the waypoint as passed once the aircraft crosses the plane through it normal to the inbound leg. Independent of turn angle and of cross-track offset, and it cannot fire early: at activation the aircraft sits a leg length short of that plane. Scoped to airplanes in WP mission mode, so RTH, trackback and the autoland approach are unaffected; FLY_BY returns earlier via wpTurnSmoothingActive and never reaches it. Verified against the logs: fires 0.1 m past the plane (6.95 s and 81 m earlier than before) on the affected turn, and never fires on a clean FLY_BY run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The into-turn corner cut ends on the outbound leg without crossing the passage plane through the waypoint - beyond a 90 deg turn it even recedes from that plane, so no geometric reached-check can fire. The old carrot then steers back toward the previous leg after hand-back until a recovery arc undoes the excursion (HITL: two of three laps at the same WP, FF pinned at full bank for 2.6-3.3 s; the third lap escaped by chance). Mark the WP reached when the main arc commits onto the outbound leg, via the same wpTurnSmoothingActive path FLY_BY has always used at turn start. State-based, so it fires at any lateral offset. Guard the mid-arc retarget so the mission advance this causes does not degrade the running arc to a bare capture; gated to FLY_INTO because FLY_OVER shares the pickup but has already advanced its WP at the overfly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
25 Hz HITL long-runs across all three WP turn modes show the residual hand-back swings come from command amplitude, not steps - rate limiting had stretched them without removing them. - Turn feed-forward: navHeadingError measures to the path-tracking carrot, so a lateral offset after a completed turn re-entered the FF at up to full bank for a plain leg capture (reproducible per waypoint to a few centidegrees), snaking every transition onto the leg. Arm the FF on a leg change and disarm it once aligned or when the arc flies the turn; leg changes the arc consumes itself do not re-arm. - Capture law: slew-limit the rise like the decay (it stepped to full bank at capped engages and mid-capture mission advances) and seed a fresh engage from the live nav command instead of zero. - RAMP_IN: seed the ramp from the live nav command as well - engaging out of a banked loiter dipped the command to zero before rebuilding (-3285 cd in one update at 50 m/s, a visible roll twitch). - Loiter exits: the loiter-time reset wipes the leg reference every cycle, so a WP advance landing on the first tracked cycle was invisible to the leg-change detection and the exit never engaged an arc - the raw FF then flew the whole turn. Unseeded plus grossly off the leg course now counts as a leg change. - Set arcR in the capture-only engage; it sizes the away-arc timeout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restack on the roll-smoothing branch freshly merged with upstream maintenance-10.x (VTOL auto-transition rework, terrain, 9.1 back-merge). navigation.c resolutions (both define blocks, conditional PG_NAV_CONFIG 12/9) carried over cleanly from the fw-roll-smoothing merge. Resolved here: DEBUG_FW_TURN moved behind the new DEBUG_VTOL_* entries in debugType_e, debugModeNames and the settings.yaml debug_modes table (order is wire-visible, upstream entries keep their indices); Settings.md regenerated with update_cli_docs.py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # docs/Settings.md # src/main/build/debug.h # src/main/fc/cli.c # src/main/fc/settings.yaml
# Conflicts: # src/main/navigation/navigation_fixedwing.c
# Conflicts: # docs/Settings.md # src/main/build/debug.h # src/main/fc/cli.c # src/main/fc/settings.yaml
…ttings nav_fw_turn_ff_gain and nav_fw_wp_turn_control_ease were kept in iNavFlight#11812 as a safety valve for builds where the defaults might misbehave. Field testing did not need them, so the defaults become constants: the 100 % FF gain is a unity factor and is dropped from the roll feed-forward path, the 100 ms control ease becomes NAV_FW_TURN_CONTROL_EASE_MS. The pure-PID fallback stays reachable through nav_fw_wp_turn_mode = DIRECT. navConfig struct layout changes, PG_NAV_CONFIG version bumped (12->13 / 9->10), the group resets to defaults. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Stacked on #11812 — merge only after that PR. The diff shows the whole stack until #11812 lands; the actual change is the last commit (375dc5f).
Why
#11812 kept two settings as a safety valve in case the defaults misbehaved on some builds:
nav_fw_turn_ff_gain(default 100 %)nav_fw_wp_turn_control_ease(default 100 ms)Field testing did not need either, so this PR removes them and hardcodes the defaults, as agreed with the maintainer. Draft until #11812 is merged and it is clear which release this lands in.
What
settings.yaml,docs/Settings.mdregenerated withupdate_cli_docs.pyturn_ff_gain/wp_turn_control_easeremoved fromnavConfig_t.fwgain == 0bypass are dropped fromgetFwTurnFeedForward(). Pure-PID behaviour stays reachable vianav_fw_wp_turn_mode = DIRECTNAV_FW_TURN_CONTROL_EASE_MS(100 ms) innavigation_fixedwing.c, used byfwTurnEaseTimeMs()and the arc roll-out leadnav_fw_wp_turn_max_lead_timestays; it depends on the airframe.Testing
🤖 Generated with Claude Code