SmolVLA 高反光与透明物体抓取复现教程:方案总览与核心改造 · 第 7 阶段
基于双 奥比中光 相机、增强深度、B601-DM 主从臂和 SmolVLA,复现高反光桌面上透明瓶与香蕉模型的自主整理链路。
01 / DOCUMENTATION 内容概述
系列教程第 7/7 阶段:将 checkpoint 带回 Jetson,完成推理安全检查、动作队列调优、实机验证并记录当前成果边界。
02 / DOCUMENTATION 把训练模型带回 Jetson 开始推理 🚀

03 / DOCUMENTATION 12.1 需要复制什么?
从云端选择一个 checkpoint,比如只复制其中的:
checkpoints/014000/pretrained_model/推理不需要该 checkpoint 外层的 optimizer 和 training state。Jetson 还需要本地 SmolVLM2 config、tokenizer 和 processor 目录。
示例路径:
/home/r/models/rebot_smolvla_b601_14000/pretrained_model/home/r/models/SmolVLM2-500M-Video-Instruct04 / DOCUMENTATION 12.2 编辑推理脚本
脚本位置:
examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh检查:
POLICY_PATH="/home/r/models/rebot_smolvla_b601_14000/pretrained_model"VLM_PATH="/home/r/models/SmolVLM2-500M-Video-Instruct"FOLLOWER_PORT="/dev/ttyACM0"TOP_SERIAL="你的 Gemini 335L 序列号"WRIST_SERIAL="你的 Gemini 305 序列号"LINGBOT_MODEL="/home/r/ws/model.sm4"05 / DOCUMENTATION 12.3 首次运行
bash examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh也可以临时覆盖路径:
bash examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh --policy-path /home/r/models/rebot_smolvla_b601_14000/pretrained_model --vlm-path /home/r/models/SmolVLM2-500M-Video-Instruct启动日志中必须看到 EnhancedDepthFilter 已成功加载 model.sm4。推理时应继续使用采集阶段的 Gemini 335L 安装位置、置信度阈值和 250-1800 mm 深度可视化范围;不要为了临时“让图更好看”而单独调整部署端色彩映射。对于本项目,深度处理一致性就是模型输入契约的一部分。
首次推理默认只运行一个 30 秒 episode,并采用更保守的:
arm max_relative_target = 5°gripper max_relative_target = 15°multi-joint hold threshold = 20° requested deltasingle-joint hold threshold = 30° requested deltaautomatic recovery = falsen_action_steps = 10max_relative_target=5° 是真正限制每个控制周期运动量的硬限幅;后两项则只负责判断模型原始目标是否已经异常离群。SmolVLA 以动作块输出绝对关节目标,动作块切换时可能出现中等幅度跳变,因此推理脚本允许这些目标先经过 5° 限幅平滑追踪,只在至少两个关节同时相差 20°,或任一关节相差 30° 时进入 safety hold。遥操采集仍保留原来的比例判据,二者不会互相改变。
开始前将从臂放在训练数据常见的安全初始姿态,托住机械臂并准备急停。不要因为第一次触发安全限幅,就直接把 max_relative_target 恢复到采集时的 12°/30°。看到 target was slew-limited ... continuing with bounded commands 只表示平滑限幅正在工作,不等于电机故障;看到 safety hold active 才表示模型目标越过了独立停机阈值。
06 / DOCUMENTATION 12.4 推理时为什么关闭夹爪映射?
采集流程保存的是 robot.send_action() 后真正下发到从臂的动作,因此模型学习的是从臂夹爪坐标。如果推理时再执行一次 leader → follower 映射,夹爪会被二次换算,开合就会失真。
所以:
遥操采集: gripper_map_leader_to_follower = true策略推理: gripper_map_leader_to_follower = false07 / DOCUMENTATION 12.5 三个检查点都要测
建议准备固定编号的 20 组随机摆放,并按普通反光、强高光靠近瓶体、瓶身与高光重叠、透明瓶横放、两物体互相遮挡等条件分层。每个 checkpoint 都使用完全相同的场景编号,分别评估:
-
完整任务成功率。
-
香蕉归位成功率。
-
可乐瓶归位成功率。
-
高反光条件下透明瓶归位成功率。
-
瓶体首次定位成功率与抓取前重定位次数。
-
安全中止次数。
-
平均完成时间。
如果 10,500 比 14,000 更好,就使用 10,500。更低的训练 loss 不一定意味着更好的真实泛化。
当模型看得对但纠偏太慢,可以尝试:
bash examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh --n-action-steps 510 FPS 下,n_action_steps=10 约等于执行 1 秒后重规划;改成 5 会更频繁推理,但 Jetson 的计算压力也会增加。
08 / DOCUMENTATION 12.6 最新实机推理记录:链路跑通,不等于任务跑通
我在 14,000 step checkpoint 上进行的一次阶段性测试使用了:
episode_time_s = 300fps = 10n_action_steps = 20max_relative_target = 3°multi-joint hold threshold = 20°single-joint hold threshold = 30°程序实际连续运行约 106 秒后安全退出。调试日志显示:
-
Gemini 305 RGB、Gemini 335L RGB-D 和 EnhancedDepthFilter 全程正常,没有相机读帧超时。
-
设备内许可校验成功,
model.sm4与置信度阈值51正常生效。 -
MotorBridge 500 Hz 命令流没有连续发送失败,所有电机保持
ENABLED,没有驱动器故障。 -
日志节流后仍记录到 64 条
target was slew-limited,说明实际发生的限幅次数只会更多。 -
joint_2和joint_3最常进入限幅,记录到的最大目标差分别约为22.48°和22.95°。 -
夹爪两次进入接触保持,又两次被策略的张开动作释放。接触位置约为
-213.60°和-215.13°。 -
最终
joint_2从当前位置-100.38°收到-69.86°目标,差值30.52°,越过单关节30°阈值后触发 safety hold。
这份日志证明视觉、模型、电机流和安全保护已经组成可持续运行的在线链路;但大量持续限幅也说明策略尚未形成稳定的闭环跟随。尤其要注意:最后的 joint_2 目标是在从较低位置返回关节中部,方向本身不一定危险。它更可能反映了“旧动作队列 + 从臂受限后未能及时跟上”造成的状态差,而不能简单归结为电机、相机或奇异点故障。
09 / DOCUMENTATION 12.7 为什么nactionsteps=20 在这里容易积累误差?
SmolVLA 的 select_action() 会在动作队列清空时才重新运行模型。10 FPS 下执行 20 个动作,名义上相当于约 2 秒开环窗口;模型推理本身还会占用时间,实际重新观察场景的间隔可能更长。与此同时,部署端把关节每周期变化限制为 3°,远比采集阶段保守。于是可能形成:
模型一次预测较长动作块 ↓从臂每周期只能追赶 3° ↓动作队列继续执行基于旧观察的未来动作 ↓真实姿态逐渐落后于队列目标 ↓持续限幅,最终触发大目标差 safety hold因此,不能通过无限提高 30° 阈值来掩盖问题。下一轮应先固定场景和初始姿态,把测试缩短到 60 秒,并使用:
bash examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh --episode-time-s 60 --n-action-steps 5 --max-relative-target 3 --safety-hold-multi-joint-delta 20 --safety-hold-single-joint-delta 30若方向正确且没有 safety hold、只是动作明显偏慢,再保持 n_action_steps=5,依次单独测试 max_relative_target=4 和 5。每次只改变一个变量,避免把 checkpoint、动作窗口和速度限制同时调整后无法判断原因。
10 / DOCUMENTATION 12.8 透明瓶抓取仍未成功
在我的调试日志中, gripper contact detected 显示夹爪满足了“已经闭合一段距离、速度较低、达到接触判据”,随后控制器切换到有界保持力矩。它不能证明透明瓶已经位于两指之间,更不能证明瓶子在抬升、搬运和放置过程中没有滑落。当前仍缺少:
-
对“空夹桌面、夹到瓶身、夹到瓶盖、夹偏后滑脱”的区分。
-
抓取后抬升阶段的视觉或状态成功判定。
-
高光与瓶身重叠、瓶体横放或斜放等难例的足量成功演示。
-
7,000、10,500、14,000 checkpoint 在同一批测试场景上的量化对比。
-
对夹爪两次接触、两次释放究竟是正常任务阶段还是策略抖动的录像复核。
透明瓶抓取也不只是视觉问题。瓶体可能变形、表面摩擦小、两指接触面窄;即使 RGB 与增强深度定位正确,接近角度、夹爪软垫、闭合速度和保持力矩仍会决定它是否滑落。后续优化应把“看见透明瓶”“对准抓取点”“形成稳定夹持”“抬升验证”“搬运并释放”分别统计,而不是只记录最终完整任务成功或失败。
到这里,我们完成的是从官方基线改造、硬件接入、重力补偿遥操、RGB-D 采集、数据合并、云端训练,到 Jetson 启动并持续运行训练模型的工程闭环。真正的任务闭环,也就是在高反光环境中稳定抓取透明可乐瓶并完成归位,目前仍处于部署微调与补充验证阶段。🛠️
11 / DOCUMENTATION 高频故障速查表 🧯
| 现象 | 常见原因 | 处理办法 |
|---|---|---|
| 所有 DM 电机握手失败 | 把 MotorBridge 当 can0、端口错、24 V/急停/线束问题 | 使用 /dev/ttyACM* + transport=motorbridge,检查供电与端口归属 |
python-can not installed 但 pip 已安装 | CLI 入口来自其他 Python 环境 | which lerobot-setup-can、which python,重新 editable install;MotorBridge 场景通常不需要该 SocketCAN 工具 |
Draccus 无法解析 Literal['motorbridge','socketcan'] | 当前 draccus 版本不支持该 Literal decode | 使用本项目中改为 str 的 transport 配置,并通过运行时校验取值 |
| Orbbec 图像是绿色噪点 | 打开了深度/IR/原始 UVC 节点 | 使用 OrbbecSDK 序列号和 C++ bridge,不使用未验证的 /dev/video* |
Export.h 找不到 | 忘了 SDK generated include | 传 ORBBECSDK_GENERATED_INCLUDE_DIR |
Config has no member enableDevice | SDK v2 API 与旧示例不同 | Context 枚举设备,再用 Pipeline(device) |
| bridge magic mismatch | SDK 日志污染二进制 stdout | 日志只写 stderr,stdout 只传帧包 |
| Gemini 305/335L 超时 | 设备占用、USB 带宽/供电、序列号错误、warmup 太短 | 单相机测试,关闭其他进程,分离 USB 3,使用 15/25 秒 warmup |
| 透明瓶在原始深度中局部消失 | 透射、折射、背景穿透导致测量无效或跳变 | 这是透明材质的物理难点;启用并验证 EnhancedDepthFilter,同时依赖 top/wrist RGB,不要用插值伪造“完美深度” |
| 增强深度在高光处仍有孔洞 | 镜面反射、入射角或过曝造成有效信息不足 | 调整相机/灯光到部署允许范围,检查曝光与对齐,补采对应难例;滤波不能恢复完全缺失的测量 |
| 训练正常但遇到高反光桌面就失败 | 采集数据大多来自哑光或固定光照,难场景覆盖不足 | 按高光位置、瓶体姿态和遮挡关系分层补采,并保持采集与推理的滤波参数一致 |
License not yet valid 2003 | Jetson 时间回到 1970 | 修复 RTC/NTP/系统时间,保留设备内官方许可校验 |
| 主臂难拖动 | 重力补偿方向/倍率、kp/kd 或机械摩擦 | 先 dry-run,逐关节调试;使用已验证参数,不盲目加力矩 |
| 主臂夹爪突然自行张大 | 辅助力矩或位置增益过大 | force_assist、kp=kd=0、open bias 0.09、limit 0.15 |
| 从臂夹爪行程不足 | 端点映射或相对限幅错误 | 先直接命令验证 -330→10,再标定 leader/follower endpoint |
| 从臂夹住物体后 gripper 失能 | 高 kp 持续堵转、机械或线束问题 | 使用限力闭合和柔和接触保持,检查机构,不要只增大力矩 |
| 从臂突然多个关节失能 | 命令 gap、电源、急停、MotorBridge、数据线受压 | 查 gap 时间关系;独立电源、线缆应力释放、同步采集系统日志 |
| 下一 episode 开始时报 stream fault | 上一个 episode 编码造成已恢复但被锁定的 gap | H.264 单线程、串行编码、500 Hz 独立命令流、0.5 秒硬阈值 |
save_episode 提示没有 frame | 第一帧前退出或故障 | 当前代码跳过空 buffer;不要手工伪造 episode |
PyAV 没有 canonical_name | ARM64 PyAV API 差异 | 使用兼容 codec 名称回退逻辑 |
| 合并提示 FPS 不一致 | 分批使用 15/10 FPS | 真正重采样到 10 FPS,不能只改 metadata |
array[uint16] ArrowTypeError | 深度扩展类型丢失 | 使用当前直接 Parquet + 显式 schema 合并代码 |
~/.cache/huggingface/datasets 爆满 | 合并产生重复 Arrow cache | 用当前 merge 实现,把 HF cache 放数据盘,谨慎清理闲置 cache |
| 云端训练仍加载旧代码 | editable install 指向原机器绝对路径 | 在云端重新 pip install -e ".[smolvla]" 并检查 lerobot.__file__ |
| 离线训练仍访问 Hub | 只上传 smolvla_base,VLM/tokenizer 路径未覆盖 | 同时上传 SmolVLM2,并传 --vlm-path、设置 offline 环境变量 |
推理报 No module named transformers | Jetson 环境只安装了基础 LeRobot,未安装 smolvla extra | 按仓库约束安装 SmolVLA 依赖;不要直接安装无约束的最新版 transformers |
| 安装 transformers 后 Hub 版本冲突 | 无约束安装了 transformers 5.x,并把 huggingface-hub 升到 1.x | 降回 transformers>=4.57.1,<5.0.0、huggingface-hub>=0.34.2,<0.36.0,再运行 python -m pip check |
tokenizer 报云端绝对路径 HFValidationError | checkpoint 的 policy_preprocessor.json 保存了训练机上的 /root/gpufree-data/... 路径,Jetson 上不存在 | 同步本项目最新版 src/lerobot/policies/factory.py,并传正确 --vlm-path;factory 会在内存中覆盖 tokenizer 路径,不必修改 checkpoint JSON |
推理启动即提示 dataset name 不以 eval_ 开头 | LeRobot 要求带 policy 的评估数据集在命名空间后的名称以 eval_ 开头 | 使用 local/eval_rebot_b601_smolvla_时间戳;当前推理脚本已按此生成并提前校验自定义 --repo-id |
| 推理夹爪开合错误 | 模型输出被再次做 leader→follower 映射 | 推理设置 gripper_map_leader_to_follower=false |
推理启动时夹爪反馈超出 -330..10° | 夹爪被断电移动到训练坐标范围之外,或零位与采集阶段不一致 | 不要直接放宽限位;先恢复到训练使用的夹爪坐标并检查校准。当前启动保护会在使能前拒绝运行 |
推理中提示 target was slew-limited | 策略绝对目标与当前位置有中等差值,但仍低于异常停机阈值 | 这是受控的 5°/周期 平滑追踪;观察是否很快收敛,并检查运动方向是否合理,无需立刻放宽硬限幅 |
推理中提示 safety hold active | 至少两个关节目标差达到 20°,或一个关节达到 30°;常见于异常初始姿态、动作块离群或模型泛化不足 | 保持托举并检查日志中的 requested_delta;先换回训练常见初始姿态,可比较 --n-action-steps 5。不要直接关闭 safety hold;只有充分验证后才分别调整 --safety-hold-multi-joint-delta 和 --safety-hold-single-joint-delta |
使用 n_action_steps=20 后长期出现限幅 | 10 FPS 下连续执行约 2 秒旧动作,同时较小的关节步长使真实姿态落后于预测队列 | 先降到 n_action_steps=5,固定场景运行 60 秒;方向正确但偏慢时,再逐级把关节步长从 3 调到 4、5,每次只改一个变量 |
日志显示 gripper contact detected,但透明瓶没有被抓起 | 接触检测只证明夹爪遇到阻力,也可能夹到桌面、瓶边或发生偏夹 | 结合 wrist RGB 和录像复核接触位置;分别统计对准、闭合、抬升、搬运成功,不要把接触事件直接算作抓取成功 |
12 / DOCUMENTATION 复现时请牢记的安全原则 ❤️
-
从臂运动、恢复、异常退出时都必须有人准备托住机械臂。
-
驱动器异常后不自动重新使能,先查明电源、通信或机械原因。
-
不通过关闭状态检查、无限提高力矩或放大安全阈值来“让报错消失”。
-
电机问题和视觉问题分开测试;单模块稳定后再叠加负载。
-
数据线走线属于安全系统的一部分,不是最后才整理的附件。
-
透明物体抓取尤其需要多样化数据和保守速度,不要仅凭训练 loss 宣布成功。
13 / DOCUMENTATION 关键代码入口 📚
| 功能 | 文件 |
|---|---|
| Orbbec Python 相机 | src/lerobot/cameras/orbbec/camera_orbbec.py |
| Orbbec 相机配置 | src/lerobot/cameras/orbbec/configuration_orbbec.py |
| Orbbec C++ bridge | src/lerobot/cameras/orbbec/cpp/orbbec_rgbd_bridge.cpp |
| Bridge CMake | src/lerobot/cameras/orbbec/cpp/CMakeLists.txt |
| B601-DM follower | src/lerobot/robots/rebot_b601_follower/ |
| B601-DM leader | src/lerobot/teleoperators/rebot_b601_leader/ |
| MotorBridge 命令流 | src/lerobot/motors/rebot_motorbridge.py |
| SmolVLA 深度过滤 processor | src/lerobot/policies/smolvla/processor_smolvla.py |
| 数据采集安全与重采 | src/lerobot/scripts/lerobot_record.py |
| 数据采集脚本 | examples/rebot_b601_smolvla_record/record_b601_smolvla_rgbd.sh |
| 数据合并脚本 | examples/rebot_b601_smolvla_record/merge_b601_datasets.sh |
| FPS 重采样 | examples/rebot_b601_smolvla_record/resample_b601_dataset.py |
| 云端训练脚本 | examples/rebot_b601_smolvla_record/train_smolvla_local.sh |
| Jetson 推理脚本 | examples/rebot_b601_smolvla_record/infer_b601_smolvla_rgbd.sh |
| 从臂只读状态检查 | examples/rebot_b601_smolvla_record/debug_follower_state_readonly.py |
| 从臂夹爪单独置零 | examples/rebot_b601_smolvla_record/zero_follower_gripper_at_closed.py |
14 / DOCUMENTATION 当前成果边界与后续工作 🧭
目前,本项目进展如下:
| 模块 | 当前状态 | 说明 |
|---|---|---|
| B601-DM 同型号主从臂遥操 | ✅ 已实机验证 | 主臂重力补偿、夹爪微力辅助、从臂位置映射可用于采集 |
| MotorBridge 独立命令流与故障保护 | ✅ 已实机验证 | 500 Hz 保活、状态检测、异常保持和安全退出已覆盖多轮故障排查 |
| Gemini 305 + Gemini 335L C++ bridge | ✅ 已实机验证 | 腕部 RGB、全局 RGB-D 可同时稳定接入 |
| EnhancedDepthFilter 与设备许可 | ✅ 已实机验证 | 设备内许可、model.sm4、对齐深度和 Python 数据包链路已运行 |
| RGB + 增强深度 LeRobot 数据集 | ✅ 已完成 | 43 episodes、18,392 frames、10 FPS,已完成重采样、合并和格式修复 |
| RTX 4090 SmolVLA 训练 | ✅ 已完成基线 | 14,000 steps 稳定收敛,生成多个可部署 checkpoint |
| Jetson Orin NX 在线模型推理 | 🟡 已进入微调 | 已连续运行约 106 秒,硬件链路稳定,动作窗口与限幅仍需调优 |
| 香蕉随机摆放归位泛化 | 🟡 尚未完成量化 | 需要固定测试矩阵比较 checkpoint 和失败类型 |
| 高反光环境透明瓶稳定抓取归位 | ❌ 尚未稳定实现 | 当前不能声称已经达到可重复成功,需要补采难例并完善闭环抓取验证 |
| 无人值守生产部署 | ❌ 不在当前完成范围 | 仍需推理时序监控、故障环形日志、工作空间保护和长期可靠性测试 |
建议后续工作按下面顺序推进:
-
用
n_action_steps=5和max_relative_target=3/4/5完成单变量实机对比。 -
在相同初始姿态和物体摆放下比较 7,000、10,500、14,000 checkpoint。
-
把透明瓶任务拆成定位、对准、闭合、抬升、搬运、释放六个可观察阶段,记录每阶段失败率。
-
针对失败最多的高光位置、透明瓶姿态和遮挡关系补充 40-80 个高质量成功 episode。
-
为部署循环增加实际 FPS、单次推理耗时、动作队列年龄和连续限幅时长统计。
-
对越阈动作采用“保持当前位置、清空旧动作队列、立即重规划;连续异常才停机”的二阶段策略。
-
增加抓取后抬升确认,并结合 wrist RGB 判断空夹、滑落和稳定持有。
-
检查夹爪指面材料、接触宽度和瓶体变形,避免把机械抓取问题全部归因于模型。
项目因为当前工作时间安排先停在这里,但阶段性结果仍然有价值:它已经把一条涉及 DM 主从臂、双 Orbbec 相机、受许可保护的增强深度、LeRobot 数据格式、云端训练和 Jetson 部署的复杂链路跑通,并留下了真实失败日志与安全边界。后续复现者可以从部署微调继续前进,而不必重新踩完前面的坑。🌱

15 / DOCUMENTATION 参考资料与致谢 🙌
感谢 Seeed Studio、奥比中光、Hugging Face LeRobot 及开源社区提供的机械臂、相机 SDK、模型与工程基础。本文中的 EnhancedDepthFilter 模型、扩展库和设备许可应遵守奥比中光对应版本的授权与分发要求。
这套系统远没有“按一下运行键就永远稳定”那么简单,欢迎继续补充更精确的电源、MotorBridge、线束和性能诊断结果,让这个项目从“能够复现”继续走向“稳定、可靠、可扩展”。🌈
硬件
软件应用和在线服务
实现步骤
复制部署文件
将选定 checkpoint、SmolVLM2 配置、tokenizer 和 processor 复制到 Jetson
配置推理脚本
核对模型路径、设备、相机键、动作维度、归一化统计和本地离线模式
执行首次安全运行
使用训练常见初始姿态、物理支撑和急停,先观察动作方向与限幅

关闭二次夹爪映射
推理输出已是从臂坐标,不再应用主臂到从臂的夹爪映射
比较多个检查点
在同一组分层测试场景中比较 7000、10500 与 14000 step
区分链路跑通与任务跑通
分别记录相机、模型、动作队列、机械臂执行和最终抓取结果
调整 n_action_steps
在响应速度、动作平滑度与误差积累之间比较不同动作队列长度
记录透明瓶失败边界
分析深度孔洞、高光重叠、视角、演示覆盖、夹爪接触和安全限幅
汇总当前成果与后续计划
明确已经完成的链路、尚未成功的场景及下一轮数据和机械改进

项目结果

已跑通 B601-DM 重力补偿遥操、双 Orbbec 相机与增强深度、LeRobot 数据集、RTX 4090 训练和 Jetson Orin NX 推理链路。当前透明瓶抓取仍未达到稳定成功,教程如实保留动作限幅、深度孔洞、演示覆盖和机械接触等失败边界,供后续阶段继续改进。