feat(cam-lower): wire OrientationLaw through lower_core (live angular emission) #120
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "patman/angular-emission"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
SE(3) S-e. The angular half goes live: lower_chained_oriented emits omega/alpha/zeta into LoweredSegment (zeta=delta-alpha/dt, acceleration-matched, mirroring the linear channel), LowerCert gains the angular cert, Fixed laws get EXACT_ZERO directly. S3 refusal (RECOMMENDED option, Patrick-revisable): AngularVelocityStep{junction,delta_kappa,step} on curvature-stepping skipped junctions only — collinear skips still lower; translational path untouched. Back-compat pinned by closed-form golden values (reviewer derived all four independently: D=1.70s/170 seg, jx=10, vel 7.5e-4, pos 1.275e-3). KNOWN LOOSENESS recorded: cert sound but ~65x design aspiration on gentle geometry, >pi (uninformative) on stiff; tightening levers logged (feed-side windowing, seam-endpoint kappa-second). Opus review PASS after 3 low conditions closed.
Stack step S-e of the SE(3) angular lowering design (docs/superpowers/se3-lowering-design.md sections 1, 3 and 4). The angular half is now live end to end: emitted into LoweredSegment, folded into LowerCert, and reflected in the initial rigid-body state. - lower_chained_oriented / lower_chained_fourth_oriented take an OrientationLaw; the un-suffixed entry points delegate with FIXED_IDENTITY and are unchanged for every existing caller. - Angular emission uses the same acceleration-matched rule as the linear half: zeta_k = (alpha(t_k+1) - alpha(t_k))/dt, so alpha is exact at every knot by telescoping. omega = kappa*v and alpha = kappa'v^2 + kappa*v_dot come from orient::angular_state fed the s-domain v_dot (lower_core's a_s); kappa'' and v_ddot are passed as ZERO because neither omega nor alpha depends on them, and the analytic zeta of that call is deliberately not read. - LowerCert gains `angular: AngularCert` and becomes #[non_exhaustive]. Fixed laws get AngularCert::EXACT_ZERO directly, not an empty-window call. Tangent-aligned laws get the windowed certificate: per-piece Omega_sup from piece_windows, with each control step charged whole to one piece so the durations sum to the pass duration exactly (the D that build_angular_cert derives). A step straddling a boundary is charged to the piece with the LARGER Omega_sup, so the bound covers the whole step. - The heading table is built once per pass, never per knot. DECISION S3 (Patrick-revisable): implemented the design's recommended option -- refuse TangentAligned on a pass with a curvature-stepping skipped junction, via LowerError::AngularVelocityStep { junction, delta_kappa_per_m, step_rad_per_s }. Tangent tracking makes omega = kappa*v, so a kappa step is a step in the STATE omega, not merely in an integrand: the reconstruction only integrates alpha and can never reproduce it, the error is O(|delta kappa|*v) independent of dt, and no jerk-primary machine can execute it. The alternatives were to certify it with a dt-independent term (honest but certifies a bound the hardware violates) or to insert an orientation-only dwell (a scheduling change, language-adjacent). The refusal keys on the curvature STEP, not on the mere presence of a skipped junction, so collinear skipped junctions still lower. This makes tangent alignment conditional on a fully-blended pass, which the clearing pipeline does not currently guarantee -- the part most likely to want revisiting. Translational lowering is unaffected and still accepts these passes. Back-compat is pinned with golden values rather than a self-comparison: comparing lower_chained against lower_chained_oriented(.., FIXED_IDENTITY) only proves the delegation works, since both now run the same code, and could not witness the angular half perturbing the translational one. Every pre-existing test is unchanged and green. HONESTY NOTE on the angular certificate's tightness. It is one kappa derivative looser than the translational one (Omega_sup leads with |kappa'''|v^4), so it is far more exposed to sup conservatism. On a stiff pass (60x40 mm, 0.2 mm blend corridor, 0.35 m/s) max_orientation_err comes out above 2*pi: still sound, measured error still under it, but vacuous as a statement -- windowing is what keeps it finite at all. It becomes informative on gentler geometry (200x150 mm, 1 mm corridor, 50 mm/s at dt = 0.5 ms gives ~6.5e-2 rad against a peak yaw rate of 1.3 rad/s), which is what the measured-vs-certified test uses. That is looser than the design doc's aspirational < 1e-3 rad; the gap is recorded rather than hidden, and reading actual seam-endpoint kappa'' values is the logged tightening. Co-authored-by: patman-assist <patrick-ai@kgroo.co>