Assets#
An asset is anything Arena places in a scene, such as a cracker box, a kitchen background,
a robot, or a light. Each asset has a name, which identifies it in the environment:
variation keys such as <name>.mass, its prim path, its contact sensor, and recorded data
use it. Most assets are objects (Object): spawned from a USD file or a spawn configuration
as a rigid, articulated, or static body. A robot (an embodiment) is an asset but not an object.
Arena ships with a library of asset classes, and new ones can be added by registering them.
Each asset class is registered under a registry_name, such as rubiks_cube_hot3d_robolab.
asset_registry.get_asset_by_name() returns the class. Calling the class creates an asset.
A library object such as CrackerBox is named after its registry name unless you pass name,
for example to name it after its role in the task:
CrackerBox = asset_registry.get_asset_by_name("cracker_box") # the class, registry_name "cracker_box"
cracker_box = CrackerBox() # an asset named "cracker_box"
pick_up_object = CrackerBox(name="pick_up_object") # an asset named "pick_up_object"
pick_up_object.registry_name # "cracker_box"
Backgrounds and robots take no name argument. Their name is always their registry name.
Most code does both steps in one line:
background = asset_registry.get_asset_by_name("kitchen")()
cracker_box = asset_registry.get_asset_by_name("cracker_box")()
Registering a new asset#
To add a new object, subclass LibraryObject, set its registry_name, provide the USD path
and object type, and decorate it with @register_asset:
@register_asset
class MyObject(LibraryObject):
registry_name = "my_object"
tags = ["object", "graspable"]
usd_path = "path/to/my_object.usd"
object_type = ObjectType.RIGID
Once registered, the class is available in the registry like any other asset class:
obj = asset_registry.get_asset_by_name("my_object")()
Assets can also be tagged to make them discoverable by category:
# All graspable objects
objects = asset_registry.get_assets_by_tag("graspable")
# A random graspable object
obj = asset_registry.get_random_asset_by_tag("graspable")()
Useful tags include "graspable", "openable", "pressable", and "background".
Assets can have multiple tags — for example, a fruit is tagged both "graspable" and "food".
Object configuration#
An object’s constructor sets its USD source, scale, initial pose, and object type.
asset_cfg_addon configures the Isaac Lab asset (for example, debug_vis or articulation
actuators). spawn_cfg_addon configures how the USD is loaded and which physics properties
are authored during spawning: mass/density, collision settings, and contact materials.
Use prim_physics within the spawn addons for selected bodies, colliders, or joints.
Physics spawn addons#
Use spawn_cfg_addon to override physics parameters:
Addon |
Example parameters |
|---|---|
|
Mass and density. |
|
Gravity, damping, and velocity limits. |
|
Collision enablement, contact offset, and rest offset. |
|
Static/dynamic friction and restitution. |
|
Self-collision and articulation solver settings. |
|
Selected-prim collision, material, mass, joint, or backend-specific settings,
defined by an environment-owned |
For example, override friction on the library red cube’s Cube collider:
import math
from isaaclab.utils.configclass import configclass
from pxr import UsdPhysics, UsdShade
from isaaclab_arena.assets.object_library import RedCube
from isaaclab_arena.assets.physics_config import UsdPrimSpawnPhysicsCfg
@configclass
class ColliderFrictionCfg(UsdPrimSpawnPhysicsCfg):
"""Bind an instance-local contact material to a selected collider."""
friction: float = 0.8
"""Static and dynamic friction coefficient."""
def validate_target(self, prim, root):
"""Require a collider and a finite nonnegative friction coefficient."""
assert prim.HasAPI(UsdPhysics.CollisionAPI)
assert math.isfinite(self.friction) and self.friction >= 0
assert not prim.GetStage().GetPrimAtPath(prim.GetPath().AppendChild("ContactMaterial"))
def apply(self, prim, root):
"""Author and bind a material within the spawned asset."""
# A local material preserves shared source materials and remaps during cloning.
material = UsdShade.Material.Define(prim.GetStage(), prim.GetPath().AppendChild("ContactMaterial"))
physics = UsdPhysics.MaterialAPI.Apply(material.GetPrim())
physics.CreateStaticFrictionAttr(self.friction)
physics.CreateDynamicFrictionAttr(self.friction)
UsdShade.MaterialBindingAPI.Apply(prim).Bind(
material,
bindingStrength=UsdShade.Tokens.strongerThanDescendants,
materialPurpose="physics",
)
class HighFrictionRedCube(RedCube):
spawn_cfg_addon = {
"prim_physics": {"Cube": ColliderFrictionCfg(friction=0.8)},
}
red_cube = HighFrictionRedCube()
prim_physics keys are exact paths relative to the asset root; use "." for the root.
Settings apply after USD loading and before cloning and physics import.
See Physics configuration for configuration order and Embodiment for robot and end-effector physics.
Object types#
Every asset has an object type that determines how it is simulated:
RIGID — a single rigid body (boxes, bottles, tools, furniture).
ARTICULATION — a multi-body scene object with joints (doors, drawers, appliances).
BASE — no physics; used for static backgrounds and markers.
Deformable and backend-specific spawn configs must match the environment’s resolved physics backend (PhysX or Newton). See Physics backend selection.
Backgrounds#
Backgrounds are registered as BASE assets, but their composed USDs may contain
dynamic rigid bodies and articulations whose states can change as they interact with
the robot or other objects. Arena resets these nested physics roots by default. Set
reset_nested_physics=False on a Background to opt out.
Arena registers the roots as private Isaac Lab reset views. After simulation and RTX initialization, Arena creates the views and records one environment-local pose and joint configuration. On each episode reset, Arena applies those values to the resetting environments and zeros all root and joint velocities. The private views are not exposed through the Isaac Lab scene entity registries.
Arena discovers nested roots through the composed USD physics APIs.
Included:
Standalone rigid bodies.
Articulation roots, which own their links and joints.
Excluded:
BASEand collision-only prims.Rigid and articulation roots owned by matching
ObjectReferenceentries.Articulation links, which cannot own reset state independently.
Authored roots without a live physics backend object after composition.
BASE object references remain observational and do not transfer reset
ownership away from the background.
Instanceable subtrees that contribute dynamic physics are materialized at spawn time because physics views cannot control dynamic instance proxies.
Object references#
A background asset like a kitchen is a single USD file containing many prims:
countertops, shelves, drawers, and so on. To use one of these internal prims
as a destination or interaction target (e.g. “place the object on the counter”),
you use an ObjectReference.
kitchen = asset_registry.get_asset_by_name("kitchen")()
counter = ObjectReference(
name="kitchen_counter",
prim_path="{ENV_REGEX_NS}/kitchen/counter_right_main_group/top_geometry",
parent_asset=kitchen,
)
task = PickAndPlaceTask(
pick_up_object=cracker_box,
destination_location=counter,
background_scene=kitchen,
)
The parent_asset tells the environment which spawned USD the prim path belongs to.
The prim path uses {ENV_REGEX_NS} so it resolves correctly across parallel environments.
Rigid object sets#
To fill one scene role with different rigid objects across parallel
environments, wrap the candidates in a RigidObjectSet. See
Rigid Object Sets for motivation, usage, and limitations.