这份手册记的是机器人每次作业都要遵守的行为规范,不是某一天的实验结论。每条有编号(P- 开跑前、G- 运行中、V- 判定与记录、S- 换臂换模型、R- 事故恢复),将来做任务链 / 行为树时节点直接引用编号,让动作自带规范。红点是曾经真的踩过的坑,鼠标移上去看当时发生了什么。
正本:仓库根目录 ROBOTIC-WORKING-HANDBOOK.yaml。改正本 → build_handbook.py → publish-reports.sh。🔴 红点:移上去 / 点一下看当时发生了什么。
行为树里的 Sequence:任一条件失败就不进入动作
| 编号 | 触发 | 规范 | 为什么 | 状态 | 节点 |
|---|---|---|---|---|---|
| P-01 | 任何会动手臂的动作前 | 两条臂都先到已知合法姿势,不只是工作臂。arm_home.py --arm both --go | 安全层对两臂都做 FK;非工作臂在哪没人管,就会把工作臂锁死 | 半自动 管线 09-11 改成 --arm both(真机未验);手跑仍要自己先归两臂 | Condition + Action |
| P-02 | 任何会握串口的进程启动前 | 一条串口链一次只能一个进程。大脑 pick 前 release_bus,pick 后 acquire_bus | 两个进程同时握会出 Incorrect status packet 和幻影硬件故障 | 自动 管线自动;手跑靠人 | Decorator(互斥锁 / mutex) |
| P-03 | 抓取前 | 头部到数据集的预设姿态并看图确认,不只比光照数字。当前 cup-grasp-v0(pan 2003 / tilt 2619) | 光照数字相近不代表看的是桌子 | 半自动 | Condition |
| P-04 | 起策略进程 | 用 train310 的 python,日志里必须出现 device:cuda | lerobot 环境的 torch 没 CUDA,会静默落到 CPU,每次推理 2.4 s | 自动 管线写死 TRAIN_PY;手跑靠人 | Condition |
| P-05 | 起策略进程 | 必带 --keep-torque | 不带则进程退出掉力矩:头掉下来、杯子掉 | 自动 管线自动;手跑靠人 | Condition |
| P-06 | 起策略进程 | 当前配方 --chunk-rate 1、speed 1.0;改任何一项就是另一组 k/n | 09-10 实测 auto/k=4 → 1/1 使 0/14 变 3/7 | 人工 | Condition |
| P-07 | 上真机前 | 跑 teach_grasp.py --check:舵机静默→断电重启;杯子在视野;臂掉 USB→先挂起 Jabra 蓝牙再拔插 | PIPELINE.md 记录的三种现场故障 | 半自动 | Condition |
| P-08 | 每次放杯 | 记杯位到 05-training/trials/cup-positions.json | trials JSON 没有杯位字段;没杯位就没法按杯位分组复现 | 人工 | Action(记录 / record) |
| P-09 | 起 VR 遥操作前 | 确认 Quest 已连接 | vr_teleop.py 一起来两条臂就上电 | 人工 | Condition |
| P-10 | 任何长时间任务前 | 根分区余量够 | 满盘会让 Claude Code 的 Bash 整个失效 | 人工 | Condition |
| P-11 | 连续搜索 / 重试之后 | 冷臂再测。shoulder_lift 十几次搜索就过热 | 过载保护一触发,同一条臂的下一次结果就不可比 | 人工 | Condition(温度 / temperature) |
| P-12 | 开跑前 | 模型路径钉死在 components.py,不让 runner 自动挑最新 checkpoint | runner 默认取磁盘上最新的,换目录就换了模型 | 自动 | — |
| P-13 | 试跑按下确认之后、连相机之前 | 确认后先等预览相机释放 10 s 再连;服务端先设让位窗口、再关预览流两次。加载期间预览页会黑 90 秒,正常,别按停止 | V4L2 设备只有一个持有者。按确认那一秒若 8770 正在给预览页开相机,那路流要 8 s 无人读才释放,试跑 4 次×3 s 重连全撞在里面,整场死在 connect | 自动 | Sequence(连接 / connect) |
每帧都在的约束,做 Decorator
| 编号 | 触发 | 规范 | 为什么 | 状态 | 节点 |
|---|---|---|---|---|---|
| G-01 | 每帧 | 安全层是整帧原子的:任一臂越界,17 维一个都不发;连续 15 帧 HELD 就中止整次试验。非工作臂也必须合法 | 一帧不能拆;没在动的臂真越界了也不该放行 | 自动 | Decorator(每帧守卫 / per-frame guard) |
| G-02 | 安全层拒帧时 | 地板按爪子俯仰角算,不是固定 z_min。一条停着不动的臂被算成穿桌 = 那条臂的标定或 FK 约定有问题,去查标定,不改地板 | 地板改过一次就够了;停着的臂穿桌是物理上不可能的 | 人工 地板自动;查标定靠人 | Condition |
| G-03 | 归位 | 按墙钟插值到目标,不按实测每拍推 0.75°;到位判定要真收敛 | 负载下 0.75° 克服不了静摩擦,原地不动还静默 | 自动 | Action |
| G-04 | 写任何兜底 | except:pass 类兜底必须偏安全侧(停、不动、报警),不能偏「继续」 | 兜底偏「继续」会把没收敛的状态当成功 | 人工 | — |
| G-05 | 非工作臂 | 钉在当前位(idle_lock);当前位越界就不钉,交给安全层 | 不钉会甩 29°;钉住越界位每帧都被拒 | 自动 09-10 改动,未提交 | Decorator |
| G-06 | 试验时长 | 管线默认 25 s,参考批用 40–60 s。对照必须同上限 | 上限不同就是另一组 k/n | 人工 | Condition |
| G-07 | 头部 | 抓取全程头部锁定预设,不跟人 | head_lock 是安全层的一部分 | 自动 | Decorator |
数字怎么才算数;多数是 Record 动作
| 编号 | 触发 | 规范 | 为什么 | 状态 | 节点 |
|---|---|---|---|---|---|
| V-01 | 报任何 k/n | 按配置分组:模型、数据集、夹爪代次、chunk、时长、杯位,六项任一不同就是另一组;跨组合计只能标「仅供参考」 | 混组的数字说明不了任何东西 | 人工 | Record |
| V-02 | 报任何结论 | 标证据等级:跑测过 / 没跑过 / 被挡住,三选一;说「从没」「唯一」前先去 trials-*.json 数 | 多次把推断当事实 | 人工 | Record |
| V-03 | 管线里的 pick | 管线一律标 void,trials JSON 不是管线成功率的来源;看录像 end 帧 + 夹爪读数 | 大脑不替人打分,成败由 grip_gate 判 | 人工 | Record |
| V-04 | 报模型结果 | 必须同时写 ① 数据集 ID ② 夹爪代次 ③ 评估类型(training-only / offline / physical) | 换夹爪后旧模型是 legacy,混着报会误导 | 人工 | Record |
| V-05 | 看老关键帧 | 09-10 之前的 keyframes/*.jpg 通道是反的(橙显蓝、粉显紫) | trial_keyframes.py 09-10 才加 RGB→BGR | 自动 | — |
| V-06 | 夜间跑测 | 夜间头相机偏绿(G/R 1.54),成绩单独标 | 白天录的数据集是中性(0.95) | 人工 | Record |
| V-07 | 选数据集 | 先核视角;sep2 那批头抬着,整批不可用 | 七个数据集视角不对,没有模型用过 | 人工 | Condition |
| V-08 | 判「抓到没有」 | grip gate 只校准了空爪(≤8 算空);「拿着」那档要用一次真实成功抓取校准后才能报 holding | 杯子被弹走但爪子停得高会被误判成功 | 半自动 | Condition |
| V-09 | 测延迟 | 必须用随机间隔 | 固定间隔会让 9 s 伪装成 1 s | 人工 | — |
配置变更的检查单
| 编号 | 触发 | 规范 | 为什么 | 状态 | 节点 |
|---|---|---|---|---|---|
| S-01 | 换臂 | 不是换路径是换臂:任务句子、arm_home、起始位、头预设、place_pose、FK 地板全要跟着换 | 任务句子在三处写死 left arm | 人工 | — |
| S-02 | 换夹爪 | 整条 PICK 从采数据重启;旧 checkpoint 是 legacy 不可当当前策略 | 几何、接触、顺应性都变 | 人工 | — |
| S-03 | 换模型 | 改 components.py 的 pick_policy path + 自检里的名字;起始位、头预设按新数据集 | robot_effectors 自检写死了模型名 | 人工 | — |
| S-04 | 训练 | 租用 GPU 跑在 tmux 里;checkpoint 每 2000 步;断网不停计费 | SSH 一断前台进程就被杀 | 人工 | — |
| S-05 | 想自研某个功能 | 先 git log -S 查上游有没有 | 一分钟的事 | 人工 | — |
| S-06 | 改任何文件 | 先查文件血统:时间戳 + 跨副本 diff,改真正在跑的那份 | 同名副本不止一份 | 人工 | — |
行为树里的 Fallback
| 编号 | 触发 | 规范 | 为什么 | 状态 | 节点 |
|---|---|---|---|---|---|
| R-01 | 抓取失败(grasp_failed) | 先 arm_home(两臂)再重试,最多 3 次,然后道歉归位 | 失败的一次会把臂留在策略没见过的地方 | 自动 | Retry(3) + Fallback |
| R-02 | 总线掉线 | 与电压、USB 无关,查 TTL 菊花链 | 零负载 12.2 V 照样掉 | 人工 | — |
| R-03 | 头相机没画面 | systemctl --user restart robot-status.service;试跑要相机时注意 8770 占着头相机 | 8770 独占头相机 | 人工 | — |
| R-04 | 进程常驻 ~30% CPU、磁盘快速增长 | 录制孤儿线程;LF 按了两次 Start | 09-03 修过 | 人工 | — |
| R-05 | 数据集没上传 | 只在录制结束当场传一次;查 meta/upload.json,补传走 /api/dataset/publish | 不会事后自动补传 | 半自动 | — |
| R-06 | 45 s 没人接杯 | 放回桌上(place_down),不是松手 | 放下的能捡,掉的一地 | 提议 place_down 目前是空函数 | Fallback |
| R-07 | 舵机过载保护触发 | 断电重启,冷却后再测;见 P-11 | 过载后读数不可信 | 人工 | — |
Root: Sequence
├── Preflight: Sequence # 任一失败不进动作 / any failure blocks the action
│ ├── Cond P-10 disk_ok
│ ├── Cond P-04 cuda_ok
│ ├── Cond P-02 bus_free (Decorator: 互斥锁包住整棵 Serve / mutex around Serve)
│ ├── Act P-03 head_to_preset → Cond head_view_confirmed
│ ├── Act P-01 arm_home(both) → Cond both_arms_in_envelope (G-02 查标定入口 / calibration entry)
│ └── Cond P-11 servos_cool
├── Serve: Sequence
│ ├── Greet / Order / Confirm (人说「是」才往下 / a human "yes" gates the arm)
│ ├── Retry(3): Fallback # R-01
│ │ └── Sequence
│ │ ├── Act P-01 arm_home(both)
│ │ ├── Guard G-01/G-05/G-07 ⟶ Act pick(policy, keep_torque P-05, cap G-06)
│ │ └── Cond V-08 grip_holding
│ ├── Hand over (45 s) → Fallback: R-06 place_down
│ └── Home(both)
└── Record: Act P-08 cup_position · V-01 config_key · V-03 verdict_from_evidence
v0.1 · 2026-09-11 · 首版。从 09-10 的管线实测和此前记忆里的规则汇总。v0.2 · 2026-09-11 · 正本改为 YAML;页面加中英切换、状态图表、行为树流程图、红点标坑位悬停显示。正本:ROBOTIC-WORKING-HANDBOOK.yaml。本页由 build_handbook.py 生成。