Skip to content

[Task Clean-up][Manager] Dexterous Part 5/9: Add the reorientation manager counterparts - #6418

Open
hujc7 wants to merge 4 commits into
isaac-sim:developfrom
hujc7:jichuanh/task-cleanup-dex-part08
Open

[Task Clean-up][Manager] Dexterous Part 5/9: Add the reorientation manager counterparts#6418
hujc7 wants to merge 4 commits into
isaac-sim:developfrom
hujc7:jichuanh/task-cleanup-dex-part08

Conversation

@hujc7

@hujc7 hujc7 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Review Map

  • Exact changes: a stacked PR's page shows the cumulative diff of its dependency chain; the link pins the commit range that is the PR's own contribution.
  • Links pin specific SHAs and go stale after a branch update. Parts 7–9 are pending a rebase onto the current stack, so their ranges are omitted rather than shown wrong.
PR Status Depends on Exact changes
#6411 Part 1/9: Newton cloner/cubric/visualizer fixes merged
#6412 Part 2/9: OVPhysX articulation + manager runtime merged
#6413 Part 3/9: Reorient Direct, torch merged
#6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct merged
📌 #6418 Part 5/9: Reorient manager counterparts
#6421 Part 6/9: Handover + camera manager counterparts #6418 changes
#6410 Part 7/9: Environment overview docs #6421 pending rebase
#6415 Part 8/9: Benchmark success-rate utilities #6421 pending rebase
#6582 Part 9/9: Warp variants → experimental (draft; merges last) pending rebase
#6324 [DO-NOT-MERGE] Lumped validation reference ALL

Summary

Adds manager-based counterparts for the Shadow cube reorientation task and its OpenAI FF/LSTM
observation variants, and aligns the existing Allegro manager task with the Direct contracts.

  • 4 manager tasks now mirror their Direct counterparts: Isaac-Reorient-Cube-Allegro,
    -Shadow, -Shadow-OpenAI-FF, -Shadow-OpenAI-LSTM.
  • −380 lines of configuration: the shared base and its unconstructed sub-configs are gone.
  • 4 commits, 30 files, +1378 / −554.

1. Manager tasks match the Direct contracts

Observations, actions, rewards, terminations, reset distributions and timing were brought to the
Direct values. A value-parity test asserts the decimation / episode length / simulation step
triple, the orientation success tolerance, the fall distance and the consecutive-success cap, so
drift on either side fails CI.

The Allegro observation space changes size, so existing manager checkpoints must be retrained.

Metrics/success_rate is left as upstream defines it. The command term keeps the per-attempt
accounting from #5415; redefining a metric shared across tasks is out of scope here.

2. Configuration hierarchy flattened

Every manager task overrode all seven of the shared base's sub-configurations, so the base carried
pre-alignment defaults that each task then undid — Allegro kept 5 of its 13 members, Shadow 3, the
OpenAI variants 1. The three environment configurations now derive from ManagerBasedRLEnvCfg
directly and declare timing, simulation and viewer settings as class fields, matching how the
Direct configurations already read.

Removed: ReorientObjectEnvCfg, the shared observation/action/command configurations no task
constructed, and reorient_common. Its constants are declared where they are used; the in-hand
offset and goal-marker position became per-robot fields on the Direct configurations, so a single
shared Direct environment can serve both hands.

3. Domain randomization is shared across physics backends

The Shadow randomization terms no longer branch on the physics backend: one ShadowHandEventCfg
declares all six terms for every backend, and ShadowHandManagerEventCfg adds only the
manager-specific reset_state.

Allegro keeps an enable_domain_randomization flag, default True. It is read in __post_init__,
so it is a configuration-file switch — env.enable_domain_randomization=false on the command line
has no effect. Individual terms remain overridable, for example env.events.robot_scale_mass=null.

Validation

8 arms × 1500 iterations, seed 42, physics=newton_mjwarp. All four manager tasks train to
convergence; the Direct references reach success rates of 0.838 (Allegro), 0.929 (Shadow), 0.706
(OpenAI-FF) and 0.615 (OpenAI-LSTM).

Manager and Direct success rates are not printed side by side: the manager command term reports
Metrics/success_rate as a per-attempt ratio and the Direct environments report a per-episode
bit, so the two columns would not measure the same quantity.

A separate arm with domain randomization disabled on Isaac-Reorient-Cube-Shadow reaches 97% of
Direct's goals-per-step against 81% with it enabled.

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds manager-based counterparts for the Shadow Hand cube reorientation task (state, OpenAI-FF, OpenAI-LSTM) and aligns the existing Allegro manager task to the Direct contracts, cutting ~320 lines of shared base config in favour of flat, per-robot configurations.

  • Success-rate fix: success_bonus is promoted to a ManagerTermBase that accumulates goals_reached per episode and logs Metrics/success_rate as a per-episode bit in reset(), matching the Direct definition. The previous per-attempt metric (which could not reach 1.0) is removed.
  • New MDP terms: reorient_timeout (success-extended timer for the OpenAI variant), reset_reorient_state (Direct-matching reset distribution), NoisyEMAJointPositionToLimitsAction, fingertip_* observation helpers, and openai_policy_observation (stateful noise with shape-probe guard) round out the manager feature set.
  • Config hierarchy flattened: all three environment configs derive from ManagerBasedRLEnvCfg directly; ReorientObjectEnvCfg and reorient_common are deleted; timing and physics are declared as class fields alongside a value-parity pytest that guards Direct/manager drift on timing, thresholds, and streak caps.

Confidence Score: 5/5

The core logic changes are well-designed and backed by empirical validation numbers; no data-corrupting or crash-inducing paths were identified.

All functional changes are self-consistent and the value-parity test guards the most critical configuration fields. The off-by-one in reorient_timeout is a 1-step difference in ~160-step episodes and is claimed to match the Direct variant behaviour. The docstring issue about Hydra overrides is misleading but does not affect training.

Files Needing Attention: terminations.py (reorient_timeout boundary) and allegro_hand_manager_env_cfg.py (enable_domain_randomization docstring) are worth a second look before merging.

Important Files Changed

Filename Overview
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/commands.py Refactored command term: pre-allocated _command_buf replaces per-call torch.cat, success rate moved to success_bonus reward term, _skip_success_update logic added to suppress spurious resample on autoreset.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/rewards.py success_bonus converted to stateful ManagerTermBase that accumulates goals_reached and logs Metrics/success_rate in reset(). Partial-reset logging bias was flagged in previous review; no new issues beyond that.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/terminations.py Adds reorient_timeout class that maintains a per-env timer restarted on each goal reach. Uses _steps_since_success >= max_episode_length - 1, which terminates 1 step earlier than standard time_out.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/observations.py Adds fingertip_pos/quat/vel helpers, fingertip_wrench ManagerTermBase with zero-fallback, reorient_last_action for autoreset-compatible last-action observation, and openai_policy_observation with stateful noise.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/allegro_hand/allegro_hand_manager_env_cfg.py Full rewrite of Allegro manager config. enable_domain_randomization defaults to True despite PR description claiming False; docstring erroneously states Hydra CLI overrides have no effect.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_manager_env_cfg.py New 241-line Shadow Hand state manager config. Clean direct derivation from ManagerBasedRLEnvCfg with backend-preset events. No issues found.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_openai_manager_env_cfg.py New OpenAI FF/LSTM Shadow manager config with asymmetric observations, stateful action noise, and reorient_timeout.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/init.pyi Updated stub exports; ReorientCommand and ReorientCommandCfg are listed twice in all, which is a copy-paste artefact.
source/isaaclab_tasks/test/core/test_reorient_value_parity.py New pytest module validating timing, success threshold, fall distance, streak cap, and success_count_threshold parity. Does not cover timeout termination logic.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/events.py New reset_reorient_state event matching Direct reset distributions; saves terminal raw action and step counter for reorient_last_action autoreset handling.
source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/noisy_actions.py New NoisyEMAJointPositionToLimitsAction applying stateful noise before EMA processing. Reset propagates to noise model correctly.

Sequence Diagram

sequenceDiagram
    participant Env as ManagerBasedRLEnv
    participant Rew as RewardManager
    participant Cmd as CommandManager
    participant Term as TerminationManager

    Env->>Env: apply_actions() + step_sim()
    Env->>Term: compute() reorient_timeout / time_out / object_out_of_reach
    Env->>Rew: compute() success_bonus accumulates goals_reached
    Env->>Cmd: compute() _update_metrics then _update_command resample on success
    Env->>Env: autoreset terminated envs
    Env->>Rew: reset(env_ids) log Metrics/success_rate zero goals_reached
    Env->>Cmd: reset(env_ids) set _skip_success_update from reset_buf
Loading

Reviews (3): Last reviewed commit: "Keep Allegro manager domain randomizatio..." | Re-trigger Greptile

Comment on lines +100 to +131
def direct_reorient_timeout(
env: ManagerBasedRLEnv,
command_name: str,
reward_name: str,
success_tolerance: float,
max_successes: int,
object_cfg: SceneEntityCfg = SceneEntityCfg("object"),
) -> torch.Tensor:
"""Apply the Direct OpenAI progress-reset and timeout semantics.

Args:
env: Environment containing the object, goal, and reward term.
command_name: Goal command term name.
reward_name: Reorientation reward term name.
success_tolerance: Goal orientation tolerance [rad].
max_successes: Goals after which the episode terminates.
object_cfg: Object scene entity.

Returns:
Per-environment timeout flags.
"""
object_asset = env.scene[object_cfg.name]
target_quat = env.command_manager.get_command(command_name)[:, 3:7]
goal_reached, _ = evaluate_reorient_success(object_asset.data.root_quat_w.torch, target_quat, success_tolerance)
env.episode_length_buf = torch.where(
goal_reached,
torch.zeros_like(env.episode_length_buf),
env.episode_length_buf,
)
reward_term: DirectReorientReward = env.reward_manager.get_term_cfg(reward_name).func
max_success_reached = reward_term.successes >= max_successes
return (env.episode_length_buf >= env.max_episode_length - 1) | max_success_reached

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.

P1 Side-effecting termination mutates shared episode state

direct_reorient_timeout writes directly to env.episode_length_buf inside what the framework expects to be a stateless predicate. When a goal is reached the counter is zeroed, which effectively hides elapsed time from every other termination term evaluated after this one in the same step. If a second fall or out-of-reach termination runs after this one, the reset can mask conditions that had been accumulating. The function is not wired into the current Allegro config (direct_timeout is used instead), but the PR description states it will be adopted by the Shadow manager parts 9–11, so the risk will materialize.

Comment on lines +226 to +235
def reset(self, env_ids: Sequence[int] | None = None) -> None:
if env_ids is None:
env_ids = slice(None)
threshold = self.cfg.params["success_count_threshold"]
self._env.extras.setdefault("log", {})["Metrics/success_rate"] = (
(self._successes[env_ids] >= threshold).float().mean().item()
)
for statistic, value in self._orientation_error.reset(env_ids).items():
self._env.extras["log"][f"Diagnostics/episode_min_orientation_error_{statistic}"] = value
self._successes[env_ids] = 0.0

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.

P2 Partial-reset logging overwrites the global success-rate metric

reset is called with only the env_ids terminating in the current step; when a fraction of environments reset, the logged Metrics/success_rate reflects only that fraction and overwrites any earlier value from the same training step. Training dashboards may see a highly-variable or systematically biased metric depending on the batch composition at each reset boundary. Consider always computing the mean over all envs (ignoring env_ids) so the logged value is representative of the full population.

Comment on lines +103 to +108


@configclass
class ObservationsCfg:
"""Full 124-dimensional state observation in Direct order."""

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.

P2 set_num_envs double-writes the physx backend via its default alias

self.default is the same Python object as self.physx (assigned by default = physx), so self.default.num_envs = num_envs and self.physx.num_envs = num_envs are redundant. The second assignment is a no-op today but could confuse readers or silently break if default is ever re-pointed to a different backend.

Suggested change
@configclass
class ObservationsCfg:
"""Full 124-dimensional state observation in Direct order."""
def set_num_envs(self, num_envs: int) -> None:
"""Set the environment count on every backend alternative."""
self.physx.num_envs = num_envs
self.newton_mjwarp.num_envs = num_envs
self.ovphysx.num_envs = num_envs
self.default = self.physx

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from 3b4f0cc to d4d1290 Compare July 17, 2026 00:56
@hujc7 hujc7 changed the title [Task Clean-up][Manager] Dexterous Part 8/11: Align the Allegro manager to the Direct contract [Task Clean-up][Manager] Dexterous Part 8: Add the reorientation manager counterparts Jul 17, 2026
@hujc7 hujc7 changed the title [Task Clean-up][Manager] Dexterous Part 8: Add the reorientation manager counterparts [Task Clean-up][Manager] Dexterous Part 8/11: Align the Allegro manager to the Direct contract Jul 17, 2026
hujc7 added a commit that referenced this pull request Jul 17, 2026
…nager runtime (#6412)

## Summary

- Fixes OVPhysX actuator joint indices to follow the common actuator
indexing contract.
- Fixes OVPhysX initialization alongside Kit by reusing Kit's registered
PhysX schema provider.
- Fixes the OVPhysX manager to support both the declared public runtime
API and the current runtime API.
- Regression tests included. Validated by full dexterous training runs
on the OVPhysX backend; split out of the lumped validation branch #6324
(Part 2 of 11).

## Dependencies

- None.

## Series review map

Full integrated diff + training/validation evidence: the lumped
validation PR #6324
(DO-NOT-MERGE).

| Part | PR |
|---|---|
| Docs: regenerate the environment overview table |
#6410 |
| Part 1/11: Newton runtime fixes (cloner rows, cubric fallback, viz
teardown) | #6411 |
| **Part 2/11: OVPhysX runtime fixes (this PR)** |
#6412 |
| Part 3/11: success-rate metrics for the Direct reorientation tasks |
#6413 |
| Part 4/11: RSL-RL training for the handover Direct task |
#6414 |
| Part 5/11: success-rate support in the benchmark utilities |
#6415 |
| Part 6/11: renderer presets for the Direct camera task |
#6416 |
| Part 7/11: OVPhysX presets for the dexterous tasks |
#6417 |
| Part 8/11: Allegro manager counterpart |
#6418 |
| Part 9/11: Shadow + OpenAI manager counterparts |
#6419 |
| Part 10/11: Shadow camera manager counterpart |
#6420 |
| Part 11/11: Shadow handover manager counterpart |
#6421 |


---
### Exact changes in this PR

- OVPhysX backend changes + tests:
1f7a433
@hujc7 hujc7 changed the title [Task Clean-up][Manager] Dexterous Part 8/11: Align the Allegro manager to the Direct contract [Task Clean-up][Manager] Dexterous Part 5/8: Add the reorientation manager counterparts Jul 17, 2026
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from f8b3611 to c5195e8 Compare July 18, 2026 11:10
@hujc7
hujc7 requested a review from a team July 18, 2026 11:10
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch 3 times, most recently from da863b8 to 957322a Compare July 20, 2026 22:36
hujc7 added a commit that referenced this pull request Jul 22, 2026
…isualizer teardown (#6411)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6410 [Docs] Environment overview regen |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| — | — |
| 📌 #6411 Part 1/8: Newton cloner/cubric/visualizer fixes (this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | — |
| #6412 Part 2/8: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | — |
| #6413 Part 3/8: Reorient Direct, torch |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — | — |
| #6414 Part 4/8: MARL-to-single-agent fix + handover/camera Direct |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/6e8a63e4e028b2d43676ea30c446b9dc9068c7b5..5cb00e7cb5cc813b202521272e043007cd255194)
|
| #6418 Part 5/8: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/79f87501ac4c81de93a71dab00dc443da62113aa..e7c9a9a3fae3a7972b0c5165ae683abffb7d0e0f)
|
| #6421 Part 6/8: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6413, #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/01c9f4d8c5c35a5688b2a5bb90209e16b8f81b99..835a5815ec49b11aada1d20a76c177054505e6e7)
|
| #6415 Part 7/8: Benchmark success-rate utilities + docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6413, #6414, #6418, #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/e1abb6b1790ccc57af42551eebccf743633f1f13..d6348539aa8032d9668c20a8fea462c5d88d3af9)
|
| #6582 Part 8/8: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/21dbb1769c4e30c8e9e5b0f563c2dae24c230349..83e1587cadd9712a60615ed2a3cb2d177c2ac24d)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

- Fixes Newton cloner label rows, the cubric IAdapter version audit
(exact-match fallback to the CPU hierarchy path), and visualizer
teardown.
- Retains an in-tree `ignore_paths` workaround for custom-frequency USD
traversal; it becomes redundant once the Newton pin advance
(#6584) merges — this PR then
only needs a rebase.

## Stacking

- Independent; based on `develop`.

## Review history

- Approved. The Newton pin + MuJoCo overrides were split out to
#6584 via revert commits
(2026-07-17) so this PR's CI runs against develop's pins.
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from e7c9a9a to 707d37f Compare July 23, 2026 21:22
@github-actions github-actions Bot added the asset New asset feature or request label Jul 23, 2026
@hujc7 hujc7 changed the title [Task Clean-up][Manager] Dexterous Part 5/8: Add the reorientation manager counterparts [Task Clean-up][Manager] Dexterous Part 5/9: Add the reorientation manager counterparts Jul 23, 2026
hujc7 added a commit that referenced this pull request Jul 24, 2026
…eorientation Direct tasks (#6413)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6411 Part 1/9: Newton cloner/cubric/visualizer fixes |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | merged |
| #6412 Part 2/9: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | merged |
| 📌 #6413 Part 3/9: Reorient Direct, torch (this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6413/changes/f4895f0f9ee..d29afc75e71)
|
| #6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/d29afc75e71..b10a84948f8)
|
| #6418 Part 5/9: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99)
|
| #6421 Part 6/9: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6413, #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc)
|
| #6410 Part 7/9: Environment overview docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d)
|
| #6415 Part 8/9: Benchmark success-rate utilities |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b)
|
| #6582 Part 9/9: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

- Adds a behavioral `Metrics/success_rate` signal (goal-reach streaks
per episode) and threshold-independent episode orientation-error
diagnostics to the Direct reorientation environments; success gates task
health, reward stays diagnostic.
- Task logic is **torch-first** per the mainline convention (plain torch
buffers; `.torch` accessors only at the core-lib boundary). This
supersedes the earlier warp-first revision of this PR; the warp
implementation moved to `isaaclab_tasks_experimental`
(#6582).
- Lands shared helpers in `isaaclab_tasks.core.utils`
(`EpisodeErrorRecorder`, `sample_joint_positions_within_limits`) with
torch math tests; fixes hand resets below lower joint limits.

## Stacking

- First stack PR; based on `develop`.

## Validation

- Kit-free torch math + utils tests green; Direct state training on
Newton: success rate 0.85–1.00, reward ≈3600–3900 at 2000 iterations,
frame-verified policy video. Full integrated evidence: #6324.

## Review history

- The earlier warp-era review rounds on this PR are superseded by the
torch restack (2026-07-16); the warp implementation and its
review-polished kernels live on in
#6582.

@AntoineRichard AntoineRichard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review]

Requesting changes for two merge blockers: this removes public APIs without the required prior deprecation, and the lazy-export stub advertises camera symbols that do not exist. Inline comments also cover the unenforced Direct/manager parity, source-comment hygiene, and duplicated quaternion construction.

Verification: ./isaaclab.sh -f passed; the added math tests passed (8 tests); Reorient config-loading tests passed (18 tests); a runtime probe of mdp.ShadowHandCameraFeatures failed with the expected AttributeError.

Removed
^^^^^^^

* Removed the legacy manager-based reorientation configuration

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] — Important

These symbols are public today (success_bonus, track_*, and the termination terms are exported from mdp.__all__), and ReorientObjectEnvCfg is an importable configuration. Removing them in this PR violates the repository rule that breaking changes require a prior deprecation release. The existing Allegro task ID also changes contract in place, making released checkpoints incompatible.

Please retain the old configuration/task behavior and exported terms with deprecation warnings for at least one release, introduce the replacement under new names/IDs, and record this under Deprecated rather than Removed.

__all__ = [
"NoisyEMAJointPositionToLimitsAction",
"NoisyEMAJointPositionToLimitsActionCfg",
"ShadowHandCameraFeatures",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] — Important

This export is broken: ShadowHandCameraFeatures, shadow_hand_camera_cached_features, and shadow_hand_goal_keypoints are imported from observations.py, but that module defines none of them. A runtime access to mdp.ShadowHandCameraFeatures raises AttributeError, and from ...mdp import * consequently fails.

Please remove these three stale exports (and the orphaned camera-section header in observations.py) until the implementation lands, or add the missing implementation. A small test that resolves every explicit symbol in this stub would catch this regression.

obs_type = "full"
# simulation

# simulation — values mirrored by the manager cfg (guarded by the value-parity test)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] — Moderate

There is no value-parity test in this PR or the existing Reorient tests, so this comment makes a false maintenance guarantee. The simulation, reset, reward, and observation contracts are duplicated across the Direct and manager configurations; future edits can silently break the parity promised by this PR.

Please centralize these tunables in a private shared parameter bundle and add an explicit Direct/manager contract test. Once enforced, keep only a concise functional comment.

state_space = 187 + 27 # asymmetric states + vision CNN embedding

def __post_init__(self):
# The vision env renders through the Isaac RTX tiled camera, whose render

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] — Moderate

This comment narrates the backend investigation, failure mode, CLI overrides, and benchmark history merely to justify one default. That is review/validation context rather than a durable source-code contract.

Please reduce it to the functional constraint, for example: # Isaac RTX requires Fabric cloning, so the camera task defaults to PhysX. Keep the benchmark and alternative-command details in the PR description or user documentation.

return torch.clamp(joint_position, min=limits[..., 0], max=limits[..., 1])


def random_xy_rotation(count: int, device: str | torch.device) -> torch.Tensor:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[AI Review] — Moderate

random_xy_rotation and randomize_rotation below implement the same X/Y quaternion composition. The Direct path uses one and the manager reset path uses the other, creating two sources of truth for quaternion order; randomize_rotation also lacks the specific type annotations required for new interfaces.

Please extract one typed composition helper and reuse it from both sampling paths, with a known-input regression test.

hujc7 added a commit that referenced this pull request Jul 29, 2026
… and enable handover Direct RSL-RL (#6414)

## Review Map

- **Exact changes**: a stacked PR's page shows the cumulative diff of
its dependency chain; the link pins the commit range that is the PR's
own contribution. This PR (#6414) is now rebased directly onto
`develop`, so its own **Files changed** tab is its contribution.
- Links pin specific SHAs and can go stale after a branch update — the
table on #6324 is refreshed first.

| PR | Status | Depends on | Exact changes |
|---|---|---|---|
| #6411 Part 1/9: Newton cloner/cubric/visualizer fixes |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6411?label=)
| — | merged |
| #6412 Part 2/9: OVPhysX articulation + manager runtime |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6412?label=)
| — | merged |
| #6413 Part 3/9: Reorient Direct, torch |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6413?label=)
| — | merged |
| 📌 #6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct
(this PR) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6414?label=)
| — (on develop) | Files changed tab |
| #6418 Part 5/9: Reorient manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6418?label=)
| #6413 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99)
|
| #6421 Part 6/9: Handover + camera manager counterparts |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6421?label=)
| #6414, #6418 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc)
|
| #6410 Part 7/9: Environment overview docs |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6410?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d)
|
| #6415 Part 8/9: Benchmark success-rate utilities |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6415?label=)
| #6421 |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b)
|
| #6582 Part 9/9: Warp variants → experimental (draft; merges last) |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6582?label=)
| — |
[changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3)
|
| #6324 [DO-NOT-MERGE] Lumped validation reference |
![](https://img.shields.io/github/pulls/detail/state/isaac-sim/IsaacLab/6324?label=)
| ALL | — |

## Summary

Converts the two-hand Shadow Hand **handover** task from multi-agent
(MARL) to **single-agent** (enabling RSL-RL training), fixes the
underlying MARL→single-agent observation bridge, and consolidates the
shared Shadow Hand definitions into the asset.

- **MARL → single-agent bridge (general, broader than this task).**
Single-agent RL libraries train `DirectMARLEnv` tasks via
`multi_agent_to_single_agent`; the bridge dropped the latest
observations from the public buffer. Fixed generally — RSL-RL
observations read from the env-owned `obs_buf`, stored by `reset` like
`step` on all env bases (`DirectRLEnv`, `DirectMARLEnv`, the
experimental warp base). Every MARL task + single-agent runner benefits;
handover is the first consumer.
- **Handover Direct → single-agent + RSL-RL.** Single-agent conversion,
RSL-RL runner config, shared identity in `handover_common`, success-rate
reward metrics, and a fix for its Newton construction failure (see
below).
- **Shadow Hand Newton robot → the asset.** Moved the Newton (MJWarp)
robot cfg into `isaaclab_assets` as `SHADOW_HAND_NEWTON_CFG` (beside
`SHADOW_HAND_CFG`); reorient and handover consume it as **siblings**
(neither imports the other). Reorient uses the default gains; handover
overrides only the finger stiffness/damping to `20/2` for its catch.
- **Shadow camera cleanup.** Renamed the camera Direct modules to
`shadow_hand_direct_camera_env[_cfg]`; moved cube-keypoint math to the
shared, unit-tested `reorient/mdp/observations.py` (replacing the
per-env `compute_keypoints` shim); and added OVPhysX physics presets to
the handover and camera Direct environments. The camera env config is
otherwise unchanged from develop.

### Behavior changes

**Reorient-on-Newton is unchanged.** The Newton hand definition moves
**verbatim** into `SHADOW_HAND_NEWTON_CFG` — same joint expressions,
effort limits, gains, friction and armature — so its config diff vs
`develop` is purely the move, and the Direct env config has no diff at
all.

Handover changes in three ways:

- Its **default physics backend moves from PhysX to Newton** (MJWarp),
matching the reorientation tasks. Pass `physics=physx` for the previous
backend.
- Its `distal_passive` actuator group is **removed**. It targeted
`robot0_(FF|MF|RF|LF)J0` — joints that **do not exist** on the Newton
asset (its fingers are numbered `J1`–`J4`/`J5`), so constructing the
environment raised `No joints found for actuator group`. The `fingers`
group already drives those joints, and the comment justifying the group
(USD-baked `stiffness=286/damping=57`) does not apply to this asset,
which authors no drive stiffness at all.
- Two orientation fixes: the goal orientation was initialized to a
180-degree rotation instead of identity, and the Newton root rotation
replaced the asset's baked rotation instead of composing with it,
leaving both palms rotated 90 degrees.

Two pre-existing discrepancies were found while verifying against the
asset and are left for a follow-up, since each is a behavior change
needing its own validation: the config sets `armature=2e-3` where the
asset authors `0.0002`, and the per-finger `J1`/`J2` pair is coupled by
a fixed tendon that the MJWarp solver currently skips — the actuator
gains are what hold that pair together today, which is why the `J4`
knuckle-abduction joints cannot simply be added to the driven set.

## Notes

- Rebased onto **latest develop**; clean 3-commit history: `Add
single-agent flattening for MARL Direct environments` / `Convert Shadow
Hand handover to single-agent Direct with RSL-RL` / `Clean up Shadow
reorient/camera tasks and consolidate the Newton hand`.

## Validation

- Kit-free suite green: handover, keypoint math, the MARL adapter, and
new checks pinning the RSL-RL wrapper observation contract (verified to
fail against the previous implementation).
- Camera Direct reaches training takeoff under `rsl_rl` (frame-verified
videos); its env config now matches develop's established vision env.
- **Reorient-on-Newton vs `develop`** (`rsl_rl`, 2048 envs, 1500
iterations, 4 runs per config): this branch spans 524–664 reward,
`develop` spans 654–822 — overlapping distributions whose per-config
spreads (140–168) exceed the gap between them. The move is additionally
verified at the config level: the Newton robot configuration is
character-for-character identical to `develop`'s.
- **Handover-on-Newton** trains end-to-end on this branch (reward 1314),
which the `develop` config cannot do at all — it fails during
construction. Full evidence: #6324.
@hujc7
hujc7 marked this pull request as draft July 29, 2026 06:17
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from d0b6848 to 81cff73 Compare July 29, 2026 06:18
@hujc7
hujc7 marked this pull request as ready for review July 29, 2026 08:51
Comment on lines +207 to +212
enable_domain_randomization: bool = True
"""Apply the shared startup domain-randomization terms.

The Direct Allegro task has no randomization, so disable this to compare the two
workflows directly. Changing it requires retraining.
"""

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.

P1 DR enabled by default contradicts PR description and class contract

enable_domain_randomization is True out of the box, but the PR description states it is "disabled by default" and the changelog repeats this. More importantly, the class docstring says "Direct-compatible semantics" and explicitly notes the Direct Allegro task has no randomization — so a default-constructed AllegroCubeEnvCfg() will silently apply physics-material, mass, and stiffness perturbations that the Direct reference task never applies. Anyone comparing the two workflows without overriding this flag will see a training-curve difference that is entirely DR, not workflow.

Set the default to False so the no-DR path is the safe default and DR must be deliberately opted in.

@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch 4 times, most recently from 54ab530 to d8a6577 Compare July 30, 2026 09:31
@hujc7

hujc7 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

@greptileai review

def __post_init__(self):
# post init of parent
super().__post_init__()
class AllegroCubeSceneCfg(InteractiveSceneCfg):

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.

Why didi we remove the manager base class?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The base class was mostly used for allegro task and inheriting into the shadow task causes a lot of overrides, so I decided to make the base class for allegro and shadow but not shared.

)

gym.register(
id="Isaac-Reorient-Cube-Shadow-Camera-Benchmark-Direct",

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.

Move to contrib



@configclass
class FullStateWithoutActionCfg(ObsGroup):

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.

Odd naming, diverges from rest of isaaclab

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

updated



@configclass
class ShadowPhysxEventCfg(PhysxEventCfg):

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.

I don't see a difference between this and the newton one, why do we need preset cfg?



@configclass
class OpenAICommandsCfg:

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.

Im not a fan of the openai naming scheme. The MDP configs should keep very generic names like the rest of isaaclab.

For openai, keep a comment at the top, link to the paper and give them a reference and acknowledgement. We don't need to use the name everywhere.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

renamed.


@configclass
class CriticCfg(FullStateWithoutActionCfg):
# -- contact sensing

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.

Strip away these stray comments. The code itself is readable and doesnt need a commen title.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

removed

# card across tasks); pop it from the returned dict so CommandManager does not
# additionally log it under ``Metrics/<term_name>/success_rate``.
self._env.extras.setdefault("log", {})["Metrics/success_rate"] = extras.pop("success_rate")
reset_buf = getattr(self._env, "reset_buf", None)

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.

We shouldn't use getattr inside the MDP like this. Either this needs to exist (so we can write a test), or it doesn't and we need to modify code elsewhere to ensure there is a reset_buf? Is it intended for it to be optional like this? When would it be None?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

it was not available at init and only get assigned during step. Created a reset buffer at init time to avoid it.

"""Threshold for the orientation error to consider the goal orientation to be reached."""
"""Threshold [rad] for the orientation error to consider the goal orientation to be reached.

Set per family at the declaration site, matching the Direct configuration's value.

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.

Stray coment

@@ -85,3 +88,58 @@ def object_away_from_robot(
dist = torch.linalg.norm(robot.data.root_pos_w.torch - object.data.root_pos_w.torch, dim=1)

return dist > threshold


class reorient_timeout(ManagerTermBase):

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.

Some of these MDP functions/terms look very generic. Is there nothing in the global MDP for this? Maybe we need to promote this to the global MDP so multiple tasks can take advantage?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

With the SR setup, I think some mdps are quite specific. I don't have a clear picture yet how to make it cleaner.

@@ -1,348 +0,0 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).

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.

I think this base class was good (and matched the convenetion across all isaaclab)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's kind of combined into the allegro one.

@hujc7
hujc7 requested a review from pbarejko as a code owner July 30, 2026 22:26
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 31, 2026
@hujc7
hujc7 requested a review from StafaH July 31, 2026 08:55
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from 461185c to c9d53c7 Compare July 31, 2026 11:36
@hujc7
hujc7 requested a review from AntoineRichard July 31, 2026 15:58
hujc7 added 4 commits August 3, 2026 03:28
Manager terms that run during the initial reset had no reset_buf to read:
the attribute was only assigned in step(), which has not run yet at that
point. Allocate it alongside episode_length_buf, before the managers load.
Provide the observation, action, event, command and termination terms the
manager-based reorientation tasks need, alongside a parity test that pins
their values against the Direct environment.

Terminations evaluate success directly rather than reading the command's
metrics, which the command manager only refreshes after the termination
phase of step() has already run.
Register manager counterparts for the Allegro, Shadow and OpenAI Shadow
reorientation tasks, each configured in its own per-robot module.

Replace the single shared reorient_manager_env_cfg with those per-robot
configurations: the shared base could only describe the Allegro task, so
every Shadow variant overrode most of what it inherited.
The benchmark variant exists to measure rendering throughput rather than to
train a policy, so it belongs alongside the other contributed tasks. Keep
the released task ID working as a deprecated alias.
@hujc7
hujc7 force-pushed the jichuanh/task-cleanup-dex-part08 branch from 27188cb to 445ad89 Compare August 3, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset New asset feature or request documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants