From 3383b2ea46f55efc108121def1d1fd4ea31abadf Mon Sep 17 00:00:00 2001 From: hujc Date: Thu, 16 Apr 2026 11:30:52 -0700 Subject: [PATCH 1/3] Enable rough terrain for bipeds (H1, Cassie) and Digit on Newton Restore per-biped overrides dropped by parent PR's consolidation: - All bipeds (H1, Cassie, G1, Digit): restore reset_robot_joints.params["position_range"] = (1.0, 1.0). Bipeds have precise init poses that should not be randomly scaled on reset. - Cassie: add leg armature=0.02 for stability on rough terrain. Out of scope (pre-existing issues that fail on PhysX too): - G1: finger joints dilute learning; addressed in follow-up PR. - Digit: closed-loop kinematics fail in 7 steps on both backends. --- .../locomotion/velocity/config/cassie/rough_env_cfg.py | 7 +++++++ .../locomotion/velocity/config/digit/rough_env_cfg.py | 2 ++ .../locomotion/velocity/config/g1/rough_env_cfg.py | 2 ++ .../locomotion/velocity/config/h1/rough_env_cfg.py | 2 ++ 4 files changed, 13 insertions(+) diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py index 3436fee7c108..b09d6c98097f 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py @@ -13,6 +13,7 @@ LocomotionVelocityRoughEnvCfg, RewardsCfg, ) +from isaaclab_tasks.utils import preset ## # Pre-defined configs @@ -60,12 +61,18 @@ def __post_init__(self): super().__post_init__() # scene self.scene.robot = CASSIE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot") + # Cassie Newton-only armature for biped stability on rough terrain; PhysX unchanged + self.scene.robot.actuators["legs"].armature = preset(default=0.0, newton=0.02) + + self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/pelvis" # Cassie uses "pelvis" as base body — disable mass randomization for bipeds self.events.add_base_mass = None self.events.base_com = None self.events.base_external_force_torque.params["asset_cfg"].body_names = ".*pelvis" + # Cassie has precise initial pose — don't scale joint defaults randomly on reset + self.events.reset_robot_joints.params["position_range"] = (1.0, 1.0) # actions self.actions.joint_pos.scale = 0.5 diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/digit/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/digit/rough_env_cfg.py index 89f6647a24f6..aa0f433e4ecc 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/digit/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/digit/rough_env_cfg.py @@ -232,6 +232,8 @@ def __post_init__(self): self.events.add_base_mass.params["asset_cfg"].body_names = "torso_base" self.events.base_external_force_torque.params["asset_cfg"].body_names = "torso_base" self.events.base_com.default.params["asset_cfg"].body_names = "torso_base" + # Digit has precise initial pose — don't scale joint defaults randomly on reset + self.events.reset_robot_joints.params["position_range"] = (1.0, 1.0) # Override actuator to target only actuated joints. Digit has ball joints (rod constraints) # that MuJoCo represents with 4 DoFs instead of 3, inflating joint_pos to 74 columns while diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/rough_env_cfg.py index a24379a1553d..a241d9c3329b 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/rough_env_cfg.py @@ -119,6 +119,8 @@ def __post_init__(self): self.events.add_base_mass = None self.events.base_com = None self.events.base_external_force_torque.params["asset_cfg"].body_names = "torso_link" + # G1 has precise initial pose — don't scale joint defaults randomly on reset + self.events.reset_robot_joints.params["position_range"] = (1.0, 1.0) # Rewards self.rewards.lin_vel_z_l2.weight = 0.0 diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py index 7d1ef73a5587..3dfb8d2f70f8 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py @@ -85,6 +85,8 @@ def __post_init__(self): # H1 uses "torso_link" as base body — disable mass randomization for bipeds self.events.add_base_mass = None + # H1 has precise initial pose — don't scale joint defaults randomly on reset + self.events.reset_robot_joints.params["position_range"] = (1.0, 1.0) self.events.base_com = None self.events.base_external_force_torque.params["asset_cfg"].body_names = ".*torso_link" From 0ee439a9ebfcb6b12a03ecfa3c78ac625768cebc Mon Sep 17 00:00:00 2001 From: hujc Date: Wed, 22 Apr 2026 08:00:26 +0000 Subject: [PATCH 2/3] Re-enable add_base_mass on H1/Cassie with log-uniform scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore base-mass randomization on H1 and Cassie that was disabled with add_base_mass = None in their rough-terrain configs (pre-existing biped convention from 2024-06 PR #444, later reinforced by PR #4165's Newton NaN TODO). The parent PR #5248 switches the shared default to log-uniform scale (1/1.25, 1.25), which is safer for bipeds than the old additive (-5, 5) kg (effectively ±25% on H1's torso vs ±100% on Cassie's pelvis). - H1 inherits the shared default (symmetric ±25% scale, body_names="torso_link"). - Cassie overrides to (1.0, 1.25) asymmetric heavier-bias: lighter-than- nominal pelvis destabilizes Cassie's closed-loop Achilles rod coupling and hip PD response, while heavier-than-nominal dampens dynamics. | Variant | reward | ep len | vs disabled | |--------------------------------|-------:|-------:|------------:| | None (disabled, prior default) | 23.93 | 910 | 1.00x | | (1/1.25, 1.25) sym25 | 14.15 | 850 | 0.59x x | | (1/1.10, 1.10) tight10 | 14.53 | 831 | 0.61x x | | **(1.0, 1.25) heavier25** | **21.50** | **932** | **0.90x** | Tightening the range symmetrically did not help (tight10 ~ sym25) — the lighter side is what destabilizes, not the magnitude. Restricting to [1.0, 1.25] (never lighter, up to +25% heavier) preserves most of the randomization benefit while avoiding the failure mode. Episode length also improves (932 vs 910), indicating the randomized policy is actively more stable during episodes — the lower aggregate reward comes from extra dof-torque regularizer paid to handle heavier instances, not degraded task completion. H1's larger base mass (≈15 kg torso) means ±25% on the default scale (11-19 kg range) is well within the controller's robustness margin. H1 reward at iter 1499: 24.02 with mass rand on vs 23.58 with it disabled (1.02x, essentially equal). Re-enabling provides sim-to-real robustness at negligible training cost. --- source/isaaclab_tasks/config/extension.toml | 2 +- source/isaaclab_tasks/docs/CHANGELOG.rst | 17 +++++++++++++++++ .../velocity/config/cassie/rough_env_cfg.py | 11 ++++++++--- .../velocity/config/h1/rough_env_cfg.py | 5 +++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/source/isaaclab_tasks/config/extension.toml b/source/isaaclab_tasks/config/extension.toml index 29bf11d4859a..158c271c5feb 100644 --- a/source/isaaclab_tasks/config/extension.toml +++ b/source/isaaclab_tasks/config/extension.toml @@ -1,7 +1,7 @@ [package] # Note: Semantic Versioning is used: https://semver.org/ -version = "1.5.28" +version = "1.5.29" # Description title = "Isaac Lab Environments" diff --git a/source/isaaclab_tasks/docs/CHANGELOG.rst b/source/isaaclab_tasks/docs/CHANGELOG.rst index 54502c8a8354..6796c5a2e99d 100644 --- a/source/isaaclab_tasks/docs/CHANGELOG.rst +++ b/source/isaaclab_tasks/docs/CHANGELOG.rst @@ -1,6 +1,23 @@ Changelog --------- +1.5.29 (2026-04-27) +~~~~~~~~~~~~~~~~~~~ + +Changed +^^^^^^^ + +* Re-enabled ``add_base_mass`` randomization on H1 and Cassie in their + rough-terrain configs (previously ``= None`` per the pre-existing biped + convention). H1 uses the shared log-uniform scale default from + ``EventsCfg``; Cassie overrides to ``(1.0, 1.25)`` asymmetric heavier-bias + (never lighter than nominal). Symmetric ±25% regressed Cassie reward by + 40% vs disabled due to closed-loop Achilles coupling destabilizing on + lighter pelvis mass; ``(1.0, 1.25)`` recovers to 90% of the + mass-rand-disabled baseline while retaining the domain-randomization + benefit. + + 1.5.28 (2026-04-24) ~~~~~~~~~~~~~~~~~~~ diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py index b09d6c98097f..4a1030534480 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/cassie/rough_env_cfg.py @@ -64,11 +64,16 @@ def __post_init__(self): # Cassie Newton-only armature for biped stability on rough terrain; PhysX unchanged self.scene.robot.actuators["legs"].armature = preset(default=0.0, newton=0.02) - self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/pelvis" - # Cassie uses "pelvis" as base body — disable mass randomization for bipeds - self.events.add_base_mass = None + # Cassie uses "pelvis" as base body. Override the shared symmetric + # (1/1.25, 1.25) log-uniform scale with asymmetric (1.0, 1.25) — + # lighter-than-nominal pelvis destabilizes Cassie's closed-loop + # Achilles coupling + hip PD response, so only heavier perturbations + # are safe. Symmetric ±25% regressed reward 40% vs disabled; + # (1.0, 1.25) recovers to 90% of baseline. + self.events.add_base_mass.params["asset_cfg"].body_names = "pelvis" + self.events.add_base_mass.params["mass_distribution_params"] = (1.0, 1.25) self.events.base_com = None self.events.base_external_force_torque.params["asset_cfg"].body_names = ".*pelvis" # Cassie has precise initial pose — don't scale joint defaults randomly on reset diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py index 3dfb8d2f70f8..de565b28bd32 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/h1/rough_env_cfg.py @@ -83,8 +83,9 @@ def __post_init__(self): if self.scene.height_scanner: self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/torso_link" - # H1 uses "torso_link" as base body — disable mass randomization for bipeds - self.events.add_base_mass = None + # H1 uses "torso_link" as base body; inherits the shared log-uniform mass + # randomization scale from EventsCfg (no per-H1 override needed). + self.events.add_base_mass.params["asset_cfg"].body_names = "torso_link" # H1 has precise initial pose — don't scale joint defaults randomly on reset self.events.reset_robot_joints.params["position_range"] = (1.0, 1.0) self.events.base_com = None From 246534873972537a87b0f1a95b33682c63b03452 Mon Sep 17 00:00:00 2001 From: hujc Date: Wed, 22 Apr 2026 19:18:56 +0000 Subject: [PATCH 3/3] Bump G1 max_iterations to 5000 on Newton for rough-terrain parity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PhysX G1 saturates near iter 3000: reward ≈ +18, ep_len ≈ 980. Past iter 3000 PhysX does not meaningfully improve on either metric — reward oscillates +16-19 through iter 7500, ep_len stays flat. Newton vanilla reaches matching (reward, ep_len) = (+16, 984) at iter 5000 and equals/exceeds PhysX by iter 6000 (+18.9 / 996). The gap is sample-efficiency, not a ceiling. Ablation (armature 0.01/0.03, damping 5→20, finger-removal from action space, Newton upstream a27277) did not change Newton's curve shape. Use the framework preset on max_iterations rather than tuning physics or reward terms, keeping the env config engine-agnostic. Precedent: Allegro Hand (5000), Spot (20000). --- source/isaaclab_tasks/config/extension.toml | 2 +- source/isaaclab_tasks/docs/CHANGELOG.rst | 16 ++++++++++++++++ .../velocity/config/g1/agents/rsl_rl_ppo_cfg.py | 10 +++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/source/isaaclab_tasks/config/extension.toml b/source/isaaclab_tasks/config/extension.toml index 158c271c5feb..2e7ee00764d7 100644 --- a/source/isaaclab_tasks/config/extension.toml +++ b/source/isaaclab_tasks/config/extension.toml @@ -1,7 +1,7 @@ [package] # Note: Semantic Versioning is used: https://semver.org/ -version = "1.5.29" +version = "1.5.30" # Description title = "Isaac Lab Environments" diff --git a/source/isaaclab_tasks/docs/CHANGELOG.rst b/source/isaaclab_tasks/docs/CHANGELOG.rst index 6796c5a2e99d..e67ac8f42161 100644 --- a/source/isaaclab_tasks/docs/CHANGELOG.rst +++ b/source/isaaclab_tasks/docs/CHANGELOG.rst @@ -1,6 +1,22 @@ Changelog --------- +1.5.30 (2026-04-27) +~~~~~~~~~~~~~~~~~~~ + +Added +^^^^^ + +* Added Newton rough terrain support for the G1 biped locomotion velocity + env. The only engine-specific change is a ~1.7x ``max_iterations`` preset on + :class:`~isaaclab_tasks.manager_based.locomotion.velocity.config.g1.agents.rsl_rl_ppo_cfg.G1RoughPPORunnerCfg` + (Newton = 5000, PhysX = 3000). PhysX saturates near iter 3000 on both + reward (≈ +18) and episode length (≈ 980) and does not meaningfully + improve further; Newton reaches the same (reward, ep_len) quality at + iter 5000. The iteration budget is bumped rather than tuning physics + or reward terms. + + 1.5.29 (2026-04-27) ~~~~~~~~~~~~~~~~~~~ diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/agents/rsl_rl_ppo_cfg.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/agents/rsl_rl_ppo_cfg.py index 61a6d0261b9f..7b61c184d353 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/agents/rsl_rl_ppo_cfg.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/locomotion/velocity/config/g1/agents/rsl_rl_ppo_cfg.py @@ -7,11 +7,19 @@ from isaaclab_rl.rsl_rl import RslRlOnPolicyRunnerCfg, RslRlPpoActorCriticCfg, RslRlPpoAlgorithmCfg +from isaaclab_tasks.utils import preset + @configclass class G1RoughPPORunnerCfg(RslRlOnPolicyRunnerCfg): num_steps_per_env = 24 - max_iterations = 3000 + # Newton needs ~1.7x the PPO iterations to match PhysX on G1. PhysX saturates near iter 3000 + # (reward ≈ +18, ep_len ≈ 980) and does not meaningfully improve on either metric past that — + # reward oscillates +16 to +19 through iter 7500, ep_len stays flat. Newton reaches the same + # (reward, ep_len) quality at iter 5000 (+16 / 984). Comparing reward alone is misleading: + # ep_len confirms the robot is stable in both cases. The gap is sample-efficiency, not a + # ceiling — no physics or reward tuning closes it. + max_iterations = preset(default=3000, newton=5000) save_interval = 50 experiment_name = "g1_rough" policy = RslRlPpoActorCriticCfg(