跳到主要内容
Projects/SmolVLA 高反光与透明物体抓取复现教程:方案总览与核心改造 · 第 5 阶段

SmolVLA 高反光与透明物体抓取复现教程:方案总览与核心改造 · 第 5 阶段

基于双 奥比中光 相机、增强深度、B601-DM 主从臂和 SmolVLA,复现高反光桌面上透明瓶与香蕉模型的自主整理链路。

Apache-2.0 / MIT

01 / DOCUMENTATION 内容概述

系列教程第 5/7 阶段:采集覆盖透明物体、高反光和多摆位的数据集,并处理断点续采、混合帧率、格式与 Arrow 合并问题。

02 / DOCUMENTATION 9.1 先编辑脚本顶部参数

主脚本:

代码块
纯文本
examples/rebot_b601_smolvla_record/record_b601_smolvla_rgbd.sh

重点修改:

代码块
Bash
DATASET_ROOT="/home/r/datasets/rebot_b601_banana_bottle_rgbd_1"DATASET_REPO_ID="local/rebot_b601_banana_bottle_rgbd_1"
FOLLOWER_PORT="/dev/ttyACM0"LEADER_PORT="/dev/ttyACM1"
TOP_SERIAL="你的 Gemini 335L 序列号"WRIST_SERIAL="你的 Gemini 305 序列号"ORBBEC_BRIDGE="${REPO_ROOT}/src/lerobot/cameras/orbbec/cpp/build/orbbec_rgbd_bridge"LINGBOT_MODEL="/home/r/ws/model.sm4"

推荐保持:

代码块
纯文本
640 × 48010 FPSdepth visualization: 250-1800 mmEnhancedDepthFilter confidence_threshold: 51H.264 encoders: serialvideo encoding threads: 1image writer: 1 process × 1 thread/cameradisplay_data: false

03 / DOCUMENTATION 9.2 启动采集

代码块
Bash
bash examples/rebot_b601_smolvla_record/record_b601_smolvla_rgbd.sh

脚本会记录:

Feature形状/类型用途
observation.state(21,) float327 个电机的位置、速度、力矩
observation.images.wrist(3,480,640)腕部 RGB
observation.images.top(3,480,640)全局 RGB
observation.images.top_depth(3,480,640)增强深度可视化,SmolVLA 输入
observation.depths.top(480,640) uint16增强深度毫米值,归档
action(7,) float32实际发送给从臂的 6 关节 + 夹爪目标

04 / DOCUMENTATION 9.3 数据要怎样才能学会“随机摆放也能归位”?

不要只在桌面中心重复同一条漂亮轨迹。尤其面对透明瓶和高反光桌面,训练集必须主动覆盖“反光关系变化”,而不只是物体坐标变化。建议给桌面划分位置网格,并按下面的场景矩阵有计划地采集:

变化维度需要覆盖的情况为什么重要
物体位置左/中/右、近端/远端、目标区附近防止模型记住固定抓取轨迹
透明瓶姿态直立、横放、斜放、不同标签和瓶盖朝向瓶壁、标签与背景形成的视觉线索不同
高光关系桌面高光落在瓶前、瓶后、瓶侧,亮度在部署允许范围内变化深度孔洞和 RGB 对比度会随角度、照明改变
遮挡关系香蕉遮瓶、瓶遮香蕉、两者相邻或分离训练模型利用全局与腕部视角互补
操作过程顺利抓取、轻微偏位后修正、重新接近学到闭环纠偏,而不是只复刻完美演示
透明瓶与香蕉的多摆位 RGB-D 数据采集设计
透明瓶与香蕉的多摆位 RGB-D 数据采集设计
  • 香蕉的左、中、右、近端、远端位置。

  • 香蕉不同弯曲朝向和旋转角度。

  • 透明瓶直立、横放、斜放及不同标签朝向。

  • 两物体互相靠近、部分遮挡和交换相对位置。

  • 部署范围内不同强度和位置的桌面高光,以及透明瓶前后背景对比变化。

  • “先香蕉后瓶子”和“先瓶子后香蕉”两种成功顺序。

  • 从轻微偏差中修正抓取的示范,而不只是每次完美直线接近。

建议把高难样本单独做标记或至少记录 episode 清单,例如“瓶身与高光重叠”“瓶子横放且标签背向相机”“瓶子和香蕉部分遮挡”。后续模型失败时,才能判断缺的是哪类演示,而不是笼统地再采几十条相似数据。

同时保持这些条件稳定:

  • 相机安装位置和内外参。

  • 目标归位区域。

  • 任务文本。

  • 深度滤波模型、阈值和 250-1800 mm 可视化范围。

  • 采集 FPS 与关节校准。

这里的“保持稳定”不等于把灯光永久锁死。相机位置、滤波链路和任务定义应固定;照明和反光变化则应在实际部署可能出现的范围内受控采样。不要在采集时全部使用柔光哑光背景,却要求模型部署后突然面对镜面高光和透明瓶。

43 个 episode 足以完成一次基线训练,但对于两种物体随机摆放,尤其是透明瓶与高光关系不断变化的泛化仍偏少。第一轮实机评估后,建议根据失败区域补充 40-80 个有针对性的成功 episode,而不是只把旧数据训练更多轮。新增数据应优先补齐失败场景,避免数量增加了,视觉分布却几乎没有变。

05 / DOCUMENTATION 9.4 中断后继续采集

读取真实已保存数量:

代码块
Bash
cat /你的数据集/meta/info.json | python -m json.tool

假设目标 30 条,已经保存 7 条:

代码块
Bash
remaining=$((30 - 7))bash examples/rebot_b601_smolvla_record/record_b601_smolvla_rgbd.sh   --num-episodes "${remaining}"   --extra --resume=true

这里的 num_episodes 是“本次还要新增多少条”,不是最终总数。必须使用完全相同的 dataset root、repo id、FPS 和 feature schema。

06 / DOCUMENTATION 9.5 为什么每次保存完 episode,下一轮反而报错?

episode 边界会执行数据映射和 H.264 编码。早期 libx264 自动选择多个工作线程,可能造成 145-190 ms 的命令 gap;更严重时超过 0.5 秒。旧代码可能在下一次 _mark_episode_start_pose() 才报告上一轮已经锁定的 stream fault,看起来像“新 episode 一开始就坏了”。

当前解决方案:

  • PARALLEL_VIDEO_ENCODING=false

  • LEROBOT_VIDEO_ENCODING_THREADS=1

  • H.264 编码

  • 图像写入放到 1 个独立进程

  • 500 Hz MotorBridge 独立线程

  • 分离 50 ms 告警与 500 ms 硬故障阈值

07 / DOCUMENTATION 9.6 空 episode 不再让程序崩溃

如果操作者立即结束或安全故障发生在第一帧之前,旧代码会对空 buffer 调用 save_episode(),报:

代码块
纯文本
You must add one or several frames with add_frame before calling add_episode

当前记录流程会检测 buffer 大小,跳过空 episode,并清理临时图像。

08 / DOCUMENTATION 9.7 PyAV 的canonicalname 兼容问题

部分 ARM64 PyAV 版本的 codec 对象没有 canonical_name。当前代码按以下顺序兼容获取:

代码块
纯文本
canonical_name → name → long_name → str(codec)

因此不会再因为视频元数据字段差异让已经采完的 episode 在保存阶段失败。

09 / DOCUMENTATION 10.1 推荐分批采集

把不同批次保存到不同目录,先检查、删除明显失败的数据,再合并:

代码块
Bash
bash examples/rebot_b601_smolvla_record/merge_b601_datasets.sh

编辑脚本中的:

代码块
纯文本
SOURCE_ROOTSSOURCE_REPO_IDSOUTPUT_ROOTOUTPUT_REPO_ID

所有源数据必须具有相同 FPS、robot type、feature 名称、形状和 dtype。

10 / DOCUMENTATION 10.2 混合 15 FPS 与 10 FPS 不能只改 JSON

aggregate_datasets 会拒绝不同 FPS。不要只把 meta/info.json 的 15 改成 10,否则图像、状态、动作和时间戳会错位。

正确做法:

代码块
Bash
python examples/rebot_b601_smolvla_record/resample_b601_dataset.py   --source-root /home/r/datasets/rebot_b601_banana_bottle_rgbd_1   --source-repo-id local/rebot_b601_banana_bottle_rgbd_1   --output-root /home/r/datasets/rebot_b601_banana_bottle_rgbd_1_fps10   --output-repo-id local/rebot_b601_banana_bottle_rgbd_1_fps10   --target-fps 10

转换器会对腕部 RGB、全局 RGB、深度可视化、原始深度、状态和动作使用同一个源帧索引。

如果看到:

代码块
纯文本
No accelerated colorspace conversion found from yuv420p to rgb24

通常只是 FFmpeg 退回 CPU 颜色转换的提示,不代表转换失败。看最后是否生成完整数据和 metadata。

11 / DOCUMENTATION 10.3 图像 CHW/HWC 与深度 dtype

PyAV/TorchVision 可能返回 (3,H,W) float 图像,而数据集期望 (H,W,3);Hugging Face 载入深度时也可能临时表现为 int64。当前 resample 工具会:

  • 将图像恢复为元数据声明的 channel-last 格式再写入。

  • 将深度安全转换回 uint16。

12 / DOCUMENTATION 10.4ArrowTypeError: array[uint16]

原始深度是 Array2D(uint16) Parquet 列,不是视频。合并代码必须使用完整 schema 恢复这个扩展类型。当前实现通过显式 feature schema 和直接 Parquet I/O 处理,避免 PyArrow 把 NumPy dtype 误当成不支持的对象。

失败的 merge 会留下不完整输出目录。确认路径后移走或删除不完整目标,再重跑;源数据不会被修改。

13 / DOCUMENTATION 10.5 Hugging Face cache 把系统盘吃满

旧合并方法使用 Dataset.from_parquet() 时,可能在:

代码块
纯文本
~/.cache/huggingface/datasets

为每个源 Parquet 生成重复 Arrow 缓存,几十 GB 很快就没了。当前合并读取绕过这类重复缓存。

仍建议把 cache 放到数据盘:

代码块
Bash
export HF_HOME=/你的数据盘/huggingfaceexport HF_DATASETS_CACHE=${HF_HOME}/datasetsmkdir -p "${HF_DATASETS_CACHE}"

清理前先确认没有训练、合并或可视化进程使用缓存。不要用未经检查的递归删除命令指向变量路径。

硬件

软件应用和在线服务

实现步骤

01

配置采集参数

设置数据集 ID、相机键、深度格式、任务说明、episode 数量和保存路径

02

启动并监控采集

同时检查主从臂状态、RGB、增强深度、帧率、磁盘写入和安全告警

03

设计场景变化

覆盖物体位置、姿态、高光关系、遮挡关系、抓取顺序和轻微偏差后的纠正

物体摆位、遮挡与目标区变化设计
物体摆位、遮挡与目标区变化设计
04

验证断点续采

中断后检查已有 episode、索引和元数据,再从正确编号继续

05

清理无效 episode

移除空 episode、处理保存后下一轮报错并修复 PyAV canonical_name 兼容问题

06

分批合并数据

合并多批数据并处理 15/10 FPS 混合、episode 索引与时间戳

07

统一深度格式

修复 CHW/HWC、dtype、shape 和 ArrowTypeError,保持 uint16 深度语义

08

验证最终数据集

随机回放 episode,核对两路 RGB、深度、关节、夹爪和 action 对齐

项目结果

SmolVLA 高反光与透明物体抓取复现教程:方案总览与核心改造 · 第 5 阶段 项目结果
SmolVLA 高反光与透明物体抓取复现教程:方案总览与核心改造 · 第 5 阶段

得到可用于 SmolVLA 的合并 RGB-D 数据集,覆盖透明瓶、高光、遮挡、摆位和纠偏变化;完成断点续采、空 episode、混合帧率、CHW/HWC、dtype 和 Arrow 数据类型问题的修复。

Bladewin Smith
我成功复现了

评论

0 comments