Lesson 1 — The Error-Floor Cascade

One number, , stands between smooth cruise and kinematic collapse — and even far from collapse, the tracking error refuses to reach zero. This lesson derives both facts and ties them to the four-layer conditioning stack in the live controller.

How to work this lesson. Paper and pencil. Work each checkpoint ■ before reading past it — the narrative after a checkpoint assumes you produced the result. No hints live in this document. Sealed solutions are in Appendix A; open it only when your derivation is finished or you have struggled honestly. Sources: gamma_closed_form_inverse, singularity_threshold_cascade, steady_state_error_floor, symbols per notation.

1. The coordinate change (given)

The robot is a free-flying inspector: a fully actuated 6-DOF base carrying a 6-DOF arm (UR3, nonredundant here). The physical velocities are . The controller does not think in these coordinates — it thinks in the circumcentroidal stack : the CoM velocity, the base angular velocity, and the end-effector twist about the system CoM. The linear map between them is the coordinate transform (giordano2019coordinated eq 19)

with , the cross-product matrix of the base-to-CoM offset (the wiki writes this — same object), the arm’s CoM-velocity Jacobian, and the circumcentroidal end-effector Jacobian. This is the free-flying transform — the base is actuated, so nothing here is the free-floating generalized Jacobian and no momentum conservation is folded in.

■ Checkpoint 1 (warm-up). Read (1.1) row by row. State, in one physical sentence each, what the three block rows assert. Which row is trivially invertible, and what does that mean physically?

■ Checkpoint 2 (warm-up). Show that

and conclude that is singular exactly where is. This is an iff, not a correlation — the measured Spearman rank correlation between and only quantifies how tightly the magnitudes track.

2. Inverting the transform

The controller commands but the robot integrates , so every control cycle must undo (1.1). Doing that with a generic solve would waste the structure you just found.

■ Checkpoint 3 (standard). Derive the closed-form inverse of by back-substitution: recover from the third row, pass through, then recover from the first row. Assemble the full block matrix and identify the single factor through which every blow-up must pass.

The live 6-DOF controller executes your back-substitution literally — arm row first, then the base row in closed form — at GNC/breve_controller.py:526-534. Because the base row multiplies by an exact rotation and carries no damping, the CoM channel survives to machine precision even when the arm row is being regularized. That asymmetry is a design decision your Checkpoint 3 structure makes possible.

3. The speed budget

Near a singular configuration the inverse amplifies. How close is too close depends on how fast you are asking the arm to move.

■ Checkpoint 4 (standard). From the SVD derive the amplification bound for a commanded task speed

then invert it at the joint-rate limit to obtain the first critical threshold . Evaluate it for the orbit cruise demand and the UR3 wrist rate . Then re-run the same budget at the derate-floored speed to show .

This threshold schedules the first conditioning layer, Tikhonov regularization of the solve

which is one line of code: GNC/breve_controller.py:540. The damping is squared quantities throughout because it is added to , whose eigenvalues are squared singular values.

4. The damped inverse and the freeze

Below the controller switches the arm pseudoinverse to the damped least-squares form of chiaverini1997singularity, replacing each with .

■ Checkpoint 5 (standard). Show that the damped gain attains its maximum at . Explain what happens to the gain for and why that motivates freezing the inverse (hold-last) rather than continuing to damp.

The damped arm solve is GNC/breve_controller.py:537-541. One honesty note the code and wiki have not finished reconciling: the pinned identity (validation/tests/test_singularity_floors.py) and the cascade page’s attribution of the code’s to the third floor disagree on which floor the number belongs to. That reconciliation is flagged Phase-D work on singularity_threshold_cascade — treat the identity as pinned and the attribution as open.

5. The floor that will not go away

Far from any singularity, with all four conditioning layers dormant, the tracking error still refuses to vanish. On the reduced attitude+EE block the closed loop at cruise obeys (current_sota eq 4.12) and the reference moves at constant .

■ Checkpoint 6 (exam). Impose steady state along the moving reference, , argue which terms of the closed loop cancel and why, and derive the cruise-lag floor

then specialize to the Coriolis-only limit . State the invertibility condition you used and where it fails.

The restoring term you inverted is live at GNC/breve_core_controller.py:90 — the product is literally J_xb.T @ K_b @ x_b_tilde.

■ Checkpoint 7 (exam). The impedance derate softens the gains, and with . Show from (5.1) that in the Coriolis-only limit the floor relocates as . Explain physically why letting the arm go slack near a singularity is preferable to a literal speed derate — which quantity does each strategy protect?

The single shared ramp is GNC/breve_core_controller.py:80-82, applied to the base wrench at :92.

6. Defense drill (prose only, no equations)

■ Drill. The examiner leans back: “Your end-effector error settles near a tenth of a meter and your thesis calls that a floor, not a bug. Convince me. Why does it exist, why does softening the gains move it rather than remove it, and what change to the architecture would actually remove it?” Answer aloud or in writing, in complete sentences, without writing a single equation. You have five minutes.

7. Code map

resultequationlive code
hierarchical back-substitutionCheckpoint 3GNC/breve_controller.py:526-534
Tikhonov schedule (3.2)GNC/breve_controller.py:540
damped arm solveCheckpoint 5GNC/breve_controller.py:537-541
restoring term (5.1)GNC/breve_core_controller.py:90
derate ramp Checkpoint 7GNC/breve_core_controller.py:80-82

Appendix A — sealed solutions

Open only after an honest attempt. Each solution ends with the SymPy test that verifies its algebra.

A1 (Checkpoint 1)

Row 1: the CoM velocity is the base velocity transported to the CoM frame — rotated by , corrected for the lever arm ( is the transport term), plus the arm’s contribution to CoM motion ( — moving the arm moves the system CoM). Row 2: the base angular velocity is itself — the identity row, trivially invertible, meaning base attitude rate needs no reconstruction. Row 3: the end-effector twist about the CoM is generated jointly by base rotation () and joint motion ().

A2 (Checkpoint 2)

In the partition of (1.1), is block triangular once the middle row is recognized as identity: the first block column has on the diagonal and zeros below. Hence and for a rotation, giving (1.2). Singularity of and of is therefore the same event — exactly, by determinant, while the -magnitudes merely track empirically. Verified: validation/tests/test_lesson01_error_floor.py::test_c2_det_gamma_equals_det_J

A3 (Checkpoint 3)

Third row: . Middle row: passes through. First row, left-multiplied by with substituted:

Assembling

Every entry that can diverge does so through the single factor — the analytic root of the whole conditioning problem, and the reason one scalar can schedule all four layers. Verified: validation/tests/test_lesson01_error_floor.py::test_c3_gamma_inverse_blocks

A4 (Checkpoint 4)

Expanding in the left singular basis, , so , giving (3.1). At the rate limit, . At the derate floor the system runs at , and re-running the budget gives . Verified: validation/tests/test_lesson01_error_floor.py::test_c4_amplification_bound and the pre-existing pins validation/tests/test_singularity_floors.py::test_sigma_crit_numeric_matches_report_and_code

A5 (Checkpoint 5)

vanishes at (positive branch), with and , so it is the maximum. For the gain decreases with : damping no longer limits amplification, it actively drives the dying direction toward zero while still injecting motion computed from a near-meaningless direction. The honest action once the gain has passed its peak is to stop trusting the inverse altogether and freeze it — hold-last. Verified: validation/tests/test_lesson01_error_floor.py::test_c5_damped_gain_peak

A6 (Checkpoint 6)

At steady state along the reference, . Through the rate map this forces (when is invertible), so the velocity-error damping term vanishes, and differentiating kills the inertial acceleration terms. What survives of the closed loop is the algebraic balance

Solving for gives (5.1): the proportional restoring force balances the cruising arm’s Coriolis force plus the CoM-coupling forcing. Coriolis-only limit: . Invertibility needs nonsingular (small attitude errors, away from the quaternion singular set) and SPD — the formula is a small-error, on-reference statement and fails where degenerates. The floor exists only because the controller tracks motion: at a setpoint and the regulator drives . Verified: validation/tests/test_lesson01_error_floor.py::test_c6_cruise_lag_floor

A7 (Checkpoint 7)

With , the inverse scales as while the Coriolis forcing is untouched, so — the equilibrium relocates to a larger lag. Physically the arm goes slack: it stops fighting to close a gap whose closure would require joint rates the amplification bound forbids, so the commanded speed into the singular direction collapses and holds. A literal speed derate protects the joint rates too, but it does so by throttling the task command itself — it cannot beat the amplification bound and it collapses the tracking-error floor, destroying the very error signal the outer loop needs. Impedance derate protects conditioning while spending tracking error; speed derate spends the task. Verified: validation/tests/test_lesson01_error_floor.py::test_c7_gamma_relocation

A-Drill (sketch of an acceptable answer)

The floor exists because the controller is a spring being dragged: tracking a moving reference means the proportional term must supply a standing force against the cruising arm’s Coriolis load, and a spring supplies force only when stretched. Softening the gains weakens the spring, so the same load stretches it further — the floor moves, it cannot vanish, because the need for a standing force is architectural, not a tuning artifact. What removes it is removing the need for the spring to supply that force: feed the required force forward analytically so the proportional term only handles disturbances — the analytic acceleration feedforward is the planned architectural change, and the predicted result is the operational floor dropping toward the small residual set by imperfect CoM tracking.