Soma Zero Tutorials
🔍 搜索功能尚未开启,敬请期待。

2.8 实战任务一:单臂抓取放置

本教程只适合单臂,双臂可跳过。

因为 lerobot_single_student 代码做了修改,请先 git pull 或者下载最新版代码

欢迎大家将复现的效果分享到答疑群,也鼓励一下其他小伙伴!不限于课程讲的 VLA 算法和任务,老师会发红包奥!

现在我们可以进入激动人心的实战环节了。我们将先用一个简单的任务(Pick & Place)来完整感受数据采集、训练、推理的流程。我们将学习:

  • 采集 Lerobot 格式的数据集

  • 将训练三个模型,分别是:

    • Lerobot 框架集成的 ACTSmolVLA
    • openpi 的 pi0

当然,现在主流的 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
  • episode 录制集数,理论上越多越好,建议不低于 80 个

2.2 恢复采集

你可以随时中断采集,如果需要恢复采集,则可以跟上一个指令:

--resume=true

此时,dataset.num_episodes=10 意味着在已录制数据上额外增加 10 个 episodes,录制才会停止。

2.3 数据集弧度转角度

录制的时候 enpei_use_radian=true 启用弧度制,因为 openpipi0 需要弧度制,但是 lerobotACTSmolVLA 需要角度制,我们可以使用下面脚本转换:

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 被转换的数据集 id
  • source-dataset-root 被转换数据集的路径
  • target-repo-id 转换后的数据集 id
  • output-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 数据集 id
  • port 网页端口
  • root 数据集位置

打开浏览器 http://127.0.0.1:3210,会看到可视化见面:

在训练之前强烈建议用可视化工具检查一下录制完成的数据

  • 检查集数够不够
  • 检查数据集中摄像头画面是否完整(非静态,要求是视频)
  • 检查关节信息格式是否正确,如弧度制下是否有明显异常值(如大于 2*pi
  • 检查关节信息是否有残缺

3. 训练

3.1 环境准备

因为 ACTSmolVLA 已经集成到 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_sizenum_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_base
    • huggingface-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=100
    • source_repo_id 源 ID
    • target_repo_id 转换后 ID
    • output_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_idroot 为自己数据集(转换后的)。

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-client

    cd ./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=true
    • host 服务器地址(这里因为用了 AutoDL 本地转发,所以是 localhost
    • port 服务器端口
    • instruction 文本指令,保持和采集数据一致
    • enpei_use_radian 需要使用弧度制
  • 测试视频

实测下来,还是 Pi0 成功率最高!

欢迎大家将复现的效果分享到答疑群,也鼓励一下其他小伙伴!不限于课程讲的 VLA 算法和任务,老师会发红包奥!