Robotics
LeRobot
Safetensors
pi05
bimanual
arx
spikefly's picture
Add files using upload-large-folder tool
4c4a210 verified
|
Raw History Blame Contribute Delete
5.9 kB
# π0.5 · ARX Lift2S「stack three cups」部署契约(一页)
> 训练:LeRobot π0.5,上游 [huggingface/lerobot](https://github.com/huggingface/lerobot) 提交 `89236ea0f4f81a81ca566081e20dd1ff5f823cbe`(训练时另有两个只管存档的本地开关,与推理无关);底座 [`lerobot/pi05_base`](https://huggingface.co/lerobot/pi05_base);数据 [`yaoxianze/arx_external_cam_cups`](https://huggingface.co/datasets/yaoxianze/arx_external_cam_cups)(版本 `2d87a09`)转 LeRobot v3.0(转换与分位数统计脚本见 `tools/`);全局批 32、3 万步(前 2 万步就是 1 万 / 2 万步档那次训练,学习率按 2 万步余弦衰减到 2.5e-6;之后从第 2 万步的完整训练状态(优化器、调度器、随机数、步数)接着训 1 万步,调度器的衰减终点改为 3 万步,所以续训开始时学习率回到约 8.1e-6,再余弦衰减到 2.5e-6);绝对关节;分位数归一化。
> 仓根 = 训练落盘的 `pretrained_model/`,`PI05Policy.from_pretrained(<仓名或本地目录>)` 直接可用。前后处理器(`policy_preprocessor*`、`policy_postprocessor*`)已经含相机改名和分位数归一化 / 反归一化参数,**客户端不要自己归一化**。
> **推理代码**:上游 lerobot 提交 `89236ea` 即可(clone 后 `git checkout 89236ea && pip install -e ".[pi,dataset]"`;`[dataset]` 是复现检查和数据转换要用的 PyAV、jsonlines 等)。
## 输入(每次推理一帧)
| 键 | 内容 | 形状 / 类型 | 注意 |
|---|---|---|---|
| `observation.images.camera_h` | 头部相机 | 640×480,**RGB** | 和采集同一台相机、同样设置 |
| `observation.images.camera_l` | 左腕相机 | 640×480,**RGB** | |
| `observation.images.camera_r` | 右腕相机 | 640×480,**RGB** | |
| `observation.state` | 当前关节读数 | float32 (14,) | 顺序 [左 j0…j5, 左夹爪, 右 j0…j5, 右夹爪];关节为弧度,夹爪为原始读数(全开约 −3.34 / −3.39(左 / 右)、抓住杯子时约 −2.0,都是数据实测;按数据集约定 0 为全闭,请以你们机器人的实际读数为准) |
| `task` | 提示词 | 字符串 | **逐字** `stack three cups` |
- 图像转换:`torch.from_numpy(rgb_uint8_HxWx3).permute(2,0,1).float() / 255`,**不要自己缩放**(预处理器内部 resize-pad 到 224)。
- **颜色**:OpenCV 取图是 BGR,必须先转 RGB。`deploy/fit_check_pi05.py` 里的客户端路径测试会抓这个错。
- 外部相机(camera_external)不参与训练和推理。
## 输出
- 一块 50 步 × 14 维**绝对关节目标**,顺序与 state 相同 [左 6, 左夹爪, 右 6, 右夹爪],单位同 state(已反归一化)。
- 数据里 action ≡ 当前状态 → 第 0 步 ≈「现在在哪」,**部署从第 1 步开始执行**。
## 执行
- 控制频率 20 Hz(和采集一致)。
- 同步重规划:推理 → 执行第 1…25 步 → 再推理(执行步数可调,默认 25)。
- 块起点渐入:**默认开**,前 5 步(k 可调)从实测关节线性过渡到预测轨迹,缓解每次重推的起点跳变;开 / 关效果在真机上对比。
- 夹爪:直接下发模型输出值,不做特殊处理。
- 推理显存约 9 GB(bf16),RTX 5090 够用。
## 上真机前
0. **先做回放测试(与模型无关,任何策略之前)**:`python deploy/replay_demo.py export --dataset-root <数据目录> --episode 0 --out replay_ep000_commands.csv`(数据目录 = 按 README 第 3 节用 `tools/prep_pi05_data.sh` 转换出来的目录;本仓不含数据),按第 0 局的布局摆好杯子,机械臂**慢速**移到第 0 行,再按 20 Hz 逐行下发,记录实测关节(`RolloutLogger.state` 或 CSV)和视频;然后 `python deploy/replay_demo.py analyze --commands … --measured …`。它回答三件事:「拿实测位置当指令」能否复现示教;夹爪停在约 −2.0 时夹不夹得住杯子(看视频);控制器跟踪滞后几帧(作为真机执行段跟踪的基线)。回放都做不成,先查硬件 / 指令语义。
1. 在部署机上跑 `deploy/fit_check_pi05.py`(命令见 `deploy/TOLERANCE.md`;`--dataset-root` 用你自己转换出来的目录,`--compare-to deploy/expected/action_fit_summary_bf16.json`),对照 `deploy/TOLERANCE.md`(脚本读 `deploy/tolerance.json`,末尾打印 `TOLERANCE_CHECK PASS/FAIL`):期望块最大差(全部 14 维和只看关节两项)、聚合拟合误差相对差都要在容差内;`client_path_test.pass` 必须为 true(判据:每帧图像差 ≤ 1/255;两条路径的块差只作提示,部分显卡上两次前向不逐位相同)。
2. **必须用你自己机器人端的「相机取图 → 张量」代码跑一遍客户端路径测试**:`--client-fn 你的模块:函数 --client-frame-format bgr|rgb`(函数收相机原样交出的 uint8 HxWx3 帧,返回进模型的 float (3,H,W) [0,1];客户端 / 服务端分开的话把两段拼起来)。模板见 `deploy/example_client_fn.py`。BGR、缩放、裁剪这类错只有这样才抓得到。
3. 第一次上机先悬空或低速,只打印一块 50 步动作,核对关节范围、顺序、夹爪方向都对了再正式执行;确认急停可用。
## 真机上查训推不一致(上真机后)
- 客户端用 `deploy/rollout_consistency.py` 里的 `RolloutLogger` 记每次推理(当前关节状态 + 预测块 + 执行区间)和每个控制步的实测关节,一局一个 jsonl。
- 跑完执行 `python deploy/rollout_consistency.py run_*.jsonl --reference deploy/expected/action_fit_summary_bf16.json`,得到和离线同口径的两个数:
- **块起点偏移** |â0 − s_t|(模型估计「手臂现在在哪」与实测关节之差,不需要标注):离线基准见 `deploy/TOLERANCE.md`;真机上超过离线 3 倍会给出排错提示(只是提示、不是关卡),先查相机机位 / 曝光、光照、取图转换、相机顺序;
- **执行段跟踪** |â_k − s_{t+k}|:含控制器跟踪滞后,离线没有这部分,应当和回放测试测出的跟踪误差比,而不是和离线拟合误差比。