面向读者

验证等级

仅配置验证。 本案例会解析真实的本地 Registry,校验 manifest 与资产摘要, 并构建不可变的 ExecutionPlan。它不会启动 PyBullet,也不声称通过了原生仿真验证。

你将学到什么

一条简短的 use: 会经过以下完整链路:

text
run.yaml 中的 use
  -> 最近的 .fastsim/project.yaml
  -> 具名 Registry index
  -> stable 指向的 1.0.0 发布版
  -> 经过摘要校验的组件 manifest
  -> pybullet variant
  -> 经过摘要解析的 URDF resource
  -> 不可变 ExecutionPlan

文件说明

  • run.yaml 请求一个可复用的方块组件。
  • main.py 编译 Run,并断言加载链路中的关键结果。
  • 组件 manifest 声明组件及其各后端 variant。
  • Registry index 把 identity 映射到 stable 版本和带摘要的 manifest。
  • ../.fastsim/project.yaml 注册 index,并声明可信资产根目录。

逐行阅读组件 manifest

链接中的 manifest 包含:

yaml
schema: fastsim-component/1              # 组件文档协议。
id: object://fastsim/component-demo-cube # 稳定、面向使用者的 identity。
version: 1.0.0                           # 不可变发布版本。
kind: object                             # 允许放到 scene.objects。
semantics:
  category: primitive                    # 可移植的描述性元数据。
variants:
  pybullet:                              # run.yaml 选择 PyBullet,因此选中它。
    resources:
      model:                             # 组件内部的资源名称。
        uri: assets/cube.urdf             # 相对于当前 manifest。
        format: model/vnd.urdf+xml       # 明确的机器可读格式。
        role: simulation                 # 用于构建仿真实体。
        sha256: 29d00308...              # 预期资源字节,编译成功前必须匹配。

真实 manifest 还包含 MuJoCo 和 Isaac Lab variant。因此切换后端时组件 identity 保持不变,由 variant 选择后端能接受的资产表达。

Registry index 提供两项不应写入 Run 的信息:

yaml
stable: 1.0.0                            # use 省略 @version 时选择的版本。
releases:
  1.0.0:
    manifest: object_cube.yaml           # 相对于 index 的位置。
    sha256: df81158b...                  # 精确的文件内容完整性门禁。

Index 的 SHA-256 校验 manifest 原始文件字节;Plan 中的 manifest_sha256 校验通过 验证后的规范化 manifest 含义。两者负责不同层次,因此不要求数值相同。

逐行阅读 run.yaml

yaml
schema: fastsim/2                        # FastSim vNext Run 协议。
name: component-loading-pipeline         # 人类可读的运行名称。
backend: pybullet                        # 选择 manifest 的 pybullet variant。

runtime:
  physics_hz: 60                         # 期望的物理频率。
  control_hz: 30                         # 期望的控制接收频率。
  seed: 101                              # 确定性运行随机种子。

scenario:
  scene:
    objects:
      cube:                              # 本次 Run 内别名:objects.cube。
        use: object://fastsim/component-demo-cube
        pose:
          xyz_m: [0.0, 0.0, 0.5]        # 世界坐标位置,单位米。
          quat_xyzw: [0.0, 0.0, 0.0, 1.0] # 单位旋转,XYZW 顺序。

cube 只是本次 Run 的别名;object://fastsim/component-demo-cube 才是可移植的 目录 identity。编译器会在 plan 中把无版本请求固定为 object://fastsim/component-demo-cube@1.0.0

enabled 是什么意思

所有场景实体都支持 enabled: trueenabled: false。像本案例一样省略该字段时, 默认值是 true

yaml
objects:
  optional_cube:
    use: object://fastsim/component-demo-cube
    enabled: false

设置为 enabled: false 后,FastSim 仍会解析并校验组件,并在 Scenario、 ExecutionPlan 和 Run Lock 中保留完整实体声明。因此,读取 Scenario 的插件仍能知道 这个实体被声明过,但当前处于关闭状态。不过在 Runtime 阶段,FastSim 不会把它投影到 UniRoboSim 物理世界:

  • 不会创建对应的原生物体、铰接体、机器人、环境、流体或传感器;
  • 不会产生实时物理、渲染或传感器状态,也不能作为控制目标;
  • 不会进入实时规划几何,也不能作为要求实体已启用的默认机器人或 Mount 目标。

它是编译场景时的开关,不是运行过程中的动态显隐或暂停命令。修改该值需要生成新的 Plan,并启动新的应用组合;普通 Runtime Reset 仍然使用原来的 Plan,不会改变它。该 开关也不会跳过配置编译阶段的 Manifest 和资源解析。一个可复用 Scenario 需要保留 可选实体时可以使用它;如果连组件和资源都不应解析,则应从场景配置中彻底删除该实体。

阅读 main.py

  1. Path(__file__).with_name("run.yaml") 从脚本位置寻找相邻 Run,不依赖当前工作目录。
  2. load_project(RUN_FILE) 向上发现 ../.fastsim/project.yaml
  3. project.compiler().compile_file(RUN_FILE) 加载 index、校验 manifest 摘要、 选择 pybullet、解析 URDF,并冻结 plan。
  4. 断言验证 identity、版本、manifest 摘要、variant、资源格式、资源摘要和 plan 摘要。

代码只使用公开的 fastsim.config API。

运行

bash
cd demo/components/01_loading_pipeline
fastsim config validate run.yaml --json
fastsim config expand run.yaml
fastsim config explain run.yaml scenario.scene.objects.cube.component.identity
fastsim config lock run.yaml --output run.lock.yaml
fastsim config verify-lock run.lock.yaml --json
python main.py

config explain 查询的是编译后的有效 Plan。仅用于编写阶段的 use 此时已经完成解析, 所以有效路径是 component.identity;选中的 versionvariant 位于同一个 component 映射中。

run.lock.yaml 是什么

run.yaml 是便于人编写的仿真意图,其中可以选择 Registry 的 stable 组件、继承 Manifest 默认值并使用资源 URI。fastsim config lock 会先编译这些意图,再把精确结果 写成生成的快照,其中包括:

  • 完整且不可变的 ExecutionPlan,包括后端、Runtime 参数、Seed、实体、插件和 Plan 摘要;
  • 每个组件的精确 identity、版本、后端 Variant 和 Manifest 摘要;
  • 每个已解析资源的位置和 SHA-256 摘要;
  • 保护规范化 Plan 与资源位置列表的 lock_digest

fastsim config verify-lock 会检查 Lock 结构与摘要,并逐个读取本地资源,确认文件字节 仍与记录一致。使用 fastsim run run.yaml --lock run.lock.yaml 启动时,还会重新编译 run.yaml;如果当前有效 Plan 与已接受的 Lock 不一致,就会拒绝启动。因此 stable 版本 变化、Pose 被修改、后端 Variant 不同或资产内容变化都会显式失败,而不会悄悄改变实验。

Run Lock 不会冻结原生仿真器、Provider 包、GPU 驱动、操作系统,也不能冻结外部 模型或硬件服务的行为。正式生产时仍需在证据中单独记录这些版本。

请把 Lock 当作生成的验收证据,而不是第二份需要手工编辑的配置。只有明确接受配置 变化后才重新生成。本教程会忽略 run.lock.yaml,练习后可以删除;正式数据生产则应将 它与本次 Run 的输出和来源信息一起归档。对外发布前还应检查其中的本地资源路径。

案例 12 会进一步展示一个多文件组件,并校验它锁定的全部资源。

预期输出

validate 会报告 "ok": truemain.py 输出类似:

text
use       -> object://fastsim/component-demo-cube
release   -> object://fastsim/component-demo-cube@1.0.0
variant   -> pybullet
resource  -> model (model/vnd.urdf+xml)
plan      -> sha256:...

修改 manifest 或有效 Run 后,摘要前缀可能改变;完整摘要始终为 64 位十六进制字符。

常见错误

  • PROJECT_CONFIG_NOT_FOUND:保持 Run 位于本 demo 树内,或显式传入 project; 仅复制 run.yaml 会丢失 Registry 上下文。
  • COMPONENT_NOT_FOUND:对照 catalog/index.yaml 检查 use identity。
  • MANIFEST_DIGEST_MISMATCH:manifest 已修改但发布摘要未更新。这是完整性错误, 不应该绕过。
  • RESOURCE_OUTSIDE_TRUSTED_ROOT:在 project 中登记所需资产根目录,不要宽泛信任 无关目录。

下一步

继续阅读 02 — Object 组件