这一天从「磁盘被写满、命令都跑不动」开始,查出深度旁路的四个缺陷, 修掉其中三个,把第四个(真正的根因)定位到 USB 2.0 带宽不够,换到 USB 3.0 后深度第一次录上。 中间还发现安全层的下限高了 8 cm,把训练示范拒掉 96.6%。 这一页是当天的完整账:做完的、发现但没修的、以及接下来谁做什么。
valid 86%、中位距离 516 mm,当晚录到 3000+ 帧深度。
根分区被写到 0 字节,连开发环境的命令都执行不了。
根因:leader_follower_server._cmd_start 覆盖 self._depth 前不停旧的,
按两次 Start 就孤儿掉上一个录制器 —— 它跑了 13.7 小时、220,412 帧、27 GB。
stop()(leader_follower_server.py)。
v4l2_depth.DepthCamera.open() 先 os.open() 拿 fd,再做一串会抛异常的 ioctl;
失败时只把 _cam 置 None,fd 永远不关。实测累积 34 个泄漏句柄。
try/except,失败调 self.close() 再抛。self.fd 回到 None。
DepthRecorder 把「0 帧」当正常收尾写 meta.json,面板一个字都不说。
这是当天代价最大的缺陷 —— 9-02 一晚 102 集里 88 集丢了深度,当场无人察觉。
_cmd_stop 现在在消息里报 depth: N frames,0 帧标红(message_kind="err")。拓扑查出来是这样:
Jetson
└ Realtek 双总线 hub(USB2 侧 1-2 + USB3 侧 2-1,同一个物理 hub)
├ 口1 iTingSbc
├ 口2 串口(手臂总线)
├ 口3 ★ 第二个 hub —— 只支持 USB 2.0 ★
│ ├ Orbbec Gemini 335 ← 深度 + 头部 RGB,两个接口
│ ├ 腕相机
│ ├ 腕相机
│ └ 键盘
└ 口4 串口(手臂总线)
三路相机全在那个 USB 2.0 hub 后面共享 480 Mbps。深度 640×480×16bit×30fps ≈ 147 Mbps, UVC 分配不到就一直超时。换到 Jetson 机身的 USB 3 口后链路 5000 Mbps,深度立刻正常。
2.3.1 → 1.1),而仓库里 9 个文件、19 处写死了旧路径 ——
面板四路相机全找不到、LF 握着两个 (deleted) 句柄、预览画面定格。usb_cameras.py 按 VID:PID 动态解析
(Orbbec = 2bc5:0800,接口 0 = 深度、接口 4 = RGB),接进
robot_server.CAMERAS 和 depth_recorder.DEFAULT_DEPTH_NODE,
动态优先、写死兜底、找不到返回 None 绝不抛异常。以后再换口不用改代码。
teleop_safety.yaml 右臂 z_min = 0.065(08-24 换夹爪时标定)
把训练集 0826-0042 全部 40 集 16,487 帧示范拒掉 96.6%,试跑第 1 帧即中止。
| 为什么错 | 数值 |
|---|---|
| z_min 的含义 = 桌面 + 爪长 | 0.065 − 爪长 0.1179 = 桌面 −0.053 |
| 桌面实测(08-16 摇臂法) | −0.137 / −0.142 |
| 差 | 8 cm,而且新爪比旧爪短、下限却抬高了,方向都反了 |
z_min → −0.11(示范最低腕高 −0.102 再留 1 cm)。outside [0.065, 0.35] 中止。
tctlRun / tctlSend / REC_TASKS 等 12 个函数 + 3 个变量
声明在 start() 函数内部(文件里没有缩进,看着像顶层),
而「重放选择器」和操作模式的按钮在外面调 → ReferenceError。
这几个按钮从来就没通过过,和当天的改动无关。用 AST 一次扫出全部,挂到 window 上修好。
顺手把这套检查固化成了技能 .claude/skills/self-debug/:
HTML 标签配平、整块 JS 语法、作用域泄漏、服务端下发一致性,四类不用浏览器就能判定的错。
对比两条路径:VR/面板录制在作业结束时起线程调 _publish_dataset;
leader-arm 的 _cmd_finish 里一行上传代码都没有。
所以 9-02、9-03 两批数据全靠人工补传,操作者以为录完就传了。
/api/dataset/publish(和 VR 同一道 verify 门);
失败时页面明说「数据已安全落盘,只是上传失败,去面板重传,数据没丢」。下次重启 8781 生效。| 做了什么 | 结果 |
|---|---|
| 数据集迁到组织 | 33 个 → xlerobot-team/(显示名 Aalto-xlerobot-team)0 失败 |
| 垃圾集归拢 | 12 个 TEST/soak 改名 trash-* + private,留在个人名下、一个没删 |
| 模型 | 7 个不动,仍在 Suyang99/ |
| owner 配置化 | bartender_tasks.HF_OWNER 一处改全局(含面板/VR/LF/traincalc 预填) |
| 9-03 录制 | 今晚 30 集已全部上 Hub(1824/1853/1906/1927),2015 还在录 |
| 磁盘 | 从 0 字节 → 33 GB 可用 |
trash-* 没删:trash-soak-20260816-220415 / -220918 是
xlerobot_vr.py 注释里的实测证据,trash-xlerobot-TEST-* 是 VR 轴污染文档的证据。
删了那些结论以后没法复核。改名+私有达到了「从视野消失」的效果,且可逆。
prune_uploaded_datasets.py 删掉了本地
xlerobot-cup-grasp-20260820-0230(Hub 上有完整副本,删得对),但
demo_coverage.py / grasp_sight_check.py / trace_vs_demo.py
硬编码了它的本地路径,现在会失败。数据没丢,从 Hub 拉回来即可。grep 有没有脚本硬编码它。
| 事项 | 状态 |
|---|---|
z_floor(pitch) 俯仰补偿写好了但零个调用方 | 安全层和 VR 用的都还是标量 z[0]。接上它才是正解(算爪尖不算腕),今天只是把 z_min 止血改成 −0.11 |
gripper_len_m = 0.1179 量了、存了、没有任何读者 | measure_table.py 只 print 不写 yaml;全靠人抄,而 08-24 抄错了 |
| 三个分析脚本指向已删的本地数据集 | 要从 Hub 拉回 0826-0042(现在在组织名下、private) |
| 两只腕相机 VID:PID 完全相同 | 身份分不出左右,仍靠 by-path;对调线缆会静默互换 |
| VR/面板录制路径的深度是整段会话一个文件夹 | 不是逐集,所以「0 帧标红」只加在了 LF 路径 |
1853 的 episode-000004 | 99 张残留 PNG 已清(是一次没录完的第 5 集,不属于任何已保存的集),4 集数据完好并已上传 |
深度现在能录了,但「能录」不等于「能用」。验收分两级:
depth: N frames。depth: 0 frames = 立刻停,别再往下录。这一条就能挡住 9-02 那种「一晚 88 集全空、第二天才发现」。
录完之后我跑这几项,全部只读:
| 指标 | 怎么算 | 合格线 |
|---|---|---|
| 每集帧数 | depth/<集>/ 里 PNG 数 | 和 RGB 时长匹配(约 10 fps × 秒数) |
| 有效像素率 | timestamps.jsonl 的 valid 中位数 | > 0.80(当晚实测 0.795–0.881) |
| 时间覆盖 | 深度起止 vs 该集 RGB 时长 | ≥ 90% |
| 收尾完整 | 每个目录有 meta.json | 缺 = stop() 没被调用 |
现成工具:python 03-software/scripts/lf_depth_doctor.py(句柄数 / 线程数 / 逐集帧数 / 磁盘四项体检)。
深度和 RGB 是两个独立的流,靠 timestamps.jsonl 的墙钟事后对齐。
这个对齐从来没被验证过。做法:现场在相机前快速挥一下手,
远程比对深度帧和 RGB 帧里手出现的时刻,量出偏移毫秒数。偏移大于一个帧间隔就得修。
路线 A = 深度不进模型,在模型旁边算出杯子的 3D 坐标,用来 ①开跑前的门 ②每次试验记录杯位 ③失败诊断。不重训、不重采。 它直冲现在最大的未知:「抓不到」到底是没看见还是抓歪了 —— 今天的试验记录回答不了。
| 做什么 | 为什么现在能做 |
|---|---|
| 写标定采集脚本 | 纯代码。采点、存 (关节角, 像素, 深度) 三元组、留出验证集 |
| 写外参求解器 | Kabsch/Umeyama 求刚体变换 + 残差报告,不碰硬件 |
写 hand_eye.json 的读写 | 内参 / 外参 / 头部预置位名 / 残差,一份配置 |
把 cup_locate_demo.py 改成可复用模块 | 现在是 demo 脚本,抽成 locate_cup() -> (x,y,z) |
| 离线跑通全链路 | 拿 2015 已录的 3000+ 帧深度当输入,验证「找最近的一团 + 反投影」在真实数据上稳不稳 |
2015 这批深度数据可以当离线测试集用 ——
不需要机器人、不需要现场,就能把杯子定位算法调到能用,等标定做完直接接上去。
trial)。
run_policy_trials.py 的 head_lock 是启动时读当前位置就锁在哪
(run_policy_trials.py:531),不是固定值。
必须:标定前、每次试跑前,都先把头移到 trial 这个预置位。| # | 事项 | 谁 |
|---|---|---|
| 1 | 录完按 Finish,让 2015 落盘并上传 | 现场 |
| 2 | 重启 8781,让「Finish 自动上传」生效 | 远程 |
| 3 | 存 trial 头部预置位 | 现场 |
| 4 | 用 2015 的深度离线跑通杯子定位 | 远程 |
| 5 | 写标定采集脚本 + 求解器 | 远程 |
| 6 | 采标定点(15–20 个姿态) | 现场 |
| 7 | 把 z_floor(pitch) 接进安全层(正解,替掉今天的止血) | 远程 |
| 8 | 重做桌面标定,核对 z_min − 爪长 ≈ −0.14 | 现场 |
| 9 | 从 Hub 拉回 0826-0042,修好三个分析脚本 | 远程 |
03-software/scripts/ 为准 ·
配套页:深度相机的调用链与缺陷 ·
深度 + SmolVLA 运行架构 ·
录制流程(含 Start 前固定动作)