我们要做的不是一只机械臂,是一个能读懂客人情绪和需求的机器人。 看见人、判断状态、开口对话、听懂他要什么、把那个东西拿给他——抓取是这条链路的最后一段。 这一页把整条链路摊开(第 0 节),然后回答:为了这个目标,现在该做什么、下一轮再做什么、各自多少钱。 时间有限,所以要分清演示的底线和加分项:左右手抓取的数据已经有了, 单纯用 SmolVLA 能把杯子抓起来,本身就已经撑得起一场演示。 深度定位和物体检测都是泛化用的,不是抓起来的前提,因此归入 Turn 2。
下面每一格都可以点开。注意最后两格才是这一页后面在讨论的东西—— 前面五格是这个机器人真正的主体,而且大部分已经在跑了。
← 左右滑动看完整条交互 →
| Turn 1 · 把杯子抓起来 | Turn 2 · 泛化 | |
|---|---|---|
| 目标 | 固定位置、固定那只杯子,稳定抓起 | 换位置也行 / 换杯子也行 |
| 需要什么 | 已经全部就位:202 集数据、已训好的 checkpoint、安全层、试跑流程 | 新代码 + 标定 + 可能要重录数据 + 重训 |
| 还差什么 | 只差跑对一次——09-04 那 0/3 的指令串和 speed 都填错了 | 见第 3 节 |
| 现场时间 | 约 30 分钟(10 次试跑) | 数小时到一天 |
| 钱 | 0 | 训练 $1–2,加上录制的人力 |
| 演示价值 | 这就是演示的底线,必须成 | 加分项 |
09-04 试跑 0/3,但在归因到「模型不行」之前,两个填错的输入框还没排除:
| 当时填的 | 应该是 | 为什么要紧 | |
|---|---|---|---|
| 任务指令串 | ...with the left arm. | ...with the right arm. |
现役模型训练集里只有右臂那一句。SmolVLA 是语言条件模型,换一句 = 换一个它没学过的任务 |
| speed | 0.3 | 1.0 | 把安全层步长上限乘了 0.3,轨迹实测削掉 shoulder_lift 的 11–20%——正是「放下去够杯子」那个关节 |
指令串这一项现在有硬拦截了(robot_server_dashboard.html:4841):不一致时直接阻止实跑启动。
但正确条件下的 10 次还没跑——截至 2026-09-04 23:28,最新记录仍是 09-04 18:33 那 4 次错误数据。
它们互补,不冲突,也不互为前提——可以只做一条:
| 换杯子(外观变,位置不变) | 换位置(同一只杯子挪走) | |
|---|---|---|
| 2A 深度 + 编码移动 | 深度对不透明杯都行 | ✅ 正是它解决的 |
| 2B 物体 token(B0) | ✅ 正是它解决的 | ❌ 架构解决不了 |
| 成本项 | 2A · 深度 + 编码移动 | 2B · 物体 token |
|---|---|---|
| 要写的代码 | 一个新脚本 guided_grasp.py。七步里五步是现成的(第 4 节),要写的只有坐标变换、退让距离、交棒时机 | object_proj + embed_prefix 的 append 分支,约 15 行,另加 pad/att mask |
| 标定 | ① 相机系→臂基座系:可用已录的 202 集离线拟合,0 现场时间(第 5 节) ② 深度相机内参:要现场拍棋盘,约 30 分钟 | 不需要任何标定 |
| 要不要重录数据 | 可能要——取决于第 7 节那个五分钟测试。 要的话:新建数据集,每集 3–5 秒,预计几十集,约 1–2 小时录制 | 不用。物体 token 从已录的 RGB 离线算 |
| 重训 | 要(新数据集)· 约 1.3 小时 / $1 | 要(object_proj 是随机初始化的)· 约 1.3 小时 / $1 |
| 算力(Jetson 每周期余量 337 ms) | 深度反投影几乎免费;在线不需要跑大检测器 | FT-DINOSAUR small@224 实测 52.4 ms ✅ 2026-09-05 本机实测,中位 52.4 / p95 53.8 / 显存 152 MB |
| 新增的失败模式 | 标定漂、深度对透明杯失效、检测锁错目标—— 这些原来都不存在,端到端是把它们一起学掉的 | slot 质量不佳时给出错误先验; 比没有先验更糟 |
| 最大的未知 | SmolVLA 能不能从预抓取位姿接上(第 7 节,未测) | 7 个 slot 有没有真的把杯子分出来(未过人工看图) |
Jetson Orin Nano 是 7.4 GB 统一内存(显存和系统内存是同一块)。 下面全部是 2026-09-05 在本机实测,不是估算。
| 加载什么 | 进程 RSS | torch 显存 | 单次耗时 | 系统仍可用 |
|---|---|---|---|---|
| 起点(只 import torch) | 490 MB | 0 | — | 3505 MB |
| + 几何路线(深度反投影 + IK) | +84 MB | 0 | 3.56 ms | 3475 MB |
| + FT-DINOSAUR small@224 | +705 MB | 138 MB | 52.4 ms | 3091 MB |
| + SmolVLA(450M 参数) | +1911 MB | 1023 MB | 1329 ms | — |
| 三者同时驻留 | 3190 MB | 1023 MB | — | 1844 MB |
GOAL-T1 里的头号未测项,现在关掉了。
| 路线 1 · 纯 SmolVLA Turn 1 | 路线 2A · 几何硬编码 + SmolVLA 收尾 | 路线 2B · 物体 token | |
|---|---|---|---|
| 怎么实现 | 已有:run_policy_trials.py 直接跑 checkpoint |
新脚本 guided_grasp.py:深度→3D→坐标变换→IK→安全层→send_action→交棒。七步里五步现成 |
模型内改动:object_proj + embed_prefix 的 append 分支,约 15 行 + mask |
| 额外内存 | 0(本来就要加载) | +84 MB,零显存 | +705 MB / 138 MB 显存(FT-DINOSAUR) |
| 额外耗时/周期 | 0 | +3.56 ms | +52.4 ms(预算 337 ms) |
| 现在能不能做 | ✅ 能,而且零成本 | ⚠️ 一半能:算出「杯子在相机系的 3D 坐标」现在就能跑;但还不能让手臂去那里——缺相机→臂基座的变换 | ⚠️ 输入端已验证(耗时 52 ms、7 个固定 slot、接近阶段纯度 2.7×),但接口代码还没写 |
| 还缺什么 | 只差跑对一次 | ① 相机→臂基座变换(可离线拟合,纯远程,见第 5 节) ② 深度相机内参(要现场拍棋盘约 30 分钟) ③ 第 7 节那个五分钟测试 |
① 写 object_proj(远程)② 重训一次 |
| 要什么数据 | 不要,202 集已有 | 标定不要新数据(用已录的 202 集拟合)。 但如果第 7 节测出「接不上」,要重录:新建数据集,每集 3–5 秒,预计几十集 |
完全不要。物体 token 从已录 RGB 离线算 |
| 成本 | 现场 30 分钟,¥0 | 远程:拟合标定几小时(含 OWLv2 跑几百帧,离线慢无所谓) 现场:内参 30 分钟 + 测试 5 分钟 若要重录:录制 1–2 小时 + 训练 1.3 小时 / $1 |
远程:写代码 + 训练 1.3 小时 / $1 无现场时间、无录制 |
| 新增失败模式 | 无 | 标定漂、深度对透明杯失效、检测锁错目标 | slot 不干净时给出错误先验 |
| 买到什么 | 固定位置稳定抓起 | 换位置 + 听懂点单(第 6 节) | 换外观 |
← 左右滑动看完整条链路 →
缺的是相机系 → 臂基座系的变换。09-04 试过棋盘格手眼,失败了——棋盘没夹在爪子上(远程给错了指示)。 但还有一条路,而且不需要再拍一张照片:
arm_kinematics.forward() → 臂基座系的 (y, z)
Pick up the cup with the right arm. task_index 0
Pick up the cup with the left arm. task_index 1
但它一共只见过这两句。喂它 Pick up the wine glass 就是分布外——
和 09-04 那个 left arm 错误是同一类问题,不是同一个程度的问题:它没有任何理由把新词映射到新行为。那为什么它的 VLM 主干「认识」高脚杯却不管用?
因为主干是冻结的(freeze_vision_encoder: True、train_expert_only: True),
训练时只有 action expert 在学,而它只在那两句指令上学过。语义知识在模型里,但没有通向动作的路径。
| 需要 | 代价 |
|---|---|
| 场景里同时放多只不同的杯子,用指令指定拿哪一只 | 重新设计录制场景 |
| 每种指令都要有足够的示范 | 数据量成倍增长(N 种杯子 × M 个位置) |
| 指令措辞要有多样性,否则只会背下固定几句 | 还要做指令改写/增广 |
这条路对我们的时间预算来说不现实。
wine glass / red cup 没测过,必须重新过逐框人工看图。depth-grasp.html 已有决策树)。结论:「用户说要什么就拿什么」是可以做到的,但它的能力来源是开放词表检测器,不是 SmolVLA。 这也反过来说明 2A 的价值——它不只是「换位置也能抓」, 它是让机器人能听懂点单的那条链路。
验证方法,五分钟,零标定、零代码:把手臂手动摆到预抓取位姿(相当于编码移动已跑完), 指令串用右臂那句、speed 1.0,启动策略,看它接不接得上。
| 结果 | 结论 |
|---|---|
| 能接上并抓住 | 2A 成立,且不用重录数据——成本立刻少一大块 |
| 动作不连贯 / 原地试探 | 起点确实分布外 → 必须按第 8 节重录(架构不变,数据要换) |
| 完全不动 / 乱动 | 先排查别的问题(指令串、speed、模型选择) |
| 现在的录制 | 2A 的录制 | |
|---|---|---|
| 每集怎么开始 | 手臂在归位姿态,从头遥操作 | 先由程序编码移到预抓取位姿,再开始遥操作 |
| 操作者做什么 | 整段:接近 → 对准 → 合爪 → 提起 | 只做最后一小段:微调 → 合爪 → 提起 |
| 每集时长 | 15–25 秒 | 约 3–5 秒 |
| 杯位 | 要变(靠它撑覆盖范围) | 要变,而且更宽——但目的从「教泛化」变成「验证编码移动到处都准」 |
| 指令串 | 右臂那一句 | 要换一句新的,单独建 tasks.parquet |
| 能不能和现有数据合并 | — | ❌ 不能,起始分布完全不同,必须新建数据集 |
| 相机 | 头 424×240 + 双腕 640×480 | 不变,但腕部相机重要性上升——定位交给深度后,策略主要看细节 |
# 03-software/scripts/guided_grasp.py (新文件,还不存在)
import arm_kinematics, policy_safety
from cup_locate_demo import locate_nearest # 已有:深度 → 相机系 3D
from v4l2_depth import DepthCamera # 已有:裸 V4L2 读 Z16
# ── ① 看:深度帧 → 杯子在相机系的 (X, Y, Z),毫米
with DepthCamera(DEPTH_NODE) as cam:
hit = locate_nearest(cam.read())
if hit is None:
return "没找到杯子" # ← 必须有这个分支,不许瞎猜
# ── ② 换坐标系:相机系 → 臂基座系 ★ 唯一缺的一环,见第 5 节
y_base, z_base = camera_to_base(hit.X, hit.Y, hit.Z)
# ── ③ 退一点:不要直接怼到杯子上,留出预抓取距离
y_pre = y_base - PREGRASP_BACKOFF_M # 需要实测确定
# ── ④ IK:(y, z) → 关节角 已有,且已绕开上游 FK/IK 不自洽的坑
lift, elbow = arm_kinematics.inverse(y_pre, z_base)
pan = pan_from_lateral(hit.X)
# ── ⑤ 安全层:和试跑用的是同一套 已有
target = policy_safety.clamp({... lift, elbow, pan ...})
# ── ⑥ 送到手臂:和 run_policy_trials 同一个原语 已有
robot.send_action(target)
# ── ⑦ 交棒:策略接管,只做最后的闭合与提起 ★ 未测,见第 7 节
run_policy(...)
| 结论 | 等级 | 来源 |
|---|---|---|
| IK 已有,且已绕开上游 FK/IK 不自洽(差 32.35°,过一遍偏 196 mm) | 读过源码 | arm_kinematics.py |
| 发关节目标的原语已有 | 读过源码 | XLerobot.send_action |
安全层已接 arm_kinematics | 读过源码 | policy_safety.py |
| 深度反投影已有,深度有效像素 0.88 | 实测 | cup_locate_demo.py / 09-03 评估 |
| OWLv2 对「cup」19/36 帧、100% 精度、1623 ms | 实测 | 36 帧逐框人工看图 |
| FT-DINOSAUR small@224 = 52.4 ms,出 7 个固定 slot(256 维) | 实测 | 2026-09-05 本机 train310,N=50 |
| 合并集含 left / right 两条指令 | 实测 | meta/tasks.parquet |
| 右臂横向覆盖 35.1° | 实测 | 合并集 202 集 |
| SmolVLA 能否从预抓取位姿接上 | 未测 | 第 7 节,2A 的前提 |
| 几何路线 +84 MB / 零显存 / 3.56 ms | 本机实测 | 2026-09-05,50 次平均 |
| FT-DINOSAUR + SmolVLA 可同时驻留,剩 1844 MB | 本机实测 | 2026-09-05,逐步加载测 RSS/显存 |
| FT-DINOSAUR 接近阶段纯度 2.7× 基线、覆盖率中位 94% | 实测 + 人工看图印证 | 9 帧,操作者判读与测量吻合 |
| 深度相机内参 | 未标 | 09-04 标的是彩色相机,不适用 |
| OWLv2 对「wine glass」等新词的效果 | 未测 | 只测过「cup」 |
| FT-DINOSAUR 的 slot 有没有分出杯子 | 未过人工看图 | 掩码图已生成,待核对 |
| 「几十集就够」 | 类比推断 | Depth Helps 的量级,非我们实测 |
Turn 1 零成本,只差跑对一次,那是演示的底线。 Turn 2 的两条路各解决一半泛化:2A 换位置、2B 换外观,都不是抓起来的前提。 而「用户说要高脚杯」这种交互,能力来源是开放词表检测器而不是 SmolVLA—— 它是 2A 的副产品。动 2A 之前,先花五分钟把手臂手动摆到预抓取位姿跑一次策略。