# Manual recorder — record and replay without the dashboard

The backup plan. Same script the web dashboard runs (`g1_record_replay.py`), driven from a
terminal instead. Use it when Docker, the dashboard or the network are unavailable — or
when you just prefer a shell.

## Run it

```bash
./record.sh doctor                              # what's available here, what's missing
./record.sh record --output wave --seconds 20   # a take
./record.sh replay --input wave --speed 0.5     # play it back
```

`record.sh` finds a working runtime for you, best first:

1. `$RECORDER_PY` — if you named a python
2. any python that can already import `unitree_sdk2py` (e.g. conda `g1_env`)
3. the vendored SDK on `PYTHONPATH`
4. the **`inspire-hand` container**, which has the SDK baked in

`./record.sh --how` prints which one it picked without running anything. Every other flag
is passed straight through to the recorder, and the interface is inserted automatically
(`eth0` on the robot, `enp3s0` elsewhere — override with `IFACE=`).

Prefer the raw command? It is exactly:

```bash
python3 g1_record_replay.py enp3s0 record --output wave --seconds 20
docker exec -it -w /opt/recorder inspire-hand python3 g1_record_replay.py eth0 replay --input wave
```

**Where takes land:** in `DataG1/` next to wherever you run it. Through the container that
is `/opt/recorder/DataG1` = `~/hand_data/DataG1` on the robot — the same library the
dashboard lists, so a CLI take shows up there and vice versa.

## A take, start to finish

1. Arms hold for ~3 s, then go **limp** — have hold of the arm before that.
2. Move the arm by hand. Fingers cannot be posed by hand, so drive them with the keys.
3. At the end it offers a **preview** (⚠ the arm replays what you just did) and then a save.
4. `Ctrl-C` stops a take early and still saves — the arm goes home and releases first.

**Keys during a take:** `o`/`c` both open/close · `[` `]` right · `;` `'` left ·
`1`-`9` saved dashboard shapes · `f` arm/disarm follow.
**During replay:** `p` or space pauses and resumes; the arm holds the frame it stopped on.

Whether the keys do anything depends on `--fingers`:

| mode | keys | what gets recorded |
|---|---|---|
| `touch` *(default)* | ignored — the hand holds the rest pose | how far a finger closes, from how hard you press it |
| `position` | drive the hand for real | the finger's measured angle |
| `external` | ignored — the recorder sends no hand commands | the angle the `:8088` sliders reach |
| `follow` | only `f` and the shape keys | the angle you push a finger into |

## Flags worth knowing

`--seconds` (20) · `--no-arm` / `--no-hand` · `--thresh` (12 g touch) · `--span` (120 g =
fully closed) · `--speed` · `--waist recorded|lock` · `--home arm_home.jsonl` ·
`--shapes <dashboard URL>|none` · `--thumb-rot closed|open`. Full list: `--help`.

## Carrying it elsewhere

```bash
./bundle.sh                 # -> manual_recorder_<date>.tar.gz (~2 MB)
./bundle.sh --with-takes    # include DataG1/*.jsonl
```

Unpack anywhere, `cd manual_recorder/recorder`, `./record.sh doctor`.

The one thing a tarball cannot carry is the **compiled** DDS bindings. On a machine with
neither the conda env nor the container, install them once:

```bash
pip install "cyclonedds==0.10.2"          # needs CycloneDDS 0.10.x + its headers present
pip install -e ../vendor/unitree_sdk2_python
```

## Cautions

- Running this from the workstation drives the **real robot** over `enp3s0`.
- Do not run it while the dashboard has a take going — two writers on the same topics.
- The hand needs `inspire_g1` running on the robot (the container). Arm-only takes
  (`--no-hand`) do not.
