105 lines
5.2 KiB
Markdown
105 lines
5.2 KiB
Markdown
# Inspire RH56 dual-hand bring-up on Unitree G1 (PC2)
|
||
|
||
Setup notes specific to **this** robot. Upstream README assumes a clean
|
||
`unitree_sdk2` install in `/usr/local` and hard-codes `/dev/ttyUSB1`+`/dev/ttyUSB2`;
|
||
neither holds here, so we adjust as below.
|
||
|
||
Canonical (workstation): `…/yslootahtech/Project/G1/DFX_inspire_service`
|
||
Deploy to PC2 `unitree@192.168.123.164:~/DFX_inspire_service` via `rsync`, then `./build.sh`.
|
||
(wifi `10.255.254.86` is flaky; the eth0 IP `192.168.123.164` is the reliable path.)
|
||
|
||
## 0. Easiest way to drive everything — `manage.sh`
|
||
```bash
|
||
./manage.sh # status: service + devices + adapters
|
||
./manage.sh start|stop|restart
|
||
./manage.sh open|close|box|menu # fingers only
|
||
./manage.sh like|handshake|thumbup # arm + hand (ARM MOVES)
|
||
./manage.sh arm "shake hand" # built-in arm action; armlist to list
|
||
./manage.sh help
|
||
```
|
||
It keeps exactly **one** `inspire_g1` running (duplicates corrupt the RS-485 bus) and
|
||
auto-starts the service for gesture commands.
|
||
|
||
## Architecture (unchanged from upstream)
|
||
`hand_example`/your app → DDS topic `rt/inspire/cmd` (`MotorCmds_`, 12 motors:
|
||
0–5 right, 6–11 left) → **`inspire_g1`** → RS-485 (CH340 USB adapters, 115200 8N1,
|
||
Inspire slave id 1) → hands. State flows back on `rt/inspire/state`.
|
||
Finger order per hand: pinky, ring, middle, index, thumb-bend, thumb-rotation.
|
||
`q` ∈ [0,1]: **0 = closed, 1 = open**.
|
||
|
||
## 1. Build (no system changes)
|
||
`unitree_sdk2` in `/usr/local` is stale (no go2 IDL). `build.sh` links against the
|
||
newer `~/unitree_sdk2` source tree instead:
|
||
```bash
|
||
cd ~/DFX_inspire_service
|
||
./build.sh # -> build/inspire_g1, inspire_h1, hand_example
|
||
```
|
||
|
||
## 2. Stable serial names + no-sudo access (one-time, needs sudo)
|
||
Both hand adapters are CH340s with identical USB serial, so we pin names by
|
||
physical port and grant access via udev:
|
||
```bash
|
||
sudo cp ~/DFX_inspire_service/udev/99-inspire-hands.rules /etc/udev/rules.d/
|
||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
||
ls -l /dev/inspire_right /dev/inspire_left # both should now exist
|
||
```
|
||
`inspire_g1.cpp` opens `/dev/inspire_right` + `/dev/inspire_left`.
|
||
Mapping (corrected after live test): right → USB port `1-2.2.1.1`, left → `1-2.2.3`.
|
||
|
||
## 3. Run + test
|
||
```bash
|
||
cd ~/DFX_inspire_service/build
|
||
./inspire_g1 # Terminal 1 (no sudo needed after the udev rule)
|
||
./hand_example # Terminal 2 -> both hands open/close ~1 Hz
|
||
```
|
||
Stop with Ctrl+C in each. If a hand doesn't move: check 24 V power, RS-485 A/B
|
||
polarity, and that the hand is at Inspire slave id 1.
|
||
|
||
## Record / replay panel (dashboard)
|
||
|
||
The dashboard's **Record / replay** card runs `g1_record_replay.py` as a child process — the
|
||
same script as the CLI, so a take made in the browser and one made from a terminal are the
|
||
same file in `DataG1/`. It needs the recorder present on whatever host serves the dashboard:
|
||
|
||
```bash
|
||
# where g1_record_replay.py lives (searched: ../Manual_Recorder, ~/Manual_Recorder)
|
||
export RECORDER_DIR=~/Manual_Recorder
|
||
# an interpreter that can import unitree_sdk2py (on a workstation: the g1_env conda python)
|
||
export RECORDER_PY=python3
|
||
./manage.sh dashboard # prints the resolved recorder path, or NOT FOUND
|
||
```
|
||
|
||
The panel starts a take, relays the in-take keys (`o c [ ] ; '`, `f`, and the saved shapes as
|
||
keys 1-9), answers the recorder's preview/save prompts, and lists `DataG1/` for replay,
|
||
rename and delete. Two things it works around, both load-bearing:
|
||
|
||
- **Keys are paced ~150 ms apart.** The recorder reads them with `select()` + buffered
|
||
`sys.stdin.read(1)`; a burst lands in Python's buffer, `select()` then reports nothing
|
||
ready and every key after the first is stranded. Measured: 3 keys 10 ms apart → 2 arrived.
|
||
- **Stop sends SIGINT, and the dashboard repairs SIGINT first.** A process backgrounded by a
|
||
non-interactive shell inherits `SIGINT = SIG_IGN`, which survives `exec` — and `manage.sh`
|
||
starts the dashboard exactly that way, so without the repair Stop would silently do
|
||
nothing. The panel shows a warning if the repair did not hold. SIGINT (not SIGKILL) is
|
||
what lets the recorder walk the arm home and release it.
|
||
|
||
Replay and preview **move the arm** and both require an explicit confirmation. Starting a
|
||
take disarms force-follow, since the bridge and the recorder would otherwise both publish
|
||
`rt/inspire/cmd` every frame.
|
||
|
||
## If you move an adapter to a different USB socket
|
||
The udev `KERNELS` value changes. Re-discover and update the rule:
|
||
```bash
|
||
udevadm info -a -n /dev/ttyUSB0 | grep -m1 'KERNELS=="[0-9]'
|
||
```
|
||
|
||
## Troubleshooting
|
||
- **`/dev/inspire_*` missing / no CH340 in `lsusb`** → the hand USB-RS485 adapters are
|
||
unplugged (or robot rebooted with them out). Re-plug them; udev recreates the names.
|
||
- **Fingers don't move (thumb might)** → usually a latched actuator fault from running
|
||
two `inspire_g1` at once. `inspire_g1` now runs `ClearError` + sets speed/force on
|
||
startup; `./manage.sh restart` re-applies it. If still stuck, power-cycle the hands (24 V).
|
||
- **Two `inspire_g1` instances** → they collide on the serial bus; `./manage.sh status`
|
||
flags it, `restart` fixes it. Kill with `pkill -x inspire_g1` (never `pkill -f`).
|
||
- **`rt/inspire/state` reads all-zeros** → cosmetic; CH340 adapters echo their TX so
|
||
position read-back is unreliable. Does not affect commands sent to the hand.
|