Skip to content

Commit 4949cca

Browse files
committed
Fixing replay bugs
1 parent b485110 commit 4949cca

2 files changed

Lines changed: 62 additions & 19 deletions

File tree

scripts/environments/teleoperation/teleop_replay_agent.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,25 @@
8080

8181

8282
def _prepare_env_cfg(task: str, num_envs: int, device: str) -> ManagerBasedRLEnvCfg:
83-
"""Build and tweak an env config suitable for non-interactive replay."""
83+
"""Build and tweak an env config suitable for non-interactive replay.
84+
85+
Mirrors the env-config mutations performed by ``record_demos.py``'s
86+
:func:`create_environment_config` so the replay-side environment behaves
87+
identically to the recording-side one. In particular the ``success`` and
88+
``time_out`` termination terms are cleared -- if either fired mid-replay
89+
it would call ``_reset_idx`` and snap the robot back to its initial
90+
pose, masking any IK tracking.
91+
"""
8492
env_cfg = parse_env_cfg(task, device=device, num_envs=num_envs)
85-
env_cfg.env_name = task
93+
env_cfg.env_name = task.split(":")[-1]
8694
if not isinstance(env_cfg, ManagerBasedRLEnvCfg):
8795
raise ValueError(
8896
"teleop_replay_agent only supports ManagerBasedRLEnv environments. "
8997
f"Received environment config type: {type(env_cfg).__name__}"
9098
)
9199
env_cfg.terminations.time_out = None
100+
if hasattr(env_cfg.terminations, "success"):
101+
env_cfg.terminations.success = None
92102
env_cfg = remove_camera_configs(env_cfg)
93103
env_cfg.sim.render.antialiasing_mode = "DLSS"
94104
return env_cfg
@@ -107,10 +117,10 @@ def _create_replay_teleop_device(
107117
Args:
108118
env_cfg: The environment configuration.
109119
task: Task identifier, used for diagnostic messages.
110-
callbacks: Teleop-command callbacks (``"START"``, ``"STOP"``,
111-
``"RESET"``) registered on the device. The XCR replay dispatches
112-
the recorded user's start/stop/reset gestures through Kit's
113-
OpenXR message bus, which the legacy
120+
callbacks: Teleop-command callbacks (typically just ``"START"`` for
121+
replay; see :func:`main`) registered on the device. The XCR
122+
replay dispatches the recorded user's start gesture through
123+
Kit's OpenXR message bus, which the legacy
114124
:class:`~isaaclab.devices.openxr.OpenXRDevice` translates into
115125
calls into this dictionary.
116126
"""
@@ -182,13 +192,19 @@ def main() -> None:
182192
183193
The loop deliberately does not call ``env.step()`` until the legacy
184194
:class:`OpenXRDevice` dispatches a ``"START"`` callback. The XCR replay
185-
streams the recorded user's start/stop/reset gestures through Kit's
186-
OpenXR message bus, and the device routes those into the callbacks
187-
registered here -- exactly the path ``record_demos.py`` uses to know
188-
when to start recording. Until that ``"START"`` arrives, the OpenXR
189-
runtime is silent and the device's :meth:`advance` would otherwise
190-
return a default zero pose for both wrists, which stepping the env
191-
with would drive Pink IK toward the world origin.
195+
restores the recorded user's start gesture through Kit's OpenXR message
196+
bus, and the device routes that into the callback registered here --
197+
exactly the path ``record_demos.py`` uses to know when to start
198+
recording. Until that ``"START"`` arrives, the OpenXR runtime is silent
199+
and the device's :meth:`advance` would otherwise return a default zero
200+
pose for both wrists, which stepping the env with would drive Pink IK
201+
toward the world origin.
202+
203+
Unlike :file:`record_demos.py`, the replay agent does **not** subscribe
204+
to the ``"STOP"`` callback: Kit's ``teleop_command`` bus drains queued
205+
events as a batch when the AR profile is enabled, so a recorded STOP
206+
gesture fires within milliseconds of START and would gate the env-step
207+
loop off again before Pink IK had time to converge.
192208
193209
Resource cleanup is wrapped in a ``try/finally`` so that ``env.close()``
194210
always runs, even when device construction or any subsequent setup
@@ -207,16 +223,27 @@ def _on_start() -> None:
207223
teleop_active[0] = True
208224
print("Teleop START received from XCR replay; forwarding actions to env.step().")
209225

210-
def _on_stop() -> None:
211-
if teleop_active[0]:
212-
teleop_active[0] = False
213-
print("Teleop STOP received from XCR replay; pausing env.step().")
214-
215-
callbacks: dict[str, Callable[[], None]] = {"START": _on_start, "STOP": _on_stop}
226+
# Intentionally only subscribe to START, not STOP. The XCR replay
227+
# restores both the recorded user's start and stop gestures from the
228+
# capture file, and Kit's ``teleop_command`` message bus appears to
229+
# drain queued events as a batch when the AR profile is enabled --
230+
# so a STOP fires within milliseconds of START and would shut the env
231+
# step loop off before Pink IK has had a chance to converge. For the
232+
# replay agent's one-shot CI use case the only valid termination is
233+
# the driver's ``post_quit`` (or a real exception in the loop).
234+
callbacks: dict[str, Callable[[], None]] = {"START": _on_start}
216235

217236
teleop_interface = _create_replay_teleop_device(env_cfg, args_cli.task, callbacks)
218237
print(f"Using teleop device: {teleop_interface}")
219238

239+
# Mirror the reset sequence used by ``record_demos.py``: ``sim.reset()``
240+
# does a hard physics reinit (re-binds articulation views, plays the
241+
# timeline) that ``env.reset()`` alone does not perform. Pink IK reads
242+
# ``data.joint_pos.torch`` every step to seed Pinocchio's configuration
243+
# and to compute ``target = curr + delta``; if the articulation view is
244+
# stale, every IK call produces zero-delta arm targets while the
245+
# hand-finger path (which bypasses IK) keeps tracking. See PR #5507.
246+
env.sim.reset()
220247
env.reset()
221248
teleop_interface.reset()
222249

source/isaaclab_teleop/changelog.d/rwiltz-xcr-replay-agent.minor.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ Fixed
2929
* Fixed ``teleop_replay_agent.py`` leaking the USD stage when device
3030
construction or environment setup raised. ``env.close()`` now runs from a
3131
``try/finally`` block so cleanup happens on every exit path.
32+
* Fixed ``teleop_replay_agent.py`` producing a frozen-arms / hands-only
33+
symptom during replay. Kit's ``teleop_command`` message bus drains
34+
queued events as a batch when the AR profile is enabled, so the
35+
recorded user's STOP gesture would fire within milliseconds of START
36+
and gate ``env.step()`` off again before Pink IK had time to converge.
37+
The replay agent now subscribes only to ``"START"``: replay is one-shot
38+
and the only valid termination is the driver's ``post_quit``.
39+
* Aligned ``teleop_replay_agent.py``'s pre-loop reset sequence with
40+
``record_demos.py`` -- ``env.sim.reset()`` then ``env.reset()`` then
41+
``teleop_interface.reset()`` -- so the hard physics reinit re-binds the
42+
articulation tensor views that
43+
:meth:`~isaaclab.controllers.pink_ik.PinkIKController.compute` reads
44+
from each step.
45+
* Cleared :attr:`~isaaclab_tasks.manager_based.manipulation.pick_place.pickplace_gr1t2_env_cfg.TerminationsCfg.success`
46+
in the replay env config so a successful replay does not snap the robot
47+
back to its initial pose mid-loop.
3248

3349
Changed
3450
^^^^^^^

0 commit comments

Comments
 (0)