• 默认禁用的托管 interface 插件:只观察有界的 Run、插件事件和场景历史,不持有仿真权限;
  • 基于操作者所拥有 FastSimApplicationInteractiveDebugSession:提供暂停、恢复、单步、 带确认门禁的重置/停止、条件暂停断点、实体检查和 RGB 截图请求。

这种拆分遵循 FastSim 的公开能力边界。托管插件拿不到实时 Runtime、后端句柄、生命周期控制命令或 simulation.query;它只能通过 run.lifecycle 请求协调终止。应用所有者才拥有暂停和相机读取所需的 公开方法。本包不穿透私有 composition 对象,也不包含抓取、放置等任务语义。

安装

支持 Python 3.11 和 3.12:

bash
python -m pip install "fastsim>=0.1.0a15,<0.2" \
  "fastsim-plugin-interactive-debug==0.1.3"

源码安装:

bash
python -m pip install /path/to/fastsim-next
python -m pip install \
  /path/to/fastsim-plugins/packages/fastsim-plugin-interactive-debug

该发行包发布两个托管插件入口:

  • fastsim.components / fastsim.interactive-debug
  • fastsim.plugins / fastsim.interactive-debug

安全默认值:零激活

仅添加组件时保持安全、无活动:

yaml
plugins:
  debug:
    use: plugin://fastsim/interactive-debug

组件默认 enabled: false。托管实例仍参与正常插件生命周期记账,但不会查找服务、查询场景、创建订阅、 发布事件、注册回调或创建后台任务,也不会注册物理 tick 钩子,因此禁用后的稳态不会增加逐 tick 工作。 启用调试必须是明确的 Run 配置选择。

托管观察器

启用观察;若需要查看整个场景而非仅查看隐式绑定的机器人/关节体,请显式写空绑定:

yaml
plugins:
  debug:
    use: plugin://fastsim/interactive-debug
    bindings: {}
    config:
      enabled: true
      watches:
        arm_joint_0:
          path: /scene/entities/robot/articulation/state/positions/0
      breakpoints:
        joint_limit:
          watch: arm_joint_0
          operator: ge
          expected: 1.2
          action: notify
          enabled: true

省略实例的 bindings 时,FastSim 会推导所有可用机器人/关节体别名;显式 {} 会让公开 scene-query 授权保持非实体限定,从而能检查普通物体。部署访问策略仍可缩小或拒绝这些可选服务。

托管 watch 文档的根路径如下:

text
/run
/scene/run_id
/scene/generation
/scene/tick
/scene/sim_time_s
/scene/entities/<entity-id>/descriptor
/scene/entities/<entity-id>/state
/scene/entities/<entity-id>/links/<link-id>
/scene/entities/<entity-id>/articulation/descriptor
/scene/entities/<entity-id>/articulation/state
/scene/attachments

路径采用 RFC 6901 JSON Pointer:/ 编码为 ~1~ 编码为 ~0,tuple 下标使用十进制。 它们只是数据查找,不是 Python 表达式。支持 eqnegtgeltlecontainschangedexists

托管断点支持 action: notify。命中会写入有界历史,并发布命名空间内的 breakpoint.hit 事件。 若配置已启用的 action: pauseprepare() 会明确抛出 CAPABILITY_UNAVAILABLE,不会静默降级。 自动暂停请使用下文的应用会话。

托管对象提供:

python
plugin.status
plugin.event_history
plugin.state_history
plugin.inspect_entity("box")
plugin.inspect_object("box")
plugin.inspect_articulation("robot")
plugin.inspect_robot("robot")
plugin.request_run_stop(confirm=True)

最后一个调用通过公开 run.lifecycle 服务提交 RunCompletionRequest(outcome="cancelled"),这是插件侧 唯一可用的终止动作。pause()resume()single_step()reset()request_screenshot() 都会抛出稳定的 DebugCapabilityUnavailableError

watch 会自动建立最小场景需求:/scene/entities/<id>/... 只读取对应实体;多个实体 watch 会合并成一次查询;/scene/tick 等时间戳 watch 直接使用 delta envelope,不重建 catalog。 使用 watch 不需要开启 streams.scene: true。该开关只用于明确要求每个保留的场景历史样本 都包含完整场景文档的情况,因此其成本会随场景规模增长。静态 catalog 会持续复用,只有 generation、catalog revision 或 catalog digest 变化时才重新读取。

应用所有者交互会话

当操作者拥有公开异步 FastSimApplication 时,使用 InteractiveDebugSession

python
import asyncio
import fastsim
from fastsim_plugin_interactive_debug import InteractiveDebugSession


async def main() -> None:
    simulation = fastsim.app("run.yaml", planning_reads=True)
    async with simulation:
        await simulation.prepare()
        debug = InteractiveDebugSession(simulation)
        debug.add_watch(
            "arm_joint_0",
            "/scene/entities/robot/articulation/state/positions/0",
        )
        debug.add_breakpoint(
            "joint_limit",
            watch="arm_joint_0",
            operator="ge",
            expected=1.2,
            action="pause",
        )
        await debug.attach()
        await debug.start_monitoring(interval_s=0.1)
        await simulation.start()

        status = debug.status
        robot = await debug.inspect_robot("robot")
        capture = await debug.request_screenshot("overview_camera")

        await debug.pause()
        await debug.step(5)
        await debug.resume()
        await debug.close()


asyncio.run(main())

FastSim 的应用 scene client 要求 planning_reads=True。会话仅调用 snapshot()scene.catalog/stateplugin_events()、公开生命周期方法和 camera_rgb()

应用会话在没有 scene watch 时不会读取场景;实体 watch 使用选择性查询并缓存静态 catalog。 只有确实需要每个调试历史样本都包含完整场景时,才传入 full_scene_history=True

reset()stop() 必须传入 confirm=True:重置会替换仿真 generation,停止会拆除 Run。 close() 只停止调试监控,不会关闭或停止传入的应用。暂停断点采用边沿触发,并在公开快照边界求值。 单次 step(count) 最多 10,000 步,断点命中后会提前结束。

应用会话 watch 文档使用 /application/scene 根路径。例如 /application/runtime/tick 读取 Runtime tick;上面的场景路径继续位于 /scene 下。

历史与状态

两个接口都返回不可变的 DebugStatusDebugHistoryRecordWatchResultBreakpointHit。托管接口默认限制如下:

历史 默认容量 最大可配置值
生命周期/插件/场景事件 256 65,536
一致场景状态 128 16,384
断点命中 128 16,384

容量满时淘汰最旧记录,历史永不无界增长;订阅队列同样有界。状态包含可用能力、精确限制、消费者运行状态、 当前 generation/tick/time、watch 结果、断点历史和有界的最后错误。

检查与截图

检查结果完全由公开 SceneCatalogSnapshotSceneStateSnapshot 组装:

  • 物体使用通用实体描述、pose 和 twist;
  • 关节体增加有序关节描述、位置、速度及 SI 单位;
  • 机器人是 kind: robot 的实体,复用同一套通用关节体契约。

结果中没有后端原生 Robot 句柄。

request_screenshot(entity_id) 调用应用公开的 camera_rgb(),返回不可变 RGB24 字节和元数据: 相机实体、宽高、Run/generation/tick/time、字节数、媒体类型和 SHA-256。它不会截取桌面或 viewport, 也不编码 PNG。若后端或实体不提供 RGB 相机,会原样传播 FastSim 的类型化查询失败。

精确限制

  • 托管插件不能暂停、恢复、单步、重置或直接停止 Runtime。
  • 托管插件不能请求按需相机截图;已配置 RGB observation 不能冒充暂停时的新截图。
  • 应用断点是轮询/快照边界检查,不是物理 tick 内的原子断点;条件可能在两次轮询间跨越。
  • 场景检查需要 scene.query;应用侧还必须启用 planning_reads=True
  • 仅支持已配置场景相机的 RGB24;桌面、viewport、深度、分割、PNG 和视频不在本版本范围内。
  • watch 不能执行代码、调用方法或修改状态。
  • 本包不会生成控制轨迹、抓取/放置、attachment、planner 或 task 动作。
  • 真实后端、GPU、相机设备和 GUI 验证取决于部署环境,单元测试不宣称这些检查已通过。

开发验证

在本包目录执行,并确保 a13 源码位于 PYTHONPATH 首位:

bash
FASTSIM_SRC=/path/to/fastsim-next/src
PYTHONPATH="$FASTSIM_SRC:src" python -m pytest -q
python -m ruff check src tests
PYTHONPATH="$FASTSIM_SRC:src" python -m mypy src/fastsim_plugin_interactive_debug
python -m build --no-isolation

测试覆盖禁用零激活与 tick 循环 A/B 性能、严格配置、不可执行 watch、断点边沿、有界历史与队列、服务拒绝、 托管生命周期清理、协调终止、参考 FastSimApplication 生命周期纵切、应用安全门禁、普通物体/机器人/通用 关节体检查、场景相机 RGB 截图元数据、manifest/digest 一致性、entry-point 元数据以及 wheel/sdist 内容。