Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion artifacts/features/FEAT-FALCON-rollout.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,70 @@ artifacts:
- type: depends-on
target: FEAT-FALCON-v0.19.5

- id: FEAT-FALCON-v0.19.7
type: feature
title: "v0.19.7 — true-velocity odometry + hover bistability characterization"
status: approved
description: >
LANDED (honest partial). Builds on v0.19.6's frame fix with a
deterministic velocity source + velocity-cascade altitude
controller. HONEST OUTCOME: reliable tight hover NOT achieved.
The controller demonstrably CAN hold a perfect hover (0.02 m RMS
in a good run) but the gz full-hover is bistable — same config
gives 0.02 m one run, grounded 1.97 m the next. Three coupled
root causes characterised; closing them is control co-design,
not gain-tuning.

Shipped (real, reliable):
1. True body velocity via gz-sim-odometry-publisher-system →
/model/quad/odometry. Bridge defines minimal local Odometry
(twist-only), subscribes, ENU→NED, exposes via new
Physics::velocity_ned(). Replaces finite-diff-of-NavSat.
2. Velocity-cascade altitude (alt-rate) + thrust clamp 0.88
for torque headroom.
3. PosController tuned for 2 kg (hover_thrust 0.5→0.72).

Headline: alt-only run A = final 0.012 m / rms 0.016 m (PERFECT
±2 cm hover); run B = 1.972 m (grounded). Verified mixer +
controller correct; the issue is RELIABILITY (startup basin).

Three coupled root causes (→ v0.19.8 design items):
1. startup tip-over (no attitude control) → deterministic
startup sequencing / attitude-hold-from-t0.
2. mixer thrust/torque limit cycle → relay-mix-quad reserves a
hover thrust floor (VERIFIED change + Verus contract).
3. EKF attitude during vertical accel → relay-ekf accel
down-weighting at high |a|.

Verification:
- cargo test --workspace → green; -p falcon-sitl-gz
--features gazebo → 9/9.
- frame-check oracle still AGREE; odometry true velocity
delivered.
- rivet validate → PASS.

Honest status: v0.19.7 goal ("full cascade 30 s hover PASS") NOT
met reliably. Delivered the velocity infrastructure + a
controller that can hover + a precise bistability diagnosis.
Claiming a 1-in-3 gain set "works" would violate the project's
falsification discipline. The reliable PASS is gated on the
three design changes, the largest (mixer thrust floor) being a
verified-component change deserving its own oracle-gated release.
tags: [falcon, milestone, v0.19.7, gazebo, odometry, hover, honest-partial, landed]
fields:
release-target: "true-velocity odometry + hover bistability characterization"
bench-date: "2026-05-28"
best-run: "alt-only final=0.012 m rms=0.016 m (perfect hover)"
reliability: "bistable (0.02 m or 1.97 m run-to-run)"
goal-met: false
v0.19.8-design-items:
- "relay-mix-quad hover thrust floor (verified + Verus contract)"
- "deterministic startup sequencing / attitude-hold-from-t0"
- "relay-ekf accel down-weighting at high |a|"
links:
- type: depends-on
target: FEAT-FALCON-v0.19.6

- id: FEAT-FALCON-v1.0
type: feature
title: "v1.0 — six-domain credit dossier + airframe variants"
Expand Down Expand Up @@ -2032,4 +2096,4 @@ artifacts:
- type: implements
target: SYSREQ-FALCON-010
- type: depends-on
target: FEAT-FALCON-v0.19.6
target: FEAT-FALCON-v0.19.7
11 changes: 10 additions & 1 deletion artifacts/verification/FV-FALCON-SIM-003.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ artifacts:
tests: 6
steps:
- run: cargo test -p falcon-sitl-gz
- run: cargo run -p falcon-sitl-gz
# v0.19.7 — explicit mock-meaningful smoke. The default
# scenario became closed-loop hover (v0.19.4); since the
# PosController is now tuned for the 2 kg gz airframe
# (hover_thrust 0.72), closed-loop hover correctly FAILs on
# MockPhysics (a ~500 g model that ignores attitude torque).
# open-loop-climb is the scenario MockPhysics can execute end-
# to-end (pure collective-thrust climb) — the right binary
# smoke. The closed-loop hover is exercised against real gz in
# FV-FALCON-SIM-013 (bench-only).
- run: cargo run -p falcon-sitl-gz -- --scenario=open-loop-climb
- run: cargo run -p falcon-sitl-gz -- --backend=gazebo --world=falcon --model=quad # bench-only
links:
- type: verifies
Expand Down
81 changes: 81 additions & 0 deletions artifacts/verification/FV-FALCON-SIM-013.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
artifacts:
- id: FV-FALCON-SIM-013
type: sw-verification
title: "v0.19.7 — true-velocity odometry + hover bistability characterization (reliable tight hover NOT met)"
status: approved
description: >
Builds on v0.19.6's frame fix with a deterministic velocity source
(gz OdometryPublisher) + a velocity-cascade altitude controller.
HONEST OUTCOME: reliable tight hover is NOT achieved. The
controller demonstrably CAN hold a perfect hover (0.02 m RMS in a
good run) but the gz full-hover is bistable/marginally stable —
same config gives 0.02 m one run, grounded 1.97 m the next. Three
coupled root causes are characterised; closing them is control
co-design, not gain-tuning.

Shipped (real, reliable):
1. True body velocity via gz-sim-odometry-publisher-system →
/model/quad/odometry (100 Hz gz.msgs.Odometry). Bridge
defines a minimal local Odometry (twist-only; gz-transport-rs
0.1.0 lacks the wrapper), subscribes, ENU→NED, exposes via
new Physics::velocity_ned(). Replaces finite-diff-of-NavSat.
2. Velocity-cascade altitude (alt-rate): outer P (alt err →
bounded climb-rate target) + inner P (rate err → thrust) +
conditional windup-guarded integral + thrust clamp 0.88 to
reserve torque headroom.
3. PosController tuned for the 2 kg body (hover_thrust 0.5→0.72).

Headline finding — a perfect hover IS reachable:
alt-only run A: final 0.012 m, rms 0.016 m (PERFECT, ±2 cm/5 s).
alt-only run B: final 1.972 m (grounded).
The verified mixer + controller are correct; the issue is
RELIABILITY (startup basin), not capability.

Three coupled root causes of bistability:
1. Startup tip-over (alt-only, no attitude control): spawn
rotor-imbalance occasionally tips the body → thrust vector
off-vertical → sits. gz scheduling jitter picks the basin.
2. Mixer thrust/torque limit cycle (alt-rate): rate-PID torque
near thrust saturation makes relay-mix-quad's
priority-preserving saturation steal thrust → ±1 m altitude
oscillation. 0.88 clamp reduced not eliminated it.
3. EKF attitude during vertical accel (full cascade): Mahony
accel-as-gravity reference tilts during climb → att/pos
chase a wrong level → drift.

Each needs a DESIGN change (v0.19.8+), not a knob:
1. deterministic startup sequencing / attitude-hold-from-t0.
2. relay-mix-quad reserves a hover thrust floor (verified-
component change + Verus contract update — the right home
for it).
3. relay-ekf accel down-weighting at high |a| (EKF2-style gate).

Verification:
- cargo test --workspace → all green (no regression).
- cargo test -p falcon-sitl-gz --features gazebo → 9/9.
- frame-check oracle (v0.19.6) still AGREE on roll + pitch.
- Odometry subscriber delivers true velocity.
- rivet validate → PASS.

Honest status vs goal: v0.19.7 goal was "full verified cascade
sustained 30 s hover PASS" — NOT met reliably. Delivered: the
deterministic velocity infrastructure + a controller that can
hover (0.02 m good run) + a precise three-cause bistability
diagnosis. Claiming a gain set "works" when it passes 1 run in 3
would violate the project's falsification discipline.
tags: [falcon, sim, gazebo, odometry, hover, bistability, honest-fail, v0.19.7]
fields:
bench-evidence-dir: bench-evidence/gz-sim/
bench-date: "2026-05-28"
gz-version: "8.11.0"
best-run: "alt-only final=0.012 m rms=0.016 m (perfect hover)"
reliability: "bistable — same config gives 0.02 m or 1.97 m run-to-run"
velocity-source: "gz OdometryPublisher twist (true), replaces finite-diff NavSat"
goal-met: false
v0.19.8-design-items:
- "relay-mix-quad hover thrust floor (verified change + Verus contract)"
- "deterministic startup sequencing / attitude-hold-from-t0"
- "relay-ekf accel down-weighting at high |a|"
links:
- type: verifies
target: SWREQ-FALCON-SIM-P04
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# v0.19.7 — true-velocity odometry + hover bistability characterization — 2026-05-28

Builds on v0.19.6's frame fix with a deterministic velocity source
(gz OdometryPublisher) and a velocity-cascade altitude controller.
**Honest outcome: reliable tight hover is NOT yet achieved.** The
controller demonstrably *can* hold a perfect hover (0.02 m RMS in a
good run) but the gz full-hover is **bistable / marginally stable** —
the same config produces a 0.02 m hover one run and a grounded 1.97 m
the next. Three coupled root causes are characterised below; closing
them is real control co-design, not gain-tuning, and is the honest
scope of the remaining work.

## What v0.19.7 ships (real, reliable)

1. **True body velocity via OdometryPublisher.** SDF adds the
`gz-sim-odometry-publisher-system` plugin → `/model/quad/odometry`
(100 Hz `gz.msgs.Odometry`). The bridge defines a minimal local
`Odometry` (twist-only; gz-transport-rs 0.1.0 lacks the wrapper),
subscribes, converts ENU→NED, and exposes it via the new
`Physics::velocity_ned()` trait method. This replaces the v0.19.4–.6
finite-diff-of-NavSat velocity, which was noisy/lagged enough to
make the altitude inner loop non-deterministic.
2. **Velocity-cascade altitude controller** (alt-rate scenario): outer
P (alt error → bounded climb-rate target) + inner P (rate error →
thrust) + conditional integral (gravity-offset trim, windup-guarded)
+ thrust clamp at 0.88 to reserve torque headroom.
3. **PosController tuned for the 2 kg body** (hover_thrust 0.5→0.72,
gentler velocity caps) in the full cascade.

## The headline finding — a perfect hover IS reachable

alt-only (PI+D altitude, no attitude torque), 30 s, true velocity:

```
run A: final_dist=0.012 m rms_steady=0.016 m min=0.000 ← PERFECT hover
run B: final_dist=1.972 m rms_steady=1.972 m ← grounded
```

Run A is a textbook hover: the body holds the 2 m setpoint to ±2 cm
for the last 5 s. **The verified mixer + the controller are correct.**
The problem is *reliability*, not capability.

## Three coupled root causes of the bistability

1. **Startup tip-over (alt-only).** With no attitude control, a small
spawn-transient rotor imbalance occasionally tips the body; its
thrust vector points off-vertical → it translates/sits instead of
climbing. Run-to-run gz scheduling jitter decides which basin.
2. **Mixer thrust/torque limit cycle (alt-rate).** Adding rate-PID
attitude damping fixes the tip-over but introduces a ±1 m altitude
limit cycle: when the rate loop demands torque near thrust
saturation, relay-mix-quad's priority-preserving saturation steals
thrust → altitude dips → the altitude loop chases → oscillation.
The 0.88 thrust clamp reduced but did not eliminate it.
3. **EKF attitude during vertical accel (full cascade).** The Mahony
filter (relay-ekf) uses the accelerometer as a gravity reference;
during a climb the gz IMU reads thrust+gravity, tilting the
attitude estimate → the att/pos loops chase a wrong "level" →
drift. Gentle climbs help but slow the response.

## Why this isn't just more gain-tuning

Each cause needs a *design* change, not a knob:

- **(1)** wants deterministic startup sequencing (arm → spin-up →
release) or attitude-hold-from-t0.
- **(2)** wants the mixer to *reserve* a thrust floor (never sacrifice
collective below hover) — that's a change to the **verified**
relay-mix-quad with a Verus contract update, the right place for it.
- **(3)** wants accel down-weighting during high-|a| (an EKF2-style
innovation gate) — a relay-ekf enhancement.

These are the honest v0.19.8+ work items. Pretending a gain set
"works" when it passes 1 run in 3 would be the opposite of the
falsification discipline this project is built on.

## Verification

- cargo test --workspace → all green (no regression).
- cargo test -p falcon-sitl-gz --features gazebo → 9/9.
- frame-check oracle (v0.19.6) still AGREE on roll + pitch.
- Odometry subscriber delivers true velocity (verified by the
improved run-to-run determinism vs finite-diff).
- rivet validate → PASS.

## Honest status vs the v0.19.7 goal

The v0.19.7 goal was "full verified cascade sustained 30 s hover
PASS". **Not met reliably.** Delivered instead: the deterministic
velocity infrastructure + the controller that *can* hover (0.02 m in
a good run) + a precise three-cause diagnosis of the bistability. The
reliable PASS is gated on the three design changes above, the largest
of which (mixer thrust floor) is a verified-component change deserving
its own oracle-gated release.
Loading
Loading