Skip to content

Add environment task record-and-replay (async parallel envs + auto-save)#425

Open
yuecideng wants to merge 20 commits into
mainfrom
design/env-replay
Open

Add environment task record-and-replay (async parallel envs + auto-save)#425
yuecideng wants to merge 20 commits into
mainfrom
design/env-replay

Conversation

@yuecideng

@yuecideng yuecideng commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds a record-and-replay capability to the environment framework. An episode can be saved as a trajectory file (.pt) and replayed later in one of two modes:

  • Pure kinematic - disable physics and write every recorded object's pose/qpos directly each step; produces observations (camera/proprioception) only, no reward/success/action.
  • Dynamic - restore the recorded initial scene, then feed the recorded robot action back through env.step so physics re-simulates; produces the full obs/reward/terminated/truncated/info.

Key capabilities

  • Async parallel envs - a dedicated per-env self._traj_buffer (states + actions) with a per-env step counter (_traj_steps) means envs that terminate/reset at different times no longer corrupt each other's recording. Only the reset envs' counters clear.
  • Pre-process action recording - the recorded action is the raw action passed to env.step (before _preprocess_action), so dynamic replay feeds it back through env.step and the ActionManager re-applies the same transform - dynamic replay is faithful even with an ActionManager (delta/eef_pose action terms).
  • Default auto-save - trajectories auto-save to ~/.cache/embodichain_data/trajectories/{run_id}/ at episode end and on close() (best-effort: IO errors warn + skip, never crash the episode). Explicit save_trajectory(path, env_ids=None) also available.
  • Multi-env replay - ReplayWrapper replays per-env lengths (meta["lengths"]); finished envs hold their last state/action. Backward-compatible with older files (no lengths -> uniform length).

It reuses the existing gym.Wrapper pattern, the _hook_after_sim_step hook, the auto-reset guard in base_env.step, and the existing per-object state read/write APIs. The shared rollout_buffer (obs/actions/rewards), current_rollout_step, LeRobot recorder, and RL mode are untouched - the trajectory buffer is fully decoupled. All new behavior defaults off (record_trajectory=False), so existing envs are unaffected.

Design spec & implementation plan: docs/superpowers/specs/2026-07-24-env-replay-async-design.md and docs/superpowers/plans/2026-07-24-env-replay-async.md (developed via brainstorming -> writing-plans -> subagent-driven-development, with per-task reviews and a final whole-branch review).

Components

  • build_trajectory_buffer / load_trajectory - pure helpers in embodichain/lab/gym/utils/gym_utils.py.
  • EmbodiedEnvCfg.record_trajectory / trajectory_uids / trajectory_save_dir / trajectory_auto_save cfg fields.
  • EmbodiedEnv._traj_buffer + _traj_steps (per-env); _preprocess_action stashes the raw action; _write_trajectory_step records states + action per-env.
  • EmbodiedEnv.save_trajectory(path, env_ids=None) + _save_trajectory_for_env (auto-save).
  • BaseEnv.step auto-reset guard (_replay_no_auto_reset) so dynamic replay isn't disrupted mid-trajectory.
  • ReplayWrapper(gym.Wrapper) - kinematic + dynamic modes, per-env lengths, num_envs broadcast, physics/flag restoration on close(), active_joint_ids/robot_dof sanity check.

Scope (deferred)

  • RL "rl"-mode rollout buffer / set_rollout_buffer injection path.
  • qvel recording.
  • Dict (non-Box) action spaces in the trajectory action buffer (Box only; current action spaces are Box).

Dependencies: none new (uses existing tensordict, torch, gymnasium).

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist

  • I have run the black . command to format the code base.
  • I have made corresponding changes to the documentation (design spec/plan included under docs/superpowers/; Sphinx user docs are follow-up)
  • I have added tests that prove my fix is effective or that my feature works
  • Dependencies have been updated, if applicable.

Testing

  • tests/gym/utils/test_gym_utils.py - unit tests for the builder/loader (mock stubs, no sim).
  • tests/gym/envs/test_replay.py - real DexSim (CPU) integration tests: recording populates _traj_buffer; save/load round-trip with per-env lengths; auto-reset guard; kinematic round-trip (state readback == recorded at atol 1e-4); dynamic replay (qpos tracks recorded); per-env truncation timing; legacy-file backward compat; num_envs broadcast; physics/flag restoration; async parallel envs don't corrupt recording; ActionManager dynamic replay (records raw delta, re-applies via ActionManager); auto-save at episode end + close.
  • tests/gym/envs/test_base_env.py CPU regression still passes (auto-reset guard preserves normal behavior).

33 tests pass (13 replay + 19 gym_utils + 1 base_env CPU).

yuecideng and others added 9 commits July 24, 2026 08:51
Design a record-and-replay feature for EmbodiChain environments with two
modes: pure kinematic (disable physics, write recorded object states each
step) and dynamic (feed recorded robot trajectory, re-simulate physics).
Reuses the existing expert-mode rollout_buffer (extended with a `states`
field), the _hook_after_sim_step write hook, and the gym.Wrapper pattern.

Co-Authored-By: Claude <noreply@anthropic.com>
Six TDD tasks: (1) trajectory states buffer builder + loader, (2) record
kinematic states into rollout_buffer, (3) save_trajectory persistence,
(4) base_env auto-reset guard, (5) ReplayWrapper pure-kinematic mode,
(6) ReplayWrapper dynamic mode + edge cases.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@yuecideng yuecideng added enhancement New feature or request gym robot learning env and its related features labels Jul 24, 2026
@yuecideng
yuecideng marked this pull request as ready for review July 25, 2026 06:57
Copilot AI review requested due to automatic review settings July 25, 2026 06:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

yuecideng and others added 9 commits July 25, 2026 08:03
Dedicated per-env trajectory buffer (states + pre-process action) with
per-env step counters to support async parallel envs; default auto-save
to ~/.cache/embodichain_data/trajectories/{run_id}/; multi-env replay
with per-env lengths. Pre-process action recording enables ActionManager
in dynamic replay. Supersedes the recording/replay portions of the
original spec.

Co-Authored-By: Claude <noreply@anthropic.com>
Four TDD tasks: (1) ReplayWrapper per-env + pre-process action
(format-compatible); (2) dedicated _traj_buffer with per-env recording +
save; (3) default auto-save to ~/.cache/embodichain_data/trajectories/
{run_id}/; (4) async + ActionManager dynamic-replay tests. Sequenced so
replay is bi-directionally format-compatible, keeping each task green.

Co-Authored-By: Claude <noreply@anthropic.com>
…ocess action

Co-Authored-By: Claude <noreply@anthropic.com>
…_action

Co-Authored-By: Claude <noreply@anthropic.com>
- Add test_async_envs_do_not_corrupt_recording proving per-env
  _traj_steps isolates envs when one resets early.
- Add ReplayDeltaEnv (delta-qpos ActionManager) and
  test_dynamic_replay_with_action_manager proving raw pre-process
  actions are recorded and dynamic replay tracks them.

Co-Authored-By: Claude <noreply@anthropic.com>
…ype hints

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 13:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@yuecideng yuecideng changed the title Add environment task record-and-replay feature Add environment task record-and-replay (async parallel envs + auto-save) Jul 25, 2026
run_env now supports three modes: data generation (default), preview
(--preview), and replay (--replay). Replay loads a .pt trajectory and
drives it via ReplayWrapper in kinematic (exact), dynamic (physics), or
control (interactive kinematic scrubber via terminal input) mode.

- ReplayWrapper.go_to_step(step): O(1) scrub to an arbitrary recorded
  step (clamped to min(lengths)-1); powers control mode.
- run_env: replay()/replay_auto()/replay_control() + --replay,
  --replay_trajectory, --replay_mode args; --replay and --preview are
  mutually exclusive.
- Tests: go_to_step scrubs to the recorded state (forward/clamp/back);
  run_env.replay() runs kinematic + dynamic without error.

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 25, 2026 14:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings July 25, 2026 16:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request gym robot learning env and its related features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants