Scene¶
The cell: one or more robots, the obstacles around them, the frames they mount on, the devices and sensors that give the environment behavior, the named motions, and the sequences that drive it all.
Units are meters, and the world is Z-up. Orientations are quaternions in
(x, y, z, w) order. Wherever a method takes robot=None, it acts on the
scene's first robot.
A scene is also the live link to the studio: state changes made from Python are pushed to connected browsers, and edits made in the browser are visible here.
import botrail as bt
scene = bt.Scene(bt.Robot.from_urdf("arm.urdf"))
scene.add_box("table", size=(0.6, 0.6, 0.05), position=(0.4, 0.0, 0.0))
scene.load_usd("cell.usda", prefix="env")
scene.set_robot_base_pose(*scene.frame("env/World/mount"))
Scene
¶
The cell: one or more robots in a workspace, with the obstacles, frames, sensors, devices, motions, and sequences around them. Shared with the studio server: state changes made here are pushed to connected browsers immediately.
collision_warnings
property
¶
Link shapes skipped for collision checking (e.g. meshes, until the mesh I/O crate lands).
robot_base_pose
property
¶
World pose of the robot root as (position, quaternion_xyzw).
scenario_names
property
¶
Defined scenario names, in authoring order (baseline — the
unmodified scene — is implicit and never listed).
add_beam_sensor
method descriptor
¶
add_beam_sensor(
name,
frm,
to,
radius=0.005,
watch=None,
watch_robot=False,
watch_robots=None,
mount=None,
watch_groups=None,
)
Adds a photoelectric beam sensor between two world points, ON while
the beam is interrupted. Watch semantics as in add_zone_sensor.
add_box
method descriptor
¶
Adds a box obstacle (full extents, meters). Returns the final name, which may be uniquified. Changes are pushed to connected studios.
add_camera
method descriptor
¶
add_camera(
name,
position=Ellipsis,
quaternion=None,
look_at=None,
fov=None,
resolution=None,
near=None,
far=None,
mount=None,
robot=None,
link=None,
from_catalog=None,
revision=None,
body_visible=True,
)
Adds a camera: a named viewpoint with pinhole optics, drawn as a
frustum in the studio. Presentation only — it publishes no signal
and never affects planning or the cycle. position/quaternion
are in the mount frame (-Z looks, +Y is image-up); look_at aims
the camera at a world point instead of giving a quaternion. Mount
it with mount= (a vehicle device) or robot=/link= (a wrist
camera); default is a world fixture. fov is the horizontal field
of view in degrees (default 60); resolution sets the frustum
aspect and the pixel size of exports (default 1280x720).
from_catalog= names a sensor.camera package: its flat specs
become the optics defaults (fov/resolution and, from the range
specs, near/far), explicit arguments still win, and the package's
identity lands on the BOM (set_part(kind="camera")). With an
explicit pose, position/quaternion place the package's mount
face and the optical axis follows the package's own calibration
(frames.camera_frames); look_at aims the optical axis itself.
add_conveyor
method descriptor
¶
Adds a conveyor: while running, any unattached obstacle whose origin
lies inside the zone box is carried at velocity (m/s). Start/stop
it from sequences with bt.seq.start/bt.seq.stop.
add_cylinder
method descriptor
¶
Adds a cylinder obstacle (URDF convention: axis along local +z).
add_field_sensor
method descriptor
¶
add_field_sensor(
name,
lidar,
watch=None,
watch_robot=False,
watch_robots=None,
range=None,
sector=None,
shadowing=True,
)
Adds a laser-scanner field sweeping through lidar: its name
becomes a read-only input signal, ON while a watched body crosses
the scanner's scan-plane sector. range shrinks the field radius
(default: the lidar's max range) and sector=(start, end) narrows
its angular window (degrees in the scan frame, 0 = +X, CCW;
default: the full sweep) — one scanner carries several fields, the
warning/protective field-set shape. shadowing (default on)
ray-tests each candidate's origin against the other obstacles, so
a body hidden behind another does not trip it. Geometry only — no
per-angle rays are cast, robot links (when watched) detect by
overlap alone, and a vehicle-mounted field ignores its own
machine's body.
add_frame
method descriptor
¶
Registers (or updates) a named world frame.
add_io_node
method descriptor
¶
add_io_node(
name,
kind="plc",
robots=None,
programs=None,
uplink=None,
channels=None,
place=None,
model=None,
label=None,
)
Declares a controller / I/O node of the cell's assignment layer:
kind is "plc", "safety_plc", "remote_io",
"robot_controller" (with robots=[...]) or "other".
programs lists the sequences this node runs (unlisted programs
are placed implicitly — see the I/O map guide); uplink is the
parent node ("PLC1" or ("PLC1", "PROFINET")) whose I/O a remote
station or safety module belongs to; channels are the dicts the
bt.io templates build (bt.io.di8(base="%IX0.0") + bt.io.do8(...)
or bt.io.ur_standard()).
add_lidar
method descriptor
¶
add_lidar(
name,
position=Ellipsis,
quaternion=None,
yaw=None,
fov=None,
range=None,
resolution=None,
channels=None,
vfov=None,
mount=None,
robot=None,
link=None,
from_catalog=None,
revision=None,
body_visible=True,
)
Adds a LiDAR scanner: a named scan origin with a planar sweep,
drawn as a sector in the studio. Presentation only — it publishes
no signal and never affects planning or the cycle (a field sensor
referencing it is the planned signal path). The scan plane is the
local XY plane, angle 0 along +X, counter-clockwise toward +Y (the
ROS laser frame); yaw aims that +X heading in the mount frame
(degrees about +Z) instead of giving a quaternion. Mount it with
mount= (a vehicle device) or robot=/link=; default is a
world fixture. fov is the full scan angle in degrees up to 360
(default 270), range the measuring band [min, max] in meters
(default (0.05, 20.0)), resolution the angular step in degrees
the scan API will default to (default 0.5).
from_catalog= names a sensor.lidar package: its flat specs
become the sweep defaults (fov/resolution and, from the range
specs, the measuring band), explicit arguments still win, and the
package's identity lands on the BOM (set_part(kind="lidar")).
The given pose places the package's mount face and the scan
origin follows the package's own frame (frames.lidar_frames —
ROS laser convention, which is botrail's, so no rotation fix).
add_lift
method descriptor
¶
add_lift(
name,
car,
zone_position,
zone_size,
stops,
speed=0.5,
axis=Ellipsis,
zone_quaternion=None,
start=None,
)
Adds a lift (elevator): the car obstacles ride along axis
between named stops, and whatever the capture zone holds when
the ride is commanded rides too — loose parts by origin, and
vehicles whole (body, deck load, mounted robot). Command it with
bt.seq.move_to(name, "2F") and await bt.seq.device_done(name).
The zone (like the car) is authored where the car stands at
start; a vehicle half out of it refuses to board by name.
Doors are ordinary authoring — an add_linear_axis panel and a
signal — not part of the device. Car entries name obstacles
exactly, or as subtree prefixes.
add_linear_axis
method descriptor
¶
Adds a linear axis (door / lifter / indexer) moving the listed
obstacles along axis at speed, positioned within range by
bt.seq.move_to; await it with bt.seq.device_done.
stops names positions along the axis ({"closed": 0.0, "open":
0.76}): bt.seq.move_to(name, "open") drives to one, and each is
a read-only input lane <name>/<stop> — ON while the axis stands
at it, off between stops — the limit switch an interlock waits on
(bt.seq.signal("door/closed")), and a DI on the I/O list.
What the axis drives is checked against every robot each tick: a
leaf closing on an arm still inside is a DeviceCollision error
naming the device, the obstacle, the robot and the link.
add_mesh
method descriptor
¶
Adds a mesh obstacle from an STL/OBJ file. The collision shape is a VHACD convex decomposition (computed on first load, then cached on disk); the studio renders the original mesh.
add_robot
method descriptor
¶
Adds another robot instance and returns its (possibly uniquified)
scene-unique instance name. name defaults to the model name.
Connected studios pick the new robot up immediately (the handshake
is re-broadcast).
add_scenario
method descriptor
¶
Defines (or replaces) a scenario — a named initial-state delta the
simulate_* calls can run under. Deltas only: signals overrides
declared internal-signal initial values, obstacles maps names to
a position or a (position, quaternion) pair, joints maps robot
instances to start configurations, and faults pins inputs for
the whole run — bt.io.stuck("part_at_pick", False) ignores the
sensor's geometry (or a program's set on an internal signal),
bt.io.open("part_at_pick") is a broken wire (input level low, so
the value follows the binding's invert). "baseline" is the
reserved name of the unmodified scene. Everything is validated when
the scenario is applied (at simulate), so deltas may name things
authored later.
add_segment
method descriptor
¶
add_segment(
motion,
goal=None,
kind="joint",
orientation_cone=None,
position_box=None,
robot=None,
group=None,
)
Appends a waypoint segment to motion (created when missing).
goal=None captures the current configuration. Constraints:
orientation_cone=(axis_local, axis_world, angle_rad) keeps the tool
axis inside a cone; position_box=(min, max) keeps the TCP inside a
world-aligned box. Both apply along the whole segment.
group names the arm a new motion drives (an existing motion keeps
its arm): only that arm's joints move, and goal components outside
it are ignored. Omitted, the robot's sole group — or every joint of
a robot with several.
add_sink
method descriptor
¶
Adds the far end of a line: any unattached carrier reaching the zone
goes back to source's magazine, free to be fed again.
add_source
method descriptor
¶
Adds a feeder: every interval seconds while running it puts the
next waiting member of pool at position.
The pool is finite because a baked timeline holds a fixed set of
named object tracks — an endless line is this plus an add_sink
that returns carriers to the magazine. Member i waits at
park + pitch * i, and a member that does not start on its slot
starts out on the line (an already-loaded belt).
add_spin
method descriptor
¶
Binds an accumulating cut trace to a signal at a robot's TCP:
while the signal is true during playback, the studio draws the
TCP's trail (the cut so far) and spins spin_link if given. Pure
presentation, like add_weld_flash; in USD the toolpath curves
already carry the picture.
Binds a spin effect to a signal: while the signal is true during
playback, the studio turns link of robot about its own Z —
a screwdriver's bit running a screw down — and draws nothing else.
Pure presentation, like add_weld_flash; USD export carries
nothing for it.
add_spray_cone
method descriptor
¶
Binds a spray-cone effect to a signal at a robot's TCP: while the
signal is true during playback, the studio draws a translucent
cone length long and radius wide at its base along the TCP's
spray direction (its -Z), and USD export carries a beam of the
same size with animated visibility. Bind it to the effective
trigger a timeline writes with with_trigger_signal so it
follows what actually sprayed rather than the enable alone. Pure
presentation, like add_weld_flash.
add_vehicle
method descriptor
¶
add_vehicle(
name,
body,
path,
stations,
speed=0.5,
turn_speed=Ellipsis,
start=None,
ring=False,
allow_reverse=False,
max_grade=None,
drive="differential",
climb_speed=None,
descent_speed=None,
fixed_yaw=None,
tray_position=None,
tray_size=None,
tray_quaternion=None,
reverse_speed=None,
prefer="forward",
arrive=None,
turn_radius=None,
)
Adds a guided transport vehicle (an AGV / AMR as the cell sees it):
it drives station to station along path — straight legs at
speed, in-place pivot turns at turn_speed — carrying the body
obstacles rigidly. Dispatch it with bt.seq.goto(name, station) and
await arrival with bt.seq.device_done(name). The arrival heading
is the last leg's direction, so the waypoint before a station sets
how the vehicle docks. Body entries name obstacles exactly, or as
subtree prefixes ("/World/AGV" takes every obstacle under it).
Waypoints are (x, y) or (x, y, z): z is the floor height on the
guidance surface, so a ramp climbs with its waypoints (the body
stays level, and speed is spent along the 3D path). A path that
climbs needs max_grade — the steepest rise over horizontal run
the machine may take (0.10 = 10 %); without it only level paths
pass validation.
drive="aerial" makes the machine a multirotor: z is its own axis
(any climb, no grade rule, vertical legs fly — a ground station
under an overhead waypoint is the takeoff), speed is the
horizontal cruise and each leg's clock is the slower axis,
max(run/speed, rise/climb_speed (or descent_speed)). The nose
faces each leg's course, or holds fixed_yaw the whole flight.
add_vision_sensor
method descriptor
¶
add_vision_sensor(
name,
camera,
watch=None,
watch_robot=False,
watch_robots=None,
detect_range=None,
occlusion=True,
)
Adds a vision presence sensor looking through camera: its name
becomes a read-only input signal, ON while a watched body overlaps
the camera's view frustum. detect_range narrows the detection
band along the view axis (default: the camera's near/far clip);
occlusion (default on) ray-tests each candidate's origin against
the other obstacles, so a body hidden behind another does not trip
it. Geometry only — no pixels are rendered or interpreted, and
robot links (when watched) detect by overlap alone.
add_weld_flash
method descriptor
¶
Binds a weld flash to a signal at a robot's TCP: while the signal
is true during playback, the studio draws an arc flash there and
the USD export blinks an emissive prim. Pure presentation, driven
by the same baked signal a weld controller's "current on" output
would be — declare the signal first (define_signal), author it
from the sequence that owns the weld.
add_zone_sensor
method descriptor
¶
add_zone_sensor(
name,
position,
size,
quaternion=None,
watch=None,
watch_robot=False,
watch_robots=None,
mount=None,
watch_groups=None,
)
Adds a box-shaped presence sensor: its name becomes a read-only
input signal, ON while a watched body overlaps the zone. watch is
a list of obstacle names (default: every obstacle); pass
watch_robot=True to sense robot links too (with watch=[] for a
robot-only light curtain).
watch_groups=[(robot, group), ...] watches the named arms only —
the interlock zone that sees one arm of a dual-arm robot and not
the other.
allow_inter_robot_collision
method descriptor
¶
Excuses one link pair of two different robots from collision checking — the escape hatch for arms that share a mount plate or are meant to touch. Unlike a robot's own self-collision matrix, which is generated by sampling, inter-robot pairs are never inferred: whether two arms may touch depends on where their bases stand, so it is the author's call.
allow_link_obstacle_contact
method descriptor
¶
Marks contact between link (of robot) and obstacle as
process-intended — a milling cutter in its stock. The pair stops
counting as a collision (checking, planning, min_clearance);
toolpath rapids deliberately ignore the exemption — while not
cutting, any contact is a crash.
allow_object_obstacle_contact
method descriptor
¶
Lets the obstacle object, while a robot carries it, meet
obstacle without counting as a collision — the part being
fitted: a cover set down on its housing and dowels, a screw in the
hole it is driven into. Without window the pair may meet anywhere;
with window = (point, axis, radius, angle) only while the carried
object's origin lies within radius (m) of the line through point
along axis and its own +Z within angle (rad) of that axis — the
hole's axis and tolerance, so a screw off its hole is still a
collision. Applies to checking, planning and min_clearance;
toolpath rapids ignore every allowance. Re-declaring a pair replaces
its window.
animate_carve
method descriptor
¶
animate_carve(
timeline,
stock,
stages=None,
chord_tolerance=1e-05,
max_deviation=1e-05,
tile_size=None,
cutter_radius=0.004,
cutter_length=0.03,
dt=0.01,
robot=None,
tcp_link=None,
voxel_size=None,
)
Progressive material removal for a baked cycle: re-cuts the sweep
in stages equal time slices (default: one slice per second of
cycle, capped at 240 — the display lags the tool by at most one
slice, so this keeps the lag around a second). The stock is kept as
tiles; at the first cut every tile is registered as a display-only
obstacle (grouped under {stock}_cut/…, cheap AABB colliders — they
never collide), and afterwards only the tiles a slice changed get a
new version, so idle stretches and untouched regions cost nothing.
Returns the timeline with the visibility windows injected: during
playback — studio, USD export, and a replayed recording alike — the
stock disappears as it is cut instead of starting pre-cut. The stock
keeps colliding unchanged; everything here is presentation.
The cut is computed with mesh booleans (cutrail): chord_tolerance
(m) is the polygonization of the cutter and max_deviation (m) how
far a sampled TCP may stray from the segment it is folded into;
tile_size (m) defaults to 2.5 cutter diameters. voxel_size is
deprecated and ignored.
animate_paint
method descriptor
¶
animate_paint(
timeline,
target,
applicator=None,
stages=None,
patch_size=0.01,
dt=0.01,
gate=None,
spec=None,
facing=None,
facing_tolerance=Ellipsis,
occlusion=True,
robot=None,
tcp_link=None,
trigger_signal=None,
style="amount",
paint_color=None,
substrate=None,
)
Progressive film build-up for a baked cycle: re-walks the coat in
stages equal time slices (default: one slice per second of
cycle, capped at 60 — the display lags the gun by at most one
slice), registers one display-only obstacle per changed slice
(grouped under {target}_film/…, cheap AABB colliders — they never
collide) each carrying the film's colour key, and returns the
timeline with the visibility windows injected: during playback —
studio, USD export, and a replayed recording alike — the target's
own colour gives way to the film building up on it. Optionally
writes the effective spray trigger as signal trigger_signal
(declare it first) for a timing lane and a spray-cone effect. The
target keeps colliding unchanged; everything here is presentation.
Stages walk at patch_size — coarser than a spray_coat for the
numbers, since a mesh per stage is what a viewer has to carry —
with the same trigger rules (applicator, gate, brushes) as
spray_coat. Coloured by amount by default (a build-up is about
how much paint is there: the ramp — in paint_color, if given —
runs from a light wash to the full colour at the spec's high edge,
or the final maximum without one), on the target's own colour;
style="spec" colours every stage against the band instead.
attach
method descriptor
¶
Attaches an obstacle to a robot link at its current relative pose —
a grasp. While attached the object follows the link (live, in
planning, and in playback) and collides as part of the robot.
link=None uses the TCP link; touch_links=None allows contact
with the link's subtree (the gripper).
group names the arm: link=None is then that arm's tip.
auto_assign_io
method descriptor
¶
Gives every unbound point a channel, deterministically: points in
table order, channels in declaration order, on the point's host
and the stations uplinked to it, first free channel of a compatible
family (safety points prefer safety channels). Existing bindings
are kept; reassign=True first drops the bindings an earlier run
placed (hand bindings keep their channels). Points on an
implicit host (<cell>, <robot>) are not placed — declare the
node that runs their program. Returns the report afterwards.
bind_input
method descriptor
¶
bind_input(
name,
node,
channel,
tag=None,
field=None,
invert=False,
contact=None,
safety=False,
voltage=None,
logic=None,
note=None,
)
Wires an input point ("beam_pick", "line" for a device's
in-position input, "far.done" for a robot's done contact) to a
channel of node. invert=True flips the wire level (NC wiring);
contact ("no" / "nc"), field (the device on the far end),
voltage / logic ("pnp" / "npn") and note document it.
bind_output
method descriptor
¶
bind_output(
name,
node,
channel,
tag=None,
field=None,
invert=False,
contact=None,
safety=False,
voltage=None,
logic=None,
note=None,
)
Wires an output point ("conv" for a run coil, "vacuum" for a
coil, "line.index" for an indexed-transfer start, "far.start"
for a robot start) to a channel of node. Same keywords as
bind_input.
bom
method descriptor
¶
The bill of materials derived from the scene: robots and their
tools (catalog identity when loaded from the catalog), the
controller every arm needs (<robot>/controller, until a
robot_controller node declares it), conveyors / axes / vehicles,
sensors and I/O nodes — each listed whether or not it has been
identified — plus every obstacle or group a part was pinned to.
Identical products merge into one row with the quantity summed.
camera_fov
method descriptor
¶
The horizontal field of view (degrees) of the named camera — what a picture channel's default decimation cell is sized from.
cell_report
method descriptor
¶
cell_report(
timelines=None,
*,
scenarios=None,
deliverables=None,
clearance_dt=Ellipsis,
title=None,
ground_z=0.02,
sequences=None,
sections=None,
)
Gathers the cell report: robots, the cycles you pass (timelines
— a SequenceTimeline, a list, or a {name: timeline} dict; each
with its step spans, robot utilization and, unless
clearance_dt=None, the tightest clearance re-scanned against the
scene it was baked from), the I/O map's counts and findings, the
scenario matrix (scenarios= a ScenarioRuns — its runs also
stand in for timelines when none are given), the BOM's totals,
the plan-view footprint, and the SHA-256 of every file in
deliverables (external attachments with unverified provenance).
sequences scopes the report's I/O summary; default all.
sections are what a domain module contributes — dicts with
title, markdown and json (bt.assembly.report_section) —
rendered under their titles before the deliverables. For a
common snapshot, fresh bakes and verified files, use bt.export_cell.
A reading surface — pytest keeps the asserts.
check
method descriptor
¶
Every static check in one report — the I/O lint, each sequence
walked for dangling references, unidentified equipment lines and
the requirement comparison (spec_short / spec_unknown). Returns
a bt.select.CheckReport (ok, findings, to_json(),
to_markdown()); botrail check prints the same thing.
check_collisions
method descriptor
¶
Colliding pairs at the current configuration, as
((kind, name), (kind, name)) tuples with kind "link"/"obstacle".
check_paint
method descriptor
¶
check_paint(
name,
target,
standoff=None,
max_incidence=Ellipsis,
max_range=None,
step_pos=0.005,
step_rot=0.05,
)
Checks a toolpath as a spray program against obstacle target
before anything is baked: every feed sample (rapids are not
spraying) looks along its spray axis — the TCP's -Z, against
the tool axis — and reports standoff and incidence, judged against
standoff (acceptable band, meters) and max_incidence (steepest
acceptable angle, radians). Pure geometry: no robot is involved,
so this runs before one is chosen. at on the issues is meters
along the path.
Like check_toolpath, the findings are drawn on the path in the
studio until the next check or edit of that path.
check_toolpath
method descriptor
¶
check_toolpath(
name,
robot=None,
tcp_link=None,
step_pos=0.005,
step_rot=0.05,
jump_threshold=0.5,
axis_tolerance=0.0,
spin="greedy",
)
Attempts every sample of a toolpath and reports all failures (unreachable / IK-branch jump / collision) without aborting — the pre-teach "which points can I not reach" face diagnosis.
clear_toolpath_marks
method descriptor
¶
Clears the marks a check left on toolpath name.
crouch_pose
method descriptor
¶
The posture a mounted walker takes crouched depth metres below its
standing height and leaned lean rad nose-down, where it stands now
(its current base pose, taken as standing): (base_pose, joints),
with base_pose as (position, quaternion_xyzw). Each leg of its
gait is solved so its foot stays where the stance puts it — the same
solve bt.seq.crouch runs every scan tick, so an arm pose taught on
this posture (set_robot_base_pose(*base_pose),
set_joint_positions(joints), then IK) is the one the bake reaches.
The scene is not changed. Raises ValueError naming the leg that
cannot keep its foot planted.
declare_io
method descriptor
¶
An exception to the derivation, or an unmodelled point. role is
"input" (an external contact whatever the sequences do),
"output" (a coil — also promotes a magazine to a real feeder),
"internal" (a relay, no I/O) or "exclude" (off the table). A
name the scene does not have becomes a new declared point when
role is input or output. kind overrides the channel type
("safe_di", ...), safety marks the safety class, pair names
the other channel of a two-channel safety input.
define_applicator
method descriptor
¶
Adds or replaces a toolpath (a continuous Cartesian process path,
see bt.toolpath). toolpath is the dict built by
bt.toolpath.builder() / bt.toolpath.from_gcode() — or its JSON
string. Targets live in the part frame named by its frame key
(resolved at bake time, so moving the frame re-solves the path).
Declares a spray applicator under name — the dict
bt.paint.applicator(...) builds — so brushes can refer to it.
Validated now, not at bake time.
define_brush
method descriptor
¶
Declares a brush: a named process setting a toolpath's strokes run
with — applicator (a define_applicator name) at flow times
its calibrated flow, opened lead seconds before each stroke with
this brush begins and closed lag seconds after it ends. The
program's own trigger, per stroke: pass the brush on
ToolpathBuilder.feed(...) (or bt.paint.strokes(brush=...)), and
the film integrator sprays each stroke with it; feed moves that
name no brush in such a path run with the gun off.
define_signal
method descriptor
¶
Declares (or re-initializes) an internal signal — a PLC internal
relay written by bt.seq.set_signal actions and read by
bt.seq.signal transitions.
detach
method descriptor
¶
Detaches an obstacle; its pose freezes where the robot holds it.
disallow_link_obstacle_contact
method descriptor
¶
Removes an allowed-contact entry added by
allow_link_obstacle_contact.
disallow_object_obstacle_contact
method descriptor
¶
Removes an allowed object contact added by
allow_object_obstacle_contact.
export_bom
method descriptor
¶
Writes the BOM to path; the format follows the extension
(.csv, .md, .json) unless format says otherwise.
export_interlocks
method descriptor
¶
Writes interlocks() to path; the format follows the extension
(.md, .csv, .json).
export_io_list
method descriptor
¶
Writes the I/O list to path; the format follows the extension
(.csv, .md, .json).
export_layout
method descriptor
¶
export_layout(
path,
format=None,
*,
scale=100.0,
units="mm",
ground_z=0.02,
frames=True,
labels=True,
reach=True,
grid=Ellipsis,
title=None,
)
Writes the layout sheet to path; the format follows the extension
(.svg, .dxf, .json) unless format says otherwise. The other
keywords are layout()'s.
export_plcopen
method descriptor
¶
Writes plcopen() to path (.xml).
export_topology
method descriptor
¶
Writes io_topology to path; the format follows the extension
(.mmd / .md Mermaid, .dot / .gv Graphviz, .json).
export_usd
method descriptor
¶
Writes the scene to a USD layer that opens in usdview / Omniverse /
Blender. With a trajectory, an animation: robot link motion as
timeSamples, obstacles as prims, grasped objects riding along —
robot names the instance the trajectory belongs to (required when
the scene has several). Without one, the cell as it stands: robots
at their current joint positions, every visible obstacle at its
pose, toolpaths and cameras — the static layer a layout is handed
around as. The extension picks the serialization — .usda text,
.usdc/.usd binary crate (about half the size). USD-sourced
robots reference their original stage (assets copied to a sibling
<stem>_assets/ directory); URDF robots are authored from the
model's visuals. Returns exporter warnings.
physics= writes the static cell as a simulation stage instead —
the world a physics engine can own (Isaac Sim / Isaac Lab), in
UsdPhysics: robots as articulations (links with mass and
colliders, joints with limits and drives), the dynamic units of
physics_plan() as rigid bodies, what a device moves as kinematic
bodies, everything else that collides as static colliders, a
conveyor's belt with a surface velocity, the ground as a plane.
The vocabulary is a bake's: True is the declared scope,
bt.Physics(world=True) the whole cell. Collision follows
enabled, the picture follows visible (an invisible collision
proxy is authored as a guide). It does not combine with a
trajectory: an animation and a simulation would fight over the
same prims.
footprint
method descriptor
¶
The plan-view extent of the equipment as a dict — min, max
(x, y in metres), width, depth, area (m²), height (tallest
non-ground item). Ground is anything whose top is at or below
ground_z.
frame
method descriptor
¶
Pose of a named frame as (position, quaternion_xyzw) — e.g.
scene.set_robot_base_pose(*scene.frame("/World/mount")).
generate_python
method descriptor
¶
Generates a Python script that rebuilds this scene with the botrail
API (same content as the studio's "Export Python").
embed_catalog=True uses captured catalog sources without Hub access.
Mesh/USD paths must exist; load a portable project first to extract them.
grasp_close
method descriptor
¶
Solves the joint values that close the robot's gripper on obstacle
name, to a signed clearance from its surface (the default is
half a millimetre of overtravel — measured to report contact
reliably under physics without disturbing the part). Returns
{joint: value}, ready to hand to bt.seq.ramp.
Pose the grasp first — the solve runs at the current configuration
and the part's current pose, the same contract as attach. Drive
joints default to every actuated joint below the tool mount (mimic
followers close with their drivers); a limitless drive joint needs
its fully-closed value in closed.
interlocks
method descriptor
¶
The interlock table over sequences (every sequence by default):
one row per output a step switches — a signal, a device command, a
robot motion or ramp, a grasp — with the condition that admits the
step (the previous step's transition, an arm's condition, the
cycle's last transition for a first step), the steps it follows and
the inputs the condition reads, each classified (sensor, signal,
device lane, device, robot), a signal traced to the program and
step that writes it, an address where the host has it bound. The
control designer's interlock sheet, derived rather than typed.
io_list
method descriptor
¶
The I/O list as text: format is "csv", "md" (Markdown table)
or "json" (raw fields, step indices included).
io_map
method descriptor
¶
The assignment layer as authored — nodes, bindings, declarations.
Pass it to to_script(io=...) to project a newer assignment onto
a timeline baked earlier.
io_points
method descriptor
¶
The cell's I/O points, derived from how the sequences use the
scene's names (nothing to author): sensors are inputs, coils and
device commands are outputs, signals read or written across
controllers are handshake wires, robots driven from another host
get start/done points. sequences picks the program set (default:
every sequence — pass what you would pass to simulate_sequences
when alternative programs coexist). See docs/guides/io-map.md.
io_report
method descriptor
¶
Lint findings over the derived I/O map: name clashes, unreferenced
definitions, numeric (word/analog) points, programs on the
implicit cell host. assert scene.io_report().errors() == [] is
the CI form.
io_topology
method descriptor
¶
The electrical topology as text: format is "mermaid" (a
flowchart LR for Markdown), "dot" (Graphviz) or "json".
layers filters the edges — any of "functional", "io",
"network", "wiring", "safety" (default: everything).
Magazines stay out unless include_cosmetic=True.
joint_positions_of
method descriptor
¶
Joint configuration of the robot instance named name.
layout
method descriptor
¶
layout(
format="svg",
*,
scale=100.0,
units="mm",
ground_z=0.02,
frames=True,
labels=True,
reach=True,
grid=Ellipsis,
title=None,
)
The plan-view layout sheet as text: format is "svg" (a
self-contained drawing, scale pixels per metre), "dxf" (a
minimal R12 file for 2D CAD, in units — "mm" or "m") or
"json" (the drawn items in world metres). The sheet is derived
from the scene: every visible obstacle as its footprint (convex
hulls of primitives, bounding boxes of meshes), robots as base marks
with the catalog reach as a dashed circle, conveyor / sink zones,
axis travel and vehicle routes, sensor zones and beams, named
frames, labels (pinned parts first, then named groups), a metre
grid and the overall dimensions. Anything whose top sits at or
below ground_z is floor: drawn faint, left out of the extents.
lidar_scan
method descriptor
¶
Simulates one sweep of the named lidar: one ray per beam at the
scanner's angular resolution, against the scene's collision
shapes — obstacles and robot links alike, massing bodies included.
That is the honest complement of capture_depth (the rendered
meshes): what the scan sees is what the cell can hit. Blind-spot
analysis in one call: 0.0 ranges are no-returns, hits names
what each beam struck, points()/save_ply() give the cloud.
Deterministic — two calls return identical data.
Without t the sweep sees the scene as it stands (a parked
vehicle, the current joint pose). t sweeps at that instant of
the last baked cycle instead — joints, moved objects and the
vehicle the scanner rides all follow the timeline's tracks
(clamped to the duration; simulate a sequence first).
noise adds Gaussian range noise, 1σ meters (a datasheet's
±3 cm accuracy reads as noise=0.03) — what a beam hits never
changes, only how far it reports it, clamped to the measuring
band. Still deterministic: the draw is a pure hash of seed,
beam and instant, so the same call repeats bit-for-bit and a
different seed is an independent stream.
link_pose
method descriptor
¶
World pose of a link as (position, quaternion_xyzw).
link_pose_at
method descriptor
¶
World pose of link_name at joint configuration joints — forward
kinematics without moving the robot (its current joints and any
connected studio are untouched). bt.select.requirements measures
taught targets through this.
load_project
staticmethod
¶
Loads a .botrail project file into a fresh scene (robots
included). URDF robots rebuild from the embedded XML; USD robots
re-import from the referenced stage path.
load_urdf
method descriptor
¶
load_urdf(
path,
prefix=None,
position=None,
quaternion=None,
args=None,
geometry="visual",
frames=True,
package_paths=None,
)
Imports a URDF or xacro as scenery: every visual becomes an
obstacle named <prefix>/<link>, posed at the model's zero
configuration and placed at position / quaternion. Links that
carry no geometry become named frames (see frame()), so a file can
name where the next thing mounts. args fills the file's
$(arg …) substitutions, which is what lets one parametric file
draw every size a product is sold in. geometry="collision" reads
the collision shapes instead of the visuals. Returns the obstacle
names it added.
This is furniture, not a machine: joints are taken at zero and
nothing here articulates. A robot is Robot.from_urdf /
Robot.from_xacro and add_robot.
load_usd
method descriptor
¶
Imports the static geometry of a USD stage (usda/usdc/usdz —
references, variants, and instancing are composed) as obstacles,
normalized to meters / Z-up. Leaf Xform/Scope prims become named
frames (see frame()), usable as robot mount points; Camera
prims become world-fixture cameras (see add_camera) with the
authored optics, whatever their visibility. Obstacle, frame and
camera names are the prim paths, optionally prefixed. Returns the
added obstacle names.
min_obstacle_distance
method descriptor
¶
Minimum robot-obstacle distance (0 when colliding); None without
obstacles. to=[...] measures against only those obstacles — each
a name or a group it sits in ("guard" for every guard/...); a
name that matches nothing raises.
motion_segments
method descriptor
¶
Segments of a motion as (kind, goal_positions) tuples.
mount_robot
method descriptor
¶
mount_robot(
device,
offset_position=None,
offset_quaternion=None,
robot=None,
gait=None,
spin=None,
*,
wheels=None,
carrier=None,
flange=None,
mount=None,
)
Puts a robot on a vehicle: from here its base is derived from that
vehicle's frame, offset away, and re-derived every scan tick — an
arm and a chassis become an AMR. Planned motions cannot start while
the vehicle is driving (a plan is baked in world coordinates); ramps
can, which is how an arm stows itself on the move.
With a gait (a bt.Gait) the robot is the vehicle's legs: it
walks whenever the vehicle drives, and stands in the gait's stance
when it does not. The offset then defaults to the one that puts the
stance feet on the vehicle plane, and the robot is set to its stance.
spin is presentation: {joint: rad/s} turned while the vehicle
is off its starting ground or moving — a multirotor's propellers,
signed so counter-rotating pairs read right. Continuous joints
only; no check reads the phase (the collision stays the swept
solid the catalog authors).
With wheels (a bt.Wheels) the robot is the vehicle's running
gear — a humanoid upper body on a wheeled base, modelled whole: its
wheel joints turn by exactly what the vehicle drives, the machine
is one purchase, and a walkable surface under it is where it
rolls, not a collision. The robot is put in the wheels' posture,
and the offset defaults to the one that stands its base frame (or
its wheels) on the vehicle frame.
With both, the robot is a wheel-legged machine — wheels for feet,
one hanging from each foot link of the gait, the wheel radius for
its foot_radius. The wheels' mode says which gear takes the
route: "roll" (the legs held in the stance with the wheels'
posture laid over it, every wheel turned by its hub's travel) or
"walk" (the wheels locked, the axles planted like feet).
carrier records the loaded vehicle model's flange frame and catalog
provenance for bt.mounting.report(scene). With no offset, the first
mount-side allowed_poses entry is used, or the mounting faces
coincide if none is declared. An explicit offset is kept and
reviewed, not corrected. flange / mount select exact model links;
defaults are the carrier flange and arm mount (or arm root). This is
a catalog-frame alignment check, not a mechanical fit certification.
obstacle_bounds
method descriptor
¶
World-frame axis-aligned bounds of an obstacle, as (min, max).
A cell that has to sit a workpiece on a pallet asks the geometry
where its underside is instead of hard-coding a measured number
that quietly stops matching when the mesh is rebuilt.
obstacle_color
method descriptor
¶
An obstacle's display colour as linear RGB, or None when it has
none and the viewer picks the shading.
obstacle_enabled
method descriptor
¶
Whether an obstacle takes part in collision checking and physics
(set_obstacle_enabled) — what a pool draw parks things out of.
obstacle_finish
method descriptor
¶
The surface pattern ("wood", "checker_plate", "plastic") the
obstacle's material carries, or None.
obstacle_material
method descriptor
¶
(metalness, roughness), or None when the obstacle has no
authored material.
obstacle_opacity
method descriptor
¶
Explicit alpha override, or None when the source/viewer supplies it.
obstacle_pose
method descriptor
¶
World pose of an obstacle as (position, quaternion_xyzw).
obstacle_visible
method descriptor
¶
Whether an obstacle is drawn (set_obstacle_visible).
open_rollout
method descriptor
¶
open_rollout(
sequences,
dt=0.01,
max_duration=120.0,
plan_resolution=None,
scenario=None,
toolpath_spin=None,
physics=None,
)
Opens the rollout simulate_sequences would bake, stopped at
t = 0 with every program in its first step, for Python to
advance one scan tick at a time (design-rl.md R0). Between ticks
the LiveRollout reads the world — joints, link and object poses,
object velocities, signals, this tick's contacts — and drives a
robot's joints toward a rate-limited target; the PLC programs,
devices, sensors and physics run exactly as in the batch bake.
sequences is one name or a list. finish() yields the ordinary
timeline (and broadcasts it to connected studios).
part
method descriptor
¶
The part pinned to name as a dict (target, kind, catalog,
manufacturer, model, category, description, qty,
attributes), or None.
physics_plan
method descriptor
¶
What a physics bake would hand the engine, before running it: the
ground, every rigid unit (its obstacles, fixed or dynamic, the
rule that decided it, its mass) and the count of obstacles
mirrored individually. The default audits the whole cell
(bt.Physics(world=True)); physics=True audits the declared
scope. Robots are not listed — their lowering is the
declaration's (set_robot_physics).
place_vehicle
method descriptor
¶
Places the vehicle name at station as if it had been authored
there: its body moves, what rests in its tray rides along, the
robots mounted on it stand on it there (holding what they hold),
and the station becomes the one a bake starts from. This is how a
mounted robot is taught where it works: set_robot_base_pose
moves the robot alone and leaves the vehicle's body at the start,
so a part in hand meeting the body only shows in the bake. Place it
back at the station it started at to undo.
plan
method descriptor
¶
Plans a collision-free, time-parameterized trajectory from the
current configuration to goal (joint positions in DOF order).
With broadcast=True (default) the result is also pushed to
connected studio clients for preview playback.
group names the arm to plan: only its joints are searched, every
other joint holds. goal may then be given in the group's own joint
order. A robot with one group needs no group.
plan_motion
method descriptor
¶
Plans every segment of motion from the current configuration into
one trajectory (rest-to-rest at segment boundaries). With
broadcast=True the result is pushed to connected studios.
plan_to_pose
method descriptor
¶
plan_to_pose(
position,
quaternion=None,
link=None,
max_iters=10000,
seed=None,
broadcast=True,
robot=None,
group=None,
)
IK to the given pose, then plan to the found configuration. group
names the arm (its tip is the default link, and only its joints
move); a link alone names the arm it hangs off.
plan_toolpath
method descriptor
¶
plan_toolpath(
name,
robot=None,
tcp_link=None,
step_pos=0.005,
step_rot=0.05,
jump_threshold=0.5,
rapid_speed=None,
axis_tolerance=0.0,
spin="greedy",
)
Bakes a toolpath into one continuous trajectory: seed-continuous IK
along the resampled path (5-DOF axis-aligned where the spin is
free), collision-checked per sample, then time-parameterized in one
piece with the commanded feed as a floor — the TCP holds the feed
and slows only where joint limits force it. segment_ends on the
result marks each move's completion time. The trajectory starts at
the path's first target; author the approach separately.
spin picks how the free rotation about the tool axis is chosen:
"greedy" (seed-continuous, milliseconds) or "optimize"
(Descartes-style global pass over a spin grid — spends spin early
to stay solvable late; seconds). axis_tolerance (rad) permits
lead/tilt deviation from the authored axis on spin-free samples.
play_usd_animation
method descriptor
¶
Plays a baked USD recording (an Isaac Sim capture or a botrail
export) on the scene's robots and broadcasts it to the studio.
Joint playback is used when the layer carries JointStateAPI
samples for every actuated joint; otherwise the recorded body
transforms are replayed directly (force_transforms forces the
latter). With several robots each is located at
/World/<sanitized instance name> (the export convention);
robot_roots maps instance names to prim paths when the recording
placed them elsewhere. Returns {"mode", "duration", "warnings"}.
plcopen
method descriptor
¶
The sequences as PLCopen XML (IEC 61131-10, TC6 v2.01): one SFC
program per sequence (sequences= a subset; default all), steps
with their entry actions and transitions, select as a selection
divergence, and the cycle jump at the end (cycle=False parks the
program in a final step). Conditions are ST expressions; device
coils and commands write the I/O map's variables (declared once as
resource globals, with AT addresses from PLC-side bindings);
robot commands call stub function blocks the control engineer
replaces — or the start / done handshake where the map says the
robot is driven from another host. Opens in Beremiz / OpenPLC
Editor. Deterministic (fixed timestamps).
remove_motion
method descriptor
¶
Removes the motion itself, name and all (clear_motion leaves an
empty motion listed — and in the project and the hand-over set). A
sequence that starts it stops validating (unknown motion) until a
motion of that name is authored again.
rename_robot
method descriptor
¶
Renames a robot instance, returning the name it actually got (a
name already taken is uniquified). Sequence actions, robot_done
conditions and a zone sensor's watch list follow the robot, so a
cell can be renamed after it has been authored.
requirements
method descriptor
¶
What every bill-of-materials line must be able to do, derived from
the cell (payload from the tool and the grasped parts, reach from
the taught targets, a beam's span, a conveyor's size and load, ...)
and compared with what the chosen part says. Returns a
bt.select.Requirements (rows, findings(), to_markdown(),
to_json()); botrail derives and compares — it does not choose.
robot_base_pose_of
method descriptor
¶
World base pose of the robot instance named name.
robot_physics
method descriptor
¶
Whether the named robot (or the only one) is declared dynamic.
save_project
method descriptor
¶
Saves the whole cell — robots (URDF embedded, USD by reference),
joint state, obstacles, frames, motions, sequences, signals,
sensors, and devices — as a .botrail project file. Plain JSON
when everything is self-contained; a zip archive (project.json +
assets/) when mesh files are referenced, so the file stays
portable across machines.
scan_sweep
method descriptor
¶
One sweep per frame over the whole last baked cycle, on the
export grid (1/fps steps plus the final instant). The corridor
survey for a riding scanner: merge the frames' points() and the
drive's visibility is one cloud. noise/seed as in
lidar_scan — every frame draws its own beams, so the merged
cloud thickens the way a real drive's does.
sequence
method descriptor
¶
Starts (or replaces) a PLC-style sequence and returns a builder:
scene.sequence("pick").step("run", actions=[bt.seq.motion("go")]).
set_camera_pose
method descriptor
¶
Moves a camera: its position and quaternion (xyzw) in its
mount frame (the world for a fixture, the link for a wrist
camera) — a domain-randomisation hook for the picture channels.
set_gripper_drive
method descriptor
¶
set_gripper_drive(
joints=None,
max_force=None,
stiffness=None,
damping=None,
finger_mass=None,
robot=None,
)
Declares a force-limited drive on the robot's gripper joints
(design-grasping.md G3). Under physics=True the driven fingers
become dynamic bodies moved by force-capped position motors: a
grasped part is held by friction, so a too-weak cap or a
too-fast carry slips for real, and grasp_report() reads the slip
back. Without a physics backend the declaration is inert.
joints— driven actuated joints; default derives every actuated joint below the tool mount (mimics follow either way).max_force— per-joint force cap in N (prismatic) / N·m (revolute); default is each joint's URDF effort limit.stiffness,damping— motor gains; the defaults saturate the cap within ~a millimetre and bound the free speed.finger_mass— mass floor per driven finger body, kg (default 0.2, a finger-plus-carriage moving mass). The engine's contact stiffness scales with the pair's masses, so a mesh-derived few-gram finger cannot develop a newton-scale clamp.
set_link_material
method descriptor
¶
Sets a robot link's contact material for physics bakes — the
name-keyed sibling of set_physics, for the surface the robot
brings to a contact (a fingertip's rubber pad). Inert without a
physics backend; links keep the engine default (friction 0.5,
restitution 0) unless set.
set_obstacle_color
method descriptor
¶
Sets an obstacle's display colour, linear RGB in 0..1. None hands
the shading back to the viewer. Display only — collision and planning
see the same geometry either way.
set_obstacle_enabled
method descriptor
¶
Includes/excludes an obstacle from collision checking (it keeps rendering in the studio either way).
set_obstacle_legend
method descriptor
¶
Attaches a colour key to an obstacle whose colours mean something
— stops is a list of ((r, g, b), label) swatches top to bottom,
linear RGB, empty labels allowed — or clears it with stops=None.
The studio draws it beside the viewport while the obstacle is in
the scene. Presentation only.
set_obstacle_material
method descriptor
¶
Sets how an obstacle's surface takes light. Passing no appearance values
clears the material, handing the choice back to the viewer. finish
— "wood", "checker_plate" or "plastic" — is a surface pattern
the studio draws over the colour (timber grain, the raised bars of
tread plate, moulded plastic); on its own it also picks the two knobs
that finish reads as. Pictures a rollout renders and a USD export
keep the colour and the knobs and ignore the pattern.
set_obstacle_visible
method descriptor
¶
Hides or shows an obstacle without touching whether it collides. A hidden obstacle is still a real obstacle: this is how a workpiece carries a display mesh and its convex collision pieces at once.
set_obstacle_visual_asset
method descriptor
¶
Sets the display gprim independently of the obstacle's collision shape. The column-major transform maps source coordinates into obstacle-local metres. Used by generated Python to reproduce imported USD appearance.
set_obstacle_walkable
method descriptor
¶
Marks an obstacle's top face as a place a walking machine's feet may stand — a stair tread, a mezzanine slab. Footfalls snap onto it and the walker may touch it (nobody collision-checks a floor against the machine standing on it); everything else still collides with it normally. Only an upright box (yaw rotation is fine) can be walkable.
set_part
method descriptor
¶
set_part(
name,
*,
kind=None,
catalog=None,
manufacturer=None,
model=None,
category=None,
description=None,
qty=1,
attributes=None,
**extra,
)
Pins a part — what the thing is commercially — to a resident or
group by name: a robot, a tool in its stack (by its BOM row name,
arm/tool, arm/tool2 — the identity of a made bracket, or the
last word on a catalog one), a device, a sensor, an I/O node, an
obstacle, or an obstacle group (everything under name/ — an
imported subtree, a generated fence). Identity is optional and
free-form: catalog ("id" or "id@revision" or (id,
revision)), manufacturer, model, category ("conveyor",
"structure.fence", ...), description, qty (how many the
target stands for), and any further keywords or attributes={...}
as free attributes (numbers are summed by bom().total(key),
text is carried). Pass kind= ("robot", "tool", "device",
"sensor", "io_node", "obstacle", "group") when a name lives in several
name spaces. Re-pinning replaces. Returns the kind resolved. The
BOM (bom()) is derived from these plus the catalog identity of
robots and tools.
set_physics
method descriptor
¶
set_physics(
name,
dynamic=None,
mass=None,
friction=None,
restitution=None,
linear_damping=None,
angular_damping=None,
ccd=None,
)
Marks an obstacle for physics: dynamic=True hands its pose to
the engine during a physics bake (simulate_sequence(...,
physics=True)) — it falls, collides, settles. All properties are
inert on a kinematic bake, so authoring them never changes an
existing cell. Repeated calls merge: only the knobs you pass
change. mass in kg (unset derives it from the collision shape's
volume at 1000 kg/m³); ccd enables continuous collision
detection for small fast parts.
set_robot_base_pose
method descriptor
¶
Places the robot root at the world-frame pose and pushes the new state to connected studio clients.
set_robot_physics
method descriptor
¶
set_robot_physics(
robot=None,
dynamic=True,
max_force=None,
damping=None,
mass_floor=None,
armature=None,
floating=None,
)
Declares a robot dynamic under physics bakes (design-rl-dynamics.md):
every link with geometry becomes a rigid body weighing what its
model states (URDF <inertial>, USD PhysicsMassAPI; else its
shape at the default density, at least mass_floor kg), every
joint a force-capped servo following the planned motion, and the
baked track is the physical joint state read back each scan. The
base assembly stays on its stand (or vehicle). Without a physics
backend the declaration is inert; dynamic=False removes it.
max_force— servo force cap in N·m (revolute) / N (prismatic); default each joint's URDF effort limit, which must then exist.damping— the velocity loop's gain (default the cap per 0.02 rad/s or 2 mm/s of velocity error).mass_floor— least mass of a link without inertials (default 0.2 kg).-
armature— reflected drive inertia per joint, kg·m² revolute / kg prismatic (default 0.1 / 10): a geared motor's rotor through the gear ratio squared, which also keeps a light wrist from drooping under the impulse-solved motor. -
floating— the base's kind under physics:Truea free rigid body (it falls, tips and collapses with the rest — a walker on its feet, a multirotor),Falsea mirror on its stand or vehicle whatever the scope,None(default) lets the bake derive it: a world-scope bake (bt.Physics(world=True)) floats walkers and aircraft, the declared scope floats nothing.
A dynamic robot is what botrail.rl.Torque drives.
set_tcp_target
method descriptor
¶
set_tcp_target(
position,
quaternion=None,
link=None,
max_iters=100,
robot=None,
group=None,
centering=None,
)
Solves IK toward the given pose (seeded from the current
configuration), applies the best-effort result to the scene, and
pushes it to connected studio clients. quaternion=None matches
position only; link defaults to the TCP link.
group names the arm (its tip is the default link; only its
joints move); a link alone names the arm it hangs off.
centering is how strongly a redundant arm's free joints are drawn
toward mid-range once the pose is met (default 0.1): 0 leaves them
where the current configuration has them, so the answer lands next
to it — teaching a pose from a near one.
set_vehicle_wheel
method descriptor
¶
Rotates a disabled wheel visual from the vehicle's travelled distance. Axis and pivot are in the visual's local frame; radius is in metres. A mecanum wheel uses lateral_ratio=-1 or +1 for its roller handedness.
show_film
method descriptor
¶
Puts a film map in the picture: the coated target's own colour
gives way to film's heatmap mesh, registered as a display-only
obstacle named {target}_film (disabled for collision, cheap
collider) with its micron colour key attached, so the studio draws
the legend beside the viewport. Collision and planning still see
the original target; everything here is presentation. Returns the
obstacle name; remove it and re-show the target to undo.
show_timeline
method descriptor
¶
Makes timeline the session's latest bake again — what a studio
opened afterwards replays and downloads — after later bakes (a
scenario matrix, a sweep) have taken its place. The timeline
carries its own scene snapshot, so nothing is re-baked; connected
studios receive it as a sequence_result.
simulate_physics
method descriptor
¶
Bakes duration seconds of the cell with no program at all:
devices parked, robots holding their pose, and the physics engine
settling, dropping or collapsing whatever it owns. The default is
the whole cell (bt.Physics(world=True), ground at z = 0):
what is unsupported falls, what rests stays, what is bolted down
(set_physics(dynamic=False), device-driven, walkable, an
equipment part pin) never moves. Pass physics=bt.Physics(...)
to choose otherwise (physics=True is the declared scope). The
result is an ordinary timeline — studio playback, USD export and
pose queries all work — broadcast to the studio like any bake.
scenario applies a named initial-state delta first.
simulate_scenarios
method descriptor
¶
Rolls the same sequences under a set of scenarios — the cell's
test-case matrix in one call. scenarios=None runs baseline
plus every defined scenario. A scenario that fails (bad delta,
plan failure, timeout) is collected into the result's errors
rather than aborting the sweep — finding the failing scenario is
the point. Each run is deterministic, so coverage and cycle times
off the result are CI-assertable numbers.
simulate_sequence
method descriptor
¶
simulate_sequence(
name,
dt=0.01,
max_duration=120.0,
plan_resolution=None,
scenario=None,
toolpath_spin=None,
physics=None,
policies=None,
)
Rolls out a sequence with the PLC scan loop against a snapshot of this scene (motions plan at their step, grasped objects ride along) and returns the baked timeline. Also broadcasts the result to connected studio clients for playback.
scenario applies a named initial-state delta (add_scenario) to
the snapshot first — the live scene is never touched. None and
"baseline" both mean the scene as it stands.
simulate_sequences
method descriptor
¶
simulate_sequences(
names,
dt=0.01,
max_duration=120.0,
plan_resolution=None,
scenario=None,
toolpath_spin=None,
physics=None,
policies=None,
)
Rolls out several sequences concurrently — the PLC picture of a
line: one program per station plus a transfer program, each a plain
serial SFC, synchronized only through signals and sensors. One scan
tick advances every program in list order, so the bake stays
bit-identical run to run; the result is a single timeline whose
step spans carry program/step names.
Every robot, device, and written signal must be commanded by at
most one of the programs — two programs driving one resource is
rejected up front, like two PLC programs writing one coil.
plan_resolution tightens the planner's edge-validity stride (rad,
joint-space L2). The default 0.05 samples a big arm's sweep every
~10 cm of TCP travel — coarse enough to step across sheet metal, so
cells full of 12 mm flanges pass 0.005.
timeline_from_trajectory
method descriptor
¶
Wraps a planned trajectory as a single-robot SequenceTimeline so
the timeline consumers — studio playback, export_usd,
min_clearance — accept it without authoring a sequence. Other
robots hold their current pose; objects stay static. Script export
is not supported on the result.
unbind_input
method descriptor
¶
Drops the binding of an input point — on node, or everywhere.
unbind_output
method descriptor
¶
Drops the binding of an output point — on node, or everywhere.
IoPoint¶
Returned by Scene.io_points: one derived I/O
point of the cell (see The I/O map).
IoPoint
¶
One derived I/O point of the cell (see Scene.io_points).
aspect
property
¶
The facet for device commands and robot handshakes ("index",
"dispatch", "station", "position", "speed", "start",
"done", "program"), or None.
host
property
¶
The controller that owns the point: "<cell>", "<robot name>"
(implicit placement) or a declared node; None when nothing pins it.
source
property
¶
The derivation rule that produced it: "sensor",
"signal:handshake", "signal:internal", "signal:write-only",
"signal:read-only", "device:run", "device:done",
"device:command", "device:cosmetic", "robot:start",
"robot:done", "robot:program".
status
property
¶
"unbound", "internal" (a relay, no I/O), "cosmetic"
(magazine), "constant" (a coil that is on from t = 0 and never
commanded).
writers
property
¶
(sequence, flat step index, step name) of the steps that write
the point (coil writes, device commands, robot starts).
IoReport¶
Returned by Scene.io_report: the findings over
the derived I/O map, by severity.
IoReport
¶
The findings of Scene.io_report().
IoFinding¶
One entry of an IoReport.
IoFinding
¶
IoMap¶
Returned by Scene.io_map: the assignment layer as
authored (nodes, bindings, declarations) — hand it to to_script(io=...).
IoMap
¶
The assignment layer of a scene's I/O map (see Scene.io_map).
Bom¶
Returned by Scene.bom: the bill of materials derived
from the scene's parts (see Parts and the BOM).
Bom
¶
The bill of materials Scene.bom() derives — one row per distinct
product, in scene order.
rows
property
¶
The rows as dicts: category, names (the residents the row
stands for), manufacturer, model, catalog (id@revision),
qty, description, attributes.
save
method descriptor
¶
Writes the table to path; the format follows the extension
(.csv, .md, .json) unless format says otherwise.
total
method descriptor
¶
Σ qty × key over the rows carrying it as a number, or None
when no row does (a missing figure must not read as zero).
unidentified
method descriptor
¶
Rows nothing identifies yet (no catalog reference, maker or model) — the purchasing to-do list.
InterlockTable¶
Returned by Scene.interlocks: every output a
step switches against the condition that admits the step (see
The interlock table).
InterlockTable
¶
One lint finding of the I/O map.
The interlock table Scene.interlocks() derives: rows are plain
dicts (program, host, step, kind, target, output,
condition, after, inputs); to_markdown() / to_csv() render
the same rows for people and spreadsheets.
io_error
property
¶
Why hosts and addresses are missing, when the I/O map could not be
derived; None when it could.
rows
property
¶
One dict per output: program, host, step, kind, target,
output, condition, after (the predecessor steps) and inputs
(name, kind, written_by, address).
save
method descriptor
¶
Writes the table to path; the format follows the extension
(.md, .csv, .json) unless format says otherwise.
CellReport¶
Returned by Scene.cell_report: cycles, I/O,
scenarios, machines, BOM totals, footprint and deliverable digests in one
page (see Layout sheet and cell report).
CellReport
¶
The cell report Scene.cell_report() gathers: robots, cycles, I/O,
scenarios, machines, BOM totals, footprint, deliverable digests. Every
section is a plain dict / list (JSON-shaped); to_markdown() renders
the same data for people.
cycles
property
¶
The cycles passed in: name, sequences, scenario, duration,
steps (name, sequence, start, end), robots (robot,
busy, utilization), clearance (distance, t, pair) and
branches.
io
property
¶
The I/O summary — points, by_kind, bound, unbound,
internal, safety, nodes, findings — or None when the map
could not be derived (see io_error).
machines
property
¶
The machine tools: name, category, manufacturer, model,
catalog, door (name, drive, stroke_mm, speed, lanes,
driven), buttons, controller, programs.
robots
property
¶
The robots: name, dof, base, and catalog / manufacturer /
model / reach when the catalog knows them.
cycle_time
method descriptor
¶
The cycle time of name (or of the first cycle), or None.
min_clearance
method descriptor
¶
The tightest clearance over every cycle that measured one, or
None.
save
method descriptor
¶
Writes the report to path; the format follows the extension
(.md, .json) unless format says otherwise.