# ACT tube-sorting inference bundle

Simulation checkpoint step 18000, architecture `ACT_resnet18_256_3enc_2dec_CVAE32`.
Execution rule: prefix 20, gripper-transition prefix 5.
Attached evaluation: 7/100 fully sorted
episodes (0.211 mean sorted fraction).

**This bundle records simulation evidence only. It does not establish hardware
readiness, and nothing in it connects to a robot.**

## The task

A centre basket holds 4-10 tubes, red and blue in any ratio including all of one
colour. **Red tubes go to the left basket, blue tubes to the right.** The mapping
is fixed and is not an input: the policy reads colour from the wrist image.

## Running it

From this directory, with the Torch, torchvision and NumPy versions recorded in
`manifest.json`:

```bash
python example.py
```

The exported checkpoint has optimizer state stripped and reproduces the source
checkpoint exactly on the attached observation sequence
(see `manifest.json:roundtrip_exact`).

## Observation

* `rgb`: raw uint8 wrist RGB, shape (200, 320, 3), current frame only.
* `state`: 16 float values - six joint positions, measured gripper spacing
  divided by 0.1008 m, base-frame TCP position in metres (3), and the first two
  TCP rotation-matrix columns flattened column by column (6).

Call `predict()` at every 20 Hz tick,
including while a chunk is still executing. Call `reset()` at each episode
boundary. The runtime keeps 16 causal proprioception frames internally and
pads missing initial history with the first observed state.

## Action

`[dx, dy, dz, rx, ry, rz, gripper]`, each component in [-1, 1].

* Translation is a base-frame delta; 1.0 corresponds to
  0.005 m for that step, and the
  three-vector norm is limited to 1.
* Rotation is a base-frame axis-angle delta, left-composed; 1.0 corresponds to
  0.017453 rad.
* `gripper` is an absolute normalized command: -1 closed, +1 open. It is not a
  force in newtons and is not linear in millimetres.

Every delta refers to the *measured* TCP at the tick the action is applied.

## Before hardware

The controller this policy was trained against runs differential IK at 1 kHz with
bounded joint-position targets and gravity-bias compensation; see
`control_contract.json`. A hardware adapter still needs calibrated TCP and
hand-eye transforms, camera distortion preprocessing, a gripper width mapping,
verified timing, and bounded IK with joint-speed limits. None of that is
validated here.
