RDK X5 BPU 部署测试
这个目录是 RobotLab BPU .bin 的隔离部署路径,不覆盖现有 ONNX/fastcpp
部署脚本。
当前包含:
bpu_policy.py:BPU policy wrapper,默认使用cpp_dnn_api_x5C++ DNN API 后端。cpp/:C++ DNN API 推理库源码、板端编译脚本和纯 C++ benchmark。deploy_go1_robotlab_bpu_x5_fastcpp.py:基于现有lab_fastcpp状态机的 BPU 版本。
重要限制
不要用 hobot_dnn.pyeasy_dnn 直接跑这个模型。这个 BPU 模型的输入是
featuremap,板端实测 pyeasy_dnn.forward() 会产生明显错误的 action,
和 hrt_model_exec infer 不一致。
当前默认不再使用 bpu_infer_lib 做实机推理,而是用 C++ 直接调用 DNN API。
部署脚本使用的 C++ 调用顺序是:
hbDNNInitializeFromFiles -> hbDNNGetModelHandle -> hbDNNInfer -> hbDNNWaitTaskDone -> hbDNNReleaseTask
这个路径已经用 00000.bin 验证,输出和 hrt_model_exec infer 对齐。
bpu_infer_lib.forward(False) 在当前板端会从 C runtime 向 stdout 每帧打印
duplicate model infer is not supported in one batch / invalid model。
虽然输出和 hrt_model_exec infer 一致,但这说明 task 提交方式不干净。旧 Python
fallback 保留为 BpuInferLibPythonPolicy,只用于对照,不作为默认部署路径。
这个判断参考 D-Robotics RDK X5 runtime sample:
03_misc/run_resnet50_feature.sh是官方 featuremap 输入模型示例,流程是 prepare feature tensor -> infer success -> task done。- 性能测量示例在循环中每帧执行
hbDNNInfer后,立刻hbDNNWaitTaskDone(task_handle, 0),再hbDNNReleaseTask(task_handle)并把 task handle 置空。
bpu_infer_lib 的 Python API 没有直接暴露 hbDNNReleaseTask,所以这里改成
C++ shared library,并由 Python 通过 ctypes 调用。
板端编译:
cd /root/go1_pro_deploy/deploy_45dim_rl_gym/bpu_deploy_x5/cpp
bash build_board.sh
模型路径
默认模型:
deploy_45dim_rl_gym/bpu_quantization/mapper_output_6500_gemm/policy_robotlab_6500_int16_gemm.bin
输入输出:
- 输入:
obs_4d [1, 1, 1, 450],float32 featuremap - 输出:
actions [1, 12, 1, 1],float32,脚本会 flatten 成 12 维 action
板端准备
同步仓库和模型后,在板端确认:
cd /root/go1_pro_deploy
ls deploy_45dim_rl_gym/bpu_quantization/mapper_output_6500_gemm/policy_robotlab_6500_int16_gemm.bin
ls deploy_45dim_rl_gym/bpu_quantization/calibration_data/00000.bin
ls deploy_45dim_rl_gym/bpu_deploy_x5/cpp/libbpu_dnn_policy.so
如果 mapper_output_6500_gemm/ 没有同步到 git,需要手动把 .bin 放到对应路径,
或用 --bpu-model 指定绝对路径。
纯离线 BPU 自检
先不连接机器人,确认 C++ BPU 后端输出和 hrt_model_exec infer 的参考值一致:
cd /root/go1_pro_deploy
PYTHONPATH=/root/go1_pro_deploy \
python3 deploy_45dim_rl_gym/bpu_deploy_x5/test_bpu_policy.py \
--check-reference-00000 \
--repeat 1000
通过时应看到:
reference_max_abs_diff 0.0
当前板端 root@192.168.150.167 已验证:
reference_max_abs_diff 4.76837158203125e-07
reference_mean_abs_diff 3.071812386679085e-07
repeat=1000 avg_ms=1.019592 # Python ctypes -> C++ DNN API
duplicate_errors=0
纯 C++ benchmark:
cd /root/go1_pro_deploy/deploy_45dim_rl_gym/bpu_deploy_x5/cpp
./bpu_dnn_bench
当前板端结果:
reference_max_abs_diff 0
repeat=1000 cpp_avg_ms=0.711932
duplicate_errors=0
离线推理检查
先不要接电机控制,只运行 BPU inference:
cd /root/go1_pro_deploy
PYTHONPATH=/root/go1_pro_sdk:/root/go1_pro_deploy \
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
这一步仍会连接 MCU 读取状态,但不会发送电机指令。
悬空状态机测试
只有 --infer-check 日志确认 action 正常后,再悬空测试状态机。先不加
--enable-rl,R2 只能走到 INFER_TEST,不会进入 RL 控制:
cd /root/go1_pro_deploy
PYTHONPATH=/root/go1_pro_sdk:/root/go1_pro_deploy \
python3 deploy_45dim_rl_gym/bpu_deploy_x5/deploy_go1_robotlab_bpu_x5_fastcpp.py \
--kill-sport \
--log-dir logs \
--kp 28 --kd 0.7 \
--kp-cal 20 --kd-cal 1.0 \
--power-factor 7 \
--position-protect-limit 0.0 \
--action-clip 5.0 \
--action-trip-limit 8.0 \
--action-hard-trip-limit 16.0 \
--max-target-step 0.025 \
--max-roll-deg 35 \
--max-pitch-deg 35 \
--swap-vy-yaw \
--rc-vx-scale 0.5 \
--rc-vy-scale 0.5 \
--rc-wz-scale 1.0
确认 OBS_TEST 和 INFER_TEST 正常后,才允许加 --enable-rl 做悬空 RL:
cd /root/go1_pro_deploy
PYTHONPATH=/root/go1_pro_sdk:/root/go1_pro_deploy \
python3 deploy_45dim_rl_gym/bpu_deploy_x5/deploy_go1_robotlab_bpu_x5_fastcpp.py \
--kill-sport \
--enable-rl \
--log-dir logs \
--kp 28 --kd 0.7 \
--kp-cal 20 --kd-cal 1.0 \
--power-factor 7 \
--position-protect-limit 0.0 \
--action-clip 5.0 \
--action-trip-limit 8.0 \
--action-hard-trip-limit 16.0 \
--max-target-step 0.025 \
--max-roll-deg 35 \
--max-pitch-deg 35 \
--swap-vy-yaw \
--rc-vx-scale 0.5 \
--rc-vy-scale 0.5 \
--rc-wz-scale 1.0
地面测试不要直接从 BPU 版本开始;先用同参数 ONNX 版本确认行为,再做 BPU/ONNX 对照。