2.8 实战任务一:单臂抓取放置
本教程只适合单臂,双臂可跳过。
因为
lerobot_single_student代码做了修改,请先git pull或者下载最新版代码。欢迎大家将复现的效果分享到答疑群,也鼓励一下其他小伙伴!不限于课程讲的 VLA 算法和任务,老师会发红包奥!
现在我们可以进入激动人心的实战环节了。我们将先用一个简单的任务(Pick & Place)来完整感受数据采集、训练、推理的流程。我们将学习:
-
采集
Lerobot格式的数据集 -
将训练三个模型,分别是:
- Lerobot 框架集成的
ACT、SmolVLA - openpi 的
pi0
- Lerobot 框架集成的
当然,现在主流的 VLA 模型都支持 Lerobot 格式数据集,学完这三个模型,你可以尝试其他 VLA 模型!
1. 准备
抓取再放置(Pick & Place)是比较基础的任务,我举的例子如下图:

目标是将杨桃从 A 处抓起来,然后放置到 B 处的盒子里。
复习一下:先确保你按照《4.单臂遥操系统校准、测试(双臂可跳过)》的教程,能使用类似下面的指令跑通遥操作测试:
具体参数可能需要修改,不要机械复制。
python -m lerobot.teleoperate \
--robot.ip_address="localhost" \
--robot.port=12345 \
--robot.type=enpei_follower \
--robot.id=enpei_follower \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}}" \
--teleop.type=enpei_leader \
--teleop.port=/dev/ttyACM0 \
--teleop.id=enpei_leader \
--fps=30\
--display_data=true \
--enpei_speed_mode=record \
--enpei_use_radian=false
在正式采集数据之前,可能你需要调整一下 fixed 固定位相机的视角,要保证可以拍摄到实际操作场景(比如杨桃起始位置),可以使用 rerun.io 检查:

顺便检查一下固定位和腕部相机序号又没有错误。
2. 数据采集
现在我们来正式采集数据。
舵机夹爪不能长时间处在堵转状态下(夹着物品),否则可能会烧毁或变得卡顿。
如果摸着过热,可以暂停采集,脚本支持恢复采集。
2.1 采集指令
使用下面命令采集数据:
python -m lerobot.record \
--robot.ip_address="localhost" \
--robot.port=12345 \
--robot.type=enpei_follower \
--robot.id=enpei_follower \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}}" \
--teleop.type=enpei_leader \
--teleop.port=/dev/ttyACM0 \
--teleop.id=enpei_leader \
--display_data=true \
--enpei_use_radian=true\
--dataset.repo_id=enpeicv/demo_move_fruit \
--dataset.push_to_hub=false \
--dataset.num_episodes=100\
--dataset.episode_time_s=15 \
--dataset.reset_time_s=3 \
--dataset.single_task="Put the starfruit to the blue box" \
--dataset.root=/media/enpei/娱乐/ubuntu_short_videos/demo_move_fruit
参数解释:
没有列入的参数,意味着使用默认值,如:
dataset.fps=30,更多参见代码src/lerobot/record.py
| 参数 | 是否需要修改 | 解释 |
|---|---|---|
robot.ip_address="localhost" |
✅ 是 | 上位机 API 的 IP 地址 |
robot.port=12345 |
✅ 是 | 上位机 API 的端口 |
robot.type=enpei_follower |
否 | 从臂类别,方便框架识别 |
robot.id=enpei_follower |
否 | 从臂 ID,方便框架识别 |
robot.cameras="{ }" |
✅ 是 | 相机配置参数 |
teleop.type=enpei_leader |
否 | 主臂类别,方便框架识别 |
teleop.port=/dev/ttyACM0 |
✅ 是 | 主臂端驱动板端口,可通过 ls /dev/ttyACM* 查询 |
teleop.id=enpei_leader |
否 | 主臂 ID,方便框架识别 |
display_data=true |
否 | rerun.io 可视化 |
enpei_use_radian=true |
✅ 是 | 是否使用弧度制(false 表示角度制)。 |
dataset.repo_id=enpeicv/demo_move_fruit |
✅ 是 | 采集数据后保存的 ID,如果数据推到 huggingface,可以使用 https://huggingface.co/datasets/enpeicv/demo_move_fruit 访问 |
dataset.push_to_hub=false |
否 | 是否将数据推到 HF,建议关闭 |
dataset.num_episodes=100 |
✅ 是 | 数据集一共采集的 episode 集数,一次成功的操作算是 1 个 episode |
dataset.episode_time_s=15 |
✅ 是 | 1 个 episode 采集需要的时长,根据任务耗时来决定 |
dataset.reset_time_s=3 |
✅ 是 | 重置时间,一般留给自己重置物品用(如把水果放回原位) |
dataset.single_task="Put the starfruit to the blue box" |
✅ 是 | 数据集描述,对于部分 VLA 算法(如 Pi0),需要用它作为文本提示 |
dataset.root=/media/enpei/娱乐/ubuntu_short_videos/demo_move_fruit |
✅ 是 | 数据集保存位置。(如不设置,默认位置:/home/enpei/.cache/huggingface/lerobot/enpeicv/demo_move_fruit ) |
启动后,便可以采集数据了,建议:
-
最好找一个帮手
-
默认
dataset.fps=30,遥操作有一定延迟,不要着急操作动作 -
先自己练习采集几个
episode,找到适合的dataset.episode_time_s(能把任务完整完成) 和dataset.reset_time_s(能快速重置场景),这样数据集不至于太大,采集、训练时间也可缩短。 -
物品放置建议:
- 一个位置录制 10
episodes,如下图:位置 1 位置 2 位置 3 


- 如果物体有角度区别,一个角度录制 10 个
episodes,如下图:角度 1 角度 2 角度 3 角度 4 



- 一个位置录制 10
-
episode录制集数,理论上越多越好,建议不低于 80 个
2.2 恢复采集
你可以随时中断采集,如果需要恢复采集,则可以跟上一个指令:
--resume=true
此时,dataset.num_episodes=10 意味着在已录制数据上额外增加 10 个 episodes,录制才会停止。
2.3 数据集弧度转角度
录制的时候 enpei_use_radian=true 启用弧度制,因为 openpi 的 pi0 需要弧度制,但是 lerobot 的 ACT 和 SmolVLA 需要角度制,我们可以使用下面脚本转换:
python enpei_scripts/convert_radians_to_degrees.py \ --source-repo-id=enpeicv/demo_move_fruit \ --source-dataset-root=./enpei_dataset/demo_move_fruit \ --target-repo-id=enpeicv/demo_move_fruit_degrees \ --output-path=./enpei_dataset/demo_move_fruit_degrees \ --max-episodes=100
source-repo-id被转换的数据集idsource-dataset-root被转换数据集的路径target-repo-id转换后的数据集idoutput-path转换后的数据集保存位置max-episodes最多转换多少个episodes
如果报类似下面错误:
RuntimeError: Could not load libtorchcodec. Likely causes:
1. FFmpeg is not properly installed in your environment. We support
versions 4, 5, 6 and 7.
2. The PyTorch version (2.6.0+cu124) is not compatible with
this version of TorchCodec. Refer to the version compatibility
table:
https://github.com/pytorch/torchcodec?tab=readme-ov-file#installing-torchcodec.
3. Another runtime dependency; see exceptions below.
The following exceptions were raised as we tried to load libtorchcodec:
[start of libtorchcodec loading traceback]
libavutil.so.59: cannot open shared object file: No such file or directory
libavutil.so.58: cannot open shared object file: No such file or directory
libavutil.so.57: cannot open shared object file: No such file or directory
/lib/x86_64-linux-gnu/libgobject-2.0.so.0: undefined symbol: ffi_type_uint32, version LIBFFI_BASE_7.0
可以安装:conda install ffmpeg=7.1.1 -c conda-forge
2.3 数据集可视化
我们使用网页可视化工具,查看录制或者转换好的数据集。
python src/lerobot/scripts/visualize_dataset_html.py --repo-id enpeicv/demo_move_fruit_degrees --port=3210 --root=/media/enpei/娱乐/ubuntu_short_videos/demo_move_fruit_degrees
repo-id数据集idport网页端口root数据集位置
打开浏览器 http://127.0.0.1:3210,会看到可视化见面:
在训练之前强烈建议用可视化工具检查一下录制完成的数据
- 检查集数够不够
- 检查数据集中摄像头画面是否完整(非静态,要求是视频)
- 检查关节信息格式是否正确,如弧度制下是否有明显异常值(如大于
2*pi) - 检查关节信息是否有残缺
3. 训练
3.1 环境准备
因为 ACT 和 SmolVLA 已经集成到 Lerobot 框架,所以只要有 Lerobot 环境即可,如果使用的是其他电脑,可以参考 4.单臂遥操系统校准、测试(双臂可跳过) 先安装好 Lerobot。
我使用的是 AutoDL 的 4090 机器训练,下面是我的租赁实例镜像:
![]()
3.2 训练 ACT
注意数据集必须是角度制(我试过弧度制,效果不好)
python ./src/lerobot/scripts/train.py \
--dataset.repo_id=enpeicv/demo_move_fruit_degrees \
--dataset.root=./enpei_dataset/demo_move_fruit_degrees\
--policy.type=act \
--output_dir=outputs/train/demo_move_fruit_degrees_act \
--job_name=demo_move_fruit_degrees \
--policy.device=cuda \
--policy.push_to_hub=false \
--wandb.enable=false\
--batch_size=32 \
--num_workers=8 \
--steps=200000
参数介绍:
-
dataset.repo_id数据集id -
dataset.root数据集存储位置 -
policy.type=act使用ACT策略训练更多策略在
src/lerobot/policies下
-
output_dir训练权重保存位置 -
job_name任务名称 -
policy.device=cuda使用显卡训练 -
policy.push_to_hub=false权重是否推到HF官网 -
wandb.enable=false是否开启wandb训练可视化如果你电脑可以连接到
wandb服务器(国内可能连不上),建议开启wandb.enable=true,可以查看训练指标,比如:
-
--batch_size=32 \ --num_workers=8 \ --steps=200000这三项是训练的基本参数,分别是数据批次大小、
workers加载数量、训练步数。如果机器性能较差,可以调小batch_size、num_workers。
开始训练的话,你会看到这样的输出(可以看到 Loss 降低):

3.3 训练 SmolVLA
类似的,训练 SmolVLA 的命令如下:
我们使用的是微调模式,而不是从头训练。
python src/lerobot/scripts/train.py \
--dataset.repo_id=enpeicv/demo_move_fruit_degrees \
--dataset.root=./enpei_dataset/demo_move_fruit_degrees\
--policy.path=lerobot/smolvla_base \
--policy.device=cuda \
--policy.push_to_hub=false \
--output_dir=outputs/train/demo_move_fruit_degrees_smolvla \
--job_name=smolvla_test \
--batch_size=32 \
--num_workers=4 \
--steps=20000 \
--wandb.enable=false
如果你在国内,可能会报错(无法下载预训练权重),可以用 HF 镜像节点:
- 先使用 HF 国内节点:
export HF_ENDPOINT=https://hf-mirror.com- 提前下载权重:
huggingface-cli download --resume-download lerobot/smolvla_basehuggingface-cli download --resume-download HuggingFaceTB/SmolVLM2-500M-Video-Instruct
重点参数介绍:
policy.path=lerobot/smolvla_base微调所需要的基础模型ID
开始训练的话,你会看到这样的输出(可以看到 Loss 降低):

3.4 训练 Pi0
3.4.1 安装
-
训练和推理 Pi0 需要显存较大的显卡,我租赁的实例是 H20:
-
训练过程中 Pi0 会保存多个时间点的权重 Checkpoint,每次约消耗磁盘 12G,请尽量保证磁盘空间足够(Autodl 可以扩容磁盘),以免中断训练
-
首先需要安装 Pi0
# 克隆我改动后的代码 git clone https://github.com/enpeizhao/openpi_episode1_student.git # 安装 GIT_LFS_SKIP_SMUDGE=1 uv sync GIT_LFS_SKIP_SMUDGE=1 uv pip install -e .
3.4.2 转换数据
-
Pi0 必须是弧度制数据
-
转换 openpi 格式:
uv run ./examples/libero/lerobot2oppi.py \ --source-repo-id=enpeicv/demo_move_fruit \ --target-repo-id=enpeicv/demo_move_fruit_openpi \ --output-path=./enpei_dataset/demo_move_fruit_openpi \ --source-dataset-root=/root/autodl-tmp/openpi/enpei_dataset/demo_move_fruit \ --max-episodes=100source_repo_id源 IDtarget_repo_id转换后 IDoutput_path输出地址source_dataset_root源地址max_episodes最多转换集数
3.4.3 修改配置文件
- 预训练权重下载,解压到一个目录,比如这里的
/root/autodl-tmp/pi0_base/params - 参考
src/openpi/training/config.py的配置文件,将enpei_robot_demo_move_fruit_low_mem_finetune修改成自己的:
重点修改 repo_id 和 root 为自己数据集(转换后的)。
3.4.4 计算 normalization
uv run scripts/compute_norm_stats.py --config-name enpei_robot_demo_move_fruit_low_mem_finetune
--config-name 后跟的是自己的配置名称。
3.4.5 训练
- 训练
XLA_PYTHON_CLIENT_MEM_FRACTION=0.9 uv run scripts/train.py enpei_robot_demo_move_fruit_low_mem_finetune --exp-name=my_experiment --overwrite
-
开始训练的话,你会看到这样的输出(可以看到 Loss 降低):

4. 推理测试
4.1 测试 ACT、SmolVLA
训练完毕,在 output_dir 下会有权重文件,使用下面脚本测试策略运行效果:
python -m lerobot.test_policy \
--robot.ip_address="localhost" \
--robot.port=12345 \
--robot.type=enpei_follower \
--robot.id=enpei_follower \
--robot.cameras="{ handeye: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}}" \
--policy.path=weights/smolvla/pretrained_model\
--fps=30 \
--time_s=120 \
--single_task="Put the starfruit to the blue box" \
--enpei_use_radian=false \
--display_data=true
重点参数介绍:
robot.cameras测试时的相机位置需要与采集数据一致policy.path训练好的权重位置,无需指定模型类型time_s测试时间,超过此时间就停止enpei_use_radian=false不用弧度
ACT 测试视频(连续测试三次)
SmolVLA 测试视频(连续测试三次)
4.2 测试 Pi0
我们使用云端部署的方式运行。
4.2.1 服务端(openpi 环境)
# 服务端
uv run scripts/serve_policy.py policy:checkpoint --policy.config=enpei_robot_demo_move_fruit_low_mem_finetune --policy.dir=checkpoints/enpei_robot_demo_move_fruit_low_mem_finetune/my_experiment/25000
policy.config配置名称policy.dir训练好的权重地址
启动服务器后,他会暴露一个服务端口(默认是 6006):

你需要保证:
-
客户端可以访问服务器这个 IP 和端口,端口没有被拦截
-
如果是
AutoDL环境,可以使用它的端口转发服务(自定义服务):
4.2.2 客户端(Lerobot 环境)
-
进入
Lerobot仓库代码,安装openpi-clientcd ./packages/openpi-client pip install -e . -
启动客户端
python -m lerobot.test_openpi \ --robot.ip_address="localhost" \ --robot.port=12345 \ --robot.type=enpei_follower \ --robot.id=enpei_follower \ --robot.cameras="{ handeye: {type: opencv, index_or_path: 0, width: 320, height: 240, fps: 30}, fixed: {type: opencv, index_or_path: 2, width: 320, height: 240, fps: 30}}" \ --host=localhost \ --port=6006 \ --instruction="Put the starfruit to the blue box" \ --fps=30 \ --enpei_use_radian=truehost服务器地址(这里因为用了AutoDL本地转发,所以是localhost)port服务器端口instruction文本指令,保持和采集数据一致enpei_use_radian需要使用弧度制
-
测试视频
▶
实测下来,还是 Pi0 成功率最高!
欢迎大家将复现的效果分享到答疑群,也鼓励一下其他小伙伴!不限于课程讲的 VLA 算法和任务,老师会发红包奥!