2026-08-04 16:09:17 +04:00

2.6 KiB

Dockerized Inspire hand service + dashboard

One self-contained image (aarch64) running inspire_g1 + hand_bridge + the Flask dashboard. Build ON the robot (it pulls unitree_sdk2 + CycloneDDS from the host).

Build (once, on the robot)

cd ~/DFX_inspire_service
./docker/build_image.sh          # assembles context + docker build -> inspire-hand:latest

Run

./docker/run.sh                  # or: docker compose -f docker/docker-compose.yml up -d
# dashboard -> http://<robot-ip>:8088
./docker/stop.sh

run.sh first stops any host-native inspire_g1/hand_bridge — running both the container and the host service would put two writers on the RS-485 bus and corrupt the hands.

Why these flags

  • --network host — CycloneDDS (rt/inspire/cmd) and the arm actions (rt/arm_sdk, reaching the G1 motion controller on eth0) need the host network.
  • --privileged -v /dev:/dev — the CH340 ttyUSB* adapters re-enumerate on the hub; mounting /dev + privileged lets the in-container dynamic detection find them.
  • IFACE=eth0 — interface for arm actions (must be eth0). Fingers work on either.

Record / replay in the image

The dashboard's Record/Replay card runs g1_record_replay.py as a child process, so the image needs the script and a python that can import unitree_sdk2py. build_image.sh pulls both into the context:

RECORDER_SRC=~/Manual_Recorder \
UNITREE_SDK2PY_DIR=~/unitree_sdk2_python \
  ./docker/build_image.sh

Neither is required — leave them out and the image still builds, with the panel reporting "recorder not found". start.sh prints which case you got.

  • That layer pip-installs (cyclonedds, unitree_sdk2py), so the robot needs network at BUILD time. Offline alternative: copy the robot's own python site-packages into the image the same way build_image.sh copies the C libs.
  • Takes are a host volumerun.sh mounts $HAND_DATA_DIR/DataG1 to /opt/recorder/DataG1, because run.sh starts with docker rm -f and would otherwise destroy every recording ever made.
  • arm_home.jsonl is seeded on first start, not baked into DataG1/ — the bind-mount would hide a baked copy, and without it every take skips its return-to-home. It is hidden from the takes list and cannot be deleted from the panel: it is a home pose, not a take.

Notes

  • Sudo/udev not needed inside the container (privileged).
  • Saved poses/combos persist via -v $HAND_DATA_DIR:/opt/hand/data + HAND_DATA (set by run.sh). They used to live in the image and were wiped by every rebuild.