前置条件
请把 FastSim 和 Isaac Lab provider 安装到同一个环境。本 Run 会以可见模式启动 Isaac Lab 3.0 / Isaac Sim 6.0。
逐项理解配置
yaml
schema: fastsim/2 # FastSim vNext Run 配置规范。
name: demo-frame-transforms # 稳定的 Run 名称。
backend: isaaclab # 选择机械臂的 Isaac Lab USD 资源。
runtime:
launch_profile: visible # 打开仿真器原生窗口。
physics_hz: 60 # 物理积分频率。
control_hz: 60 # 控制帧接收频率。
seed: 41 # 可复现的 reset 随机种子。
scenario:
scene:
robots:
arm: # Scenario 别名;规范 ID 为 robots.arm。
use: robot://fastsim/demo-two-joint-arm
pose:
xyz_m: [0.25, -0.20, 0.0] # 非零世界平移,单位米。
quat_xyzw: [0.0, 0.0, 0.2588190451, 0.9659258263] # 绕 Z 轴 30 度。
initial_state:
joints:
joint_1: 0.35 # 转动关节位置,单位弧度。
joint_2: -0.50
非零根位姿和关节值可以证明返回的是实际组合变换,而不是写死的单位变换。
逐行理解 Python
- Docstring 明确说明程序执行可移植 Frame 查询。
asyncio、math、Path和fastsim分别提供异步运行器、有限数检查、 相邻 Run 定位和公共 API。RUN_FILE指向run.yaml;VISIBLE_HOLD_SECONDS控制短暂的可视检查时间。main()定义异步应用流程。fastsim.app(..., planning_reads=True)显式开启按需付费的 Frame 发布路径。async with保证后端被完整清理。start()构建真实场景;pause()在稳定的变换边界保留场景。frames.catalog()返回当前 generation 的不可变 Frame Graph。- 第一个
next(...)查找类型为world的唯一 descriptor。代码不假设 provider 使用什么世界坐标系字符串。 - 第一个列表推导式选择规范实体
robots.arm的全部 frame,第二个列表只保留 link frame。 parent_frame_ids收集所有拥有子节点的 frame;程序要求机械臂恰好只有一个 叶子 link,再选择这个真实末端 link,不依赖不透明的哈希 frame ID 排序。 生产代码也可以改成选择组件显式声明的 named frame。frames.transform(source, target)返回target_T_source。因此先传 link、后传 world,查询的正是world_T_link。- 验证块要求平移和四元数全部有限,且四元数模长与 1 的误差不超过
1e-4; 否则返回非零退出码。 - 打印内容包括每个 Frame 及其父节点、选中的叶子 link、明确的变换方向、SI 平移、四元数和实测模长。
- 最后的等待让暂停后的可见场景保留三秒。
asyncio.run(main())在直接运行文件时执行程序。
验收门禁
- 机械臂 Frame Graph 必须恰好有一个叶子 link。
- 所有变换分量必须有限,四元数模长误差不得超过
1e-4。 - 2026-08-25 的可见 Isaac Lab 真机验收选中的末端 link 约位于
(0.25, -0.20, 0.50) m,四元数模长为1.000000,退出码为 0。
运行
从本案例目录运行:
bash
cd demo/fundamentals/09_frame_transforms
fastsim config validate run.yaml --json
python main.py
预期输出至少一个属于 robots.arm 的 link frame,并以 world_T_<link> 形式打印
查询方向,随后输出有限的平移和四元数数值。
验证等级
真实可见 Isaac 已通过。 真机运行选择了真实叶子 link,返回的变换全部有限,
四元数模长为 1.000000;程序正常退出,并且没有遗留 Isaac worker 进程。
变换记法
A_T_B 把坐标从 frame B 变换到 frame A。因此:
python
await simulation.frames.transform(source_frame, target_frame)
返回 target_frame_T_source_frame。始终明确这个顺序,可以避免常见的位姿取逆错误。
常见错误
SERVICE_ACCESS_DENIED:Frame 读取要求planning_reads=True。FRAME_NOT_FOUND:从frames.catalog()发现 ID,禁止根据后端路径自己拼接。arm_links为空:provider 没有发布组件声明的 link;应把它当作组件/provider 不匹配处理,而不是猜一个 Frame。