Running Tasks with run-task#
embodichain run-task is the common entry point for loading a configured
Gymnasium environment. It supports three primary workflows: inspecting an
environment interactively, running an expert rollout while recording data, and
replaying a previously recorded trajectory.
Mode |
Command switch |
What it does |
Typical use |
|---|---|---|---|
Rollout |
No mode switch |
Generates task actions, steps the environment, and lets configured dataset or video recorders save each episode. |
Expert demonstration expansion and task smoke tests. |
Preview |
|
Resets the environment and opens an interactive IPython session on request. Dataset saving is disabled automatically. |
Inspecting scene state, stepping manually, and checking observations. |
Replay |
|
Restores recorded states, re-applies recorded actions, or provides an
interactive trajectory scrubber, depending on |
Reproducing a rollout and diagnosing dynamics or task behavior. |
--preview and --replay are mutually exclusive. Browser visualization with
--viser is a display backend rather than a fourth execution mode, so it can
be used while running or replaying an environment.
Inputs and startup behavior#
Every invocation requires a gym config:
embodichain run-task --gym_config path/to/gym_config.yaml
JSON, YAML, and YML files are supported. The input must be a runnable config
with a non-empty id. It may declare simulation, robot, sensors, managers, and
recorders inline, or select reusable components. A pure physical env.yaml
component uses environment_id instead of id and is not runnable by itself.
A configuration-defined Task Program deployment conventionally uses
task.<embodiment>.yaml. It selects either one environment.component or a
environment.default/newton mapping, all three task_program paths (program,
integration, and execution_policy), and embodiment.component:
embodichain run-task \
--gym_config embodichain_tasks/configs/tasks/manipulation/tableware/pour_water/task.cobotmagic.yaml
At startup, run-task:
discovers installed task packages through the
embodichain.tasksentry point and executes their initialization hooks;loads the runnable config, expands its selected physical components, and composes any declared Task Program components;
merges launcher runtime values; optional overrides such as
--device,--renderer, and--max_episodesapply only when supplied;creates the environment selected by the gym config’s
id; andenters rollout, preview, or replay mode.
Task-facing trajectory expansion can be kept in a sibling configuration and referenced from the runnable task:
expansion:
config: expansion/<task-profile>.yaml
The referenced file may contain runtime, policy, overrides, and
collection. The runner resolves it relative to the task, applies its runtime
overlay after expanding the selected environment variant, and merges task-local
expansion fields on top. run-task then uses that declaration for Task Program
expansion. --expansion-profile remains a per-run profile override;
--expansion-recipe-indices selects explicit logical recipes. The legacy
--expansion-candidate-indices spelling is still accepted as an alias.
Episode targets and batches#
All offline collection paths use one target count:
collection:
target_episodes: 64
max_attempts: 3
selection:
mode: sequential
start_recipe_index: 0
target_episodes is the number of successfully committed environment rows.
num_envs only sets the maximum width of one parallel batch, so
target_episodes: 64 with num_envs: 16 runs four batches. A final partial
batch uses only the rows needed to reach the target. max_attempts applies to
one selected batch attempt and failed attempts are discarded before retrying.
The legacy --max_episodes CLI option remains supported and maps to
collection.target_episodes. An environment component’s max_episodes is the
fallback when no collection target is declared. A task-level collection target
takes precedence over that component default; conflicting explicit target
values are rejected during parsing.
Expansion selection has two modes:
# Select recipe 0 through recipe 63 and split them into batches automatically.
collection:
target_episodes: 64
selection:
mode: sequential
start_recipe_index: 0
# Select exactly four logical recipes and collect four rows.
collection:
target_episodes: 4
selection:
mode: explicit
recipe_indices: [0, 16, 32, 48]
Recipe indices identify logical expansion candidates. They do not identify batch starts. Affordance branches, scene families, trajectory variants, and visual profiles change the selected episode’s content; they do not increase the target count.
Collection manifests record target_episodes, planned_episodes,
committed_episodes, rejected_episodes, attempts, batch_count, and the
prepare, commit, and discard reset counts. A prepare reset happens before a
batch, a commit reset finalizes selected rows, and a discard reset clears a
failed attempt. None of these reset boundaries adds an episode.
The runnable config, or its selected environment component, must declare
physics: default or physics: newton. With an environment.default/newton
mapping, the requested variant is expanded before this check. See
Configuration Guide for paired backend configuration fragments. That backend is
file-owned: --physics selects a named variant when the task declares an
environment.default/newton mapping and confirms it for a single component. It
never rewrites the selected file. Omitting --device preserves
an authored device or the selected backend’s default; supplying --device
overrides both environment tensors and backend execution, including an explicit
CPU selection for Newton.
Use embodichain run-task --help for the complete option list. The
CLI Reference also lists defaults and
visualization arguments.
Preview an environment#
Preview mode is intended for inspection before an expensive data-expansion run:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--preview
After constructing and resetting the environment, the terminal accepts:
p: enter an IPython session withenvin scope;q: close the preview.
IPython is required only when entering the embedded session. Install it with
pip install ipython if the p command reports that it is unavailable.
Inside the session, use the regular Gymnasium interface and EmbodiChain helpers to inspect state or advance the simulation. For example:
# Inspect the current robot configuration.
env.unwrapped.robot.get_qpos()
# Advance with an action that is valid for this task.
obs, reward, terminated, truncated, info = env.step(action)
# Display an RGB sensor observation.
env.unwrapped.preview_sensor_data("camera")
Preview mode does not execute the task’s expert policy. It also sets
filter_dataset_saving=True, so configured structured dataset recorders do not
write debugging episodes. Visual randomization remains enabled unless
--filter_visual_rand is supplied.
Native window and Viser#
--preview controls the interactive terminal workflow. --viser instead
selects the browser visualization backend and makes the simulation headless:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--viser \
--viser-host 127.0.0.1 \
--viser-port 8080
Use Viser to inspect selected environments, camera frustums, and all camera RGB
previews locally or remotely. The expanded preview panel separates cameras
created by record_camera_data under Record cameras from configured
observation sensors under Sensor cameras.
Limit the published batch with --viser-env-ids, and tune scene, image, or
soft-body publication rates with the corresponding --viser-*-fps options. See
Browser visualization with Viser for browser controls and remote-access
details.
Run and record#
Without --preview or --replay, run-task enters offline rollout mode. For
each vector batch, it asks the task for its demonstration segments, applies
every action through env.step(), and commits selected environment rows with an explicit reset.
collection.target_episodes is the exact number of persisted environment rows,
not the number of vector batches. For example, target_episodes=10 with
num_envs=4 runs three batches and commits only two rows from the final batch.
The legacy --max_episodes option maps to the same target:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--action_config path/to/action_config.yaml \
--headless \
--device cuda \
--max_episodes 10
Headless execution is normally preferred for throughput. Use
--filter_dataset_saving for a rollout smoke test that should not create a
structured dataset.
Failed attempts are discarded and retried by default, up to
collection.max_attempts (with demo_max_attempts retained as a legacy
fallback). Set save_failed_episodes: true on a dataset functor to keep a
failed or truncated attempt that contains recorded frames. Such a commit
counts toward collection.target_episodes and is not retried. Empty plans and
exceptions have no complete dataset transaction and are still discarded.
Multi-segment episodes#
An episode is the complete task; a segment is one semantic subtask inside it. For example, moving three objects is one episode containing three pick/place segments, even if each segment has its own motion trajectory. The task owns the number, order, and targets of those segments. The runner only manages the episode lifecycle, termination checks, retry, and commit/discard boundary.
Existing tasks implementing create_demo_action_list() remain compatible and
are recorded as a single legacy segment. A multi-object task can instead
implement a lazy segment planner:
from embodichain.lab.gym.envs import DemoSegment
def create_demo_segments(self):
for object_uid in self.object_order:
# This runs after the preceding segment, so planning sees the latest
# scene state.
actions = self.plan_pick_and_place(object_uid)
yield DemoSegment(
actions=actions,
name="pick_and_place",
target_uid=object_uid,
instruction=f"Place {object_uid} in its target bin",
# Segment validation is separate from Gym episode termination.
validator=lambda uid=object_uid: self.is_object_placed(uid),
)
Direct callers of generate_function() must no longer use num_traj as a
sub-trajectory count. Only None and 1 are accepted; larger values raise
ValueError. Move the repeated subtasks into create_demo_segments() so the
task, rather than the runner, owns their order and validation.
Gym terminated and truncated always describe the whole episode, never an
individual segment. A segment normally ends when its action iterable is
exhausted; its optional zero-argument validator then returns one boolean per
parallel environment. A failed validator aborts the batch. Episode-level
success termination stops the remaining lazy plan without requesting another
segment.
The executor checks terminal signals after every action and temporarily
disables Gym auto-reset. Dataset recording is transactional: an explicit reset
commits selected rows, while reset(options={"save_data": False}) discards
them. Successful final validation always commits. A failed result commits only
when a configured dataset functor enables save_failed_episodes; exceptions,
interrupts, empty plans, and closing an environment with a live rollout abort
pending structured data, videos, and trajectories.
Segment actions pass through the same action-dimension normalization used by
legacy create_demo_action_list() tasks. A time-limit truncation is always an
unsuccessful expert result, including when it occurs on the planner’s final
action. It is discarded by default or retained as failed data when configured,
so a task’s max_episode_steps must be greater than the longest valid expert
plan when collecting successful demonstrations.
In a vectorized environment, segments and actions remain on one shared planner
clock, but completion is tracked independently. When one environment reports
success, its terminal result and recording cursor become sticky; subsequent
shared actions use a safe hold/no-op command for that row while unfinished rows
continue. Consequently, rollout and trajectory lengths may differ by row.
The executor’s result remains batch-atomic: without failed-data saving every
row must eventually succeed, while any failure or truncation invalidates the
batch. With save_failed_episodes, selected failed rows are committed with
their per-row failure metadata. Rows not needed to reach collection.target_episodes are
explicitly discarded, so parallel collection never overshoots the requested
episode count.
save_failed_episodes belongs beside func and mode, not inside params:
{
"func": "LeRobotRecorder",
"mode": "save",
"save_failed_episodes": true,
"params": {
"robot_meta": {"robot_type": "UR5"}
}
}
Declare the overall goal as env.task_instruction for a handwritten task or
root instruction in program.yaml for a Task Program. Declare finer
instructions on DemoSegment values or program segment nodes. Recorder
instruction remains a legacy fallback. See Task and segment language for expert data for
complete examples, resolution rules, and reading both levels in training.
Run the built-in three-cycle example#
The shipped
embodichain_tasks/configs/tasks/manipulation/repeated_pick_place/task.ur5.yaml
deployment combines a reusable physical environment with a UR5 parallel-gripper
embodiment to pick up and place the same cube three times. Each cycle has a
grasp segment and a placement segment, giving six lazy segments. Later calls
are grounded against the scene state left by earlier calls.
embodichain run-task \
--gym_config embodichain_tasks/configs/tasks/manipulation/repeated_pick_place/task.ur5.yaml \
--headless \
--device cuda \
--max_episodes 1
The Default physical component (envs/default.yaml) already enables
LeRobotRecorder under /tmp/repeated-pick-place/datasets. The command records
one overall task with six semantic segment occurrences and two subtask
descriptions. Add --filter_dataset_saving for an execution-only smoke test. See
Expert Data Expansion for recorder setup and
Inspect Recorded LeRobot Data for
validation and preview.
Choose the recording output you need#
EmbodiChain uses “recording” for three related but distinct outputs:
Output |
How it is enabled |
Contents |
Intended consumer |
|---|---|---|---|
Structured dataset |
A dataset manager in the gym config. |
Observations, actions, episode/segment annotations, task metadata, and optionally sensor videos. |
Imitation-learning or data-processing pipelines. |
Debug or demo video |
|
Human-viewable RGB video from a configured camera pose. |
Visual debugging, reports, and demonstrations. |
Replay trajectory |
|
Per-step robot and object kinematic state, raw task action, and replay
metadata in a PyTorch |
|
Dataset video is still structured training data; it is not interchangeable
with a replay trajectory. Conversely, --record_trajectory does not configure
a LeRobot dataset or export an MP4.
For structured datasets, see Expert Data Expansion and Dataset Functors. For human-viewable video, see Event Functors.
After finalization, use the exact auto-numbered dataset directory with the validation, grouped split, and recovery commands in Validate, split, and recover expert datasets. For official LeRobot 0.6.1 language and depth features, follow Export expert data for LeRobot 0.6.1 in its independent Python environment.
Record replayable trajectories#
Add --record_trajectory to a normal rollout:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--action_config path/to/action_config.yaml \
--record_trajectory \
--trajectory_save_dir outputs/trajectories
The recorder stores the robot root pose and complete joint position, the raw
action before ActionManager preprocessing, and the pose or joint state of scene
rigid objects and articulations. Each environment in a vectorized rollout is
tracked independently. A trajectory is saved only at an explicit commit reset;
this is normally a successful episode, or a recorded failure when
save_failed_episodes is enabled on a dataset functor. close() is a
durability barrier for already committed writes, not an implicit commit, so an
unfinished trajectory is discarded.
Files are named like traj_env0_000000.pt. When
--trajectory_save_dir is omitted, they are written below:
${EMBODICHAIN_DATA_ROOT:-~/.cache/embodichain_data}/trajectories/<run_id>/
Each file contains states, actions, and meta. Metadata includes the actual
per-environment lengths, segment ranges and targets, timestep, robot identity
and DOF, active joint IDs, recorded object IDs, and original environment IDs.
LeRobot exports also contain per-frame annotation.segment_* fields and a
meta/embodichain_episodes.jsonl sidecar with the complete segment records.
The overall episode instruction stays in LeRobot’s task field; each semantic
segment is exposed through a per-frame subtask_index resolved by
meta/subtasks.parquet.
The task/program owns these instructions before recording begins; configuration,
fallback, and readback examples are in Task and segment language for expert data.
The final directory is also printed when the run finishes.
Replay a trajectory#
Replay requires the trajectory file and the gym config used to record it:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--replay \
--replay_trajectory outputs/trajectories/traj_env0_000000.pt
Keep the robot, active joint selection, scene object IDs, action processing,
and episode horizon compatible with the recording run. Robot DOF or active
joint mismatches are rejected. Missing or additional scene objects produce
warnings. A single-environment trajectory can be broadcast with
--num_envs; a multi-environment trajectory requires the replay environment
count to match. Recorded lengths that exceed the current episode horizon are
clamped.
If the task needs an action config to construct its environment or
ActionManager, pass the same --action_config during replay as during
recording.
If the gym config contains dataset recorders, add --filter_dataset_saving
when the replay is for inspection only. Control replay applies this filter
automatically.
Kinematic replay#
Kinematic replay is the default and the best first check:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--replay \
--replay_trajectory path/to/trajectory.pt \
--replay_mode kinematic
Physics is disabled and recorded poses and joint positions are written into the
scene at every step. This gives an exact visual/state reproduction and renders
new observations, but it does not recompute meaningful task rewards or
successes from the recorded actions. At completion, run-task reports the
maximum robot joint-state error against the recording.
Dynamic replay#
Dynamic replay sends each recorded raw action back through env.step():
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--replay \
--replay_trajectory path/to/trajectory.pt \
--replay_mode dynamic
Physics, ActionManager preprocessing, observations, rewards, and termination logic all run normally. Use this mode to test whether the behavior can be re-simulated rather than merely restored. Results may diverge if the replay configuration changes physics, control, randomization, assets, or timestep settings that are not stored in the trajectory file.
Interactive control replay#
Control mode uses kinematic state restoration and lets you scrub the trajectory from the terminal or Viser:
embodichain run-task \
--gym_config path/to/gym_config.yaml \
--replay \
--replay_trajectory path/to/trajectory.pt \
--replay_mode control
The commands are:
n: next step;porb: previous step;<N>followed by Enter: jump to stepN;a: auto-play, then press any key to pause;r: return to step 0;q: quit.
Run control mode with a native render window. --headless leaves no window in
which to see the scrubbed state. Alternatively, add --viser to open an
expanded Replay control panel in the browser. Its integer Frame slider
jumps directly to any recorded frame, stays synchronized with terminal and
auto-play commands, and pauses auto-play when dragged.
Recommended workflow#
Use the modes in this order when bringing up a task:
Run
--preview --filter_visual_randto inspect the initial scene and sensor output without saving a dataset.Run one headless episode with
--filter_dataset_savingand--record_trajectoryto validate the expert policy and create a compact replay artifact.Replay the artifact in
kinematicmode to inspect the exact recorded motion, then usedynamicmode if physics reproducibility matters.Remove
--filter_dataset_saving, choose the desired episode count, and run the full data-expansion job.
For rollout profiling, renderer selection, and every available CLI option, see the CLI Reference.