Skip to main content
se3labs.interface.eval.policy

Robot Policies

Lifecycle​

se3labs.interface.eval.policy.Policy defines the station-driven episode lifecycle:

MethodCalled whenReturn value
initialize(station, task)Before each episodeStation_JointPose: the pose the arms move to before rollout
infer(observation)On each observation tickStation_ActionChunk, or None to continue the current chunk
resume()After a station operator took the rollout over and handed it back, before the next observationNothing; the chunk in progress and an EndEpisode raised before are dropped: answer with a new chunk from where the operator left the arms. Optional: only a policy that overrides it is handed back; an operator who takes over any other policy ends the rollout
refused(reason)Before the next observation, after the station refused the chunk infer() returnedNothing; that chunk did not run and the arms hold the last accepted target. Optional
ended(end_condition, detail)After an episode, before reset()Nothing; why the station ended it, such as the safety check behind a safety_stop. Optional
reset()After an episodeNothing; clear per-episode state

Model initialization and access to task.instruction belong in initialize(). Inference frequency, preprocessing, and chunk length are controlled by the policy.

Observations and actions​

station.arms and station.cameras describe the available hardware. Observation and action dictionaries use those same names. A bimanual station uses left and right for its arms; a single-arm station uses arm.

Joint targets are absolute angles in radians. Gripper positions are open fractions: 0 is closed, 1 is open. Each arm action contains arrays shaped (horizon, n_arm_dof) and (horizon, n_gripper_dof).

An action chunk's row i targets station time timestamp + i / rate. Use the observation's station-clock timestamps, not your computer's wall clock. All arms in a chunk share its horizon and rate. A new chunk replaces the remaining targets from the previous chunk; returning None keeps that chunk.

Task specification​

A Task_Spec contains an operator-facing description and reset_instruction, a model-facing instruction, a max_rollout_time in seconds, and a Task_ScoreSheet. Its success question must be binary: yes means success. Additional questions can be binary, multiple choice, or exact unscored counts. The station operator supplies the answers. Sampled tasks also carry their initial layout, seed, and semantic parameters. The policy's initialize() returns the starting arm pose for each episode.

Episode completion and errors​

Raising se3labs.interface.eval.policy.EndEpisode from infer() requests normal scoring, reset, and homing. Other inference exceptions are added to SessionReport.errors; that tick sends no new chunk. An initialization exception ends the session and propagates to the caller.

For a complete implementation, follow the Python API tutorial. Data types are listed in the Python Interface reference, and session reports in the Python SDK reference.

EndEpisode​

class EndEpisode(Exception)

Raise from infer to finish normally: scoring, reset, then station homing.

Policy​

class Policy(ABC)

Methods​

initialize(station: Station_Spec, task: Task_Spec) -> Station_JointPose​#

Prepare for one episode of task on station and return the pose the arms start from.

infer(observation: Station_Observation) -> Station_ActionChunk | None​#

A new chunk, None to continue, or raise EndEpisode to score and home.

resume() -> None​#

A station operator took the rollout over and handed it back; called before the next observation. Override it to be handed back at all: without it the operator who takes over ends the rollout, so no policy runs on from state that predates the takeover.

refused(reason: str) -> None​#

The station refused the chunk the previous infer returned, for reason (a safety check's words, such as "unsafe: left: row 3 joint 5 at +2.301 rad, 0.057 rad outside the envelope's [-2.242, +2.244]"): it does not run, and the arms hold the last target the station accepted. Called before the next infer. No-op by default.

ended(end_condition: str, detail: str) -> None​#

How the episode ended: end_condition as in EpisodeResult (timeout, safety_stop, ...) and the station's detail, such as the check that stopped the arms ("right: joint 4 reads +3.4 N*m"; empty when there is none). Called once, before reset. No-op by default.

reset() -> None​#

Clear per-episode state. Called once after the episode ends. No-op by default.

implements_resume​

implements_resume(policy: Policy) -> bool

policy overrides Policy.resume, so a station operator who takes its rollout over may hand it back.