运行时状态总线
本文定义跨任务共享实时状态的职责边界、主题契约和消费方式。实现以
src/runtime_state/、src/tasks/mixin/runtime_state_mixin.py 和当前单元测试为准。
目录名使用 runtime_state 而不是 runtime:后者会与
src/core/base_mixin/runtime_mixin.py 的“任务运行时能力”混淆,也容易被误解为
整个应用运行时。这里的包只承载跨任务共享状态。
1. 职责边界
| 模块 | 单一职责 | 不负责 |
|---|---|---|
src/runtime_state/state_hub.py |
保存 latest-value 快照、序号和时效 | 采样、融合、任务调度 |
src/runtime_state/topics.py |
定义稳定主题名 | 数据类型和业务逻辑 |
src/runtime_state/world_pose.py |
把定位内部状态映射为稳定坐标契约 | WS 连接、小地图计算 |
src/tasks/mixin/runtime_state_mixin.py |
给任务提供发布、读取、等待和定位采样入口 | 识别算法、路径规划 |
WorldPoseService |
唯一维护应用级定位服务并发布 world.pose |
导航、物品选择、游戏输入 |
| 普通业务任务 | 读取快照并执行自己的状态机 | 直接启动 WS、里程计或融合 |
RuntimeStateHub 使用 latest-value 语义:新快照覆盖旧快照,消费者按
max_age 判断是否仍可用。过期数据返回 None,不能继续伪装成实时状态。
2. 主题
| 主题 | 类型 | 当前生产者 | 典型消费者 |
|---|---|---|---|
world.pose |
最新值 | WorldPoseService |
物品导航、网格导航、滑索、调试任务 |
world.scene |
最新值 | 预留 | 自动交互、自动拾取、任务状态机 |
world.targets |
最新值 | 预留 | 物品导航、自动拾取 |
sensor.ws |
最新值 | 预留 | 状态栏、诊断 |
system.health |
最新值 | 预留 | 调试面板、日志 |
主题名通过 RuntimeTopic 引用,业务代码不要散落字符串。
3. 坐标契约
world.pose 至少包含:
| 字段 | 含义 |
|---|---|
x / y / z |
世界坐标;x/z 为融合水平坐标,y 为最新 WS 高度 |
heading / heading_score |
罗盘方位角和朝向置信度 |
map_id |
当前地图 |
position_trusted / trust_reason |
绝对坐标是否可信及原因 |
anchor_set / rest |
是否已锚定、当前是否静止 |
odom_ok / odom_reason |
本拍是否有有效里程计样本 |
sync_seq / sync_checked / sync_needed |
静止校准状态 |
ws / ws_xyz |
原始 WS 水平坐标和完整坐标 |
sample_t |
定位所有者使用的采样时间 |
source |
official_ws、local_ws 或 minimap |
状态网关会在信封中附加 sequence、published_at、expires_at 和发布者名称。
PoseProvider 是导航侧依赖的最小定位接口,包含位置采样、朝向控制、朝向阈值和
静止诊断。导航模块不得导入 src/localization/ 的具体实现。
4. 消费方式
普通任务继承 RuntimeStateMixin,只调用下列接口:
pose = self.world_pose(frame=frame, max_age=0.6)
if pose is None:
return
x = pose["x"]
z = pose["z"]
if not pose.get("position_trusted") or x is None or z is None:
return
map_id = pose["map_id"]
等待条件成立时使用:
pose = self.wait_world_pose(
lambda value: bool(value.get("position_trusted")),
frame=frame,
max_age=1.0,
timeout=10.0,
tick=0.1,
)
其他信息使用通用接口发布和读取:
self.publish_runtime_state(
RuntimeTopic.WORLD_SCENE,
{"scene": "world"},
source="SceneDetector",
ttl=2.0,
)
scene = self.runtime_state(RuntimeTopic.WORLD_SCENE, max_age=1.0)
5. 调度约束
ok-script 的执行器是单线程协作调度。长任务运行期间,其他 TriggerTask
不会并行执行,因此定位不能假设自己会独立按固定周期运行。
RuntimeStateMixin.world_pose(refresh=True) 会通过统一控制面调用定位所有者的
sample_world_pose()。消费者不接触 WS、小地图或融合对象,但可以请求所有者
采一帧并发布快照。这样同时满足单所有者、单线程调度和统一消费接口。
6. 扩展规则
- 高频变化的数据使用 latest-value,消费者慢时丢弃旧值,不能阻塞生产者。
- 离散状态变化使用事件流,每个订阅者拥有独立队列,禁止共享单消费者队列。
- OCR、模板扫描等按需任务使用请求响应,不要把所有请求广播给全部消费者。
- 配置、物品点位、地图文件和网格文件属于参考数据,继续通过 Config 或数据服务读取。
- 状态值必须带时间、来源和可信状态;需要旧值时返回过期错误,不返回陈旧值。