Skip to content

fix: claim/start must park head at home before orient stream begins #800

@SlyWombat

Description

@SlyWombat

Summary

When /api/mover-control/start transitions a claim to state=streaming, the head should be parked at home (Home anchor) before any subsequent orient updates can land. Currently /start only sets dimmer + colour and starts the engine pump; the head stays at whatever wire DMX was previously on.

Why this matters

/api/mover-control/calibrate-end captures _mover_current_aim_stage(mover) — the head's current stage-frame aim — and uses that as the reference direction the phone's current pose is anchored to. If the head was at a stale pose at calibrate-time (because /start didn't park it), the operator's phone-pose-now is locked to that stale stage direction. Subsequent orient packets are anchored against the wrong reference, and the head appears to "jump" on calibrate-release because the new lock doesn't match where the operator expected the reference to be.

Symptom in the wild: today's Android live-test on fid 17 (2026-05-03) — claim+start brought the head to pan16=53376, tilt16=6272 (a stale aim from a previous test, ≈ stage az=-74°), then calibrate-end-with-phone-steady locked the phone to that stale pose, then the very next orient update moved the head to a "different" pose because the operator was holding the phone where they thought "stage forward" was — but the lock was anchored to az=-74° instead of home. That's the visible "jumped to stage -90X after calibrate" symptom.

Fix

In /api/mover-control/start (or MoverControlEngine.start_streaming), after the claim transitions to state=streaming:

  1. Compute the head's home aim DMX via AimSphere.aim_direction(home_az, home_el) for the fixture (uses the new sphere; honours rotation + Home + Secondary).
  2. Write that pose to the universe buffer for the fixture's pan/tilt channels.
  3. Wait for the engine to settle (or skip the wait — engine pump will catch up within a frame or two).
  4. Only then accept incoming orient packets.

Equivalently: the engine's tick loop, when it sees a claim that's state=streaming but calibrated=false, drives the head to home as the streaming reference. Calibrate-end then locks the phone to that home pose. First orient update post-release uses home as the stable reference.

Acceptance

  1. fid 17 cold-claim + /start from Android (no calibrate yet): head physically moves to home position (panDmx16=44364, tiltDmx16=0). Wire confirms the writes.
  2. Hold phone steady through calibrate-hold + release. After calibrate-end, aim_stage reported by the orchestrator is approximately (0, 1, 0) (stage forward) — i.e., maps to the head's current stage aim, which is now home.
  3. Subsequent steady-phone orient packets keep aim_stage ≈ (0, 1, 0) — head stays at home.
  4. Tilt phone +20° forward (gesture) → head physically tilts toward floor by ~20° (assuming rotation=[0,0,0] and operator's expected stage convention). No "jump."
  5. Same test on fid 14 (rotation [-75, 0, 0]): claim+start parks head at fid 14's home pose (32269, 28298), which is at stage (az=0, el=+75). Calibrate locks phone to that pose. Steady phone keeps head there.

Related

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions