Compare commits

..

3 Commits

Author SHA1 Message Date
cyy_mac
ab7fcf480d docs: expand deployment logging guidance 2026-07-31 16:46:58 +08:00
cyy_mac
8c1dd4f82b docs: expand bpu quantization guide 2026-07-31 16:38:02 +08:00
cyy_mac
ca80135bc4 docs: polish deployment guide 2026-07-31 16:32:11 +08:00

View File

@@ -384,22 +384,27 @@ python -c "import onnxruntime as ort; s=ort.InferenceSession('policy_robotlab_26
预期输入为 450 个 `float32`,输出为 12 个动作。输入输出不匹配时不要继续 sim2sim 或量化。
### 8.4 训练仓库自带的 MuJoCo 快速检查
### 8.4 独立 MuJoCo 快速检查
训练仓库还提供了基于 TorchScript 的 Go1 MuJoCo 入口。它接收当前 45 维单帧观测,并在模型内部维护 10 帧历史,适合在进入完整 RoboGauge 评估前做一次快速检查
如果你要做的是“和部署链路一致”的快速检查,直接使用部署仓库里的 ONNX 入口。它读取当前 45 维单帧观测,并在脚本内部维护 10 帧历史,适合在进入完整 RoboGauge 评估前核对观测、动作缩放和地形 XML
```bash
mkdir -p deploy/pre_train/go1
cp <RUN_DIR>/exported/policy.pt deploy/pre_train/go1/policy.pt
cd /path/to/go1_pro_deploy
MUJOCO_GL=glfw mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
--onnx deploy_45dim_rl_gym/policy_robotlab_26000.onnx
```
确认 `deploy/deploy_mujoco/configs/go1.yaml` 中的 `policy_path``xml_path` 指向正确模型与场景,再运行
楼梯测试同样直接切 terrain
```bash
MUJOCO_GL=glfw python deploy/deploy_mujoco/deploy_go1.py
MUJOCO_GL=glfw mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
--onnx deploy_45dim_rl_gym/policy_robotlab_26000.onnx \
--terrain deploy_45dim_rl_gym/terrains/stairs/stairs_3.xml \
--spawn-x -0.6 \
--spawn-z 0.34
```
该入口默认检测游戏手柄,`LX/LY` 控制前后和侧向速度,`RX` 控制转向;未检测到手柄时使用 YAML 中的固定指令。它与后文带键盘、ONNX 和更多日志检查的独立部署脚本用途不同
脚本默认 `--clip-actions 100.0``--max-target-step 0.0`。如果你要做更保守的起步测试,可以再按日志逐步收紧这些参数;不要把旧版本的示例值当成固定默认
## 9. RoboGauge 自动评估
@@ -506,22 +511,18 @@ task_name="go1_lab"
cd /path/to/go1_pro_deploy
conda activate <DEPLOY_ENV>
mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
--onnx deploy_45dim_rl_gym/policy_robotlab_26000.onnx \
--clip-actions 4.0 \
--max-target-step 0.15
MUJOCO_GL=glfw mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
--onnx deploy_45dim_rl_gym/policy_robotlab_26000.onnx
```
楼梯测试:
```bash
mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
MUJOCO_GL=glfw mjpython deploy_45dim_rl_gym/deploy_go1_onnx_mujoco_lab.py \
--onnx deploy_45dim_rl_gym/policy_robotlab_26000.onnx \
--terrain deploy_45dim_rl_gym/terrains/stairs/stairs_3.xml \
--spawn-x -0.6 \
--spawn-z 0.34 \
--clip-actions 4.0 \
--max-target-step 0.15
--spawn-z 0.34
```
键盘映射:
@@ -557,9 +558,47 @@ BPU 量化不是把 ONNX 改一个后缀。至少需要:
当前量化脚本会保留 actions 输出、降级 opset、包装为 BPU 需要的 4D 输入,并把 MoE grouped Conv 等价替换为 Gemm以减少 CPU fallback。中间 norm 节点位于 actor 之前,不能随意删除或移到后处理。
量化脚本内部流程如下:
```text
真实日志 steps.jsonl
-> make_calibration_data.py 生成 float32 featuremap 校准样本
-> keep_actions_output.py 只保留 actions 输出
-> downgrade_policy_to_opset11.py 降级到工具链可接受的 opset
-> make_bpu_4d_onnx.py 把 [1, D] 输入包装成 [1, 1, 1, D]
-> replace_group_conv_with_gemm.py 把 MoE grouped Conv 替换为等价 Gemm
-> compare_4d_onnx.py 检查浮点图变换等价
-> hb_mapper / hb_compile 生成板端模型
```
脚本中的主要可调变量含义:
| 参数 | 含义 | 常用设置 |
| --- | --- | --- |
| `--policy` | 原始 ONNX 路径,必须在部署仓库内 | `../policy_robotlab_26000.onnx` |
| `--round` | 输出目录和校准目录里的轮次标签,不参与计算 | `26000``35k` |
| `--name` | 输出模型 basename不填时取 ONNX 文件名 | `policy_robotlab_26000` |
| `--history-len` | 历史帧数,用于重建输入维度 | RobotLab 为 `10`Gym 为 `5` |
| `--flat-dim` | 平铺输入维度;不填时为 `45 * history-len` | RobotLab 为 `450`Gym 为 `225` |
| `--samples` | 校准样本数量,越大越慢但覆盖更稳 | 默认 `64`,必要时 `128` |
| `--min-samples` | 最少有效样本数,不足则中止 | 默认 `32` |
| `--log-prefix` | 从 `logs/` 下筛选部署日志的目录前缀 | `robotlab_go1_deploy` |
| `--cal-tag` | 校准目录标签,区分 RobotLab/Gym | `robotlab``gym` |
| `--compare-limit` | 浮点 ONNX 等价对比样本数 | 默认 `64` |
| `--quant` | 量化策略 | 默认 `int16``int8` 仅作对照 |
| `--docker-image` | D-Robotics CPU 工具链镜像 | X5/S100 各自不同 |
量化建议在 Mac 或训练机的 Docker 中完成,不在 X5/S100 板端跑 Docker。板端只负责加载产物做离线测速、数值对齐和实机部署。
### 11.2 RDK X5
量化机执行
X5 使用 D-Robotics X5 CPU 工具链镜像
```bash
docker pull openexplorer/ai_toolchain_ubuntu_20_x5_cpu:v1.2.8
```
脚本默认会用 `docker run --rm --platform linux/amd64` 启动这个镜像,并把当前仓库挂载到 `/workspace/deploy_go1_pro`。量化机执行:
```bash
cd /path/to/go1_pro_deploy
@@ -573,9 +612,17 @@ bash deploy_45dim_rl_gym/bpu_quantization/quantize_policy_x5.sh \
--min-samples 32 \
--log-prefix robotlab_go1_deploy \
--cal-tag robotlab \
--docker-image openexplorer/ai_toolchain_ubuntu_20_x5_cpu:v1.2.8 \
--quant int16
```
X5 关键配置:
- `march` 固定为 `bayes-e`
- 输入类型为 `featuremap`,运行时输入 shape 是 `obs_4d [1, 1, 1, 450]`
- int16 时脚本在 YAML 中写入 `optimization: "set_all_nodes_int16"`
- `hb_mapper checker` 默认会先运行;明确知道模型已检查过时才使用 `--skip-checker`
预期产物:
```text
@@ -583,6 +630,18 @@ deploy_45dim_rl_gym/bpu_quantization/mapper_output_26000_gemm/
policy_robotlab_26000_int16_gemm.bin
```
如果要量化旧 Gym 5 帧模型,必须同步修改历史长度、日志前缀和标签:
```bash
bash deploy_45dim_rl_gym/bpu_quantization/quantize_policy_x5.sh \
--policy ../policy_35k.onnx \
--round 35k \
--history-len 5 \
--log-prefix rlgym_go1_deploy \
--cal-tag gym \
--quant int16
```
板端先做完全离线自检,不连接电机控制:
```bash
@@ -598,6 +657,14 @@ X5 的 featuremap 模型不要直接改用 `hobot_dnn.pyeasy_dnn.forward()`。
### 11.3 S100
S100 使用新版 S100/S600 CPU 工具链镜像:
```bash
docker pull registry.d-robotics.cc/deliver/ai_toolchain_ubuntu_22_s100_s600_cpu:v3.7.0
```
脚本同样在量化机 Docker 中运行,不在 S100 板端运行 Docker
```bash
cd /path/to/go1_pro_deploy
@@ -610,10 +677,18 @@ bash deploy_45dim_rl_gym/bpu_quantization/quantize_policy_s100.sh \
--min-samples 32 \
--log-prefix robotlab_go1_deploy \
--cal-tag robotlab \
--docker-image registry.d-robotics.cc/deliver/ai_toolchain_ubuntu_22_s100_s600_cpu:v3.7.0 \
--march nash-e \
--quant int16
```
S100 关键配置:
- `--march nash-e` 对应当前 S100 平台;不要沿用 X5 的 `bayes-e`
- 输出是 `.hbm`,不是 X5 的 `.bin`
- int16 时脚本在 YAML 中写入 `quant_config.model_config.all_node_type: int16`
- `compiler_parameters.core_num` 当前为 `1`,优先保证单次策略推理低延迟;需要多核吞吐测试时应另做离线 benchmark不要直接改实机脚本。
预期产物:
```text
@@ -621,6 +696,13 @@ deploy_45dim_rl_gym/bpu_quantization/mapper_output_26000_s100_gemm/
policy_robotlab_26000_s100_int16_gemm.hbm
```
产物同步到 S100 后,先看模型信息再测速:
```bash
/usr/hobot/bin/hrt_model_exec model_info \
--model_file deploy_45dim_rl_gym/bpu_quantization/mapper_output_26000_s100_gemm/policy_robotlab_26000_s100_int16_gemm.hbm
```
板端测速:
```bash
@@ -775,6 +857,8 @@ pgrep -fl 'keep_sport_alive|Legged_sport|appTransit'
运行 ONNX/BPU 推理并记录 action仍不发送电机命令。检查 action 无 NaN/Inf、无持续饱和、静止状态不发散ONNX 和 BPU 的动作差在离线验收范围内。
从这一级开始,命令必须显式保留 `--log-dir logs`;只要要判断板端实时性,就同时加 `--log-timing`。日志目录会在启动时自动创建,终端退出时会打印 `Log saved:` 路径。
X5 示例:
```bash
@@ -784,7 +868,8 @@ python3 deploy_45dim_rl_gym/bpu_deploy_x5/deploy_go1_robotlab_bpu_x5_fastcpp.py
--infer-check \
--log-dir logs \
--print-every 50 \
--max-steps 500
--max-steps 500 \
--log-timing
```
S100 示例:
@@ -796,7 +881,8 @@ python3 deploy_45dim_rl_gym/bpu_deploy_s100/deploy_go1_robotlab_bpu_s100_fastcpp
--infer-check \
--log-dir logs \
--print-every 50 \
--max-steps 500
--max-steps 500 \
--log-timing
```
### 14.5 第 4 级:悬空状态机,不启用 RL
@@ -832,6 +918,8 @@ IDLE -> CALIBRATE -> HOLD -> OBS_TEST -> INFER_TEST
先用已经通过地面测试的 ONNX 版本确定基线,再在相同软件保护、相同指令、相同场地上测试 BPU。两次测试只替换推理后端。若 BPU 行为异常,回到离线输入逐帧对比,不能通过放宽关节或姿态保护继续测试。
对照日志至少要能证明三件事:同一段动作里 `commands` 接近一致,`action_raw/action_safe/joint_targets` 的差异在离线验收范围内,`policy_ms/loop_dt_ms/state_age_ms` 没有让 BPU 版本比 ONNX 版本产生额外控制延迟。若 BPU 端 `policy_ms` 很低但 `loop_dt_ms` 仍不稳,应继续查 SDK 收包、构包和系统调度,而不是只看 BPU 占用率。
### 14.10 第 9 级:坡面、台阶和扰动
复杂地形是最后阶段。先从低难度、低速度和正向通过开始,再逐步测试侧向、反向、急停和摩擦变化。每次增加难度前必须确认前一级多次可复现。
@@ -845,20 +933,54 @@ metadata.json
steps.jsonl
```
元数据应包含 Git commit、模型哈希、推理后端、控制周期、PD 参数、动作限制、保护阈值、设备型号、测试人员和场景。逐步日志至少包含
部署脚本默认在 `--log-dir` 下创建带时间戳的目录,例如
```text
timestamp / state / state_reason
commands_raw / commands
obs_single / obs_history
logs/robotlab_go1_deploy_YYYYMMDD_HHMMSS/
```
不要关闭日志来“省性能”。实机调试阶段宁可降低打印频率,也要保留 JSONL 日志后续量化校准、ONNX/BPU 对齐、力矩保护分析和动作异常定位都依赖这些记录。
`metadata.json` 用来复现实验条件。当前部署脚本会自动写入:
```text
created_at
num_obs / history_len / onnx_input_dim
action_scale / default_dof_pos
joint_names_sdk / joint_names_policy / joint_order_policy
lowcmd_backend 或 BPU backend
history_expected_span_ms
命令行传入的所有标量参数
```
发布或多人复现实验时,还应额外记录 Git commit、模型哈希、板端系统版本、BPU runtime 版本、设备型号、测试人员和场景。只给一条 `Log saved:` 路径而没有对应模型与参数后续无法判断问题来自策略、量化、SDK 还是现场操作。
`steps.jsonl` 是逐周期日志。当前脚本每条记录至少包含:
```text
step / time_wall / mode / state_reason
commands_raw / commands / rc_lx / rc_ly / rc_rx / rc_ry / rc_buttons
obs_single / history_fill / history_zero_pad
action_raw / action_safe
joint_targets
dof_pos / dof_vel / tau_est
base_ang_vel / projected_gravity / imu_rpy
inference_ms / loop_ms
battery / temperature / communication_status
dof_pos / dof_vel / tau_est / motor_mode / motor_temperature / motor_reserve
imu_rpy_deg / imu_quat / base_ang_vel / projected_gravity
battery_soc
loop_dt_ms / recv_ms / policy_ms / work_ms / state_fresh / state_age_ms
```
这些字段的用途:
- `mode``state_reason`:判断处于 `MONITOR``OBS_CHECK``INFER_CHECK``RAMP``RL` 还是故障/阻尼路径;保护触发时首先看这里。
- `commands_raw``commands`区分遥控器原始输入、deadzone/比例/交换后的策略输入,避免把遥控映射问题误判成模型问题。
- `obs_single``history_fill``history_zero_pad`:检查 45 维观测和历史缓存是否正确预热;刚进 RL 时历史未填满属于高风险段。
- `action_raw``action_safe`:区分模型原始输出与 clip、smooth、trip 检查后的实际动作;若二者差异大,说明部署端限制正在影响行为。
- `joint_targets``dof_pos``dof_vel``tau_est`:分析目标角、实际角、速度和力矩保护之间的因果关系。
- `motor_mode``motor_reserve``motor_temperature`:定位电机是否掉出 servo、是否有错误码或过热。
- `loop_dt_ms``recv_ms``policy_ms``work_ms``state_age_ms`:判断慢在推理、收包、构包发送还是系统调度。
分析日志时不要只看最后一帧。应从 `state_reason` 第一次不为 `ok``action_safe` 第一次明显被 clip、`motor_mode` 第一次异常、`tau_est` 第一次接近阈值、`loop_dt_ms` 第一次超过 20 ms 的位置向前回看至少 1 到 2 秒。
一次测试通过的最低条件:
- 无 NaN/Inf、状态超时和控制周期持续超期。