← reports index
上机实测 · 2026-09-10

chunk 1/1 实测:右臂从 0/14 变成 3/7

把右臂的执行配置逐字段对齐左臂(只差 chunk_rate 一个字段),跑了 7 次。结果既不是「修好了」也不是「没用」—— 它把横向增益从 0.6 提到 0.85,但成败真正取决于杯子放在训练数据密的地方还是疏的地方。

先标清楚这轮的证据等级。脚本自己打了这行:No pre-registration — this run counts as EXPLORATORY only and must not be used for conclusions。 7 次的 95%CI 是 14.7–94.7%,宽到几乎不排除任何东西。下面所有数字都要按探索性读,不能当结论引用。

一、七次的结果

#杯位档该档在 0826 里的集数结果闭爪 pan夹爪开合
1P43失败−3.2°0
2P43失败−1.2°0
3P2.513–15成功−12.5°1
4P2.513–15成功−9.2°1
5P215成功−25.0°1
6P15失败−27.0°1
7P4/P4.52–3失败−3.7°0
按数据密度分开看,分得非常干净:
数据密的档(P2 / P2.5,13–15 集):3 / 3 全成
数据疏的档(P1 5 集、P4 3 集、P4.5 2–3 集):0 / 4 全败
这个对比在本轮内部是干净的 —— chunk 配置全程不变,唯一变的是杯子放哪。

二、chunk 1/1 到底改了什么

09-08 auto/k=409-10 1/1
控制回路4.20 Hz6.1–11.3 Hz
推理停顿占时长46%19–26%
横向增益(闭爪 pan 对杯位回归斜率,示范隐含 1.0)0.59–0.630.85 r=0.923
k/n0/143/7
成功 失败 虚线 = 完美跟随(增益 1.0)
它跟得住杯子,但一律偏向同一侧 -40° -20° 0° -40° -20° -2° 杯子放在哪(档中心) 闭爪时的 pan P4:杯位约 -8.5°,闭爪 pan -3.2°,失败 P4:杯位约 -8.5°,闭爪 pan -1.2°,失败 P2.5:杯位约 -22.0°,闭爪 pan -12.5°,成功 P2.5:杯位约 -22.0°,闭爪 pan -9.2°,成功 P2:杯位约 -26.5°,闭爪 pan -25.0°,成功 P1:杯位约 -35.5°,闭爪 pan -27.0°,失败 P4/P4.5:杯位约 -4.0°,闭爪 pan -3.7°,失败
七个点都落在虚线上方——闭爪时的 pan 一律比杯子所在的角度偏正,平均偏 +6.5°。斜率 0.85 说明它会跟,但整体带一个固定偏置。注意成功的三个点(绿)并不是误差最小的:绿点误差中位 9.5°,红点反而只有 6.3°。

三、推翻了两个我们都以为对的判断

①「转不够是失败原因」不成立。成功三次的横向误差中位 9.5°,失败四次 6.3° —— 失败的那几次瞄得更准。现场观察到的「偏右 / 偏左」是真的(一律偏正 +6.5°),但它不是这七次里决定成败的那一项。
②「推理停顿是主因」不成立。停顿从 46% 降到 19–26%,前进有效率却几乎没动(失败 12.9%/14.5%,成功 18.3%/13.2%)。停顿确实拖慢了它,但不是它抓不到的原因。
失败的四次里三次夹爪 0 次开合(成功三次全是 1 次)。在 P4 那三次,它从头到尾没闭过爪。
★ 2026-09-11 更正 ★ 这一段原来写的是「不是瞄歪了所以夹空,而是根本没做出『该夹了』这个决定」。写反了,已撤回。

撤回的理由有两条。第一,原来的论据本身是坏的:我拿「闭爪时 pan 的误差」做比较,但那三次根本没有闭爪时刻 —— 检测规则在夹爪始终没跌破峰值一半时会退化成「夹爪开度峰值往前数 8 帧」,那是够取途中的任意一帧,和抓取无关。拿它算出的「失败误差 6.3° 比成功的 9.5° 还小」不成立。
第二,直接看图就清楚了(下面六张 end 关键帧):三次失败里杯子全部在爪外,一次都没进到两指之间;三次成功里杯子都在两指之间。
失败 · 杯子在爪外 成功 · 杯子在两指之间
P4 失败:夹爪停在杯子左边
P4 失败
P4 失败:夹爪停在杯子左边
P4 失败
P4/P4.5 失败:夹爪贴着杯子但在左侧
P4/P4.5 失败
P2.5 成功:杯子在两指之间
P2.5 成功
P2.5 成功:杯子在两指之间
P2.5 成功
P2 成功:杯子在两指之间
P2 成功
每次试跑结束时的头部画面。上排三次失败,夹爪一律停在杯子左侧,杯子从没进到爪口里;下排三次成功,杯子就在两指之间。第三张(P4/P4.5)最能说明问题:爪子已经贴到杯子旁边了,但仍然偏在左边。
正确的因果链(操作者 2026-09-11 指出):
瞄歪 → 杯子始终没进到两指之间 → 腕部相机看不到「该夹的东西」→ 不闭爪。

「夹爪 0 次开合」是瞄歪的下游症状,不是一个独立的失败原因。而且这么看,腕部相机的行为是对的 —— 爪口里没有杯子,本来就不该闭爪。下面的消融显示闭爪决定 73% 来自右腕相机,两件事是一致的:它在正确地执行「没看到就不夹」。
那为什么用 pan 算出来失败的误差反而更小?因为「档中心」这把尺子太粗。操作者的 P 标号是桌面上的摆位,而档中心是从示范的闭爪 pan 反推的区间,两者不是同一把尺子。而在 20 cm 的伸出距离上,1° pan ≈ 0.35 cm 指尖位移 —— 几度之差对「杯子在不在爪口内」是决定性的,而这个尺度正好落在换算误差里。所以这轮的 pan 误差数字不能用来判成败,只有图能判。

四、现场观察到的两个方向,其实是同一件事

操作者在 P1(杯子在最左)报「明显靠右」,在 P4/P4.5(杯子偏右)报「偏左,把杯子往更左推」。看着矛盾,量出来是一致的:闭爪 pan 一律比杯位偏正 +6.5°,而 0826 训练集的杯位中位是 −22.1°、最密档是 −31~−22°。

档位到角度的换算是近似的。操作者的 P 标号是桌面上的实际摆位,而这里的「档中心」取自录制指南按示范闭爪 pan 划的区间。两者不是同一把尺子,所以 +6.5° 这个偏置里有多少是真实偏置、有多少是换算误差,这轮分不开。斜率 0.85 受这个影响较小,偏置受影响较大。

四·四、操作者的第二个症状:「抓夹开得太大」

现场反复观察到夹爪张得过大。量下来幅度没问题,问题在时长:

接近段最大张开张开状态占整集时长(开度 > 30)
示范 0826(40 集)43.622.5%
成功 3 次42.1 – 47.213.8% · 14.2% · 14.4%
失败 4 次40.1 – 48.375.0% · 55.8% · 73.7% · 64.8%
张开幅度是对的(试跑中位 42.5 vs 示范 43.6,0.97×),张开时长完全不对:失败时爪子有大半场是张着的,示范只有 22.5%、成功只有 14%。成功和失败在这一列上零重叠 —— 这是本轮分得最干净的指标,比前进有效率和 pan 误差都干净。
而它和上面那条因果链是同一件事的两端:
瞄歪 → 杯子进不了爪口 → 腕部相机拿不到「该夹」的信号 → 爪子一直张着 → 张开的外指把杯子推走。
操作者报的两个症状(「pan 不到位」和「抓夹开太大」)不是两个独立问题,是同一条链的首尾。
操作者进一步的判断(2026-09-11):「它学会了要在爪口里看到杯子再合上」。

如果成立,这不是缺陷,而是这个模型学到的最好的一件事 —— 闭爪是被视觉真正门控的,不是数拍子的条件反射。这也和消融一致(闭爪 73% 来自右腕相机)。
它把「要修什么」也改了:不需要去动夹爪策略;要修的是瞄准,让这个前提能被满足。爪子张着不合,是它在正确地等一个没出现的条件。
但这一条目前在数据上证不了 —— 试跑只存头部画面。
要判定「腕部画面里杯子在不在两指之间」,就得有腕部帧,而 run_policy_trials.py:1703 只把 observation.images.head 交给关键帧采集器,两路腕部图直接丢掉。

已修(2026-09-11):trial_keyframes.KeyframeCollector.observe() 增加可选的 wrists 参数, 在 init / closure / end 三个时刻额外写干活那条臂的腕部帧 (kf-…-{phase}-wrist.jpg,记录里对应 wrist_init / wrist_closure / wrist_end)。 不传 wrists 时行为逐字节不变,模块自带 selftest 仍然通过;新路径也单独验过,六个文件都写出来了。
下一轮跑测就能直接判这条假设:把失败那几次的 wrist_end 调出来看杯子在不在爪口内。

四·五、腕部相机到底学没学会看

操作者的判断是「大概率是腕部相机没学会看」。用 camera_ablation.py 直接量 —— 把某一路换成中性灰,看输出变多少,取样点是示范里闭爪的前一帧(问的是「闭爪这个决定是看着什么做出来的」)。12 集,中位绝对变化:

遮掉哪一路Δ夹爪(行程 %)Δpan(度)Δelbow(度)
left_arm_wrist3.700.827.16
right_arm_wrist11.731.022.21
head6.389.7618.58
全部三路16.1019.0659.48
分工是清楚的,而且不是「没学会看」。
右腕相机 → 闭爪决定。遮掉它夹爪输出变 11.73,三路里最大,占「遮掉全部三路」总影响(16.10)的 73%。
右腕相机 → 横向几乎无关(Δpan 仅 1.02)。转向靠头部(Δpan 9.76 / Δelbow 18.58)。

把这一页所有观察串起来就自洽了:

  1. 横向瞄准靠头部相机 —— 所以增益 0.85、r=0.923,它确实在看、跟得住;
  2. 闭爪决定几乎全靠右腕相机;
  3. 四次失败里三次是夹爪 0 次开合 —— 但那是因为瞄歪了、杯子从没进到爪口(见上面六张 end 关键帧),腕部相机看不到该夹的东西,于是正确地没有闭爪。
所以「腕部相机没学会看」这个说法要修正 —— 消融显示它确实在被用,而且主导闭爪。这一轮失败里它的表现是正确的:爪口里没杯子就不闭。坏掉的是横向瞄准那一路(头部相机 + 数据覆盖),腕部只是忠实地反映了「没够到」这个事实。
这个消融有一个限制。取样点是 0826 训练集里的闭爪帧,量的是「在训练数据上各路相机权重多大」,没有直接测失败的那几个杯位。想分档做消融,0826 在 P4 只有 3 集,样本量不够。等 73 集重训之后可以按档重做一次。

四·六、试跑的腕部相机改成 MJPG(2026-09-10 已改)

录制那条路(leader_follower_server.py:410)09-09 起就显式设了 fourcc="MJPG",而试跑这条路(run_policy_trials.py)一个 fourcc 都没传,于是 OpenCV 协商出 YUYV。两条路的相机设置本来就该一致,已改齐。

cams = ({name: OpenCVCameraConfig(index_or_path=path, width=w, height=h, fps=30,
                                  fourcc=None if name == "head" else "MJPG")
         for name, (path, w, h) in CAMERAS.items()} if cameras else {})

头部保持 None:它是 USB3 上的 Orbbec,不在腕部那条 USB 2.0 总线上;而且 robot_server.py:938 记着,对 Orbbec 的 RGB 节点 set(FOURCC, MJPG) 会「返回成功」但之后每次 read() 都抛 !buf.empty() in imdecode_。

但要说清楚:这个改动不能解释失败。当场做了 A/B,两路腕部相机同时开、各读 40 帧:

两路同开实际格式读成功每路 fps
不设 fourcc(旧行为)YUYV80/8026.5
MJPG(改后)MJPG80/8030.0
YUYV 下也是 26.5 fps、一帧不丢。所以「腕部帧被带宽饿着、发旧」这条不成立。
改它的理由是别的:对齐录制配置、给 USB 2.0 总线留出带宽(LF 那边记着两路 YUYV 会把同 hub 的键鼠饿死)、拿到满 30 fps。该改,但别把它当成失败的原因。

五、下一步该做什么

用 73 集合并数据重训,配方一个字不动。失败的四个位置正是补录补上的那几档:
P1 5 → 11 集 · P4 3 → 11 集 · P4/P5 2 → 10 集。
而这轮已经证明:在有 13–15 集的位置,同一个模型、同一套执行配置能连成三次。

重训后的跑测指令(已按本轮结果更新)

# ① 训练(4090,配方与前两次逐字段相同,只换数据集)
REPO_ID=xlerobot-team/xlerobot-right-pick-cup-0826sep8-full-20260910 \
TAG=right-0826sep8 ./train_smolvla_state_dropout.sh

# ② 上机跑测 —— 三处和 09-08 那轮不同
~/miniconda3/envs/train310/bin/python run_policy_trials.py \
  --panel --send --trials 8 --seconds 60 \
  --chunk-rate 1 \          # ← 09-08 用的是 auto(k=4)
  --keep-torque \           # ← 不加的话 connect 时头会掉力矩、抬起来看墙
  --speed 1.0 --trace \
  --model .../checkpoints/020000/pretrained_model
改动为什么
train310 的 pythonlerobot 环境的 torch 对不上驱动,会静默落到 CPU,每次推理 2.4 s、动作计划拉长十倍。日志里必须看到 == device: cuda (Orin)。
--chunk-rate 1本轮实测:停顿 46%→22%、横向增益 0.6→0.85、k/n 0/14→3/7。
--keep-torque2026-09-10 实测:不加时试跑 connect 之后头部从 tilt 2613 掉回 1901,相机对着墙,整轮作废。
开跑前对头/api/head/aim 设 cup-grasp-v0(pan 2003 / tilt 2619,会被限位钳到 2617),然后要看图确认,别只看光照数字 —— 本轮就因为只比数字而漏掉了一次对着墙的情况。
每次记杯位trials JSON 至今没有杯位字段(录制指南第 4 项未做)。本轮的杯位记在 05-training/trials/cup-positions.json,不记就没法复现上面那张表。

六、证据等级

结论等级出处
chunk 1/1 下 3/7;密档 3/3、疏档 0/4跑测过,但探索性trials-20260910-143830.json(3/5)+ -144442.json(0/2)· 无预注册
横向增益 0.85(r=0.923)跑测过,换算近似7 条 trace 的闭爪 pan 对档中心回归
停顿 46%→19~26%,回路 4.2→6.1~11.3 Hz跑测过trace 时间戳差分
失败时夹爪 0 次开合跑测过trace 夹爪维,迟滞双阈值计数
失败是瞄歪(杯子没进爪口),不闭爪是下游症状跑测过六张 end 关键帧逐张看;2026-09-11 更正了原来相反的结论
夹爪张开幅度正常(0.97×),时长失败 56–75% vs 示范 22.5% / 成功 14%跑测过示范 40 集 + 7 条 trace,阈值开度>30
闭爪被「爪口里看到杯子」视觉门控没跑过与消融和现象都自洽,但试跑此前不存腕部帧;2026-09-11 已加上腕部关键帧,下一轮可直接判
失败时横向误差比成功小已撤回那三次没有闭爪时刻,旧口径退化成任意帧;且档中心换算过粗
不加 --keep-torque 头会掉下来跑测过2026-09-10 实测 tilt 2613 → 1901
右腕相机主导闭爪决定(占 73%),头部主导横向跑测过camera_ablation.py 12 集遮盖法,取闭爪前一帧
MJPG 不是失败原因(YUYV 也有 26.5 fps 不丢帧)跑测过2026-09-10 两路同开 A/B,各 40 帧
73 集重训能补上疏档的失败没跑过这是下一步要回答的
数据:05-training/trials/trials-20260910-143830.json · -144442.json · cup-positions.json(杯位)· 7 条 trace + 7 段录像
相关:失败机制:右臂在原地刷 · 还剩哪些可能 · 0826+sep8 合并数据 · 录制指南
本页数字实测于 2026-09-10 本机 Jetson