Audience
Verification level
Configuration only. The example validates the robot manifest, resolves its real URDF, and inspects the portable vocabulary. It does not start PyBullet or validate actuation, dynamics, IK, or planning.
Files
run.yamladds one two-joint arm and its initial joint positions.main.pyasserts joints, links, frames, groups, and instance state.- Robot manifest declares the reusable robot contract.
Component manifest, line by line
schema: fastsim-component/1
id: robot://fastsim/component-demo-arm # Stable robot identity.
version: 1.0.0 # Immutable component release.
kind: robot # Legal under scenario.scene.robots.
semantics:
joints: [joint_1, joint_2] # Portable joint names.
links: [base_link, link_1, link_2] # Portable link names.
frames: [base_link, link_2] # Named application-facing frames.
joint_units:
joint_1: rad # State/control unit for joint_1.
joint_2: rad # State/control unit for joint_2.
groups:
arm: [joint_1, joint_2] # Ordered arm command group.
variants:
pybullet:
resources:
model:
uri: ../../_shared/assets/two_joint_arm.urdf
format: model/vnd.urdf+xml
role: simulation
A useful robot manifest separates portable intent from backend representation.
Application code uses stable joint, link, frame, and group names. Each backend
variant supplies the model it can consume. More complex robots can declare multiple
groups such as base, left_arm, right_arm, and gripper without changing the
Run structure.
When authoring your own robot, make these names match the public vocabulary you want users to depend on. A manifest is not a controller implementation and does not hide missing native actuators or bad dynamics.
run.yaml, line by line
schema: fastsim/2
name: robot-component
backend: pybullet # Select the PyBullet-compatible model.
runtime:
physics_hz: 60 # Physics frequency declaration.
control_hz: 30 # Control admission frequency.
seed: 104 # Reproducible run seed.
scenario:
scene:
robots:
arm: # Local entity alias: robots.arm.
use: robot://fastsim/component-demo-arm
pose:
xyz_m: [0.0, 0.0, 0.0] # Robot root in world metres.
quat_xyzw: [0.0, 0.0, 0.0, 1.0]
initial_state:
joints:
joint_1: 0.20 # Radians, as declared by the manifest.
joint_2: -0.40 # Negative angles are valid.
arm is an instance alias; it need not equal the component name. A Run can create
multiple instances of one robot under unique aliases.
What main.py proves
Using only from fastsim.config import load_project, the program compiles the Run
and asserts:
- the selected component has
kind: robot; - its ordered joint, link, and frame declarations are available to upper layers;
- group
armresolves to both joints in order; - the initial joint mapping reaches the immutable entity record.
Run it
cd demo/components/04_robot_component
fastsim config validate run.yaml --json
fastsim config expand run.yaml
fastsim config explain run.yaml scenario.scene.robots.arm.initial_state.joints.joint_1
fastsim config lock run.yaml --output run.lock.yaml
fastsim config verify-lock run.lock.yaml --json
python main.py
Expected output
Entity: robots.arm
Joints: ('joint_1', 'joint_2')
Links: ('base_link', 'link_1', 'link_2')
Frames: ('base_link', 'link_2')
Group 'arm': ('joint_1', 'joint_2')
Common errors
- An initial-state joint absent from
semantics.jointsis rejected. - Group order matters for vector commands; keep it deliberate and documented.
- A
toolframe declaration is a name contract, not proof that every asset variant has been calibrated correctly. Native onboarding must verify it. - A robot component describes a robot entity. A refrigerator or laptop with joints
belongs in an
articulation://component instead.
Next
Previous: articulation component · Next: environment component