
## Figure-of-eight stage (later)

Travel a figure of eight as fast as possible. The point is that it forces the
robot to LEAN into the turns, which nothing in the course exercises yet.

Blocked on two things that are still open:

1. Turning drives a growing roll oscillation (~1.4s period, amplitude climbing
   until it goes over). Ruled out: wheel torque saturation, gyroscopic
   precession (0.09 Nm against the 11.9 needed to tip it), centrifugal load
   from the off-axis mass (0.07 N against 62 N of weight), crowned-tyre roll
   instability, turn stealing balance headroom. Yaw wind-up WAS real and is
   fixed - turn is now a closed-loop rate command, not a torque difference.
2. Drive mode limit cycle: 1.90 Nm mean and 43% saturation standing still,
   where auto-balance holds the same robot in the same pose at 0.10 Nm. Not
   the lean clamp, trim, shift reflex, yaw loop, gearing, gains, tether or
   stale state - all eliminated. Next move is to stop having two
   implementations: make drive CALL the auto-balance computation instead of
   reimplementing it, so the difference disappears by construction.

Learning this on top of either would repeat today's worst mistake: hunting for
a behaviour the model makes unreachable.

## Shove detection and driving

The brace fires on acceleration the robot did not command for itself:

    shove_felt = measured_accel - (commanded_speed_change / dt)

Not on raw acceleration. A detector that cannot tell your own throttle from
someone pushing you would brace against its own driving. In the recover stage
v_cmd is always zero so the two are identical, but a driving stage MUST set
v_cmd from its speed command or the robot will lean into every acceleration it
asked for.

Measured: brace gain +0.02 improves every shove strength (5.94 -> 7.15 at
2.5 m/s). The window is narrow - 0.05 falls immediately, and the wrong sign
is catastrophic (-1.09). Lean INTO the shove.

## Lateral bank statics (blocker, contact model)

Measured: with legs frozen in the adapted pose and wheels completely dead,
the robot falls off an 8 deg laterally banked floor in 0.57s. Pure statics
fail, so no controller can ever pass a static-bank case in this model.

Suspect: the crowned ellipsoid tyre's roll-plane curvature at the contact,
b^2/a = 20^2/62.5 = 6.4mm - a near knife edge sideways. On a tilted plane
the contact migrates around the crown and the robot rolls downhill
continuously. Candidate fixes to evaluate IN STATICS FIRST (frozen robot,
dead wheels, does it stand): wider tyre ellipsoid (larger b), a flatter
crown (capsule/cylinder blend), or condim/friction changes. Only after a
frozen robot stands on 12 deg should any bank case return to the level score.

Related finding: an accelerometer at the top of a toppling robot reads
apparent gravity on the WRONG side once tangential acceleration (alpha x
0.35m) exceeds the gravity component - a control reference must blend gyro
(complementary filter); pure accel low-pass is for scoring only.

## Torque-speed legs (blocker: sensing, not motors)

Measured end-state of the level stage work: leg commands at full servo speed
fall in ~0.5s on FLAT ground even when spawned exactly in pose, at every gain
and limit tried. The loop is: leg correction -> lateral chassis acceleration
-> accelerometer reads it as roll -> bigger correction. The accel-only roll
reference is polluted by the very motion it commands; the leg ramp was never
a speed limit, it was an accidental stabiliser. The motors are NOT the limit.

Fix on real machines: complementary filter - gyro carries the fast roll path
(immune to leg-induced linear acceleration), accel corrects drift slowly.

BUT: our varying-slope world is slewed GRAVITY, which a gyro cannot see (the
world never rotates), so this test world structurally hides the gyro's value
and cannot validate the fix. Before building it, the test world needs a REAL
tilting platform: a large flat box on an actuated hinge under the robot.
Static world geoms cannot move, but a platform BODY can - this also gives an
honest home for bank statics once the tyre contact question is resolved.

Order of work:
1. hinged-platform world (actuated tilt, step-and-hold profile)
2. verify gyro sees platform tilt instantly (it will - real rotation)
3. complementary roll reference for the leveller (tau ~1s accel correction)
4. reopen the leg ramp - torque-speed legs should then stand, react near-
   instantly, and absorb side shoves by bending, which is the requirement
