# YAM — data recording

How we collect demos for training. Single-arm "place mug" task is the
current focus.

## Recorder script

The project's own `record.py` lives at `~/lab/para/robot/yam/record.py`
(source-of-truth in puget's `~/yam_para/` via sshfs). It replaces the
older `record_skip_wrist.py` flow as of task #114 — built on
`LiveRerunSession`, world-frame is `right_arm_base` (no T_lfr), and
supports the `c+Enter` mid-session scene-cam recal added in task #117.

The stock raiden `rd record` is still used only for bimanual flows.

## Single-arm launch (current canonical)

```bash
# on russet (the rig host)
ssh robot-lab           # password: robot-lab
source ~/cameron/raiden_fork.venv/bin/activate
python ~/lab/para/robot/yam/record.py --name <dataset_name>
```

Episodes auto-number under `~/recordings/<dataset_name>/NNNN/`.

Flags (see `record.py --help` for the full list):

- `--name <dataset_name>` — required, becomes the subdir under `--output_root` (default `~/recordings`).
- `--arm right` (default) | `left` — which arm to drive.
- `--rerun_port 9092` (default).
- `--wrist` — also open + save the right wrist camera. Off by default.
- `--scene_save_wh 960 540` / `--wrist_save_wh 1280 720` (defaults).
- `--jpeg_quality 90` (default).

The recorder will:

1. **Startup**: lock scene-cam pose via aruco (`--n_detections 10`).
2. Open a rerun web viewer on port `--rerun_port` (default `9092`).
3. Start the right-arm leader teleop loop.
4. Listen for the yellow-button toggle: YELLOW = start/stop episode.
5. Accept `c` + Enter mid-session to recal scene cam between episodes
   (recal is queued during an active recording).

## Yellow-button toggle

YELLOW on the leader is a single toggle:
- First press → start a new episode (frames + lowdim stream to `<dataset>/NNNN/`).
- Second press → stop, save, return to armed.

Repeat until Ctrl-C. The first few camera frames before the first YELLOW
are discarded (waiting for user readiness).

Typical demo cycle:
1. Teleop the leader to a "ready" pose above the object.
2. Press YELLOW → recording starts.
3. Teleop the task.
4. Press YELLOW → episode saved.
5. Reposition the object; back to step 1.

There's no in-script success/failure flag — every episode under the
dataset root is recorded as-is. If you want a failure marked, manually
move the directory aside post-hoc.

## Mid-session scene-cam recal

Type `c` + Enter at any time during the session. The recorder queues a
fresh aruco lock-in and applies it between episodes (so an active
recording isn't disturbed). Useful after the rig is bumped or the lighting
changes.

## Per-cam overlay (rerun viewer)

The viewer panel shows the live scene RGB with the rendered exo+arm
silhouette overlaid (mujoco + saved calibration). Sanity-check the
overlay alignment before pressing YELLOW — if the rendered arm doesn't
match the real arm to within a few px, recal (`c+Enter`) before recording.
Uses `YAM_BASE_ONLY_CONFIG` — see `rendering.md` for details.

## Archival JSON

At the end of each episode, the recorder writes
`calibration_results.json` next to the SVO2 + lowdim files. **Must
include `"success": True` for the converter to pick up the extrinsics**
— raiden's `rd convert` silently drops extrinsics if the JSON is
missing this flag, leaving you with identity-extrinsic PKLs at training
time. This was the source of a 7687-file hot-patch a week back. Don't
remove this write.

## Dataset directory layout

```
~/recordings/<dataset_name>/
├── 0000/                              # episode 0
│   ├── calibration_results.json
│   ├── lowdim/
│   │   └── 0000000000.pkl             # per-frame state + extrinsics (world = right_arm_base)
│   ├── rgb/
│   │   ├── scene_camera/
│   │   │   └── 0000000000.jpg         # 960x540 JPEG q90
│   │   └── right_wrist_camera/        # only if --wrist
│   │       └── 0000000000.jpg         # 1280x720 JPEG q90
├── 0001/
└── ...
```

`record.py` writes JPEGs + PKLs directly (no SVO2 → convert step), so
the directory is ready for training immediately. Episode count:
`ls ~/recordings/<dataset_name>/ | wc -l`.

## Browsing collected data remotely

Russet/yukon's `/home/robot-lab/recordings/` is sshfs-mountable on
puget at `~/mnt/robot-lab/recordings/`. To rsync a finished dataset
puget-side for training:

```bash
rsync -av robot-lab@yukon:~/recordings/<dataset_name>/ \
    ~/yam_para/data/<dataset_name>/
```

## Sanity-check viz after a recording session

Two scripts, pick whichever fits the moment. Prefer the grid for a
fresh dataset because it fits on screen in one shot.

**Grid (all episodes in one PNG, with trajectory keypoints)** — the
default "do I want to train on this?" view. EE world trajectory FK'd
from joints, projected through the scene-cam, overlaid on the start
frame of each episode:

```bash
python ~/lab/para/robot/yam/vis_dataset_grid_kp.py \
    --data_root ~/yam_para/data/<dataset_name>
```

Output: `unit_tests/output/dataset_grid_kp/<dataset_name>/grid_start_frames_kp.png`.
Auto-sized grid (≤6 cols). Reads from the lowdim PKLs, so a wrong
scene-cam extrinsic shows up as a polyline that misses the table.

**Per-episode (one PNG each, with overlays)** — keep for deep dives:

```bash
python ~/lab/para/robot/yam/vis_dataset.py \
    --data_root ~/yam_para/data/<dataset_name>/ \
    --out_dir ~/yam_para/viz/<dataset_name>/
```

Inspect for: missing frames, mis-projection (wrong extrinsic),
obvious motion artifacts. A single bad-extrinsic episode contaminates
training.

## Common gotchas

- **ZED 2i lockup mid-session**: typically after `Killed` or OOM. Only
  unplug-30s or reboot recovers. See `known-bugs.md`.
- **Yellow button unresponsive**: leader arm power cycle; or `rd serve`
  is dead and the recorder isn't getting button events.
- **Footpedal "Permission denied" warning**: the soft e-stop is unavailable
  but recording proceeds. Fix with `sudo bash scripts/install_footpedal_udev.sh`
  (run once per rig).
- **Recording at wrong scene-cam res**: confirm `cameras/zed.py:57`
  patch is in place; without it scene cam silently falls back to HD720
  even though raiden reports HD1080.
