学习 / 实践
具身智能实践(十三):下降中断之后,应该从哪一步恢复?
具身智能 / 探索 · 工程案例
18 个 MuJoCo 回合与同步回放,将阶段契约接入恢复预算,区分正常下降误停、物理放置和控制器终止。
这篇之后,已经有了哪些结果?
保留本文发表时的结论与下一步设想;以下是已发表的后续内容,不代表所有局限都已解决。
继续探索
继续探索
浏览统计暂不可用
本文目录 9
从干净环境复现 · 本篇固定版本
以下为 Windows PowerShell,Python 3.12。使用新的目录;不要在有未保存改动的工程里切换版本。每篇固定提交不同,首篇的旧提交不包含后续实验。
git clone https://github.com/VirtualSelect/hohoo-embodied-agent.git hohoo-embodied-agent-study
cd hohoo-embodied-agent-study
git checkout ad2e33523e8e5580da90ae914e1cccf765c8d1b1
python -m venv .venv
$py = '.\.venv\Scripts\python.exe'
& $py -m pip install -r requirements-lock.txt
& $py experiments/vl01_phase_recovery/run.py --out outputs/my-run
& $py experiments/vl01_phase_recovery/audit.py outputs/my-run预期得到原始轨迹、摘要和审计结果。请使用新的输出目录,避免覆盖旧结果;不同实验对已存在目录的处理并不相同。E8–E10 共用一组实验入口。以上命令不调用模型;先运行数值部分,视频回放按正文单独执行。
排错:找不到实验目录先核对提交;导入失败检查解释器与安装环境;OpenGL 报错仅影响需要渲染的步骤。Linux/macOS 将解释器替换为 .venv/bin/python,尚未在这些平台复测。
查看本篇固定代码 ↗上一轮发现,下降阶段即使暂时失去观测,transfer-only 门控也不会响应。扩大监控范围似乎很直接:让下降也使用同一套抓取检查。
但搬运要求方块保持一定高度,下降本来就要把它放低。把条件直接复制过去,正常运动会被当成故障。这一轮把阶段契约、恢复窗口和恢复轨迹真正接在一起,检查系统在什么时候暂停、凭什么恢复、恢复到哪一步。
先看回放:三个控制器遇到同一次间断
视频来自已经保存的 MuJoCo 状态。每画面同一时刻读取同一采样 tick,没有重新运行物理来拼接“更好的结果”。左侧只监控搬运,中间让下降复用搬运规则,右侧使用阶段感知规则。
这一组观测间断发生在 6.10~6.34 秒。中间控制器在间断发生之前,已经因为正常下降误停;左侧无视间断继续执行;右侧暂停,重新积累证据后继续下降。
冻结了哪些条件
沿用同一桌面、双指夹爪、方块与目标盒,物理步长 2ms,每回合 12 秒。没有训练策略,没有接入 ROS2 或真实机器人。
| 条件 | 干预 |
|---|---|
| 无故障 | 不注入干预 |
| 搬运间断 | 4.60~4.84 秒不交付观测包 |
| 下降前段间断 | 5.60~5.84 秒不交付观测包 |
| 下降后段间断 | 6.10~6.34 秒不交付观测包 |
| 下降永久间断 | 5.60 秒起不再交付观测包 |
| 下降松爪 | 5.60~5.84 秒强制夹爪张开,观测仍正常 |
每种条件对照三个策略,共 18 回合。干预按绝对仿真时间注入;控制策略一旦改变轨迹,同一个时段不保证遇到完全相同阶段。分析必须查看 scheduled_phase 和事件记录,不能只看条件名称。
所有策略保留最多两次恢复、至少 400ms 暂停、800ms 恢复截止时间。终止后统一保持当时目标,不混入上一轮的不同退出动作。
哪个条件应该属于哪个阶段
| 策略 | 搬运时检查 | 下降时检查 |
|---|---|---|
| transfer-only | 双指接触、抓取误差、方块高度 | 不检查 |
| reuse-transfer | 同上 | 直接复制搬运规则 |
| phase-aware | 双指接触、误差小于 5cm、方块高于 12cm | 双指接触、误差小于 5cm |
下降去掉高度下限,不意味着下降时什么都不检查。接触、相对位置误差和观测新鲜度仍然有效。是否已经正确放置,使用最后 500ms 的物理记录另行验收,不能用“下降阶段允许低高度”代替完成条件。
HOLD 不能覆盖被中断的阶段
执行状态有 running / hold / aborted,作业阶段有 transfer / lower / release。它们是两套不同维度。
当下降进入 HOLD 时,需要保存 interrupted_phase=lower。如果下一轮将这个字段改成 hold,控制器就丢失了判断观测和重建轨迹的上下文。
本轮仅在正常执行、作业阶段改变时更新上下文;暂停期间保留原阶段。暂停截止时间也不会因为上层传入了 release 或 hold 而重新开始。
if self.state == 'running' and phase != self.context:
self.context = phase
self.bad_since = None暂停后的恢复证据继续沿用之前的要求:必须是 HOLD 之后采集、时间连续、仍然新鲜的合格观测窗口。只是其中“合格”的定义现在依赖被中断阶段。
恢复下降,不应该再升回搬运高度
旧恢复路径总是先回到 18cm 搬运终点,再做下降。现在根据保存的阶段选择路径:
搬运中断:当前测量夹爪位置 → 搬运终点 → 下降 → 松爪 → 后退
下降中断:当前测量夹爪位置 → 下降终点 → 松爪 → 后退第一段统一用 0.5 秒平滑连接。这里是固定目标的简单轨迹拼接,不是避障规划、重抓取或最优控制。起点使用恢复时测量的夹爪位置,避免假设机器人仍处在原计划位置。
实测:下降后段的 400ms 暂停
阶段感知策略在后段间断中留下以下事件:
| 事件 | tick | 仿真时间 |
|---|---|---|
| 观测变旧,进入 HOLD | 3071 | 6.142s |
| 新的连续合格窗口开始 | 3171 | 6.342s |
| 满足暂停下限,恢复 lower | 3271 | 6.542s |
恢复后从当时夹爪位置直接继续下降,最终方块中心高度约 25.98mm,接触目标盒底,最后 500ms 满足沿用的放置条件。
相比之下,reuse-transfer 在 6.002s 就因高度下降而进入 HOLD,6.802s 因无法重新满足搬运高度而终止。这发生在 6.10s 注入观测间断之前。因此不能把这个失败归因于断流;无故障组也在同一时刻误停。
物理上在盒里,不代表控制流程完成
下面报告的是物理放置验收,不是成功率估计。固定场景每格只运行一次,没有随机初始化或统计置信区间。
| 条件 | transfer-only | reuse-transfer | phase-aware |
|---|---|---|---|
| 无故障 | 满足 | 不满足,误停 | 满足 |
| 搬运间断 | 满足,恢复 1 次 | 不满足,下降误停 | 满足,恢复 1 次 |
| 下降前段间断 | 满足,未监控 | 不满足,恢复后误停 | 满足,恢复 1 次 |
| 下降后段间断 | 满足,未监控 | 不满足,干预前已误停 | 满足,恢复 1 次 |
| 下降永久间断 | 满足,未监控 | 不满足,终止保持 | 不满足,终止保持 |
| 下降松爪 | 满足 | 满足,但已终止 | 满足,但已终止 |
两个地方不能省略说明。
永久丢失观测时,transfer-only 仍然完成了固定轨迹。 这证明这个场景的开环轨迹碰巧足够,不证明“忽略观测更安全”。阶段感知策略在 5.642s 暂停、6.442s 终止,方块停留在约 157.81mm,未完成放置。
松爪故障时,方块刚好在盒子上方落下。 两个监控下降的控制器都检测到接触失败并终止,但方块最终满足物理验收。这不是控制器成功恢复,也不是设计好的松爪策略。若只统计“方块是否在盒里”,就会把偶然落入目标的事故奖励为成功。
本轮 18 回合中有 12 回合满足物理验收;其中 2 回合控制器处于终止状态。后续评价至少应分别保留物理结果、观测合规性和控制器生命周期,不能合成一个未经定义的成功数字。
如何确认这些不是画出来的结论
归档包含 108,000 行控制与观测记录、10,800 个可回放状态、54 份原始文件。审计重新计算最终放置条件、检查观测间断与松爪注入时段、核对恢复窗口和预算,并验证 18 组策略比较在首次决策分歧之前的物理轨迹一致。
8 个契约测试覆盖低高度下降、低高度搬运、暂停阶段保留、绝对截止时间、释放阶段不触发新门控、接触失败、恢复路径和预算耗尽。
回放调用 mj_forward 根据已保存的 qpos/qvel 更新可视状态,不调用 mj_step 产生新的实验轨迹。MuJoCo 仿真文档解释了这两个操作的区别。回放是证据的展示方式,不增加实验样本数。
复现与边界
在 hohoo-embodied-agent 仓库的现有 MuJoCo 环境执行:
python -m unittest discover -s experiments/vl01_phase_recovery -p test_gate.py
python experiments/vl01_phase_recovery/run.py --out evidence/my-run
python experiments/vl01_phase_recovery/audit.py evidence/my-run
python experiments/vl01_phase_recovery/replay.py --evidence evidence/my-run本次运行使用 MuJoCo 3.3.7、NumPy 2.2.6、Python 3.12.14。回放需要现有的 imageio/FFmpeg 与可用渲染环境。
结果只覆盖固定仿真、固定目标和上述干预。它没有证明真实硬件安全,没有解决永久缺测后的安全撤离,也没有重抓取。完整 VL01 与更高阶段里程碑仍未完成。
接下来最值得验证的不是再提高一个总分,而是将“完成”契约接入当前阶段恢复链:什么时候允许宣布完成,终止后偶然落入目标应当如何记录,完成后观测失效又该如何撤销状态。 这一轮先把恢复阶段与物理结果分开,给后续组合留下可审计的基础。
写给未来的自己合上文章前,留下一点自己的理解。
你的私人学习便签,只存在当前浏览器,不会上传或公开。清理浏览器数据会丢失,请导出留存。三种语言共用这篇文章的便签。
下一篇已发布内容:具身智能实践(十四):方块落进盒子,就能宣布任务完成吗? →
当前学习位置
探索 / 具身智能
- ○ 具身智能实践(十二):恢复预算耗尽之后,夹爪应该做什么?
- ○ 具身智能实践(十三):下降中断之后,应该从哪一步恢复?
- ○ 具身智能实践(十四):方块落进盒子,就能宣布任务完成吗?
继续探索
继续探索
接下来,走哪条路?
- 具身智能实践(十二):恢复预算耗尽之后,夹爪应该做什么? →
12 个 MuJoCo 回合与三画面回放,对比保持、松爪、松爪后退,区分终止决定与实际退出后果。
- 具身智能实践(十一):已经放好了,为什么还要撤销“完成”? →
七条 MuJoCo 轨迹与双画面回放,将历史完成事件和当前有效状态分开,保留传感误报与过期边界。
- 具身智能实践(七):搬运规则,为什么会误停正常下降? →
21回合MuJoCo对照:下降需要自己的抓取契约。用正常误停、旧包报警与晚下降残留接触,拆开监测范围、停止动作和最终放置。
依据文章关联与同主题已发布内容整理,不使用随机推荐。