Draft — Fixed wing: predictive coordinated waypoint turns (Needs/Includes #11804) - #11812
Draft — Fixed wing: predictive coordinated waypoint turns (Needs/Includes #11804) #11812b14ckyy wants to merge 21 commits into
Conversation
…y-state lag) nav_fw_control_smoothness applied a PT1 low-pass to the FW nav roll command. That trades smoothness for a permanent, uncompensated lag between what the navigation controller commands and what is executed: every course correction is delayed, also during steady tracking where no smoothing is needed, and the lag grows with the smoothness setting. Replace the roll-axis PT1 with a triggered S-curve easing: - Fires only on an abrupt commanded-bank step (setpoint-rate change above 20% of the configured roll rate between nav loops), e.g. a new course at a waypoint or a nav-mode entry (RTH engage, WP start). - Eases from the pre-step output to the live target with a smoothstep over a control_smoothness-derived window (n x 100 ms, 0 = off, capped at 1000 ms), then passes the command 1:1 again. - The window timer does not reset on further steps mid-ramp, so the smoother can never get stuck damping steady tracking. - On position-controller reset the smoother re-seeds from the last applied nav roll command when nav was commanding until just now (nav-mode to nav-mode transition, e.g. RTH -> CRUISE: the level-off is eased), and from the neutral baseline after a pilot-flown phase (stick release: a roll-out in progress is not re-commanded). Stale state can never fire a spurious ramp. Same knob, same range and same intent (soft control feel, structural protection on large airframes); the pitch/pitch-to-throttle PT1 smoothing is deliberately unchanged. No settings or PG layout changes. HITL-tested on real hardware (window rescaled to n x 100 ms from flight observation; re-seed behavior derived from RTH engage, cruise stick release and RTH->CRUISE fallback tests).
In COURSE_HOLD/CRUISE the course is locked the moment the mode engages or the pilot releases the stick (roll-stick path: last course stored in ADJUSTING; yaw path: on release with a one-iteration gyro lead; mode entry: in INITIALIZE). If the aircraft is still banked at that moment - stick released mid-turn, or the mode switched out of e.g. an RTH turn - it keeps turning through the level-off, overshoots the locked course and flies a reverse correction turn. A longstanding annoyance, made more visible by softer roll-out (control smoothing). Delay the course lock until the roll-out is actually complete: while the bank is above 10 deg the course keeps following the actual COG (roll-stick path stays in ADJUSTING; yaw release and banked mode entry share one lock-pending flag), then locks with the gyro-lead compensation. The course now locks where the aircraft has effectively stopped turning - no overshoot, no reverse correction - and the controller reset/re-engage happens near wings-level, so the smoothing re-seed cannot cause a roll jerk. Fixed-wing only; multicopter course hold is unaffected.
…asing cap to 900ms The course-lock applied 'cog - DEGREES_TO_CENTIDEGREES(gyroRateDps(YAW))', mixing a rate (deg/s) into an angle - effectively a fixed one-second yaw lead. With the new bank gate the turn has essentially stopped at lock time, so lock directly to the current COG. NAV_FW_SMOOTH_TCONST_MAX_MS claimed a 1000ms cap that was unreachable with control_smoothness max 9 (n x 100ms = 900ms); set the cap and comments to 900ms to match the setting range and documentation.
…fault ON) On maintainer feedback the level-off course lock in course hold is a behavior change, so make it optional: ON locks the course only once rolled out below 10 deg bank (new behavior), OFF locks on stick center / mode entry as before. Bumps PG_NAV_CONFIG to 9. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
PR Summary by QodoFixed-wing: predictive coordinated waypoint turns + loiter arc control
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Code Review by Qodo
1.
|
- 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>
|
RAM / Flash usage vs. base branch — commit
See RAM/flash optimization guide for techniques to reduce usage. |
|
Test firmware build ready — commit Download firmware for PR #11812 244 targets built. Find your board's
|
Summary
FW waypoint turns are currently flown reactively: the heading PID chases a moving carrot, so
every corner is a late, speed-dependent overshoot followed by a correction back to track. This
PR plans the turn instead: from the aircraft's actual coordinated-turn radius
R = V²/(g·tan φ)(speed andnav_fw_bank_angle), each corner is constructed geometrically andflown as an explicit coordinated arc — smoothstep roll-in, steady arc with live feed-forward plus
radial/tangent feedback, and a predictive roll-out that hands back aligned and level. Loiter
circles are held by the same steady law once established.
Detailed technical information:
coordinated-turns-overview.html
Companion PR: iNavFlight/inav-configurator#2711
Note: branch is stacked on
fw-roll-smoothing(triggered S-curve roll smoothing + cruisecourse lock). Either merge that first and rebase, or include it here — maintainer's call.
What it does
Turn modes (one consolidated setting,
nav_fw_wp_turn_mode):R·tan(Δ/2)plus aroll-in lead, so the arc joins the next leg tangentially; the WP is passed abeam.
line to the next WP. With
nav_fw_wp_tracking_accuracyenabled it instead flies abounded-intercept S (intercept ≤ 45° to the new leg, reverse-roll straight, corner-cut arc)
that rolls out ON the new leg.
arc pinned at the WP cross the waypoint already aligned with the outbound course.
Robustness
tracking enabled the capture steers onto the leg line (tapered intercept, capped at
nav_fw_wp_tracking_max_angle) instead of ending parallel to it a turn-diameter off.continuous capture; missions continue without error (HITL-verified).
Loiter
replaces the carrot PID as a latch and regulates the radius directly (the pursuit carrot
plus any additive feed-forward always settles inside the commanded circle). Approach and
entry stay on stock guidance.
per-revolution peak hold (ratchet up instantly, decay slowly) — no more "kidney" deformation
in wind; the circle widens smoothly at speed and migrates back down afterwards.
Bank semantics: target vs. ceiling
nav_fw_bank_anglechanges meaning: it is now the sustained target bank — the value allturn and loiter radii are planned for — not an absolute limit for nav modes. Corrections
(holding an arc against wind, capturing the exit course) may exceed it temporarily.
max_angle_inclination_rllremains the absolute hard ceiling; no nav command everexceeds it. The reserve between target and ceiling is what makes the planned geometry
robust: the radius is sized for a bank the aircraft can always deliver, with headroom left
for corrections.
Energy bank guard (introduced to make that headroom safe)
commanded climb near the pitch/throttle limit can stall while the reserve is being used.
When a banked climb stagnates, the effective bank ceiling eases down toward (and if needed
below) the planning target — the turn widens, the climb recovers. After a hold-off it
gradually releases back to the hard ceiling.
the PID clamp and the planning bank itself (a reduced ceiling also widens newly planned
radii). Manual throttle raises are respected as recovery input.
use the FLY_BY construction.
Settings
nav_fw_wp_turn_modenav_fw_bank_anglemax_angle_inclination_rllstays the absolute ceilingnav_fw_wp_turn_max_lead_timenav_fw_turn_ff_gainnav_fw_wp_turn_control_easeMigration:
PG_NAV_CONFIGis version-bumped — nav settings reset to defaults on first boot.Debugging
debug_mode = FW_TURNexposes the full system (radius, coordinator state machine, exit course,bank command, FF, guard ceiling, ease time) — documented in
docs/development/fw-turn-debugging.md.docs/Fixed Wing Landing.mdupdated (approach turningpoints now derive from the coordinated turn radius).
Validation (HITL: X-Plane, MATEKF765, MSP debug telemetry)
correlate with the (uncompensated) wind vector estimated from the logs.
reversal. Tracking-ON S: 14/14 corners at 0.5–6.5 m from the leg wind-off; worst 9.1 m at
≈15 km/h wind.
offset and a late 46° tracker correction).
radius migration (previous additive-FF experiment settled 28 % inside the commanded radius —
replaced by the circle controller).
Known limitations / follow-ups
shifts the effective radius around the turn (±3–9 m residuals at ~15 km/h wind).
Wind-vector compensation is planned as a follow-up PR (10.1).
nav_fw_turn_ff_gainandnav_fw_wp_turn_control_easestay CLI-adjustable until the systemis field-proven across airframes; both are candidates for hardcoding in a follow-up.