com_breve_decoupling — decoupling the CoM inner loop from the Breve/Tikhonov solve

Concept

For a free-flying manipulator the system CoM obeys plain Newton, m v̇_c = f_c — independent of the
arm’s internal configuration. So the CoM velocity should carry no arm-singularity (Tikhonov) damping. The
reconstruction solves the arm row alone (damped) and then recovers the base/CoM row in closed form, so v_c
stays exact to machine precision near a singularity while the arm alone absorbs the damping.

Status: ADOPTED on the trunk (merge to main, 2026-06-25) — composed architecture

The decouple was built two ways: a flattened single-class experiment on gnc-com-decouple and the composed
form on speed-derate. The merge kept the composed form after proving the two byte-identical
(max_abs_diff = 0.000e+00 on a matched rollout — see Evidence). The CoM force law is its own
COMController (com_guidance, e14ee16); the hierarchical-Γ reconstruction lives in
BreveController.reconstruct_generalized_velocity (4ef96e4).

What this spans

  • GNC/breve_controller.py (breve_controller) — reconstruct_generalized_velocity (:504) + the damped
    arm sub-solve _qdot (:537): the hierarchical inverse.
  • utils/robot.py (robot) — the coupled transform Γ and its closed-form inverse Gam_inv (:303-309),
    whose block structure the hierarchical solve reads directly.
  • GNC/com_guidance.py (com_guidance) — COMController, the CoM force law (f_c), composed into the loop
    by reference (has-a, not is-a).

Constituent pages

Mechanism — the hierarchical inverse (where it lives in code)

Γ (utils/robot.py) maps [v_b, ω_b, q̇] → [v_c, ω_b, ν_e⊕] with block structure:

Γ = [ R_cb   -R_cb[p_bc]×   R_cb·J̄_v ]   → v_c
    [ 0       I             0        ]   → ω_b
    [ 0       G_ωb          J⊕       ]   → ν_e⊕

reconstruct_generalized_velocity (GNC/breve_controller.py:504) inverts it hierarchically for the 6-DOF case,
reading the blocks straight off dyn.Gamma:

  1. ω_b — identity row, exact.
  2. arm row, damped: q̇ = (J⊕ᵀJ⊕ + λI)⁻¹ J⊕ᵀ (ν_e⊕ − G_ωb·ω_b) via _qdot (:537), with λ on the
    s_min_G schedule — applied to the arm only.
  3. base/CoM row, exact: v_b = R_cb⁻¹·(v_c − (−R_cb[p_bc]×)·ω_b − (R_cb·J̄_v)·q̇). R_cb is a rotation
    (orthogonal, condition number 1), so v_c passes through with zero regularization.

The closed-form Gam_inv (utils/robot.py:303-309) already encodes this hierarchy (damping confined to the arm
sub-block); the old monolithic controller computed it and threw it away in favour of a contaminating
normal-equations solve. The 7-DOF redundant path (the v_n = 0 fibre via _augment_with_null_row,
GNC/com_controller.py:188) is kept under a guard.

Design B (minimal & attributable): keep the existing s_min_G damping schedule, just confine it to the arm.
Design A (the native s_min_J schedule of Gam_inv) is a documented follow-on — it also changes the arm
damping, risking the targeting-ON s_min_J collapse the tikhonov_regularization footgun warns of.

Evidence

  • Exactness: the v_c block uses a rotation inverse (condition number 1), so its Γ@v residual is at
    machine precision by construction — measured 3.3e-16 on a 120-step near-singular drive (min s_min_G ≈ 0.019); the ω_b identity row is 0.0; the arm block carries the intended damping residual.
  • Composed ≡ flattened: B1 (composed) vs committed B2 (flattened) on a matched rollout —
    max_abs_diff = 0.000e+00, identical key schema (_heredocs/test_parity_b1_b2.py; Jun25 CLAIMS “CoM parity
    B1 vs B2”). The residual above is inherited byte-identically.
  • Full-mission benefit (decouple vs pre-decouple monolithic): the EE floor is preserved (pe_p99 flat),
    ze_p99 is sharper, arm effort drops, s_min_G holds — full A/B in
    generated_reports/GNC/com_decouple_pitch and the Jun25 CLAIMS. (The current gold, post orbit-sync, reports
    operationally: pe_p99 0.1483, smin_median 0.0245.)

Footguns

The cruise-median floor is NOT the contamination

Decoupling fixes the near-singular CoM-coupling side-effects (effort, pointing), not the feedforward residual
that sets the cruise-median p_e. Don’t expect ~0.044 m (the idealized perfect-CoM-tracking limit); the
honest operational floor is ~0.10-0.15 m. See error_floor.md / current_sota.

brake_decel and velocity_correction_alpha are gone

Two former footguns here are resolved on the trunk: the velocity_correction_alpha CoM “band-aid” was purged
(522c085 — it was an inert no-op), and the orbit-end brake_decel was removed (8d24ad9) once orbit-synced
termination eliminated the overrun that produced the end spike. Neither exists in desired_at_window now.

Equations & references

tikhonov_regularization · robot · breve_controller · com_controller · com_guidance ·
com_vs_base · circumcentroidal_control · terminology