Relations and Strategies#
Relations describe where a placeable asset should be positioned or oriented.
Attach them to an asset with add_relation(). Arena considers all relations
on that asset together.
Positional relations use solver strategies that convert the requested
arrangement into optimization objectives. Orientation relations and placement
modifiers are handled separately. Most users keep the default strategies;
advanced users can replace entries in RelationSolverParams.strategies.
from isaaclab_arena.relations.relations import IsAnchor, NextTo, On
table.add_relation(IsAnchor())
mug.add_relation(On(table))
bowl.add_relation(On(table))
bowl.add_relation(NextTo(mug))
This describes the intended arrangement without requiring coordinates derived from the dimensions of the table, mug, and bowl.
Anchors#
An anchor is a fixed reference in the relation graph. Mark it with
IsAnchor(); the solver does not move it. A standalone anchor needs a fixed
initial pose; in YAML, an omitted pose defaults to identity. An
ObjectReference instead derives its pose from the referenced prim within
its parent asset. A tabletop or counter reference is a common anchor.
An anchor’s fixed root rotation must be a multiple of 90 degrees about world Z,
with no tilt. For an ObjectReference, this restriction applies to its parent
asset’s pose; the referenced prim’s authored rotation is already included in its
bounds. The solver rotates these bounds into world-aligned bounds.
When the support surface is part of a larger background, use an
ObjectReference to identify that surface:
from isaaclab_arena.assets.object_reference import ObjectReference
from isaaclab_arena.assets.object_type import ObjectType
table_reference = ObjectReference(
name="table",
prim_path="{ENV_REGEX_NS}/maple_table_robolab/table",
parent_asset=background,
object_type=ObjectType.RIGID,
)
table_reference.add_relation(IsAnchor())
mug.add_relation(On(table_reference))
Anchor the background asset directly when its complete bounds represent the
support. Use an ObjectReference when only an internal tabletop, counter, or
similar prim should support placement.
Common Relations#
Most environments can be described with a small set of relations:
On(parent)Places an object on a support surface and keeps its footprint within the support bounds. Use
clearance_mto leave a vertical gap andedge_margin_mto keep the object away from the support edges.Set
overlap=Trueto allow the object to extend beyond the support:box.add_relation(On(table, overlap=True))
This requires overlap in both X and Y (edge contact counts), ignores
edge_margin_m, and keeps the same height constraint. It does not guarantee stable support: the object may tip or fall. The default isoverlap=False.Onuses the top and horizontal footprint of the parent’s axis-aligned bounding box. For L-shaped, hollow, or concave supports, anchor anObjectReferencethat identifies the valid support surface.During initial sampling, a movable parent directly on an anchor uses that anchor’s bounds as a proxy. For a deeper chain, such as a spoon
Ona cupOna trayOna table, initialization of the spoon uses the first anchor collected byObjectPlaceras a proxy. This affects only the starting pose; final solving and validation use each relation’s actual parent.ClutterOn(parent)Defines release poses above a fixed
IsAnchorsupport.ObjectPlacersamples within the central fraction of the support’s width and depth (spread, default 0.2), then stacks overlapping footprints above the surface.clearance_msets the minimum surface clearance;gap_msets the initial inter-object gap, increased to the solver’s collision clearance when larger. Subsequent solving uses the shared collision clearance.The
clutter_on_relationcheck enforces the release footprint and minimum height; contact is not required. Height validation allows 1 micrometre of numerical slack onclearance_m, but never permits penetration below the support top. The ordinaryon_relation_z_tolerance_mcontact tolerance does not apply to clutter.ObjectPlacercomputes release poses, and normal simulation makes the objects fall. Release validation certifies the initial geometry; it does not certify the final pile after physics. With explicitenabled_checksorrequired_checks, includeclutter_on_relationfor clutter andon_relationfor ordinary On objects. Both are enabled by default.ClutterOnmust be the object’s only spatial relation and cannot useRandomAroundSolution.RotateAroundSolutionsets the base rotation;random_yaw(default True) adds world-Z yaw while preserving its tilt. Tilted clutter requirescollision_mode="bbox"on the object; these bounds enclose the full rotation. MESH collision checks support yaw only. For pooled placement, disableObjectPlacerParams.allow_best_loss_fallbacksto reject invalid layouts. DirectObjectPlacer.place()callers must check each result’ssuccessbefore using it.
NextTo(parent)Places an object beside another object. A side and distance can be specified when needed. Geometric validation rejects candidates that are not on the requested side, or whose gap to the parent differs from
distance_mby more thantolerance_m(0.01 m by default). Placing the object closer than requested also fails.With no additional arguments,
NextTo(parent)places the subject on the parent’s positive X side at a distance of 0.05 m.sideacceptsSide.POSITIVE_X,Side.NEGATIVE_X,Side.POSITIVE_Y, orSide.NEGATIVE_Y.NotNextTo(parent)Defines a side-specific keep-out region next to the parent. The region extends outward from the selected side and spans the parent’s footprint along the perpendicular axis. Validation rejects candidates inside that region. The keep-out margin defaults to 0.1 m. Advanced users can change it by providing a
NotNextToLossStrategyforNotNextToinRelationSolverParams.strategies.AtPosition(...)Constrains selected world-coordinate axes. It can be combined with
Onso the relation determines height while coordinates determine horizontal position.PositionLimitsBoxandPositionLimitsCylindricalPositionLimitsBoxconstrains selected world X, Y, or Z coordinates between optional minimum and maximum values.PositionLimitsCylindricalconstrains the XY distance from a chosen center using a minimum radius, maximum radius, or both; it does not constrain Z.FaceTo(target)Rotates an object around world Z so that its local +X heading points toward another object.
from isaaclab_arena.relations.relations import FaceTo
target.add_relation(On(table))
camera_prop.add_relation(On(table))
camera_prop.add_relation(FaceTo(target))
FaceTo determines the heading after position solving:
It cannot be combined with
RotateAroundSolution.When random yaw initialization is enabled, it replaces the random heading.
The target must also participate in relation placement.
A movable subject can have only one
FaceTorelation.Neither the subject nor target can use
RandomAroundSolutionwith nonzero XY offsets.The subject and target must have different XY positions.
Combining Relations#
Relations are most useful in small combinations:
Onalone means “somewhere on this surface.”OnwithNextTomeans “on this surface, beside that object.”OnwithAtPositionmeans “at this horizontal location on the surface.”A positional relation with
FaceTocontrols both location and orientation.
Avoid specifying more relations than the environment needs. Extra constraints can make the intended layout harder or impossible to satisfy.
Placement Modifiers#
RandomAroundSolution and RotateAroundSolution are pose modifiers applied
after solving. They change how a solved pose is used rather than adding spatial
constraints:
RandomAroundSolutioncreates a range of positions and orientations around the solved pose. It is intended for direct, single-environmentObjectPlaceruse; the default builder does not apply it as a continuous reset range.RotateAroundSolutionadds a fixed roll, pitch, or yaw to the solved pose. The robot-placement example later in this sequence uses it to set the robot’s final heading.
Relations in Environment Specifications#
YAML environment specifications use the same model:
relations:
- kind: is_anchor
subject: table
- kind: 'on'
subject: mug
reference: table
- kind: next_to
subject: bowl
reference: mug
Each entry identifies the relation, its subject, and—when needed—the object it
references. Add parameters only when the default relation does not express the
intended arrangement. Quote 'on' so YAML treats it as a string rather than
a Boolean value.
Collision handling is integrated into placement and is not expressed as a relation.
Recorded Layouts#
Pass the companion file to the environment builder:
/isaac-sim/python.sh isaaclab_arena/scripts/environment_runner.py \
--env_spec scene.yaml --placement_layouts layouts.jsonl
For a registered Python environment, place --placement_layouts layouts.jsonl
before the environment subcommand. Python callers use
ArenaEnvBuilderCfg(placement_layouts_path="layouts.jsonl"). All file paths are
relative to the working directory.
A ten-layout example for isaaclab_arena/tests/test_data/placement_replay.yaml
is available in isaaclab_arena/tests/test_data/placement_replay.jsonl.
Each JSONL line contains one complete layout under
variations["scene.relation_placement"]["poses"]. Poses use runtime scene keys
for both YAML and Python environments. Use asset.get_scene_root_keys() to
identify all owned physics roots. Ordinary objects use their instance names;
single-root embodiments commonly use "robot". Compound embodiments expose
each owned root, whose runtime name can differ from the YAML node ID.
Positions are environment-local, in metres; rotations are xyzw quaternions.
Every nonblank line must contain the placement block with the same object set.
Additional episode fields are ignored; episodes without placement records cannot
be loaded. Python callers can pass PlacementLayouts directly to
IsaacLabArenaEnvironment instead of configuring a file path.
Supplying both is rejected.
from isaaclab_arena.relations.placement_layouts import PlacementLayouts
arena_env.placement_layouts = PlacementLayouts.from_episode_jsonl("layouts.jsonl")
Set replay inputs before compose_manager_cfg() or make_registered().
For registered Python environments, a Python runner can set
builder.arena_env.placement_layouts after obtaining the builder. Replay inputs
are read when the environment configuration is composed.
PlacementLayouts.write_episode_jsonl(path, source=...) writes the same format.
The caller supplies the source label, such as "solver" or "settled";
the writer does not solve or simulate the poses.
Resetting environments draw consecutive layouts from one shared queue, in reset
request order. The queue wraps after its last layout. For four layouts and three
environments, successive full resets select [0, 1, 2], then [3, 0, 1].
A partial reset consumes only the layouts needed by those environments; other
poses remain unchanged. Layouts can repeat across active environments after the
queue wraps. If the environment count is a multiple of the layout count,
repeated full resets assign the same layout to each environment. The queue covers
all layouts across the batch; it does not guarantee that each environment visits
every layout. Partial-reset order determines later assignments, so different
policies may receive different per-environment sequences.
Replay validates finite poses, unit quaternions, consistent object coverage and reset ownership. Recorded objects share one reset writer, which zeros their root velocities. All non-anchor objects with spatial relations must be included, as must a non-anchor embodiment carrying any placement relation or marker. Object sets, disabled pose resets, non-fixed pose-reset policies and nonzero initial velocities are unsupported.
Replay requires resolve_on_reset=True; an explicit
--no-resolve_on_reset or a false environment default is rejected. An explicit
placement_seed in the placement configuration or on the CLI is also rejected
because layouts are read in file order.
--no_solve_relations is compatible: replay never invokes the solver.
Placement validator settings apply only when solving; they do not revalidate a
recorded layout or open the solver’s debug viewer.
Loading bypasses solving and does not rerun geometry, reachability or settling checks. Recordings must match the scene and robot configuration being replayed; disable pose-changing variations and callbacks when exact replay is required.
Next Steps#
See Record and Replay Clutter Layouts for offline settling.
To generate a pose file from an existing environment, see Record and Replay Placement Poses.
Continue to Collision Handling to learn how Arena checks placed assets against one another and against fixed geometry.