Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Added
^^^^^

* Added :func:`~isaaclab.envs.mdp.body_lin_vel_out_of_manual_limit` to terminate environments when an
articulation body exceeds a configured linear speed.
2 changes: 2 additions & 0 deletions source/isaaclab/isaaclab/envs/mdp/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ __all__ = [
"joint_pos_out_of_limit",
"joint_pos_out_of_manual_limit",
"joint_vel_out_of_limit",
"body_lin_vel_out_of_manual_limit",
"joint_vel_out_of_manual_limit",
"pose_command_success",
"root_height_below_minimum",
Expand Down Expand Up @@ -295,6 +296,7 @@ from .terminations import (
joint_pos_out_of_limit,
joint_pos_out_of_manual_limit,
joint_vel_out_of_limit,
body_lin_vel_out_of_manual_limit,
joint_vel_out_of_manual_limit,
pose_command_success,
root_height_below_minimum,
Expand Down
11 changes: 11 additions & 0 deletions source/isaaclab/isaaclab/envs/mdp/terminations.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,14 @@ def illegal_contact(env: ManagerBasedRLEnv, threshold: float, sensor_cfg: SceneE
return torch.any(
torch.max(torch.linalg.norm(net_contact_forces[:, :, sensor_cfg.body_ids], dim=-1), dim=1)[0] > threshold, dim=1
)


def body_lin_vel_out_of_manual_limit(

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.

🟡 Warning · Implementation — Missing changelog fragments for touched packages

Repository rules require one fragment per touched package under source/<pkg>/changelog.d/. This PR touches isaaclab (new exported body_lin_vel_out_of_manual_limit) and isaaclab_tasks (physics preset retune, new body_speed termination, AnymalD init pose) but adds none, so these user-visible changes will be omitted from the compiled changelog. Add an Added fragment for the termination and a Changed fragment for the locomotion config updates.

env: ManagerBasedRLEnv, max_speed: float, asset_cfg: SceneEntityCfg = SceneEntityCfg("robot")
) -> torch.Tensor:
"""Terminate when any of the asset's bodies moves faster than the provided limit."""

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.

🔵 Suggestion · Api — Docstring lacks Args and SI unit

Public API docstrings must be Google-style with an Args: section and inline SI units for physical quantities. This newly exported termination documents neither max_speed ([m/s]) nor asset_cfg, so callers cannot tell how the threshold is interpreted. Add an Args: block using name: description form and annotate the speed unit.

# extract the used quantities (to enable type-hinting)
asset: Articulation = env.scene[asset_cfg.name]
# compute any violations
speed = torch.linalg.norm(asset.data.body_lin_vel_w.torch[:, asset_cfg.body_ids], dim=-1)
return torch.any(speed > max_speed, dim=1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Fixed
^^^^^

* Fixed Newton MJWarp locomotion training instability by tuning contact capacity and parameters, adjusting the
ANYmal-D initial height, and terminating excessively fast bodies.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class AnymalDRoughEnvCfg(LocomotionVelocityRoughEnvCfg):
def __post_init__(self):
super().__post_init__()

# sim
# lower margin to avoid self-collision
self.sim.physics.newton_mjwarp.default_shape_cfg.margin = 0.001
# scene
self.scene.robot = ANYMAL_D_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
self.scene.robot = ANYMAL_D_CFG.replace(
prim_path="{ENV_REGEX_NS}/Robot", init_state=ANYMAL_D_CFG.init_state.replace(pos=(0.0, 0.0, 0.65))
)
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class CassieRoughEnvCfg(LocomotionVelocityRoughEnvCfg):

def __post_init__(self):
super().__post_init__()

self.sim.physics.newton_mjwarp.num_substeps = 2
# scene
self.scene.robot = CASSIE_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
self.scene.robot.actuators["legs"].armature = preset(default=0.0, newton_mjwarp=0.02)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class G1RoughEnvCfg(LocomotionVelocityRoughEnvCfg):

def __post_init__(self):
super().__post_init__()

self.sim.physics.newton_mjwarp.num_substeps = 2
# scene
self.scene.robot = G1_MINIMAL_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot")
self.scene.height_scanner.prim_path = "{ENV_REGEX_NS}/Robot/torso_link"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class RoughPhysicsCfg(PresetCfg):
physx = PhysxAutoCfg(isaacsim_physx=isaacsim_physx, ovphysx=ovphysx)
newton_mjwarp = NewtonCfg(
solver_cfg=MJWarpSolverCfg(
njmax=200,
nconmax=100,
njmax=1000,
nconmax=300,
cone="pyramidal",
impratio=1.0,
integrator="implicitfast",
Expand All @@ -62,10 +62,7 @@ class RoughPhysicsCfg(PresetCfg):
collision_cfg=NewtonCollisionPipelineCfg(max_triangle_pairs=2_500_000),
num_substeps=1,
debug_mode=False,
# 1 cm shape margin is the single most important Newton setting for rough
# terrain — without it, non-AnymalD robots fail to learn stable contact
# on triangle-mesh terrain. See isaaclab_newton 0.5.22 changelog.
default_shape_cfg=NewtonShapeCfg(margin=0.01),
default_shape_cfg=NewtonShapeCfg(margin=0.0, ke=160000.0, kd=1100.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.

P1 Zero margin breaks terrain contact

When inherited rough-terrain tasks run with the newton_mjwarp preset, this shared zero margin removes the nonzero margin required for stable triangle-mesh contact, causing affected robots to lose contact stability and fail to learn rough-terrain locomotion. It also combines with the removed AnymalD override to discard that robot's separately tuned margin.

Knowledge Base Used: isaaclab_tasks: Task Registration and Organization

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.

🟡 Warning · Design Architecture — Shared preset drops margin other robots rely on

RoughPhysicsCfg is inherited by every rough-terrain velocity task, not only AnymalD. The comment deleted from these exact lines stated the 1 cm margin was required for non-AnymalD robots to learn stable contact on triangle-mesh terrain, and the AnymalD-specific override was removed in the same change. Setting margin=0.0 (plus new ke/kd) in the shared preset therefore regresses the other inheriting configs. Keep the shared default and scope the retune to the AnymalD config.

)
default = isaacsim_physx

Expand Down Expand Up @@ -321,6 +318,7 @@ class TerminationsCfg:
func=mdp.illegal_contact,
params={"sensor_cfg": SceneEntityCfg("contact_forces", body_names="base"), "threshold": 1.0},
)
body_speed = DoneTerm(func=mdp.body_lin_vel_out_of_manual_limit, params={"max_speed": 20.0})


@configclass
Expand Down Expand Up @@ -362,6 +360,8 @@ def __post_init__(self):
self.sim.dt = 0.005
self.sim.render_interval = self.decimation
self.sim.physics_material = self.scene.terrain.physics_material
newton = self.sim.physics.newton_mjwarp
newton.collision_cfg.rigid_contact_max = newton.solver_cfg.nconmax * self.scene.num_envs

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 Contact capacity becomes stale

rigid_contact_max is calculated from the construction-time environment count, but play mode and CLI/Hydra overrides change scene.num_envs afterward without recalculating it. This leaves play mode with a substantially oversized contact allocation and larger runs with a contact budget that no longer matches the requested number of environments.

Knowledge Base Used: isaaclab_tasks: Task Registration and Organization

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.

🟡 Warning · Implementation — Contact buffer sized from default num_envs

rigid_contact_max is computed in __post_init__, which runs at config construction while scene.num_envs is still the class default (4096). CLI/Hydra --num_envs overrides are applied to the instantiated config afterwards and do not re-run __post_init__, so the buffer stays at 300*4096 regardless: heavily over-allocated for small runs and undersized above 4096 envs. Derive this where num_envs is final.

# update sensor update periods
# we tick all the sensors based on the smallest update period (physics update period)
if self.scene.height_scanner is not None:
Expand Down
Loading