Skip to content

[Task Clean-up][Manager] Dexterous Part 11/11: Add the Shadow handover manager counterpart#6421

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

[Task Clean-up][Manager] Dexterous Part 11/11: Add the Shadow handover manager counterpart#6421
hujc7 wants to merge 6 commits into
isaac-sim:developfrom
hujc7:jichuanh/task-cleanup-dex-part11

Conversation

@hujc7

@hujc7 hujc7 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds the manager-based counterpart for the two-hand Shadow handover task with its own MDP term set, registered as Isaac-Shadow-Handover with a benchmark row.
  • Completes the family-wide OVPhysX preset acceptance test and the handover configuration tests now that all manager counterparts exist (23 tests pass on the fully stacked tree).
  • The benchmark row gates on evidence-calibrated thresholds: reward 500 (measured plateau 785 on PhysX) plus the provisional sustained success-rate gate the validation campaign used (0.3 over 20 consecutive samples).
  • Validated by full handover manager training on PhysX (success streaks met at step 674); the Newton column is fixed by Part 4's per-backend joint mapping (Direct row retrains to ~0.95 success rate). Split out of the lumped validation branch [DO-NOT-MERGE][Task Clean-up] Dexterous: lumped validation branch (split into Parts 1-11) #6324 (Part 11 of 11 — merges last).

Dependencies

Review updates (2026-07-09)

  • Replaced parity-only customs (direct_timeout, object_below_height, hand_joint_pos_normalized, hand_joint_vel) with their isaaclab.envs.mdp equivalents and deleted them.
  • The 24-dimensional object/goal observation block moves to a Warp kernel with a caller-owned buffer and parity tests; scalar task parameters come from the shared constants module.

Manager-based counterpart for the two-hand Shadow handover task with
its own MDP term set (commands, events, observations, rewards,
terminations), registered as Isaac-Shadow-Handover with a benchmark
row. Completes the family-wide OVPhysX preset acceptance test and the
handover configuration tests now that all manager counterparts exist.

Validated by full handover manager training on PhysX (success streaks
met; Newton column blocked by the upstream asset joint renumbering
tracked separately).
@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds the manager-based counterpart for the two-hand Shadow Hand handover task (Isaac-Shadow-Handover), completing Part 11 of the dexterous task clean-up series. It introduces a new MDP term set (commands, events, observations, rewards, terminations), wires them into a HandoverManagerEnvCfg, and lands the family-wide OVPhysX acceptance test and handover configuration tests that depend on all prior parts being merged.

Confidence Score: 4/5

The change adds new files only (plus a two-line extension to init.py); no existing behavior is modified. The new env config correctly delegates scene/physics to the Direct base, and the MDP terms are consistent in frame conventions.

All newly added files follow the established lazy_export + PresetCfg pattern from the reorient task family. Frame conventions (local vs world) are consistent across commands, events, observations, and rewards. The single finding — storing two log values as zero-dim tensors while adjacent keys use .item() — is an inconsistency that could silently break a strict logging backend but does not affect training correctness.

source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/rewards.py — the dist_reward/dist_goal logging inconsistency noted above.

Important Files Changed

Filename Overview
source/isaaclab_tasks/isaaclab_tasks/core/handover/handover_manager_env_cfg.py New manager-based handover env config; delegates all scene/physics/action settings to the Direct base config via module-level _DIRECT_CFG and PresetCfg presets. Clean structure with no logic bugs found.
source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/rewards.py HandoverReward class computes sticky episode success and logs diagnostics; dist_reward and dist_goal are stored as zero-dim tensors without .item(), unlike the Metrics/* keys. Reward scaling via /step_dt is intentional and explained in comments.
source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/commands.py HandoverCommand samples fixed goal position from object default_root_pose plus offset and randomizes X/Y orientation per episode; consistent with Direct env's distribution. Goal position is correctly in local/env frame throughout.
source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/events.py reset_handover_state mirrors Direct env's reset distribution for object pose/velocity and both hands; uses env._handover_reset_actions side-channel to thread pre-reset actions into observations cleanly.
source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/observations.py All seven observation terms are frame-consistent (local/env frame for positions, world frame for velocities which are origin-invariant). object_goal returns a 24-dim block matching the Direct env layout.
source/isaaclab_tasks/isaaclab_tasks/core/handover/mdp/terminations.py Two simple termination terms: height-based fall detection and direct_timeout that exactly matches the Direct MARL boundary (>= max_episode_length - 1).
source/isaaclab_tasks/isaaclab_tasks/core/handover/init.py Registers new Isaac-Shadow-Handover manager env and adds rsl_rl_cfg_entry_point to the existing Direct registration.
source/isaaclab_tasks/test/core/test_handover_env_cfg.py New config tests verify asset reuse, pose consistency across backends, and Newton distal-joint override. Tests look correct and cover the key structural invariants.
source/isaaclab_tasks/test/core/test_dexterous_ovphysx_presets.py Family-wide OVPhysX acceptance test covering 15 dexterous variants including the new HandoverManagerEnvCfg; also tests Newton presets for allegro/handover variants.
source/isaaclab_tasks/test/benchmarking/configs.yaml Adds Isaac-Shadow-Handover benchmark row with same thresholds as the existing Direct variant (max_iterations=3000, reward>=1000, episode_length>=150).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ManagerBasedRLEnv\nIsaac-Shadow-Handover] --> B[HandoverManagerEnvCfg]

    B --> C[HandoverManagerSceneCfg\nPresetCfg: physx / newton_mjwarp / ovphysx]
    C --> C1[_HandoverManagerSceneCfg\nright_hand / left_hand / object]
    C1 --> C2[_DIRECT_CFG.right_robot_cfg\n_DIRECT_CFG.left_robot_cfg]

    B --> D[ActionsCfg\nEMAJointPositionToLimitsActionCfg\nright_hand + left_hand]
    B --> E[CommandsCfg\nHandoverCommand\nfixed pos + random X/Y orientation]
    B --> F[ObservationsCfg\nPolicyCfg: right 157-dim + left 157-dim]
    B --> G[EventCfg\nreset_handover_state]
    B --> H[RewardsCfg\nHandoverReward\n2x exp reward / step_dt]
    B --> I[TerminationsCfg\nobject_below_height + direct_timeout]

    G -->|env._handover_reset_actions| J[hand_action obs term]
    H -->|sticky success flag| K[Metrics/success_rate at reset]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[ManagerBasedRLEnv\nIsaac-Shadow-Handover] --> B[HandoverManagerEnvCfg]

    B --> C[HandoverManagerSceneCfg\nPresetCfg: physx / newton_mjwarp / ovphysx]
    C --> C1[_HandoverManagerSceneCfg\nright_hand / left_hand / object]
    C1 --> C2[_DIRECT_CFG.right_robot_cfg\n_DIRECT_CFG.left_robot_cfg]

    B --> D[ActionsCfg\nEMAJointPositionToLimitsActionCfg\nright_hand + left_hand]
    B --> E[CommandsCfg\nHandoverCommand\nfixed pos + random X/Y orientation]
    B --> F[ObservationsCfg\nPolicyCfg: right 157-dim + left 157-dim]
    B --> G[EventCfg\nreset_handover_state]
    B --> H[RewardsCfg\nHandoverReward\n2x exp reward / step_dt]
    B --> I[TerminationsCfg\nobject_below_height + direct_timeout]

    G -->|env._handover_reset_actions| J[hand_action obs term]
    H -->|sticky success flag| K[Metrics/success_rate at reset]
Loading

Reviews (1): Last reviewed commit: "Add the Shadow handover manager counterp..." | Re-trigger Greptile

Comment on lines +80 to +82
env.extras.setdefault("log", {})["dist_reward"] = per_agent_reward.mean()
env.extras["log"]["dist_goal"] = goal_distance.mean()
env.extras["log"]["Metrics/goal_distance"] = goal_distance.mean().item()

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 Mixed tensor/scalar types in extras log dict. dist_reward and dist_goal are stored as zero-dim PyTorch tensors (.mean() without .item()), while the Metrics/* keys on the very next lines use .item() to produce Python floats. A logging backend that serializes extras["log"] to JSON or passes values to a scalar summarizer will silently fail or produce unexpected output for those two keys.

Suggested change
env.extras.setdefault("log", {})["dist_reward"] = per_agent_reward.mean()
env.extras["log"]["dist_goal"] = goal_distance.mean()
env.extras["log"]["Metrics/goal_distance"] = goal_distance.mean().item()
env.extras.setdefault("log", {})["dist_reward"] = per_agent_reward.mean().item()
env.extras["log"]["dist_goal"] = goal_distance.mean().item()
env.extras["log"]["Metrics/goal_distance"] = goal_distance.mean().item()

hujc7 added 5 commits July 9, 2026 01:06
Mirrors the Warp general-function rewrite from the handover enablement
PR; the handover configuration tests slim to the manager-side checks
now that the Newton-backend tests live with the enablement PR.
Consumes the shared constants module and per-backend joint preset,
normalizes log scalar types, forwards replicate_physics, and gates the
benchmark row on evidence-calibrated thresholds including the
provisional sustained success-rate gate.
The parity-only customs (direct_timeout, object_below_height,
hand_joint_pos_normalized, hand_joint_vel) are replaced by their
isaaclab.envs.mdp equivalents and deleted, the 24-dimensional
object/goal observation block moves to a Warp kernel with a
caller-owned buffer and parity tests, and the scalar task parameters
come from the shared constants module.
The parity-only customs (direct_timeout, object_below_height,
hand_joint_pos_normalized, hand_joint_vel) are replaced by their
isaaclab.envs.mdp equivalents and deleted, the 24-dimensional
object/goal observation block moves to a Warp kernel with a
caller-owned buffer and parity tests, and the scalar task parameters
come from the shared constants module.
The parity-only customs (direct_timeout, object_below_height,
hand_joint_pos_normalized, hand_joint_vel) are replaced by their
isaaclab.envs.mdp equivalents and deleted, the 24-dimensional
object/goal observation block moves to a Warp kernel with a
caller-owned buffer and parity tests, and the scalar task parameters
come from the shared constants module.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant