Adds async retarget to IsaacTeleopDevice (on by default)#5235
Adds async retarget to IsaacTeleopDevice (on by default)#5235hougantc-nvda wants to merge 6 commits intoisaac-sim:developfrom
Conversation
Greptile SummaryThis PR adds an
Confidence Score: 4/5Safe to merge after addressing the split-lock TOCTOU in One P1 finding (split-lock in source/isaaclab_teleop/isaaclab_teleop/async_retarget_loop.py — Important Files Changed
Sequence DiagramsequenceDiagram
participant Main as Main Thread
participant ARL as AsyncRetargetLoop
participant BG as Background Thread
participant Session as TeleopSessionLifecycle
Main->>ARL: update_inputs(anchor_matrix, target_T_world)
Main->>ARL: consume(block=True)
activate ARL
ARL-->>BG: wait on _cond until fresh result
activate BG
BG->>BG: _pace() EMA sleep until predicted deadline
BG->>Session: step_fn(anchor_matrix, target_T_world)
Session-->>BG: action tensor
BG->>BG: action.clone() plus CUDA sync
BG->>ARL: set _latest and notify_all()
deactivate BG
ARL-->>Main: returns (action, fresh=True)
deactivate ARL
Main->>Main: _poll_buttons() reads last_right_controller
Main->>Main: update _cached_action
Main-->>Main: return action
Reviews (1): Last reviewed commit: "Update version and changelog" | Re-trigger Greptile |
8fcd6e8 to
06e4a47
Compare
60bb8e0 to
be0e9ca
Compare
eeb9e77 to
d84a74e
Compare
Retargeting now runs in a background thread by default so it overlaps
with env.step() instead of blocking the render path. An EMA-based
pacer predicts when the next advance() call will happen and starts
each retarget just early enough to have a fresh result ready in time.
To disable and revert to synchronous retargeting:
device.set_async(False)
Key changes:
- New AsyncRetargetLoop class with EMA-paced scheduling, configurable
blocking/non-blocking consume, and automatic retry with a cap on
consecutive failures.
- IsaacTeleopDevice enables async mode in __init__. set_async() can
toggle between sync and async at runtime; the first async advance()
runs synchronously to seed the cache, then starts the background
loop.
- TeleopSessionLifecycle gains add_on_stop_callback() so the device can
cleanly shut down the background thread before the session is torn
down.
…o alleviate stuttering. The gate enforces a strict 1:1 retarget-to-advance ratio (preventing double retargets), while the EMA pacer delays input reading until just before the predicted deadline to maximize input freshness.
…fault EMA implementation in AsyncRetargetLoop. Improve async readability in IsaacTeleopDevice and make async restart detection compare timing config values rather than object identity.
d84a74e to
d611f3b
Compare
When _seed_async_loop called _advance_sync, both _poll_buttons and _dispatch_control_callbacks fired once inside _advance_sync and again at the end of _advance_async on the seed frame. This double-dispatched START/STOP/RESET callbacks and corrupted the right-A rising-edge state. Call _session_lifecycle.step directly from _seed_async_loop so the poll/dispatch happens exactly once per advance, matching the consume path. Made-with: Cursor
There was a problem hiding this comment.
🤖 Isaac Lab Review Bot
Summary
All previous concerns have been addressed in this revision. The torch.Tensor cloning gap in update_inputs() is now fixed (line 322-325), and EmaTimingEstimatorCfg.__post_init__ now validates ema_alpha is in (0, 1] (lines 197-198).
Implementation Verdict
Ship it ✅
The code is clean, the threading model is correct, and test coverage is solid. Nice work!
Description
Retargeting now runs asynchronously by default so work overlaps with env.step() instead of blocking the render path. This PR also hardens async scheduling by combining a consumption gate (strict 1:1 retarget-to-advance() cadence) with paced timing, and then refactors pacing into a pluggable estimator interface (EMA remains the default).
To disable async and use synchronous retargeting:
device.set_async(False)
Key changes:
Added AsyncRetargetLoop and wired IsaacTeleopDevice to use async retargeting by default.
Added consumption-gated pacing to prevent double-retargets and keep inputs fresh.
Refactored pacing into pluggable TimingEstimator / TimingEstimatorCfg with EmaTimingEstimator as default.
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.
List any dependencies that are required for this change.
Fixes # (issue)
Type of change
Screenshots
Please attach before and after screenshots of the change if applicable.
Checklist
pre-commitchecks with./isaaclab.sh --formatconfig/extension.tomlfileCONTRIBUTORS.mdor my name already exists there