安装
运动学求解器不是 FastSim 的基础依赖。包索引已经提供这些发行包时,可以安装:
python -m pip install 'fastsim[kinematics]'
从源码安装时,先安装 FastSim-Plugins 中的 SPI 和 Portable Provider,再安装
FastSim:
python -m pip install ./FastSim-Plugins/packages/fastsim-kinematics-solver-spi
python -m pip install ./FastSim-Plugins/packages/fastsim-kinematics-solver-portable
python -m pip install ./FastSim
没有安装这些可选包时,import fastsim 和普通 Run 仍能正常工作。只有第一次查询
Descriptor 或调用求解时,才会返回带安装提示的
KinematicsSolveErrorCode.SERVICE_UNAVAILABLE。
准备机器人组件
FastSim 只能从不可变 ExecutionPlan 中已经编译的机器人实体选择模型,调用方不能传入
主机文件路径。组件需要包含一个 URDF 资源。存在 role: kinematics 时优先选它;否则
组件内必须恰好只有一个 URDF 资源。
因此,Isaac Lab 组件可以用 USD 运行仿真,同时用同一机器人的 URDF 做可移植求解:
schema: fastsim-component/1
id: robot://example/arm
version: 1.0.0
kind: robot
semantics:
joints: [shoulder, elbow]
joint_units:
shoulder: rad
elbow: rad
groups:
arm: [shoulder, elbow]
frames: [base, tool]
variants:
isaaclab:
resources:
simulation:
uri: arm.usd
format: model/vnd.usd
role: simulation
kinematics:
uri: arm.urdf
format: model/vnd.urdf+xml
role: kinematics
第一次使用时,Core 会打开 ExecutionPlan 指定的精确文件,不跟随符号链接;随后检查 它是大小受限的普通文件,并核对锁定的 SHA-256,最后才把 URDF 文本交给 Provider。 公开请求中没有文件路径或仿真器原生句柄。
初学者 API
import asyncio
import fastsim
async def main() -> None:
async with fastsim.app("run.yaml") as simulation:
result = await simulation.kinematics.solve(
robot="arm", # Scenario 别名或完整 robots.* ID
base_frame="base",
tip_frame="tool",
xyz_m=(0.55, 0.10, 0.42),
quat_xyzw=(0.0, 1.0, 0.0, 0.0),
group="arm", # 多 Group 机器人建议明确填写
timeout_s=1.0,
)
if result.status.value != "success":
print(result.status.value, result.failure_code, result.message)
return
joints = result.solutions[0].joints
operation = await simulation.control.submit_joints(
actor="arm",
group="arm",
path=[joints.positions],
dt=1.0 / 60.0,
timeout=10.0,
)
print((await operation.result()).status)
await operation.release()
asyncio.run(main())
不填写 start 时,Core 会从当前 Run Generation 最新一次已提交 WorldState 中原子
读取当前关节位置。关节 ID、顺序和逐轴单位来自已编译组件语义。双臂或移动操作机器人
应填写 group,使当前状态与指定 URDF 运动链精确一致。
默认 Provider 提供确定性的可移植 URDF 运动学。首版只支持
collision_mode="none"。请求世界或自碰撞时会返回明确的 unsupported 响应,
FastSim 不会静默降级为无碰撞求解。
高级 API
高级用户可以从 fastsim.api.kinematics 按需导入不可变类型,并提交完整
IKRequest:
from fastsim.api.kinematics import IKRequest, Pose
state = await simulation.state()
request = IKRequest(
request_id="layout-check-0042",
run_id=simulation.run_id,
generation=state.world.generation,
robot_entity_id="robots.arm",
base_frame_id="base",
tip_frame_id="tool",
target=Pose("base", (0.55, 0.10, 0.42), (0.0, 1.0, 0.0, 0.0)),
start=None,
timeout_s=1.0,
)
result = await simulation.kinematics.solve_request(request)
同一个 Generation 内,request_id 具有幂等语义。完全相同的请求会返回缓存的不可变
响应;用同一个 ID 提交不同输入会被拒绝。
创建 Application 时可以显式选择其他已安装 Provider:
simulation = fastsim.app(
"run.yaml",
kinematics_solver="kinematics-solver://vendor/gpu-ik",
kinematics_config={"device": "cuda:0"},
)
Provider 发现要求 fastsim.kinematics_solvers 下恰好有一个匹配的 Entry Point,并在
使用前核对 Distribution、版本、Entry Point 名称和值、服务 API 与 Descriptor 标识。
生命周期与错误
只有显式查询 Descriptor 或调用求解时,才开始 Solver 发现、模型读取、Executor 创建 和 Provider 工作。未使用时不导入 Solver 包、不创建线程,也不注册 Tick Hook。
每个请求在 Provider 工作前与结果发布前各检查一次 Generation。Reset 会取消旧 Generation 的在途任务;即使 Provider 之后返回,旧解也会被丢弃。Provider 在 Application Owner Loop 外执行。超时与调用方取消会设置线程安全取消标志;不配合取消的 工作也只能留在有界 Orphan 配额中。
Core 边界错误统一抛出 KinematicsSolveError,其中包含稳定 code 以及请求、Run、
Generation 和实体上下文。目标不可达、关节限位不可行、不支持碰撞模式或不收敛等正常
数学结果仍是有类型的 IKSolveResponse,不是异常崩溃。
常见 Core 错误码如下:
| 错误码 | 含义 |
|---|---|
service_unavailable |
可选 SPI 缺失、不兼容、重复或无效 |
solver_not_found |
没有安装显式选择的 Provider |
entity_not_found / entity_not_robot |
编译实体不存在或不是机器人 |
model_unavailable / model_unsupported |
没有唯一且校验通过的 URDF,或 Provider 拒绝模型 |
state_unavailable |
无法取得新鲜、有序的当前关节状态 |
stale_generation |
Reset 或 Run 替换使请求失效 |
request_conflict |
同一个请求 ID 被用于不同输入 |
capacity_exhausted |
有界 Active/Orphan 配额已满 |
timeout / cancelled |
Core 截止时间或调用方取消结束了请求 |
provider_failure |
Provider 在正常响应契约之外失败或违反契约 |