Sequences (bt.seq)¶
The process vocabulary: a sequence is a list of steps, and a step is entry actions plus a transition condition, evaluated on a fixed scan cycle — the PLC step-advance model.
sq = scene.sequence("cycle")
sq.step("feed", actions=[bt.seq.start("belt")], transition=bt.seq.signal("eye"))
sq.step("stop", actions=[bt.seq.stop("belt")])
sq.step("pick", actions=[bt.seq.motion("approach"), bt.seq.attach("crate")])
Omitting transition supplies the obvious default: a step that starts a motion
waits for it (done()), a step that starts nothing falls through
(immediately()).
Actions at a glance¶
| Action | Effect |
|---|---|
motion(name) |
Start a named motion; await it with done() |
ramp(targets, duration) |
Drive joints to targets over a fixed duration — gripper open/close |
attach(obj) / detach(obj) |
Grasp, and release where the robot holds it |
track(obj) / untrack() |
Latch taught poses onto a moving part, and let go |
set_signal(name, value) |
Write an internal signal (declared with scene.define_signal) |
start(device) / stop(device) |
Run or halt a device — a conveyor or a source |
set_speed(device, speed) |
Rescale a conveyor's velocity, direction kept |
move_to(device, position) |
Command a linear axis; await with device_done |
goto(device, station) |
Dispatch a vehicle; await with device_done |
crouch(robot, depth, lean=) |
Lower a parked walker's body, feet planted; crouch(robot, 0) stands it up |
Conditions at a glance¶
| Condition | Advances when |
|---|---|
immediately() |
Always, on the next scan |
done() |
This step's motion has finished |
robot_done(robot) |
A named robot is idle — the inter-robot handshake |
elapsed(seconds) |
A timer expires |
signal(name, value) |
A signal, sensor, or device state matches |
device_done(device) |
A device reached its commanded target |
all_of(...) / any_of(...) |
Composed conditions hold |
Reference¶
seq
¶
PLC-style sequence authoring: action / transition-condition helpers and
the step builder returned by scene.sequence(name).
A sequence is a list of steps (工程). Each step fires its entry actions
and completes when its transition condition holds — the SFC /
step-ladder mental model. When transition is omitted, a step that
starts a motion, ramp, policy or crouch waits for it (done());
anything else moves on immediately().
sq = scene.sequence("pick_place")
sq.step("approach", actions=[bt.seq.motion("approach")])
sq.step("close", actions=[bt.seq.ramp({"finger": 0.008}, 0.4)])
sq.step("grasp", actions=[bt.seq.attach("/World/Conveyor/Box_A")])
sq.step("carry", actions=[bt.seq.motion("to_pallet")])
sq.step("release", actions=[bt.seq.detach("/World/Conveyor/Box_A")])
timeline = sq.simulate()
SelectBuilder
¶
Arms of one branching step (see _Steps.select).
when
¶
when(condition: Dict[str, Any]) -> ArmBuilder
Appends an arm guarded by condition. Arms are tried in the
order added (SFC's left-to-right priority); the first whose
condition holds runs. An arm left empty skips straight to the
rejoin.
ArmBuilder
¶
Bases: botrail.seq._Steps
One arm's step list — the same step/select API as the
sequence itself, so arms nest.
SequenceBuilder
¶
Bases: botrail.seq._Steps
Accumulates steps for one sequence, mirroring every edit into the scene (and any connected studio). Creating a builder for an existing sequence name starts it over from zero steps.
simulate
¶
Rolls the sequence out (see Scene.simulate_sequence).
scenario runs it under a named initial-state delta
(scene.add_scenario).
toolpath
¶
Start a toolpath (continuous Cartesian process path — see
bt.toolpath): an automatic approach to the path start, then the
feed-floored follow. Await it with done(). robot names the
instance (required when the scene has several robots).
ramp
¶
ramp(
targets: Mapping[str, float],
duration: float,
robot: Optional[str] = None,
check: bool = False,
) -> Dict[str, Any]
Ramp joints to targets over duration s (gripper open/close);
await it with done(). robot names the instance (required when
the scene has several robots). A ramp is not planned: with check,
its straight joint line is checked against the cell as it stands when
the ramp starts — as a planned motion's is — and a contact fails the
bake by name. A walk that has just stopped still sways for a moment:
each point is then held where the body will be when the arm gets
there. Leave it off for a gripper closing on its part.
policy
¶
policy(
name: str,
robot: Optional[str] = None,
group: Optional[str] = None,
hz: float = 20.0,
max_duration: float = 10.0,
) -> Dict[str, Any]
Hand the robot (or the arm group) to the registered policy
name for this step: a learned or scripted controller passed to
simulate_sequence(policies={name: ...}) (see botrail.rl.Policy),
asked for a joint target hz times a second until it declares
itself done or max_duration seconds pass. Its targets move the
joints under the model's velocity limits; a collision with the scenery
while it drives fails the bake. Await it with done().
crouch
¶
crouch(
robot: Optional[str],
depth: float,
*,
lean: float = 0.0,
duration: Optional[float] = None,
) -> Dict[str, Any]
Lower a parked walker's body while it stands: over duration s
its body (the root link) goes from the crouch it is in to depth
metres below its standing height, pitched nose-down by lean rad
about its own lateral axis — the feet stay where they stand, each leg
re-solved every scan tick by the walk's own leg IK. crouch(robot,
0) stands it back up. Await it with done().
robot names the mounted walker (None: the scene's sole robot).
duration=None takes a pace: 0.3 m/s of depth and 0.6 rad/s of
lean at the mean (the smoothstep peaks at 1.5 × that), at least 0.6 s.
The bake prices the whole crouch when the step fires — a leg that
cannot keep its foot planted fails it by name — and checks the robot
and what it holds against the cell every tick on the way down. Fired
while the walk before it is still settling, it begins when the last
foot lands. While the body is lowered the vehicle does not drive (a
goto is refused until it stands up), and a planned motion waits for
the crouch to finish; ramps may run alongside it (with check,
each point is held where the body will be).
attach
¶
attach(
obj: str,
link: Optional[str] = None,
touch_links: Union[str, Iterable[str], NoneType] = None,
robot: Optional[str] = None,
group: Optional[str] = None,
) -> Dict[str, Any]
Grasp: rigidly attach an obstacle at its current relative pose.
robot names the carrying instance (required with several robots);
group names the arm of a dual-arm robot (link then defaults to
that arm's tip). touch_links="tool" exempts the whole tool subtree
— palm and fingers — which a closed gripper needs (the default exempts
only the anchor link's own chain).
detach
¶
Release: the obstacle's pose freezes where the robot holds it.
track
¶
track(
obj: str,
link: Optional[str] = None,
robot: Optional[str] = None,
group: Optional[str] = None,
) -> Dict[str, Any]
Conveyor tracking: latch onto a moving part. Until :func:untrack,
every commanded pose is carried by the part's motion since this step, so
poses taught at the station keep meeting the part while it travels — the
line never has to stop. Grasping the tracked part freezes the offset, so
the lift after it goes straight up. Planned motions cannot run while
tracking; ramps can. group names the arm that follows on a dual-arm
robot: only its joints are spent, so the other arm may drive on — or
carry the very part this one follows (a two-handed hold is one hand
grasping and the other tracking).
untrack
¶
Stop following the tracked part; the robot holds where it stands.
group names the arm whose track to release when several follow.
set_signal
¶
Write an internal signal (declare it with scene.define_signal).
set_speed
¶
Rescale a conveyor's velocity to speed (m/s, direction kept).
move_to
¶
Command a linear axis to position (metres) — or a lift to a
named stop (move_to("lift", "2F")); await with device_done.
A lift's cargo (vehicles and loose parts in its capture zone) is
fixed the moment this fires: the doors are closed.
goto
¶
Dispatch a vehicle to a named station (the AGV call); await arrival
with device_done. Travel is uninterruptible: a second goto while
the vehicle is still moving is a sequencing error.
advance
¶
Indexed transfer: run a stopped conveyor for exactly distance
metres along its velocity direction, then stop; await it with
device_done. The final scan tick moves exactly the remainder, so
the pitch is exact no matter how the scan period divides it — no more
elapsed(pitch/v) plus one tick of slack.
robot_done
¶
The named robot has no motion/ramp in flight — whichever step
started it. The idle test interlocks are built from. group narrows
it to one arm of a dual-arm robot: nothing drives any of its joints.
signal
¶
Level test of a signal (internal relay or sensor input).
rising
¶
Rising edge (-|P|-): the signal turned on since this program's
previous scan — "the next part", not one already sitting on the
beam. Startup state is not an edge.
falling
¶
Falling edge (-|N|-): the signal turned off since this
program's previous scan.
device_done
¶
A linear axis has reached its commanded position.
otherwise
¶
Always-true branch guard — the else arm of a select. Put it
last: arms are tried in order, so it catches whatever the guards
before it did not (and the exported script skips the wait entirely,
since some arm is always ready).