跳到主要内容

真机推理训练

本文档介绍 Spacemit K3 上基于 LeRobot 开源 SO101 机械臂真机数采、训练、推理与自然语言控制流程。内容整合 ACT/SmolVLA 模型从数据采集、训练到部署推理的完整链路,并给出将抓取能力封装为平台工具后,通过 Hermes 自然语言触发机械臂抓取任务的方法。

1. 方案概述

本方案面向 LeRobot 开源 SO101 机械臂真机抓取场景,支持以下功能:

  • 校准和数采:SO101 机械臂校准、遥控操作和数据采集;
  • ACT 模型训练和部署:ACT 模型在 GPU 服务器训练,并部署到 Spacemit K3 开发板本地推理;
  • SmolVLA 模型微调和分布式推理:SmolVLA 模型在服务器微调,并介绍分布式推理方式控制开发板端机械臂;
  • MCP 工具封装:将 LeRobot 抓取流程封装为 C++ 原生应用,通过 mlink device → mlink gateway → MCP 链路注册为 MCP 工具;
  • Hermes 自然语言控制:将 MCP 绑定到 Hermes,并使用 Hermes 以自然语言方式调用 lerobot.pick_cube 工具,触发 SO101 机械臂执行抓取任务。

2. 硬件清单

项目内容
训练平台一台配置 RTX 系列及以上 GPU 的服务器
数采平台(可选)推荐 PC,可视化数采必须
本地环境Spacemit K3 开发板 + bianbu v3.0+ 固件
机械臂SO101 双臂(主导臂 + 随从臂);自然语言调用场景只需要 SO101 随从臂
视觉输入两个 USB 相机,本文布置为 top 全局视角和 wrist 腕部视角
关键接口机械臂串口通常为 /dev/ttyACM*,相机设备通常为 /dev/video*

运行前请确认机械臂和相机已经正确上电并连接到 K3 开发板:

  • 机械臂:确认电源、通信线缆和控制接口连接正常,可通过 lerobot-find-port 检查端口;
  • 相机:确认 USB 相机已正确接入,可通过 lerobot-find-cameras opencv 查看可用相机索引。

抓取场景和硬件连接如图所示:

image-20260326100056147

3. 环境搭建

[!NOTE]

本方案需要准备三类环境:

  • 训练环境:部署在 GPU 服务器上,用于 ACT 训练或 SmolVLA 微调;
  • 数采环境:可部署在 K3 或 PC 上,建议 PC 端数采以提升视频编解码效率;
  • 开发板本地环境:部署在 Spacemit K3 上,用于 ACT 本地推理、mlink device 运行和 Hermes 调用。

当使用了某个流程时,需在对应平台下载代码并安装虚拟环境及依赖。

3.1 下载源码

#克隆 Spacemit 版本代码,基于 LeRobot v0.5.0 适配,集成了 Linksee 等机器人能力
git clone git@github.com:spacemit-robotics/lerobot.git

3.2 安装系统依赖

sudo apt update
sudo apt install ffmpeg
sudo apt install -y \
libavformat-dev \
libavcodec-dev \
libavdevice-dev \
libavutil-dev \
libavfilter-dev \
libswscale-dev \
libswresample-dev

sudo apt install -y \
build-essential \
cmake \
pkg-config \
python3-dev
  • ffmpeg:用于视频帧处理和数据集视频编码。

3.3 uv 安装和使用

K3 使用 Bianbu v3+ 固件时,系统 Python 版本为 3.14。当前 LeRobot 使用的 Spacemit PyTorch wheel 基于 Python 3.12 构建,因此本方案使用 uv 安装 Python 3.12 并创建虚拟环境。更多平台说明参见进迭时空 Python 开发文档uv 的完整命令参见 uv 官方文档

  1. 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh

安装完成后重新进入终端,或在当前终端加载 uv

source "$HOME/.local/bin/env"
  1. 使用 Python 3.12 创建 LeRobot 虚拟环境,并通过 --seed 预装 pip:
cd ~/lerobot
uv venv ~/.lerobot-venv --python 3.12 --seed
source ~/.lerobot-venv/bin/activate
python -V
python -m pip --version

3.4 设置 Python 包索引

激活虚拟环境后,为该环境内的 pip 设置 Aliyun 主索引和进迭时空附加索引:

source ~/.lerobot-venv/bin/activate
python -m pip config --site set global.index-url https://mirrors.aliyun.com/pypi/simple
python -m pip config --site set global.extra-index-url https://git.spacemit.com/api/v4/projects/33/packages/pypi/simple
python -m pip config --site list

--site 将索引配置写入当前虚拟环境,不影响系统 Python。后续始终使用 python -m pip,确保软件包装入当前激活的 Python 3.12 环境。

3.5 安装 Python 依赖

cd ~/lerobot

# 激活 3.3 节创建的虚拟环境
source ~/.lerobot-venv/bin/activate

# 安装 PyTorch 和运行时依赖
python -m pip install \
torch==2.7.1 \
torchvision==0.22.0 \
wandb==0.24.0 \
pyarrow==23.0.0

# 以 editable 模式安装 LeRobot 和 Feetech 依赖
python -m pip install -e ".[feetech]"

python -m pip check

训练或推理 SmolVLA 时,还需安装:

python -m pip install -e '.[smolvla,async]'

4 场景一:ACT/SmolVLA 模型训练到推理

本场景覆盖 SO101 机械臂从真机校准、遥操作、数据采集,到模型训练和部署的完整流程。

4.1 复现步骤

4.1.1 机械臂校准

  1. 如果是组装好的机械臂,一般已完成舵机标定,直接校准即可。校准之前,接入主导臂、随从臂的电源和 USB 口,查询设备端口:
lerobot-find-port
  1. USB 设备在 K3 中通常以 /dev/ttyACM0/dev/ttyACM1 形式出现,按需获取权限:
sudo chmod 666 /dev/ttyACM0
sudo chmod 666 /dev/ttyACM1
  1. 分别校准随从臂和主导臂:
# 随从臂
lerobot-calibrate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_follower_arm

# 主导臂
lerobot-calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=my_awesome_leader_arm

[!TIP]

  1. 请根据实际系统中的端口号替换 /dev/ttyACM0/dev/ttyACM1
  2. 首次启动会发起机械臂校准流程,校准过程参考 SO101 机械臂校准流程
  3. 校准文件存放于 ~/.cache/huggingface/lerobot/calibration 目录下。
  4. 主导臂主要用于遥操作和数采,推荐将其接入 PC 进行校准、遥操和数采。

4.1.2 遥控操作验证

  1. 无相机遥操作:
lerobot-teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_follower_arm \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=my_awesome_leader_arm
  1. 将用户加入 video 组获取相机访问权限
sudo usermod -aG video $USER

USER 为当前系统用户名。设置之后需要重新登入系统以生效。

  1. 查询相机索引:

摄像头的摆放原则是确保摄像头能够捕捉到任务执行过程中的关键细节,同时避免画面中出现其他无关物体,从而保证数据集质量和精度。笔者使用了两个 USB 摄像头,其中一个固定在操作台面顶部(top),提供全局视角;另一个固定在机械臂腕部(wrist),用于获取更加细致的操作视角。top 视角和 wrist 视角分别如下图所示:

image-20260326102623190

在固定好摄像头视角后,将两个 USB 摄像头连接至开发板,并运行以下命令查看摄像头 ID:

lerobot-find-cameras opencv

终端会打印检测到的相机信息。随后可在 outputs/captured_images 目录中查看每个摄像头拍摄的图片,并确认不同位置摄像头对应的端口 ID。需要注意的是,由于 K3 上同时读多路 YUYV 格式帧不稳定,第二个相机可能会报访问失败,将第一个相机拔掉再执行一次 lerobot-find-cameras opencv。重点查看 top 视角是否与图中一致。

  1. 可视化遥操作,确认 top 和 wrist 两路视觉输入质量:
lerobot-teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_follower_arm \
--robot.cameras="{
top: {type: opencv, index_or_path: 13, width: 640, height: 480, fps: 30, fourcc: MJPG},
wrist: {type: opencv, index_or_path: 15, width: 640, height: 480, fps: 30, fourcc: MJPG}
}" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=my_awesome_leader_arm \
--display_data=true

记得修改相机和机械臂的设备号为系统实时索引。

4.1.3 数据集采集

[!TIP]

开发板端也可以采集数据集。若开启 --display_data=true,建议在 X86 PC 端进行数采以获得更流畅的显示效果。

  1. 可选:登录 Hugging Face,便于上传数据集和模型。如需登录请先前往 https://huggingface.co/ 创建 huggingface 帐号:
hf auth login
HF_USER=$(hf auth whoami | head -n 1 | awk '{print $3}')
echo $HF_USER

# 如果不登录 Hugging Face,手动设置 $HF_USER 变量
HF_USER=annyi
echo $HF_USER
  1. 开始采集抓取绿色方块数据集:
lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_follower_arm \
--robot.cameras="{
top: {type: opencv, index_or_path: 13, width: 640, height: 480, fps: 30, fourcc: MJPG},
wrist: {type: opencv, index_or_path: 15, width: 640, height: 480, fps: 30, fourcc: MJPG}
}" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=my_awesome_leader_arm \
--dataset.num_episodes=60 \
--dataset.episode_time_s=30 \
--dataset.reset_time_s=30 \
--dataset.repo_id=${HF_USER}/record-green-cube \
--dataset.single_task="Place the green cube into the box" \
--dataset.root=./datasets/record-green-cube \
--dataset.push_to_hub=True \
--dataset.vcodec=h264 \
--play_sounds=false \
--display_data=true

关键参数说明:

  • dataset.num_episodes:采集数据条数;
  • dataset.episode_time_s:每条数据的采集时长;
  • dataset.reset_time_s:每次采集之间的准备时间;
  • dataset.repo_id:数据集仓库 ID;
  • dataset.single_task:任务自然语言描述,可用于 VLA 模型输入;
  • dataset.root:本地数据集保存路径;
  • dataset.push_to_hub:是否上传到 Hugging Face Hub;
  • dataset.vcodec=h264:K3 上推荐使用 H.264 编码;
  • display_data:是否显示图形化界面。

录制期间可使用以下键盘控制(X11 模式下生效):

  • :提前停止当前 episode 或 reset,并进入下一条;
  • :取消当前 episode 并重新录制;
  • ESC:立即停止会话,编码视频并上传数据集。

也可直接使用笔者采集的 数据集,确保场景一致可复用于训练。数据集下载之后解压放至 ~/.cache/huggingface/lerobot/${HF_USER}/ 目录。

4.1.4 ACT 模型训练

ACT(Action Chunking Transformer)是一种模仿学习算法,结合 Transformer 表达能力与动作分块技术,适合精细操作和较长时序的机器人控制任务。

act

如果数据集在开发板本地采集,需要先移动到 GPU 服务器:

  • 若服务器可访问 Hugging Face,可通过 dataset.repo_id 加载数据集;
  • 若使用本地数据集,请将数据集移动到服务器 lerobot/datasets 目录。
  1. 可选:登录 wandb 观察训练曲线,登录之前需要先前往 https://wandb.ai/site/ 创建 wandb 帐号:
wandb login
  1. 在服务器端启动 ACT 训练:
lerobot-train \
--policy.type=act \
--policy.repo_id=${HF_USER}/record-green-cube \
--dataset.repo_id=${HF_USER}/record-green-cube \
--dataset.root=datasets/record-green-cube \
--output_dir=outputs/train/so101_act_pick_green_cube_amp \
--job_name=so101_act_pick_green_cube \
--batch_size=4 \
--steps=100000 \
--policy.device=cuda \
--policy.use_amp=True

参数说明:

  • policy.type:策略类型;
  • dataset.repo_id:从 Hugging Face 下载数据集;
  • dataset.root:使用本地数据集,优先级高于 dataset.repo_id
  • output_dir:模型检查点和训练数据保存路径;
  • job_name:训练任务名称;
  • policy.device:训练设备,可选 cpucudamps
  • policy.use_amp:是否开启混合精度;
  • policy.repo_id:策略模型 ID。

[!NOTE]

参考配置:RTX 4090、60 组操作数据、batch size 为 8,训练到 loss 收敛通常需要三小时。

4.1.5 ACT 模型部署与本地推理

  1. 训练完成后,将模型检查点复制到开发板 lerobot 工作空间。

模型目录结构示例:

lerobot/outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model
├── config.json
├── model.safetensors
├── policy_postprocessor.json
├── policy_postprocessor_step_0_unnormalizer_processor.safetensors
├── policy_preprocessor.json
├── policy_preprocessor_step_3_normalizer_processor.safetensors
└── train_config.json

其中:

  • config.json:模型配置文件;
  • model.safetensors:模型权重文件;
  • train_config.json:训练参数记录文件。

也可以下载笔者已训练好的 模型权重,下载之后放置于 lerobot/outputs/train/ 目录下。

  1. 开发板端执行 ACT 推理示例:
lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{
top: {type: opencv, index_or_path: 13, width: 640, height: 480, fps: 30, fourcc: MJPG},
wrist: {type: opencv, index_or_path: 15, width: 640, height: 480, fps: 30, fourcc: MJPG}
}" \
--robot.id=my_awesome_follower_arm \
--display_data=false \
--dataset.repo_id=${HF_USER}/eval_act \
--dataset.single_task="Place the green cube into the box" \
--dataset.vcodec=h264 \
--policy.path=outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model \
--policy.device=cpu \
--dataset.episode_time_s=180 \
--dataset.reset_time_s=30 \
--play_sounds=false

[!NOTE]

  1. 请根据实际模型路径替换 --policy.path
  2. 多轮测试时,每轮测试前请先删除上次测试保留的评估数据集避免冲突:rm -rf ~/.cache/huggingface/lerobot/${HF_USER}/eval_act

4.1.6 SmolVLA 微调与分布式推理

SmolVLA 是轻量级视觉-语言-动作模型,参数量约 450M,可理解视觉输入和自然语言指令,并生成机器人动作序列。

smolvla

  1. 服务器端微调示例:
lerobot-train \
--dataset.root=datasets/record-green-cube \
--dataset.repo_id=${HF_USER}/record-green-cube \
--output_dir=./outputs/train/so101_smolvla_pick_green_cube_2cam \
--job_name=so101_smolvla_pick_green_cube_2cam \
--policy.repo_id=annyi/so101_smolvla_pick_green_cube_2cam \
--policy.path=lerobot/smolvla_base \
--policy.device=cuda \
--steps=100000 \
--batch_size=4 \
--policy.empty_cameras=0 \
--policy.input_features=null

当前开发板本地算力不建议直接运行 SmolVLA,可使用分布式推理:开发板作为客户端负责采集观测和执行动作,PC/服务器作为服务端负责模型推理,双方通过 gRPC 通信。

  1. 服务端启动:
python -m lerobot.async_inference.policy_server \
--host=0.0.0.0 \
--port=8080 \
--fps=30 \
--inference_latency=0.033 \
--obs_queue_timeout=1
  1. 开发板客户端启动:
python -m lerobot.async_inference.robot_client \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{
top: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30, fourcc: MJPG},
wrist: {type: opencv, index_or_path: 4, width: 640, height: 480, fps: 30, fourcc: MJPG}
}" \
--robot.id=my_awesome_follower_arm \
--task="Place the green cube into the box" \
--server_address=${server_ip}:8080 \
--policy_type=smolvla \
--pretrained_name_or_path=outputs/train/so101_smolvla_pick_green_cube_2cam/checkpoints/last/pretrained_model \
--policy_device=cuda \
--actions_per_chunk=50 \
--chunk_size_threshold=0.5 \
--aggregate_fn_name=weighted_average \
--debug_visualize_queue_size=True

更多参数可参考 LeRobot async inference 文档:https://huggingface.co/docs/lerobot/en/async

4.2 运行效果

ACT 模型训练完成后,可在 K3 上通过 CPU 执行本地推理,控制随从臂完成“将方块放入盒子”的任务。

lerobot

5 场景二:自然语言控制 SO101 机械臂抓取

本场景将底层 LeRobot 抓取流程封装为 C++ 原生应用,并通过 mlink device → mlink gateway → MCP 链路注册为 MCP 工具,并将 MCP 绑定到 Hermes Agent 框架中,支持使用自然语言控制 LeRobot 开源机械臂完成抓取任务。

5.1 复现步骤

5.1.1 运行环境准备

代码下载

先下载 Spacemit Robot SDK 代码:

mkdir spacemit_robot
cd spacemit_robot
repo init -u https://github.com/spacemit-robotics/manifest.git -b main -m default.xml \
--repo-url=https://gitee.com/spacemit-robotics/git-repo
repo sync -j4
repo start robot-dev --all

自然语言控制示例代码位于:

spacemit_robot/application/native/lerobot_app
模型准备

pick_cube 依赖底层 LeRobot 工作流及对应模型文件。首次运行前,请先准备模型:

  • 可根据前文训练得到 ACT 策略模型;
  • 也可下载笔者已训练好的 模型权重
  • 将模型放置到本地约定目录,例如 models/ 或运行脚本中指定的模型目录;
  • 确认模型路径与 scripts/pick_cube_record.sh 中配置一致。
修改相机和机械臂设备索引

查看相机和机械臂设备索引,确保索引号与 scripts/pick_cube_record.sh 中配置一致。

机械臂校准

按照 4.1.1 节完成随从臂校准。如果校准过且 Robot ID 与前文一致,可跳过此步骤。

系统依赖安装
sudo apt update
sudo apt install -y python3-cryptography libssl-dev cargo rustc pkg-config build-essential python3-dev
虚拟环境安装

底层 lerobot 属于 Python 生态,首次运行前需要准备当前应用的虚拟环境:

# 进入 spacemit robot sdk,并设置环境变量
cd spacemit_robot
source build/envsetup.sh

# 激活 3.3 节创建的 Python 3.12 虚拟环境
source ~/.lerobot-venv/bin/activate
python -V

m_env_build application/native/lerobot_app

或者进入应用目录安装:

cd application/native/lerobot_app
bash scripts/setup_env.sh

脚本会在仓库根目录下准备虚拟环境:

output/envs/lerobot_app

lerobot_device 在编译时依赖 mlink 提供的头文件和动态库。编译 lerobot 相关程序前,先完成 mlink device 构建:

cd spacemit_robot
source build/envsetup.sh
cd components/agent_tools/mlink_device
mm

构建完成后,通常可看到以下产物:

output/staging/include/mlink.h
output/staging/lib/libmlink_device.so
output/staging/bin/mlink_device_test

其中:

  • output/staging/include/mlink.h:供 lerobot_device 编译时引用的头文件;
  • output/staging/lib/libmlink_device.so:供 lerobot_device 链接及运行时加载的动态库;
  • output/staging/bin/mlink_device_testmlink device 组件自带测试程序。

5.1.3 构建 lerobot 原生应用

进入目录构建:

cd spacemit_robot
source build/envsetup.sh
cd application/native/lerobot_app
mm

构建完成后,产物安装到:

output/staging/bin/lerobot_native
output/staging/bin/lerobot_device
  • output/staging/bin/lerobot_native:本地命令行执行入口,用于直接触发 pick_cube 等 task;
  • output/staging/bin/lerobot_device:mlink 设备进程,用于向 gateway 动态注册工具并转发调用到 lerobot_native

如果只做本地调试,也可以使用独立 CMake:

cd application/native/lerobot_app
cmake -B build -S .
cmake --build build

此时本地产物位于:

build/lerobot_native
build/lerobot_device

5.1.4 直接运行工具

lerobot_native tool-pick-cube

该命令会直接启动抓取任务。

5.1.5 验证工具注册

  1. 启动 gateway
cd spacemit_robot
source build/envsetup.sh
m_env_build components/agent_tools/mlink_gateway

source output/envs/mlink-gateway/bin/activate
mlink gateway restart
  1. 启动 mlink device
lerobot_device unix lerobot
  1. 检查 gateway 工具列表:
mlink gateway tools

若注册成功,应看到工具名:

lerobot.pick_cube

5.1.6 Hermes 自然语言调用

  1. 安装 Hermes:
sudo apt-get update
sudo apt-get install --reinstall hermes-agent
  1. 配置模型:
hermes model

随后按照命令行向导完成密钥和模型配置。

  1. 绑定 MCP Servers

将本机 gateway 的 HTTP MCP endpoint 写入 Hermes 配置,在 ~/.hermes/config.yaml 文件末尾追加:

mcp_servers:
mlink-gateway:
transport: http
url: http://127.0.0.1:18765/mcp
enabled: true
  1. 启动交互式 CLI:
hermes

当 gateway 已运行且 lerobot_device 已连接后,在 Hermes CLI 中输入自然语言指令,例如“抓木块”。Hermes 会将请求路由到 lerobot.pick_cube tool,进而触发机械臂执行对应抓取动作。

5.2 运行效果

在 K3 上打开 hermes 终端,用自然语言与它对话,查询可调用的工具可以看到“抓木块”工具;输入“抓木块”,机械臂会执行对应任务,效果如 4.2 节所示。

6 场景三:ACT FP16 加速推理部署

本场景在保留原有 ACT FP32 推理方式的基础上,增加面向 K3 的 SpineTorch FP16 加速模式。FP16 模式使用独立虚拟环境 ~/.lerobot-venv-torh2.8examples/spine-torch-deploy 中的专用入口,所有扩展仅在 FP16 Python 进程内生效,不修改 src/lerobot 下的原始代码。

6.1 安装虚拟环境

  1. 使用 uv 和 Python 3.12 创建 FP16 专用虚拟环境,并预装 pip:
uv venv ~/.lerobot-venv-torh2.8 --python 3.12 --seed
source ~/.lerobot-venv-torh2.8/bin/activate
python -V
python -m pip --version

该命令创建独立的 Python 3.12 环境,不会继承默认 LeRobot 环境的 Torch 和 site-packages。

  1. Torch 2.8 依赖 libopenblas.so.0libomp.so.5,直接安装对应系统库:
sudo apt update
sudo apt install -y libopenblas0-pthread libomp5
  1. 使用虚拟环境内的 pip 安装 FP16 运行环境:
cd ~/lerobot
source ~/.lerobot-venv-torh2.8/bin/activate

python -m pip config --site set global.index-url https://mirrors.aliyun.com/pypi/simple
python -m pip config --site set global.extra-index-url https://git.spacemit.com/api/v4/projects/33/packages/pypi/simple

python -m pip install --no-deps \
"torch @ https://git.spacemit.com/api/v4/projects/33/packages/pypi/files/51484d46602b0e9537a5eb83c251ecd2227cea571127c2560cb8411bca154a42/torch-2.8.0%2Bspacemit.2-cp312-cp312-linux_riscv64.whl#sha256=51484d46602b0e9537a5eb83c251ecd2227cea571127c2560cb8411bca154a42" \
"spine-torch-extension @ https://git.spacemit.com/api/v4/projects/33/packages/pypi/files/81ac3ccb44810bc6d8a89ff136daeda3b1527fa0c103d3c986059594f9e76a97/spine_torch_extension-2.8.0%2Bspacemit.0-cp312-cp312-linux_riscv64.whl#sha256=81ac3ccb44810bc6d8a89ff136daeda3b1527fa0c103d3c986059594f9e76a97"

python -m pip install \
numpy==2.2.6 \
pyarrow==23.0.0 \
torchvision==0.23.0 \
torchcodec==0.5 \
setuptools==80.9.0 \
fsspec==2026.2.0

python -m pip install \
-e ".[feetech]" \
wandb==0.24.0

python -m pip check
  1. 验证 FP16 环境。无需应用补丁,专用启动脚本会在当前进程中加载 ACT FP16 增量源码:
cd ~/lerobot
source ~/.lerobot-venv-torh2.8/bin/activate

./examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh python - <<'PY'
import importlib.metadata as metadata
import torch
import spinednn_torch_plugin as plugin

print("torch:", torch.__version__, torch.__file__)
print("mkldnn available:", torch.backends.mkldnn.is_available())
print("plugin:", metadata.version("spine-torch-extension"), plugin.__file__)
plugin.only_enable(["addmm", "bmm", "softmax", "layer_norm", "relu", "add"])
print("plugin enabled:", plugin.is_enabled())
PY

FP16 环境中应显示 Torch 2.8.0、插件 2.8.0+spacemit.0mkldnn available: True 以及 plugin enabled: True

6.2 模型转出 FP16

进入 LeRobot 源码目录,将第 4.1.4 节训练得到的 FP32 模型转换为 FP16:

cd ~/lerobot
source ~/.lerobot-venv-torh2.8/bin/activate

python examples/spine-torch-deploy/convert_act_model_to_fp16.py \
--input-path outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model \
--output-path outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model_fp16

转换脚本会执行以下操作:

  • 将 ACT 权重转换为 torch.float16
  • 保持原有 config.json 结构,FP16 精度由专用运行入口在进程内设置;
  • 保留原模型目录中的预处理、后处理、归一化统计和训练配置文件;
  • 不修改原 FP32 模型目录。

转换完成后检查模型文件:

ls -lh outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model_fp16

python - <<'PY'
from pathlib import Path

import torch
from safetensors import safe_open

model = Path("outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model_fp16/model.safetensors")
with safe_open(model, framework="pt", device="cpu") as handle:
dtypes = {handle.get_tensor(key).dtype for key in handle.keys()}

print("weight dtypes:", dtypes)
assert dtypes == {torch.float16}
PY

6.3 配置启动环境

examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh 用于设置 K3 AI Core 和 SpineDNN 运行参数,主要包括:

# 使用 8 个 OpenMP 工作线程执行模型推理
export OMP_NUM_THREADS=8

# 将 SpineDNN 算子内线程绑定到 K3 的 8 个 AI Core
export SPINEDNN_INTRA_THREAD_AFFINITY="8;9;10;11;12;13;14;15"

# 不启用通用 CPU Core 路径,使当前启动配置仅使用 AI Core
unset USE_COMMON_CORE

# 设置 SpineDNN 卷积切分优化强度
# 配置范围为[1,1000]内的整数,默认值50。配置值越高,在A100上conv matmul性能越好,每个ai core的负载越大。
export SPINEDNN_CONV_TILING_STRENGTH=900

# 为 ACT 视觉骨干网络启用可复用的 SpineDNN 执行上下文
export SPINEDNN_TORCH_PLUGIN_VISUAL_CONTEXT=1

# 将视觉上下文优化应用到完整视觉骨干网络
export SPINEDNN_TORCH_PLUGIN_VISUAL_SCOPE=full

# 在视觉优化路径内部使用 NHWC 数据布局
export SPINEDNN_TORCH_PLUGIN_VISUAL_LAYOUT=nhwc

首次使用前添加执行权限:

cd ~/lerobot
chmod +x examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh

该脚本接收需要运行的命令及其参数,并在启动 Python 前完成 AI Core 亲和性和 SpineDNN 运行参数配置。由于 OpenBLAS 和 OpenMP 已安装为系统库,无需配置额外的动态库路径。

6.4 运行 FP16 推理

  1. 确认机械臂和两路相机设备索引:
lerobot-find-port
lerobot-find-cameras opencv
  1. 删除同名的历史本地评估数据集,避免 LeRobot 拒绝重复创建:
# 已登录 Hugging Face 时,填写自己的 Hugging Face 用户名
export HF_USER=annyi

# 不登录且仅保存到本地时,也可以设置为固定的本地命名空间
# export HF_USER=local

# 确认变量非空后再删除对应的历史评估数据集
test -n "${HF_USER:-}" || { echo "HF_USER 未设置"; exit 1; }
rm -rf "$HOME/.cache/huggingface/lerobot/${HF_USER}/eval_act_fp16"

HF_USER 是 LeRobot 数据集 ID 的命名空间,通常设置为 Hugging Face 用户名或组织名。后续命令中的 --dataset.repo_id=${HF_USER}/eval_act_fp16 会同时使用该变量确定本地缓存目录。即使设置了 --dataset.push_to_hub=false、不上传数据,也需要提供该命名空间;此时可以使用固定的本地名称,例如 local

  1. 启动 ACT FP16 推理:
cd ~/lerobot
source ~/.lerobot-venv-torh2.8/bin/activate

./examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh \
lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{
top: {type: opencv, index_or_path: 13, width: 640, height: 480, fps: 30, fourcc: MJPG},
wrist: {type: opencv, index_or_path: 15, width: 640, height: 480, fps: 30, fourcc: MJPG}
}" \
--robot.id=my_awesome_follower_arm \
--display_data=false \
--dataset.repo_id=${HF_USER}/eval_act_fp16 \
--dataset.single_task="Place the green cube into the box" \
--dataset.num_episodes=1 \
--dataset.vcodec=h264 \
--dataset.push_to_hub=false \
--policy.path=outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model_fp16 \
--policy.device=cpu \
--dataset.episode_time_s=180 \
--dataset.reset_time_s=30 \
--play_sounds=false

其中:

  • --policy.path:指向转换后的 FP16 模型目录;
  • examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh:设置 AI Core/SpineDNN 环境,并将 lerobot-record 切换到仅当前进程生效的 FP16 入口。

启动日志中出现 Enabled SpineDNN torch plugin for ACT FP16 inference.,表示插件已经启用。

6.5 性能验证与分阶段计时

部署前可先使用虚拟输入测试完整模型推理,避免直接驱动机械臂:

cd ~/lerobot
source ~/.lerobot-venv-torh2.8/bin/activate

./examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh \
python examples/spine-torch-deploy/benchmark_act_dummy_inference.py \
--model-path outputs/train/so101_act_pick_green_cube_amp/checkpoints/100000/pretrained_model_fp16 \
--device cpu \
--use-half \
--keep-mkldnn \
--use-spinednn \
--warmup 3 \
--iters 5

如需在真机运行时输出完整推理和缓存 action 路径耗时,在 lerobot-record 启动命令前增加:

export LEROBOT_PREDICT_TIMING=1

日志中的计时含义如下:

  • path=full:一次完整真机推理,包含 observation 转换、输入预处理、ACT select_action 和输出后处理;不包含相机取帧、数据集写入和机械臂通信;
  • path=cached:直接读取 ACT 已生成的 action chunk,不重复执行输入预处理和模型推理。

测试结果汇总如下:

测试项计时范围实测结果
Benchmark模型前向推理一次,即 select_action361.9 ms
真机 pipelineobservation 转换、输入预处理、select_action、输出后处理463.6 ms
队列取出 action从 action chunk 取出 action 并执行输出后处理0.5 ms

6.6 切回默认 FP32 推理

需要使用原始 FP32 路径时,直接执行第 4.1.5 节的 lerobot-record 命令:

  • 先执行 deactivate,再激活 source ~/.lerobot-venv/bin/activate
  • 不通过 examples/spine-torch-deploy/run_lerobot_fp16_a100x8.sh 启动;
  • --policy.path 指向原 pretrained_model
  • 直接使用标准 lerobot-record 入口。

无需执行任何回退操作:FP16 扩展只存在于专用 Python 进程内,进程退出后标准 LeRobot 仍使用 ~/.lerobot-venv 中的默认 PyTorch 和原始 ACT FP32 路径。

7. 常见问题

现象处理
找不到机械臂串口执行 lerobot-find-port 确认端口,检查电源和 USB 连接,并根据实际情况替换 /dev/ttyACM*
串口权限不足执行 sudo chmod 666 /dev/ttyACM0,如有多个设备则对对应端口分别授权。
找不到相机或相机索引不正确执行 lerobot-find-cameras opencv,根据输出替换 index_or_path
可视化数采卡顿建议在 X86 PC 端开启 --display_data=true 进行数采;K3 端可设置 --display_data=false
Rerun 渲染失败Bianbu LXQt 图形渲染后端为 GLES,执行 export WGPU_BACKEND=gles 后重试。
推理模型路径错误检查 --policy.pathscripts/pick_cube_record.sh 中的模型路径是否与实际文件一致。
lerobot.pick_cube 未出现在工具列表确认 mlink gateway 已启动,lerobot_device 已运行,并重新执行 mlink gateway tools
Hermes 无法调用工具检查 ~/.hermes/config.yaml 中 MCP endpoint 是否指向 http://127.0.0.1:18765/mcp,并确认 gateway 正常运行。