--- title: "Chapter 08 — 端到端运行时序" date: 2026-05-20 draft: false tags: ["PRISM", "世界模型", "空间记忆", "机器人", "iOS", "ZED2i"] categories: ["PRISM"] --- # Chapter 08 — 端到端运行时序 > 本章目标:把 Chapter 04–07 的四个管线**串成一条完整的时间线**,用一个具体酒店场景的"剧本"展示 PRISM 如何在 T0 到 T4 的全生命周期工作。 --- ## 8.1 场景设定 > 某商务酒店 3 楼,共 8 间客房 + 走廊 + 电梯厅,约 300 m²。 > 部署一台轮式服务机器人「Robo-Concierge」,搭载 ZED 2i,需要: > - 自主巡逻 > - 接受客人语音指令"去 308 取一下遥控器" > - 早晨给打扫清单上的房间送备品 > - 检测家具异常移动(防盗 / 维护提醒) --- ## 8.2 时间线全景 ```mermaid timeline title PRISM 端到端运行时序 T0 -- T6 section 部署前 T0 D-7 : iPhone 离线扫描 → 灌入 LTM section 开机当天 T1 9点 : 机器人首次开机
重定位握手 T2 全天 : 巡逻/任务
delta 累积 T3 14点30 : 取遥控器任务 T4 22点 : 充电桩
记忆巩固 section 长期维护 T5 D+30 : 月度深度巩固 T6 D+90 : 装修后部分重扫 ``` --- ## 8.3 T0:iPhone 离线扫描(D-7,运维人员) ### 物理动作 ``` 09:00 运维进入 3 楼电梯厅 09:01 放置 ArUco 标识在地面(id=42, 30 cm×30 cm) 09:03 打开 PRISMScanner App 09:05 ── 单 session 开始 ── 1) 在电梯厅扫一圈,看到 ArUco ✓ 2) 沿走廊缓慢推进 3) 进 301,扫描 12 分钟 4) 退出 301,沿走廊 5) 进 302...... 重复直到 304 09:55 暂停 session(4 个房间) 10:00 换电池 + 第二 session(305–308) 10:50 全部完成 ``` ### 数据落地(D-6,工作站) ``` data/scans/ ├── 2026-05-09_3F_session1/ # 301-304 │ ├── Hotel.usdz │ ├── roomplan.json │ └── arkit/ (rgb + depth + pose) └── 2026-05-09_3F_session2/ # 305-308 └── ... ``` ### Ingest(D-5,工程师) ```bash # Session 1 python -m tools.prism_ingest_iphone \ --scan data/scans/2026-05-09_3F_session1/ \ --out robot_memory/ltm/ \ --aruco-id 42 # Session 2(追加进同一 LTM) python -m tools.prism_ingest_iphone \ --scan data/scans/2026-05-09_3F_session2/ \ --out robot_memory/ltm/ \ --aruco-id 42 \ --merge # 检查 python -m tools.check_anchors # 期望 ≥ 16 个 anchor(每房 2 个) python -m tools.viz_octomap # 人眼检查走廊可通行 ``` 输出: ```yaml nodes: 289 (8 房 + 8 走廊 + ~273 家具) edges: 312 anchors: 21 LTM size: 3.4 GB ``` ### 部署 ``` D-3: 把 robot_memory/ 拷贝到机器人 SSD D-2: 机器人在测试间预演重定位(不到现场) D-1: 机器人运到 3 楼电梯厅,关机待命 ``` --- ## 8.4 T1:机器人首次开机(D 早上 9:00) ### 时序(精确到毫秒) ```mermaid sequenceDiagram autonumber participant U as 用户 电源 participant R as ROS 2 PRISM participant Z as ZED 2i SDK participant FP as Frame Producer participant RL as Relocalizer participant NAV as Avoidance Nav participant FSM as 状态机 U->>R: 09:00:00.000 Power on R-->>R: 09:00:02.500 节点 launch 完成 R->>Z: 09:00:02.600 启动 ZED 2i SDK Z->>FP: 09:00:03.100 第一帧到达 FP->>RL: 09:00:03.150 触发 cold_start RL-->>RL: 09:00:03.230 CLIP 编码当前帧 RL-->>RL: 09:00:03.310 L3 Top-3 lobby_3F 0.82 room_308 0.41 hallway_3F 0.39 RL-->>RL: 09:00:03.320 几何配准 FPFH+RANSAC 0.74 ICP refine 0.91 通过 RL->>R: 09:00:03.510 发布 TF map to zed2i_init R->>NAV: 09:00:03.550 Avoidance Nav 上线 R->>FSM: 09:00:03.600 状态机 to IDLE FSM-->>U: 09:00:04.000 开始默认任务 巡逻 Note over U,FSM: 总冷启动约 3.6 秒 其中 PRISM 握手约 400 ms ``` **总冷启动时间:~ 3.6 秒**(其中 PRISM 的握手 ~ 400 ms) ### 内部状态变化 | 时刻 | L1 | L2 局部 | L3 当前位置 | L4 缓存 | TF | |------|----|---------|-------------|---------|----| | 09:00:00 | 空 | 空 | 未知 | 全部从盘加载 | base_link→? | | 09:00:03.1 | 1 帧 | 空 | 未知 | 已加载 | 仍未对齐 | | 09:00:03.5 | 多帧 | 开始融合 | lobby_3F | — | **map→zed2i_init 发布✓** | --- ## 8.5 T2:日间巡逻(持续 ~ 8 小时) ### 高频循环(30 Hz 主循环) ``` 每帧 33.3 ms: ZED grab → FrameProducer.append → 局部避障 → 30Hz 控制循环 ``` ### 中频循环(5 Hz TSDF) ``` 每 200 ms: 取一个关键帧 → TSDFWorker.integrate - 检查 prior_mask: 卫生间镜面区被跳过 - 检查 prior_weight: 走廊墙面 weight=0.1(轻微校准) - 走廊地面新发现的"水迹"区域:正常融合,weight=1.0 ``` ### 低频循环(2 Hz 检测) ``` 每 500 ms: YOLO-World on 当前 RGB → 检出: bed_room_303, lamp_room_303, person, slipper Person → 隐私过滤,丢弃这帧的语义写入(只保留几何) bed_303 → 命中 LTM,更新 last_seen + EMA pose(微调) lamp_303 → 命中 LTM,OK slipper → 未在 LTM,propose_new → DeltaEvent(object_added, payload=...),写 delta/pending.jsonl ``` ### 异常事件(11:34) ``` 机器人巡逻到 305: - TSDF 在沙发区域显示"空" - LTM mesh 显示"有沙发" - ChangeDetector 1 Hz 跑: diff > 5 cm → 聚类 → DeltaEvent( event_type="object_removed", target_uid="sofa_305", evidence=[kf_305_1134_01, kf_305_1134_07]) - 写入 delta/pending.jsonl 但机器人 *不立刻*认为沙发没了: - LTM 中 sofa_305 仍在 - 后续路径规划仍把它当障碍(保守) - 等下次累计观测足够 + 充电时巩固才真删 ``` ### Anchor 校正(11:42) ``` 机器人路过 304 床前: - YOLO 检到 'bed' (high conf) - 与 LTM bed_304 关联成功 - 在线触发 fine_register_anchor: fitness=0.88 → 更新 T_zed→map drift 估计归零 - 自此重新校准过;与上次校准间隔 38 分钟(< 1 h 健康) ``` ### 任务级中断(13:00) ``` 语音:"去 306 把客人遗忘的伞拿到前台" LLM Agent 查 PRISM API: find("伞", room="room_306") → L4 检索: umbrella_xxx (source=zed2i, conf=0.5, last_seen=今早 10:21, parent=nightstand_306) → L3 路径: cur(hallway) → 306 → L2 度量路径 → 执行 ``` --- ## 8.6 T3:完整任务剧本——"取遥控器" ### 13:00:00 用户输入 ``` 客人在 308 房间说:"请帮我去 308 桌上拿遥控器" (机器人当前位于 hallway 走廊中段) ``` ### 13:00:01 LLM Agent 查询 ```python # Agent 不直接访问数据库;用 PRISM API api = SpatialMemoryAPI("robot_memory/ltm/") # 1) find 物品 result = api.find("remote control", filters={"parent_room": "room_308"}) # → [SpatialNode(uid='remote_xx33', label='remote_control', # parent_uid='tv_stand_308', confidence=0.6, # last_seen=2026-05-16T08:14:22)] # 2) describe(给 LLM 看的自然语言) print(api.describe(result[0].uid)) # "A black remote_control on tv_stand_308 in room_308 (Bedroom), # last seen 4h 45min ago, confidence 0.6." # 3) 检查最近 delta(是否被搬过) recent = api.changes_since(time.time() - 3*3600) # 关于这个遥控器的 delta? → 没有 # OK,假定还在 # 4) 路径规划 path_rooms = api.path_rooms(src="hallway_3F", dst="room_308") # → ["hallway_3F", "room_308"] metric_path = api.l2.plan(start=cur_pose, goal=result[0].pose) ``` ### 13:00:02 执行 ``` 13:00:02.300 开始驱动,沿走廊向东 13:00:14.200 到达 308 门前 13:00:14.300 ChangeDetector 注意到 308 的门 LTM 标 closed 但实际开着 → 写 delta(object_state_change, door_308) 13:00:14.500 进入 308 13:00:16.800 到 tv_stand_308 前 0.5 m 13:00:17.000 ZED 视野中检出 remote_xx33 ✓(YOLO conf=0.78) 位置与 LTM 偏 12 cm(在桌面被人挪过 12 cm) EMA 更新 pose,不写 delta(< 20 cm 阈值) 13:00:18.000 机械臂伸出抓取 13:00:20.000 抓握成功,撤回 13:00:25.000 返回走廊 13:00:40.000 抵达前台,交接 ``` **任务耗时 38 秒;查询 PRISM 总耗时 < 50 ms。** --- ## 8.7 T4:充电时记忆巩固(D 22:00) ### 触发 ``` 21:55:00 机器人电量 < 25% 21:55:05 返回充电桩(导航 ~ 8 min) 22:03:00 上桩,开始充电 22:13:00 静止 > 10 min,触发 prism consolidate --mode=full ``` ### 巩固内容(当天积累) ``` pending.jsonl 当天总计 1234 条事件: ├── object_added (slippers, towels, ...) 413 ├── object_moved (人挪过的小物) 382 ├── object_removed 91 ├── geometry_changed (走廊积水/物件堆放) 38 └── 重复信号 310 ``` ### Step 1: 筛选 ``` 观察累积 > 5 + 时间跨度 > 5 min + 多视点 > 2: → 162 条通过 confirm → 798 条 reject(< 5 min 的短暂物) → 274 条 keep(继续等待第二天) ``` ### Step 2-3: 应用 ``` 其中: - sofa_305 的 object_removed: 累积 47 次观测,跨越 6 小时 → 通过 ✓,标记 sofa_305 state=removed,confidence ×= 0.3 - 12 个新增的 small_item(拖鞋、毛巾、水瓶)→ 加入 L4 - 41 个家具位置微调 ``` ### Step 4: 锚点 / 索引刷新 ``` 21 → 20 个 anchor(sofa_305 被淘汰) 受影响的 12 个新节点:渲染图像 + CLIP → 入 Faiss 索引 room_305 的房间 CLIP 重算(因为 sofa 不再) ``` ### Step 5: 增量重训 ``` 受影响房间:room_305 3DGS warmstart from outputs/room_305/last.ckpt 3000 iter (~ 4 min on Orin AGX) → ply 替换 ltm/dense/3dgs/room_305.ply TSDF 在 sofa_305 bbox 内 reset → 用今日 keyframes 重融合 ``` ### Step 6: 验证 + 切换 ``` sanity_relocalize on 10 历史关键帧: 10/10 成功,RMSE 4.2 cm ✓ validate(new_mem): 0 errors ✓ snapshot: robot_memory/snapshots/20260516_2230.tar.zst (3.4 GB) 原子切换:ltm.staging → ltm;旧 ltm → ltm.prev(next day 删除) 22:34:00 consolidate 完成,总用时 31 min 22:34:01 机器人继续充电 ``` ### 第二天早晨 ``` 07:00:00 机器人启动,加载新 LTM 07:00:03 重定位(在充电桩,看天花板灯)→ Top-1 = hallway_3F ✓ 07:00:04 IDLE 等待任务 ``` --- ## 8.8 T5:月度深度巩固(D+30 凌晨) ``` 01:00:00 定时任务触发 prism consolidate --mode=deep 01:00:30 完整巩固 + 全场景 3DGS 重训(每房间 5000 iter) 03:45:00 全部完成 (8 房 × ~ 20 min) 03:46:00 自检:sanity_relocalize 20 张历史帧 → 19/20 通过 ✓ ``` --- ## 8.9 T6:装修后部分重扫(D+90) ``` 酒店在 D+85 改造了 307 房间(新家具) D+90: 运维带 iPhone 重扫 307 + 走廊端 ingest 时指定 --only-rooms room_307: - 仅替换 LTM 中 room_307 相关的 nodes/edges - 其他房间保持不变 - 重新生成 room_307 的 anchor + CLIP - 重训 room_307 的 3DGS ltm_version 从 v15 → v16 ``` --- ## 8.10 全生命周期 KPI(连续运行 90 天后回看) ```yaml 重定位: 冷启动成功率: 98.4% (1230/1250 次) 平均冷启动时长: 670 ms 绑架恢复成功率: 93% (用 ArUco 兜底后 100%) 记忆维护: pending 平均长度: ~ 800 条/日 每日 confirmed: ~ 150 条 reject 率: ~ 64%(健康,说明门槛起作用) 错误巩固撤销次数: 2 次(手工回滚) 任务表现: "取物"任务成功率: 94% (n=412) 错误归因: - 物品已被移走 (delta 未及时巩固): 4% - 抓取失败: 2% - 重定位失败: < 1% 资源占用 (Jetson Orin AGX): CPU 平均: 37% GPU 平均: 52% 内存: 12.3 GB / 64 GB 磁盘增长: + 0.2 GB / 月(snapshots) ``` --- ## 8.11 完整状态图 ```mermaid stateDiagram-v2 [*] --> BOOTING: power BOOTING --> IDLE: relocalize ok IDLE --> EXECUTING_TASK: task assigned EXECUTING_TASK --> IDLE: done IDLE --> RELOCALIZING: relocalize lost EXECUTING_TASK --> RELOCALIZING: relocalize lost RELOCALIZING --> IDLE: recovered RELOCALIZING --> FALLBACK_HUMAN: failed > N FALLBACK_HUMAN --> IDLE: human help IDLE --> CONSOLIDATING: charging + idle > 10min CONSOLIDATING --> IDLE: done note right of IDLE 巡逻或待命 end note note right of CONSOLIDATING Background (并行): • FrameProducer (30 Hz, always) • TSDFWorker (5 Hz when moving) • DetectorWorker (2 Hz when moving) • ChangeDetector (1 Hz when stationary) • HealthMonitor (0.2 Hz) end note ``` --- ## 8.12 本章小结 | 阶段 | 时间 | 主体 | PRISM 角色 | |------|------|------|-----------| | **T0** D-7 | 人工 | iPhone 扫描 | LTM 灌入 | | **T1** D 9:00 | 机器人 | 冷启动 | 重定位握手 | | **T2** D 全天 | 机器人 | 巡逻 | 在线感知 + delta 累积 | | **T3** D 13:00 | 机器人 | 任务 | 查询四层记忆 + 路径 | | **T4** D 22:00 | 机器人 | 充电 | 巩固 | | **T5** D+30 | 机器人 | 深夜 | 深度巩固 | | **T6** D+90 | 人工 | 重扫部分 | 增量 LTM 更新 | 读完本章你应能: - ✅ 在脑中"播放"完整的 PRISM 一天 - ✅ 解释为什么 sofa_305 不会被"瞬间删除" - ✅ 估算系统的资源占用 - ✅ 设计 PRISM 的状态机 下一章 [`09_roadmap.md`](09_roadmap.md) 给出 8 周内把这一切跑通的具体里程碑。 --- **章节版本**:v1.0 **估计阅读时间**:18 分钟 **关键收获**:把抽象架构变成"看得见的一天"