siyuhsu commited on
Commit
59010e5
·
verified ·
1 Parent(s): c43de42

Model card: cover both robots (G2 + Piper)

Browse files
Files changed (1) hide show
  1. README.md +80 -78
README.md CHANGED
@@ -6,108 +6,110 @@ tags:
6
  - openpi
7
  - pi0
8
  - lerobot
9
- - bimanual
10
  - manipulation
 
11
  library_name: openpi
12
  pipeline_tag: robotics
13
  ---
14
 
15
- # G2 Dual-Arm — π₀ policy + LeRobot dataset
16
 
17
- A π₀ (pi0) vision-language-action policy trained on an **AgiBot G2** dual-arm robot, together
18
- with the dataset it was trained on. The policy runs closed-loop on the real robot from live
19
- camera observations and completes the task.
20
 
21
- **Task:** `Make a yogurt bowl with cereal and fruit.`
 
 
 
 
22
 
23
- | | |
24
- |---|---|
25
- | Robot | AgiBot G2, dual 7-DOF arms + 2 grippers |
26
- | Action / state | 16-D `[L_j1..j7, L_grip, R_j1..j7, R_grip]`, **absolute joint radians** + boolean gripper |
27
- | Cameras | `head` (400×640), `hand_left` / `hand_right` (528×640), RGB |
28
- | Control rate | **10 Hz** (dataset fps); robot servo runs at 30 Hz |
29
- | Action chunk | 50 |
 
 
30
 
31
- ## Contents
32
 
33
- ```
34
- params/ π₀ weights (12 GB, JAX/orbax)
35
- assets/ norm stats bundled with the checkpoint
36
- _CHECKPOINT_METADATA
37
- dataset/g2_dualarm_yogurt_rs10/ LeRobot v2.1 — 58 episodes / 48,332 frames / 10 Hz
38
  ```
39
 
40
- ## Training
41
 
42
- | | |
43
- |---|---|
44
- | Config | `pi0_g2_dualarm` (openpi) |
45
- | Steps | 30,000, batch 32, 1× H200 |
46
- | Wall time | 17 h 06 m |
47
- | Final loss | 0.0047 (from 0.3207) |
48
-
49
- Actions are converted to deltas at train time via `make_bool_mask(7, -1, 7, -1)` — 7 joint
50
- dims as deltas, gripper kept absolute, per arm.
51
 
52
- ## Dataset notes (read before training on it)
 
53
 
54
- * **`_rs10` = resampled to a uniform 10 Hz grid.** The raw recordings are badly jittered
55
- (only 13.6% of inter-frame gaps fall within ±20% of the median) because the on-robot
56
- *disk writer* not the cameras or the control loop is the bottleneck: the control loop
57
- runs at a rock-steady 29.5–29.9 Hz and the cameras at ~30 Hz, but 60–65% of frames are
58
- dropped before they reach disk. Naive contiguous re-indexing distorts episode duration by
59
- −18%…+35%; the resampled variant is accurate to +0.06%.
60
- * **The right gripper's position sensor is dead** (constant 0.2173 across all 60 episodes),
61
- so both gripper dims come from the *command* boolean, not from a sensor.
62
- * **Gripper polarity in this dataset: `1.0` = OPEN, `0.0` = CLOSED.** The underlying raw
63
- field is named `gripper_closed`, and **the name is backwards relative to the physical
64
- behaviour**. Verified from the physical semantics: in episode 27 the right gripper dim
65
- flips `1.0 → 0.0` at step 54, exactly as the right arm reaches its deepest point — the
66
- grasp. If you drive real hardware, confirm your wire convention separately; on this robot
67
- the DDS tool wire is the opposite (`1.0` = CLOSED), so the mapping is an inversion.
68
- * 2 of 60 recorded episodes are excluded (camera dropouts mid-episode, broken on the robot).
69
 
70
- ## Evaluation
71
 
72
- Offline replay against a live server, 120 frames over 12 episodes:
73
 
74
  | metric | value | threshold |
75
  |---|---|---|
76
  | joint MAE | **0.28°** (worst 0.95°) | < 5° |
77
  | gripper agreement | **99.8%** | > 90% |
78
  | delta direction cosine | **0.999** | > 0.8 |
79
- | first-step jump | 1.47° (worst 5.43°) | worst < 15° |
80
-
81
- On real hardware the policy was validated in four stages — dry-run → ground-truth replay →
82
- policy-replay on dataset observations → live closed loop — and completes the task in the
83
- last stage.
84
-
85
- ## Using the weights
86
-
87
- ```bash
88
- # serve (openpi)
89
- python examples/g2_dualarm/g2_serve_openpi.py \
90
- --config pi0_g2_dualarm --ckpt-dir <this repo>/ --port 8000
91
- ```
92
-
93
- The server publishes the deployment contract in its connect-time metadata:
94
- `action_chunk_size=50`, `action_rate_hz=10.0`, `robot_servo_hz=30.0`,
95
- `action_space="absolute_joint_rad_plus_gripper_cmd"`, plus a `reset_pose`.
96
-
97
- > ⚠️ **Advance the chunk at 10 Hz, not at the servo rate.** Actions are absolute joint
98
- > targets; stepping them at 30 Hz executes the trajectory 3× too fast.
99
-
100
- ## Caveats
101
 
102
- * Single task, single scene, 58 demonstrations. Expect it to be brittle outside the
103
- recorded prop layout.
104
- * The policy is stochastic (flow matching): identical input gives joint outputs differing
105
- by ~1.2°. Do not use repeated inference as a determinism check.
106
- * **Do not JPEG-compress observations to save bandwidth.** Measured on this checkpoint,
107
- JPEG q92/q85 flips the *gripper decision* outright (|Δ| = 1.007 on a boolean dim, 3 of 6
108
- trials) while joint dims move only ~2°. The mean error hides this completely.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  ## Code
111
 
112
- Evaluation stack, real-robot client and the staged validation tooling:
113
- `examples/g2_dualarm/` in the accompanying openpi fork.
 
6
  - openpi
7
  - pi0
8
  - lerobot
 
9
  - manipulation
10
+ - bimanual
11
  library_name: openpi
12
  pipeline_tag: robotics
13
  ---
14
 
15
+ # openpi_labreal-robot π₀ checkpoints + the datasets they were trained on
16
 
17
+ Two robots, each with its trained π₀ weights and the exact LeRobot dataset behind them.
18
+ Everything here has been run on real hardware, not only in replay.
 
19
 
20
+ ```
21
+ g2/model/ π₀, 30k steps g2/dataset/ 58 ep / 48,332 frames / 10 Hz
22
+ piper/model/pi0/ π₀, 30k steps piper/dataset/ 125 ep / 71,702 frames / 30 Hz
23
+ piper/model/pi05/ π₀.₅, 30k steps
24
+ ```
25
 
26
+ | | **G2** | **Piper** |
27
+ |---|---|---|
28
+ | Robot | AgiBot G2, **dual** 7-DOF arm | AgileX Piper, **single** 6-DOF arm |
29
+ | Action / state | 16-D `[L_j1..7, L_grip, R_j1..7, R_grip]` | 7-D `[j1..j6, gripper]` |
30
+ | Action space | absolute joint rad + boolean gripper | joint **delta** from episode start + absolute gripper (m) |
31
+ | Cameras | head + hand_left + hand_right | head + hand |
32
+ | Control rate | **10 Hz** | **30 Hz** |
33
+ | Chunk | 50 | 16 |
34
+ | Tasks | 1 (`Make a yogurt bowl with cereal and fruit.`) | 4 (pen→cup, carrot→bowl, blocks→drawer, stack bowls) |
35
 
36
+ ## Download
37
 
38
+ ```bash
39
+ hf download siyuhsu/openpi_lab --include "g2/model/*" --local-dir ./g2_ckpt
40
+ hf download siyuhsu/openpi_lab --include "piper/model/pi0/*" --local-dir ./piper_pi0
41
+ hf download siyuhsu/openpi_lab --include "g2/dataset/*" --local-dir ./g2_data
 
42
  ```
43
 
44
+ ## Serving
45
 
46
+ ```bash
47
+ # G2
48
+ python examples/g2_dualarm/g2_serve_openpi.py --config pi0_g2_dualarm \
49
+ --ckpt-dir ./g2_ckpt/g2/model --port 8000
50
+ # Piper
51
+ python examples/piper/code/piper_serve_openpi.py --config pi0_piper_4task \
52
+ --ckpt-dir ./piper_pi0/piper/model/pi0 --port 8000
53
+ ```
 
54
 
55
+ Each server publishes its deployment contract in the connect-time metadata
56
+ (`action_chunk_size`, `action_rate_hz`, `robot_servo_hz`, `action_space`, `reset_pose`).
57
 
58
+ > ⚠️ **Advance the action chunk at the DATASET rate, not the servo rate.** G2 is 10 Hz,
59
+ > Piper is 30 Hz. Actions are absolute (G2) or delta-from-start (Piper) joint targets;
60
+ > stepping G2's chunk at 30 Hz would execute it too fast.
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ ## Results
63
 
64
+ **G2** — offline replay against a live server, 120 frames / 12 episodes:
65
 
66
  | metric | value | threshold |
67
  |---|---|---|
68
  | joint MAE | **0.28°** (worst 0.95°) | < 5° |
69
  | gripper agreement | **99.8%** | > 90% |
70
  | delta direction cosine | **0.999** | > 0.8 |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
+ Validated on hardware in four stages dry-run ground-truth replay policy-replay on
73
+ dataset observations → live closed loop — and completes the task in the last stage.
74
+
75
+ **Piper** — replay eval, all 4 tasks GO: pi0 joint MAE 0.74° / cos 0.940; pi0.5 0.44° / cos 0.995.
76
+ Real-robot success rates over 160 rollouts (10 per model × task × condition):
77
+
78
+ | model | in-dist | OOD-L1 | overall |
79
+ |---|---|---|---|
80
+ | baseline QwenOFT | 55% | 30% | 42.5% |
81
+ | ctxdemo QwenLAP | 80% | 75% | 77.5% |
82
+ | **π₀** | **85%** | **80%** | **82.5%** |
83
+ | π₀.₅ | 80% | 60% | 70% |
84
+
85
+ ## Things that will bite you
86
+
87
+ * **G2 gripper polarity is inverted between dataset and wire.** In the dataset `1.0` = OPEN,
88
+ `0.0` = CLOSED — the raw field is called `gripper_closed` and **the name is backwards**
89
+ relative to the physical behaviour. Verified from physical semantics: in episode 27 the
90
+ right gripper dim flips `1.0 → 0.0` at step 54, exactly as the arm reaches its deepest
91
+ point (the grasp). On that robot's DDS tool wire the convention is the opposite again.
92
+ Confirm your own wire convention before driving hardware.
93
+ * **G2's right gripper position sensor is dead** (constant 0.2173 in all 60 episodes), so
94
+ both gripper dims come from the *command* boolean, not a sensor.
95
+ * **G2 `_rs10` = resampled to a uniform 10 Hz grid.** Raw recordings are badly jittered —
96
+ but the cause is the on-robot **disk writer**, not the cameras or the control loop
97
+ (control runs at a steady 29.5–29.9 Hz; 60–65% of frames never reach disk). Naive
98
+ contiguous re-indexing distorts episode duration by −18%…+35%; resampling is +0.06%.
99
+ * **Do not JPEG-compress observations to save bandwidth.** Measured on the G2 checkpoint,
100
+ q92/q85 flips the *gripper decision* outright (|Δ| = 1.007 on a boolean dim, 3 of 6
101
+ trials) while joint dims move only ~2°. Mean error hides this completely.
102
+ * **These policies are stochastic** (flow matching): identical input gives joint outputs
103
+ differing by ~1.2°. Repeated inference is not a determinism check.
104
+ * Piper's `action` is the recorded teleop target and **leads the state by ~3 frames**;
105
+ G2's satisfies `action[t] == state[t+1]` exactly. Do not assume one convention for both.
106
+
107
+ ## Scope
108
+
109
+ Single scene per task, 58 (G2) / 125 (Piper) demonstrations. Expect brittleness outside the
110
+ recorded prop layout.
111
 
112
  ## Code
113
 
114
+ `examples/g2_dualarm/` and `examples/piper/` in the accompanying openpi fork, including the
115
+ real-robot clients, the staged validation tooling and the hardware-verification scripts.