Dashboard (web/hand_web.py) - Record/replay panel driving g1_record_replay.py as a pty child: take library (replay/download/duplicate/rename/delete/upload/delete-all), pause & resume, and in-take key buttons that grey out in the --fingers modes the recorder ignores (measured: in touch mode the keys change nothing at all). - /api/restart is container-aware: it kills inspire_g1 and lets the supervisor relaunch it. It used to run manage.sh, which started a SECOND inspire_g1 beside the supervised one - two writers on one RS-485 bus - and never returned. - Shape/combo libraries take a .bak on every write, with an undo button. Both files are rewritten in full, so deleting the last entry was unrecoverable. recorder/ - The recorder lives in this project now: one source of truth for the CLI and the dashboard, with pause/resume added to replay. - record.sh picks a runtime by itself (a python with the SDK, the vendored SDK, or the inspire-hand container). bundle.sh packs a ~340KB portable kit. tools/ - preflight.sh: read-only readiness report for a new robot (hardware, docker, build prerequisites, per-robot settings) ending in an install-path verdict. - fetch_deps.sh: stage build dependencies, verifying the libs are aarch64. - export_ui.py: regenerate an embedding app's vendored copy of the UI. docker/ - build_image.sh resolves its dependencies from several layouts: deps/ inside the project, /usr/local, a source install prefix, or a ROS2 colcon workspace (where the idl headers live when /usr/local has none). - web/ is copied in the last layer, so dashboard edits skip the C++ rebuild. - restart=always, and start.sh always builds so an edit cannot silently run a stale image. deps/unitree_sdk2 is vendored so a robot that has never seen the SDK can build. Docs: README quickstart + embedding notes, SETUP_G1 corrected (that udev rule stopped creating /dev/inspire_* symlinks a while ago), ROBOT_README describing a live install.
86 lines
3.6 KiB
Markdown
86 lines
3.6 KiB
Markdown
# 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.
|