Prerequisites
Install FastSim and the Isaac Lab provider in the same environment. This Run starts Isaac Lab 3.0 / Isaac Sim 6.0 with a visible window.
Configuration, key by key
schema: fastsim/2 # FastSim vNext Run schema.
name: demo-frame-transforms # Stable Run name.
backend: isaaclab # Select the arm's Isaac Lab USD resource.
runtime:
launch_profile: visible # Open the native simulator window.
physics_hz: 60 # Physics integration frequency.
control_hz: 60 # Control admission frequency.
seed: 41 # Reproducible reset seed.
scenario:
scene:
robots:
arm: # Scenario alias; canonical ID is robots.arm.
use: robot://fastsim/demo-two-joint-arm
pose:
xyz_m: [0.25, -0.20, 0.0] # Non-zero world translation, in metres.
quat_xyzw: [0.0, 0.0, 0.2588190451, 0.9659258263] # 30 deg about Z.
initial_state:
joints:
joint_1: 0.35 # Revolute position in radians.
joint_2: -0.50
The non-zero root pose and joint values make it easy to see that the returned transform is a real composed result rather than a hard-coded identity.
Python, line by line
- The docstring states that this is a portable frame lookup.
asyncio,math,Path, andfastsimprovide the async runner, finite-value checks, adjacent Run lookup, and public application API.RUN_FILEpoints torun.yaml;VISIBLE_HOLD_SECONDScontrols the short visual inspection period.main()defines the async application flow.fastsim.app(..., planning_reads=True)explicitly enables the pay-for-play frame publication path.async withguarantees complete backend cleanup.start()builds the real scene;pause()preserves it at a stable transform boundary.frames.catalog()returns the immutable frame graph for this generation.- The first
next(...)finds the one descriptor whose kind isworld. Code does not assume a provider-specific world-frame spelling. - The first list comprehension selects every frame owned by canonical entity
robots.arm; the second keeps only its link frames. parent_frame_idscollects frames that have a child. The program requires exactly one leaf link, then selects that physical distal link without depending on opaque hashed frame-ID ordering. Production code can instead select an explicitly declared named frame.frames.transform(source, target)returnstarget_T_source. Passing the selected link first and world second therefore requestsworld_T_link.- The validation block requires finite translation/quaternion components and a
quaternion norm within
1e-4of one; otherwise the process exits non-zero. - The print loop shows each portable frame and parent, the selected leaf, explicit transform direction, SI translation, quaternion, and measured norm.
- The final sleep holds the paused visible scene for three seconds.
asyncio.run(main())executes the program when launched directly.
Acceptance gates
- The arm graph must have exactly one leaf link.
- Every transform component must be finite and quaternion norm error must be at most
1e-4. - The visible Isaac Lab acceptance run on 2026-08-25 selected the distal link at
approximately
(0.25, -0.20, 0.50) m, measured quaternion norm1.000000, and exited with code 0.
Run it
From this case directory:
cd demo/fundamentals/09_frame_transforms
fastsim config validate run.yaml --json
python main.py
Expected output lists at least one robots.arm link frame, prints a lookup in the
form world_T_<link>, and returns finite translation and quaternion values.
Verification level
REAL VISIBLE ISAAC PASS. The native run selected the actual leaf link, returned
finite transform data with quaternion norm 1.000000, exited normally, and left no
Isaac worker process behind.
Transform notation
A_T_B maps coordinates expressed in frame B into frame A. Consequently:
await simulation.frames.transform(source_frame, target_frame)
returns target_frame_T_source_frame. Keeping that order explicit prevents a common
class of inverted-pose bugs.
Common errors
SERVICE_ACCESS_DENIED: frame reads requireplanning_reads=True.FRAME_NOT_FOUND: discover IDs fromframes.catalog(); never construct one from a backend path.- An empty
arm_linkslist: the provider did not publish the component's declared links; treat this as a component/provider mismatch rather than guessing a frame.