# Arm + Hand record / replay

The teach/replay scripts now capture and replay the **Inspire hand** alongside the
G1 arm. Backward compatible: old recordings (no hand track) replay arm-only.

## What changed
- **`g1_teach_v4_stable.py`** — while recording the arm, it also subscribes to
  `rt/inspire/cmd` and saves the commanded finger pose as `"h": [12]` per frame
  (0–5 right, 6–11 left). Meta gains `"hand": true`. On by default; `--no-hand` disables.
- **`g1_replay_v4_stable.py`** — auto-detects the `h` track and publishes it to
  `rt/inspire/cmd` every frame, so the hand follows the arm (incl. move-to-start,
  pause-hold, and home-return).

The hand *state* read-back is unreliable on the current adapters, so we record the
**commanded** hand pose (`rt/inspire/cmd`) — i.e. whatever you drive the hand to
during teaching (via the dashboard) is what gets captured.

## Prerequisites
- Env with `unitree_sdk2py`: **`conda activate g1_env`** (also works: teleop, g1ik, …).
- Workstation ethernet to the G1 (`enp3s0`, 192.168.123.x) — same DDS domain as the robot.
- **`inspire_g1` running on the robot** (the Docker container) so it receives
  `rt/inspire/cmd` and drives the physical hand. Same domain reaches it over the eth link.

## Record (teach)
```bash
conda activate g1_env
cd ~/Robotics_workspace/yslootahtech/G1/G1_Lootah/Manual_Recorder
python3 g1_teach_v4_stable.py enp3s0 --output wave_hi --seconds 20
```
- First 3 s: arms locked. Then arms go limp — **move the arm by hand**.
- **Default (`--hand-source keys`, terminal focused):** `o`=open · `c`=close (fist) ·
  `b`=box · `t`=thumbs-up — each key drives the hand and is recorded. Reliable.
- **`--hand-source push` (push-to-teach):** after a 2 s force-baseline calibration,
  **press a finger to move it** (via the force sensor, since fingers can't be pushed
  directly). Two behaviours:
  - `--push-mode hold` (default): press-and-**HOLD** → the finger closes *gradually*
    (harder press = faster, `--close-rate`); release → **holds at that level**, so you
    get any partial close. Press again to open it back.
  - `--push-mode toggle`: a press flips the finger full open↔close.

  Keyboard while recording: `o`/`c` = open/close **both** hands · `[` `]` = open/close
  **right** · `;` `'` = open/close **left**. Sensitivity: `--push-thresh 50` default
  (auto-raised per finger to its resting noise); lower it (e.g. `30`) for a lighter press.
- `--hand-source cmd`: command the hand from the dashboard http://<robot-ip>:8088.
- `--hand-source follow`: low-force by-hand — **does NOT work on the RH56** (see below).
- Arm-only: add `--no-hand`.

> **The RH56 fingers ARE back-drivable when RELEASED** (corrected 2026-07-30). Sending
> `q=-1` turns the motor OFF (0xFFFF) → the fingers go loose and you can pose them by
> hand, and the position sensor follows. (An earlier note here wrongly said
> non-backdrivable — that test used a low *grip force*, which still COMMANDS/holds a
> position, not a release.) So the simplest record-by-hand is **release + record the
> actual position** — see `hand_record.py`, which does exactly that. The `keys` / `push`
> / `follow` teach modes were built before this was understood; `keys` still works fine,
> but posing by hand (release) is the natural way.
>
> ⚠️ The two hands are on a **flaky USB hub** that intermittently drops one or both
> adapters (a dropped hand reads flat 0 / can't be driven). For reliable recording,
> reseat the USB-RS485 adapters or plug them **direct into the Jetson**.

### Recording fingers by physically moving them (default `--hand-source state`)
`rt/inspire/state` read-back now **works** (the frame-header fix — this hand replies
`90 EB`). In the default `state` source the recorder **releases the fingers** (sends
`-1` each frame so the motors go free) and logs the **actual** finger degrees, so you
can bend the fingers by hand and it captures the real motion. Sources:
- `--hand-source state` (default) — release + record actual positions (move fingers by hand).
- `--hand-source keys` — drive with the keyboard (`o`/`c`/`b`/`t`) and record that.
- `--hand-source cmd` — record whatever the dashboard commands.

> Note: **both** hands track (open≈1.0 → close≈0), verified 2026-07-29. If a hand reads
> a flat `0`, restart the hand service (`./manage.sh restart` / re-run the container);
> if it persists on only one hand, check that hand's RS-485 adapter.

## Preview before saving
After the arms return home (and before the save prompt) the teach asks:
`▶️  Replay this recording to preview before saving? [y/n]`. Answering `y` replays the
just-recorded arm **and** hand in real time (arms + fingers move), returns to home, and
asks again — so you can watch it as many times as you like, then choose save `y/n`.

## Replay (arm + hand together)
```bash
conda activate g1_env
python3 g1_replay_v4_stable.py enp3s0 --input wave_hi.jsonl
```
- Detects the hand track automatically and drives the hand with the arm.
- Keys: `x` pause · `z` resume · `q` quit. `--speed 0.5` for slow-mo.

## File format
```
{"meta":{"hz":60.0,"motors":29,"hand":true,"hand_motors":12}}
{"t":0.0,"q":[..29..],"h":[..12..]}
...
```
