[Task Clean-up][Benchmark] Dexterous Part 8/9: Add success-rate support to the benchmark utilities - #6415
[Task Clean-up][Benchmark] Dexterous Part 8/9: Add success-rate support to the benchmark utilities#6415hujc7 wants to merge 70 commits into
Conversation
| def _extract_sustained_feature(log_data, feature, uses_lower_threshold, consecutive_samples): | ||
| """Extract the best threshold-facing value sustained over a sample window.""" | ||
| values = np.asarray(log_data[feature], dtype=float)[:, 1] | ||
| if len(values) < consecutive_samples: | ||
| return None | ||
| if not np.all(np.isfinite(values)): | ||
| return math.nan |
There was a problem hiding this comment.
Global NaN check rejects series with any early non-finite value
np.all(np.isfinite(values)) is applied to the full historical series before any windowing, so a single NaN anywhere — including in early warm-up steps before the metric stabilises — causes the function to return math.nan and fail the threshold even when a valid consecutive_samples-length window exists entirely within the finite portion of the data. For success_rate in particular, early episodes may not record any successes and could produce NaN values before converging; those early samples would silently disqualify an otherwise passing run. Restricting the finiteness check to each candidate window (or filtering non-finite entries before slicing) would make the "best sustained window" semantics consistent with the function's name.
There was a problem hiding this comment.
[AI Review] Confirmed on the current head: [NaN] + [0.3] * 20 returns NaN even though the suffix contains a valid contiguous 20-sample window. Please evaluate finiteness per candidate window without filtering across gaps, and add this exact regression case.
| @@ -230,7 +271,7 @@ def _extract_log_val(name, log_data, uses_lower_threshold, workflow): | |||
| "skrl": "Reward / Total reward (mean)", | |||
| } | |||
| tag = reward_tags.get(workflow) | |||
| if tag: | |||
| if tag and consecutive_samples is None: | |||
| return _extract_reward(log_data, tag) | |||
|
|
|||
| elif name == "episode_length": | |||
| @@ -241,8 +282,20 @@ def _extract_log_val(name, log_data, uses_lower_threshold, workflow): | |||
| "skrl": "Episode / Total timesteps (mean)", | |||
| } | |||
| tag = episode_tags.get(workflow) | |||
| if tag: | |||
| return _extract_feature(log_data, tag, uses_lower_threshold) | |||
| elif name == "success_rate": | |||
| success_rate_tags = { | |||
| "rl_games": "Episode/Metrics/success_rate", | |||
| "rsl_rl": "Metrics/success_rate", | |||
| "skrl": "Metrics/success_rate", | |||
| } | |||
| tag = success_rate_tags.get(workflow) | |||
|
|
|||
| if tag: | |||
| if consecutive_samples is not None: | |||
| return _extract_sustained_feature(log_data, tag, uses_lower_threshold, consecutive_samples) | |||
| return _extract_feature(log_data, tag, uses_lower_threshold) | |||
There was a problem hiding this comment.
reward bypasses _extract_reward when consecutive_samples is set
When name == "reward" and consecutive_samples is not None, the early return _extract_reward(...) branch is skipped (lines 274–275) and the code falls through to the generic if tag: block, where _extract_sustained_feature is called instead. _extract_reward uses an "average of the top-k" aggregation that is quite different from the sliding-window min/max in _extract_sustained_feature. Any future YAML config that specifies a structured threshold for the reward metric would silently receive a semantically different aggregation than the scalar-threshold path. There are no tests covering this combined path, and the behaviour change is not documented.
There was a problem hiding this comment.
[AI Review] Confirmed on the current head: values 1 through 10 produce 6.5 with the scalar reward path and 8.0 with consecutive_samples=3. Because structured specs are accepted generically, this is a silent aggregation-contract switch. Restrict structured specs to success_rate, or define and test an explicit reducer for every supported metric.
AntoineRichard
left a comment
There was a problem hiding this comment.
I think we should store the success rate / metrics / expectations somewhere else.
AntoineRichard
left a comment
There was a problem hiding this comment.
I think we should discuss how to go about this. It's not clear if we should do any training tests on our regular CI. If we make such changes to this API they should not belong in that PR series. I would rather discuss this first.
There was a problem hiding this comment.
This is also hiding major changes under an incorrect PR scope
There was a problem hiding this comment.
[AI Review] Confirmed at the current head. The exact b50ac890...f21a2124 contribution includes a camera physics-default change, rendering coverage, install-order coverage, manager/direct parity coverage, and a manager changelog fragment in this benchmark PR. Please move each item to its owning stack layer so the benchmark behavior can be reviewed and reverted independently.
| def _is_training_task(task_id: str) -> bool: | ||
| """Return whether a registered task is intended for training benchmarks.""" | ||
| stem, separator, version = task_id.rpartition("-v") | ||
| if separator and version.isdigit(): | ||
| task_id = stem | ||
| return not {"Play", "Benchmark"}.intersection(task_id.split("-")) | ||
|
|
||
|
|
There was a problem hiding this comment.
This is a major change.
There was a problem hiding this comment.
[AI Review] Agreed: this expands discovery from one Play-v0 suffix to every task containing a Play or Benchmark token, across versions. The unit test covers synthetic IDs only and does not prove that every excluded registered task is inference-only. Please split this into the separately discussed discovery-contract change and validate it against the actual registered task set.
Add a behavioral Metrics/success_rate signal (goal-reach streaks per episode) and threshold-independent episode orientation-error diagnostics to the Direct reorientation environments, with the shared helpers in isaaclab_tasks.core.utils and torch math tests. The task logic is torch-first per the mainline convention; success gates task health while reward stays diagnostic. Also fix hand resets that could initialize joints below their lower position limits.
Add the RSL-RL runner configuration for the Shadow handover Direct task and success-rate metrics on the torch-first path, fix handover construction on Newton (renamed distal joints), and land the camera Direct renderer presets with configuration validation. RSL-RL observations now read from the public environment-owned obs_buf on all Direct env bases (reset stores the buffer like step), replacing the adapter-side private hook.
Add manager-based training environments for the Allegro and Shadow cube reorientation tasks (state and OpenAI FF/LSTM variants). The manager cfgs share the Direct tasks' scalar parameters through per-family task constants, and the shared MDP terms reuse the Direct success evaluation so both variants report the same boolean success metric.
Add manager-based training environments for the Shadow handover and Shadow camera reorientation tasks, completing manager coverage of the dexterous families. Direct-vs-manager scalar parity across all families is enforced by a new value-parity test.
Report the success-rate metric through the environment training benchmark utilities, exclude inference-only camera benchmark registrations from training-benchmark discovery, regenerate the environment overview table, and cover the install-order constants with a unit test.
381c55b to
df070af
Compare
The rename round updated the camera gym-registration entry-point strings to shadow_hand_direct_camera_env* at this layer, but the camera modules here still carry their pre-rename names, so every registry-driven cfg load failed at import (isaaclab_tasks suites, forbidden-imports test, registered-tasks rendering). Point the registrations back at the modules that exist at this layer.
The lower layer's registration revert merged forward and un-renamed the camera entry points here, where the camera modules do carry the renamed filenames. Pin the registration block back to the final state.
…eanup-dex-part11 # Conflicts: # source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/__init__.py
…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 |  | — | — | | 📌 #6411 Part 1/8: Newton cloner/cubric/visualizer fixes (this PR) |  | — | — | | #6412 Part 2/8: OVPhysX articulation + manager runtime |  | — | — | | #6413 Part 3/8: Reorient Direct, torch |  | — | — | | #6414 Part 4/8: MARL-to-single-agent fix + handover/camera Direct |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/6e8a63e4e028b2d43676ea30c446b9dc9068c7b5..5cb00e7cb5cc813b202521272e043007cd255194) | | #6418 Part 5/8: Reorient manager counterparts |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/79f87501ac4c81de93a71dab00dc443da62113aa..e7c9a9a3fae3a7972b0c5165ae683abffb7d0e0f) | | #6421 Part 6/8: Handover + camera manager counterparts |  | #6413, #6414, #6418 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/01c9f4d8c5c35a5688b2a5bb90209e16b8f81b99..835a5815ec49b11aada1d20a76c177054505e6e7) | | #6415 Part 7/8: Benchmark success-rate utilities + docs |  | #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) |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/21dbb1769c4e30c8e9e5b0f563c2dae24c230349..83e1587cadd9712a60615ed2a3cb2d177c2ac24d) | | #6324 [DO-NOT-MERGE] Lumped validation reference |  | 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.
Applies the P3-owned share of the lump review-response commits: - Default the dexterous tasks to newton_mjwarp (from 3f9ce324). - Drop solver defaults matching the backend + inline the scene preset via preset() instead of a wrapper class (from 29e189bf). - Simplify the Direct reorientation reward computation (from bfb73735). - Source the actuated-joint and fingertip body-name lists from the robot assets instead of the config module (from 34676102). Deferred to their owning layers: the core/utils relocation (S17) lands at the manager layer where reorient/mdp/events.py is introduced, and the handover default/preset changes land with the handover part.
P4-owned share of the lump review-response commits: - Default the handover task to newton_mjwarp and add the ovphysx object preset alias (from 3f9ce324, 29e189bf). - Source the handover joint/body name lists from the robot assets (from 34676102). S17 (core/utils relocation) defers to the manager layer where reorient/mdp/events.py is introduced.
Rebuilt from the reviewed lump so the manager counterparts land with the review rounds folded in: inline section values per file (drift guarded by the value-parity test incl. sim), identity from the common modules, the OpenAI variant in its own module, and no sim mixins. Lump review commits folded: 2c22af0, 792e400, 42675b6, 1f05f85, c6140f9, 173e9dc, 2727616, 1732493, 3659a33, ee272c9, cdaadac.
P5-owned share of the lump review-response commits: - Relocate the shared reset/rotation helpers into reorient/mdp/events.py and EpisodeErrorRecorder into reorient/mdp/rewards.py, removing the core/utils.py module (S17, from 428297c2). - Default the reorient manager cfgs to newton_mjwarp and source the hand name lists from the robot assets (from 3f9ce324, 34676102). - Repoint the Direct env to the relocated helpers.
Rebuilds P6 on the updated P4+P5, folding the P6-owned share: - Repoint handover to the relocated reorient.mdp helpers after the core/utils.py removal (S17 handover side, from 428297c2). - Inherits N2/preset/reward/names fixes via the rebuilt P4 and P5.
…6415-fold # Conflicts: # source/isaaclab_tasks/isaaclab_tasks/core/handover/handover_manager_env_cfg.py # source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/events.py # source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/rewards.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/allegro_hand/allegro_hand_manager_env_cfg.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_camera_manager_env_cfg.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_manager_env_cfg.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/config/shadow_hand/shadow_hand_openai_manager_env_cfg.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/events.py # source/isaaclab_tasks/isaaclab_tasks/core/reorient/mdp/rewards.py
Repoints the shadow-hand env.rst source links to the renamed _direct_ modules and lists ovphysx on the OpenAI-FF illustrated row (C1), completing the dexterous environment docs in the series.
The environment overview updates for the dexterous series belong in the dedicated docs PR (isaac-sim#6410), not the benchmark part. Reverts env.rst to the base version here.
The vision env renders through the Isaac RTX tiled camera, whose render products require the Fabric cloning path. The Newton backend disables Fabric cloning, so under Newton the rgb annotator has no render products at num_envs > 1 and the default RGB/depth/semantic render fails with "Annotator rgb is not attached to any render products". The shared PhysicsCfg/RobotCfg/ObjectCfg now default to Newton, so the camera env inherited a Newton default it cannot render with. Override the camera env's backend PresetCfgs to default to PhysX in __post_init__; Newton stays selectable via physics=newton_mjwarp for the depth-only Newton-warp-renderer benchmark path.
…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 |  | — | merged | | #6412 Part 2/9: OVPhysX articulation + manager runtime |  | — | merged | | 📌 #6413 Part 3/9: Reorient Direct, torch (this PR) |  | — | [changes](https://github.com/isaac-sim/IsaacLab/pull/6413/changes/f4895f0f9ee..d29afc75e71) | | #6414 Part 4/9: MARL-to-single-agent fix + handover/camera Direct |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6414/changes/d29afc75e71..b10a84948f8) | | #6418 Part 5/9: Reorient manager counterparts |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99) | | #6421 Part 6/9: Handover + camera manager counterparts |  | #6413, #6414, #6418 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc) | | #6410 Part 7/9: Environment overview docs |  | #6421 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d) | | #6415 Part 8/9: Benchmark success-rate utilities |  | #6421 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b) | | #6582 Part 9/9: Warp variants → experimental (draft; merges last) |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3) | | #6324 [DO-NOT-MERGE] Lumped validation reference |  | 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
left a comment
There was a problem hiding this comment.
[AI Review] Reviewed the exact stacked contribution from b50ac890 through f21a2124 (10 files). The inline comments identify correctness, scope, comment-quality, duplication, and repository-hygiene issues that should be addressed before merge. Local verification: 76 focused tests passed and ./isaaclab.sh -f passed; the GPU/Kit rendering test was not run. The PR is currently conflicting with its base.
| physx = _ShadowHandCameraManagerSceneCfg(clone_in_fabric=True) | ||
| newton_mjwarp = _ShadowHandCameraManagerSceneCfg(clone_in_fabric=False) | ||
| ovphysx = physx | ||
| default = newton_mjwarp |
There was a problem hiding this comment.
[AI Review] Important — the manager camera default remains incompatible with RTX. The final fix changes only ShadowHandCameraEnvCfg, while this scene still resolves to newton_mjwarp (clone_in_fabric=False) and its camera resolves to IsaacRtxRendererCfg. The newly added rendering test uses four environments, so it exercises the exact no-render-products combination described in f21a2124; retrying it as flaky cannot fix a deterministic incompatibility. Make the manager training and play camera defaults PhysX too, or select a compatible renderer, and add a config-level assertion for the resolved pair.
| workflow, | ||
| consecutive_samples=consecutive_samples, | ||
| ) | ||
| if val is None or not isinstance(val, Real) or not math.isfinite(float(val)): |
There was a problem hiding this comment.
[AI Review] Important — this changes every existing benchmark's failure semantics. Previously, a missing or non-finite reward/episode-length metric was omitted; now any configured metric fails the job. That is broader than success-rate support and can turn existing workflow runs red when a tag is absent or renamed. Please either scope the new failure behavior to success_rate, or split it into a separately discussed change with coverage for every supported workflow and an explicit changelog entry.
| Isaac-Reorient-Cube-Shadow-Camera: | ||
| max_iterations: 3000 | ||
| lower_thresholds: | ||
| # interim reward gate: catches pipeline breakage well below the truncated |
There was a problem hiding this comment.
[AI Review] These calibration notes are transient review history rather than durable functional documentation: evidence-calibrated, interim, tighten ... once, and provisional describe past runs and future intentions. Move that evidence to the PR or a benchmark artifact. Keep only stable metric semantics next to the configuration; the detailed rationale for why a numeric threshold was chosen should not live here.
| 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 |
There was a problem hiding this comment.
[AI Review] The constraint is useful, but this seven-line diagnostic/history comment is too long for the implementation. Keep the stable functional rule only, for example: Default to PhysX because RTX tiled cameras require Fabric cloning; Newton remains available for depth-only benchmarks. Put the failure text and investigation details in the regression test or PR.
| @@ -0,0 +1,159 @@ | |||
| # Copyright (c) 2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | |||
There was a problem hiding this comment.
[AI Review] New files must use the repository's current header exactly: Copyright (c) 2022-2026, .... Please replace the single-year 2026 header.
| @@ -0,0 +1,8 @@ | |||
| Added | |||
There was a problem hiding this comment.
[AI Review] This is a second fragment for isaaclab_tasks and describes manager work owned by an earlier stack layer. The repository requires one fragment per touched package. Move this fragment to the owning PR and keep one isaaclab_tasks fragment here. Also add a source/isaaclab/changelog.d/*.skip fragment for the test-only install change, remove the internal with unit tests wording from the user-facing entry, and document the camera default change if it remains in this PR.
| def test_reorient_direct_manager_scalars_match(family): | ||
| """Direct cfg scalars equal the manager term params they mirror.""" | ||
| direct_cfg, manager_cfg = _pairs()[family] | ||
| for i, (direct_value, manager_value) in enumerate(_reorient_cases(direct_cfg, manager_cfg)): |
There was a problem hiding this comment.
[AI Review] This constructs all four config pairs for every parameterized family, and failures report only an opaque case N. Make the cases lazy and named, such as (field_name, direct_value, manager_value), instantiate only the selected pair, and report the field name. That removes repeated construction/lookups and makes CI failures directly actionable.
AntoineRichard
left a comment
There was a problem hiding this comment.
[AI Review] Follow-up comment-quality pass: each remaining transient calibration comment and each redundant Verify ... test docstring now has its own inline remediation. The manager interim-threshold block and camera-default comment were already anchored in the previous review.
| Isaac-Reorient-Cube-Shadow-Camera-Direct: | ||
| max_iterations: 3000 | ||
| lower_thresholds: | ||
| # evidence-calibrated: full-budget Newton run crosses 1000 at iter ~2300 |
There was a problem hiding this comment.
[AI Review] This records run-specific calibration evidence (iter ~2300, iter ~1000, and a measured tail rate) rather than a stable functional contract. Remove it from the configuration and keep the evidence in the PR or benchmark results. The threshold fields are self-describing.
| Isaac-Shadow-Handover: | ||
| max_iterations: 3000 | ||
| lower_thresholds: | ||
| # evidence-calibrated: the manager variant plateaus near 785 on PhysX |
There was a problem hiding this comment.
[AI Review] This comment explains why 500 was chosen using one observed PhysX plateau. That calibration history will become stale and is not needed to understand the configuration. Remove it and retain the supporting run evidence outside the source file.
| # (the Direct rows keep the shared 1000 gate) | ||
| reward: 500 | ||
| episode_length: 150 | ||
| # provisional gate matching the validation campaign's controller |
There was a problem hiding this comment.
[AI Review] Provisional and matching the validation campaign are process/history notes, not functional documentation. Either define the stable semantics of this gate or remove the comment and track its provisional status in the PR or follow-up issue.
| ], | ||
| ) | ||
| def test_training_task_filter_excludes_play_and_benchmark(task_id: str, expected: bool): | ||
| """Verify inference-only variants never enter the training benchmark matrix.""" |
There was a problem hiding this comment.
[AI Review] This docstring only restates the descriptive test name. Remove it; the test name and parameter cases already express the behavior.
| ids=["missing", "nan"], | ||
| ) | ||
| def test_evaluate_job_fails_when_configured_reward_is_unavailable(monkeypatch, log_data): | ||
| """Verify missing or invalid configured metrics cannot produce a successful KPI payload.""" |
There was a problem hiding this comment.
[AI Review] This Verify ... docstring repeats the test name without adding a contract or non-obvious constraint. Remove it and keep the test self-documenting through its name and parameter IDs.
|
|
||
|
|
||
| def test_evaluate_job_fails_when_success_rate_is_missing(monkeypatch): | ||
| """Verify a missing configured success-rate metric fails.""" |
There was a problem hiding this comment.
[AI Review] This docstring restates the test name exactly. Remove it.
|
|
||
|
|
||
| def test_evaluate_job_treats_success_rate_as_missing_for_unsupported_workflow(monkeypatch): | ||
| """Verify an unmapped workflow fails the KPI instead of raising an exception.""" |
There was a problem hiding this comment.
[AI Review] This docstring repeats the already explicit unsupported-workflow test name and assertion. Remove it.
|
|
||
|
|
||
| def test_evaluate_job_fails_when_success_rate_is_nonfinite(monkeypatch): | ||
| """Verify a non-finite configured success-rate metric fails.""" |
There was a problem hiding this comment.
[AI Review] This docstring adds no information beyond the non-finite success-rate test name and input. Remove it.
|
|
||
|
|
||
| def test_evaluate_job_resets_sustained_success_streak(monkeypatch): | ||
| """Verify a below-threshold sample resets the consecutive-success streak.""" |
There was a problem hiding this comment.
[AI Review] This docstring repeats the sustained-streak reset behavior already stated by the test name. Remove it.
|
|
||
|
|
||
| def test_scalar_threshold_behavior_is_preserved(monkeypatch): | ||
| """Verify numeric thresholds retain the existing reward aggregation behavior.""" |
There was a problem hiding this comment.
[AI Review] This docstring is redundant with test_scalar_threshold_behavior_is_preserved and the assertions below it. Remove it.
… 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 |  | — | 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 (this PR) |  | — (on develop) | Files changed tab | | #6418 Part 5/9: Reorient manager counterparts |  | #6413 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6418/changes/d29afc75e71..707d37f8f99) | | #6421 Part 6/9: Handover + camera manager counterparts |  | #6414, #6418 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6421/changes/707d37f8f99..b50ac8906fc) | | #6410 Part 7/9: Environment overview docs |  | #6421 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6410/changes/b50ac8906fc..af259c0778d) | | #6415 Part 8/9: Benchmark success-rate utilities |  | #6421 | [changes](https://github.com/isaac-sim/IsaacLab/pull/6415/changes/b50ac8906fc..c7f2f019d8b) | | #6582 Part 9/9: Warp variants → experimental (draft; merges last) |  | — | [changes](https://github.com/isaac-sim/IsaacLab/pull/6582/changes/d29afc75e71..167c28578b3) | | #6324 [DO-NOT-MERGE] Lumped validation reference |  | 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.
Review Map
Summary
Stacking
Validation