Fixes navigation env config for PresetCfg compatibility#5396
Fixes navigation env config for PresetCfg compatibility#5396kellyguo11 wants to merge 3 commits intoisaac-sim:developfrom
Conversation
The navigation environment configuration was broken after the Newton preset system was introduced (isaac-sim#4794, isaac-sim#5014). The LOW_LEVEL_ENV_CFG contained unresolved PresetCfg wrappers (e.g. VelocityEnvContactSensorCfg for contact_forces, preset() for actuator armature) which caused two issues: 1. update_period set on PresetCfg wrappers in __post_init__ was silently lost when resolve_presets() replaced the wrapper with the actual config during env creation via parse_env_cfg / gym.make. 2. sim.physics_material was not propagated from the terrain, resulting in default friction values instead of the terrain's configured values. Fix: - Call resolve_presets() on LOW_LEVEL_ENV_CFG at module import time so all PresetCfg wrappers (contact sensor, actuator armature, etc.) are resolved before they are referenced by NavigationEnvCfg defaults. - Call resolve_presets(self.scene) in __post_init__ so that any remaining PresetCfg nodes in the deep-copied scene are resolved before update_period is assigned. - Propagate sim.physics_material from the terrain, matching the pattern used by LocomotionVelocityRoughEnvCfg.
There was a problem hiding this comment.
🤖 Isaac Lab Review Bot
Summary
This PR fixes a configuration bug in the navigation environment where PresetCfg wrappers were not being resolved before their attributes were modified, causing update_period and physics_material settings to be silently lost. The fix correctly calls resolve_presets() at module import time for the shared LOW_LEVEL_ENV_CFG and again in __post_init__ for the instance's deep-copied scene.
Architecture Impact
The change is well-scoped to the navigation environment configuration. The pattern of calling resolve_presets() at module level for shared config objects and again in __post_init__ for instance-specific copies aligns with how the preset system is designed to work. The LOW_LEVEL_ENV_CFG is referenced by ActionsCfg at class definition time (lines 51-56), so resolving it at import time is correct. Other environments using similar patterns may need analogous fixes.
Implementation Verdict
Minor fixes needed — The core fix is correct, but there's a potential issue with the physics material assignment order.
Test Coverage
The PR description claims tests were added ("I have added tests that prove my fix is effective"), but no test files are included in this PR. For a bug fix of this nature, a regression test verifying that:
contact_forces.update_periodequalssim.dt(0.005, not 0.0)sim.physics_materialmatches the terrain's physics material
would be appropriate. Without tests, this bug could regress silently.
CI Status
No CI checks available yet — cannot assess whether the fix passes existing tests.
Findings
🟡 Warning: navigation_env_cfg.py:141 — Physics material assignment occurs before resolve_presets(self.scene)
self.sim.physics_material = self.scene.terrain.physics_material # line 141
...
resolve_presets(self.scene) # line 146If self.scene.terrain itself contains a PresetCfg wrapper, physics_material might be read from an unresolved wrapper. The safer order would be to call resolve_presets(self.scene) first, then assign self.sim.physics_material. Looking at the code flow: self.scene is assigned from LOW_LEVEL_ENV_CFG.scene (line 123), and LOW_LEVEL_ENV_CFG is already resolved at import time (line 21). However, when NavigationEnvCfg is instantiated, self.scene may be a deep copy with fresh PresetCfg wrappers depending on how @configclass handles copying. Recommend moving resolve_presets(self.scene) before the physics_material assignment for safety.
🔵 Improvement: navigation_env_cfg.py:143-146 — Comment placement could be clearer
The comment block (lines 143-146) explains why resolve_presets is called, but it's placed between unrelated assignments (decimation, episode_length_s) and the actual resolve_presets call. Consider moving the comment directly above the call, or restructuring so resolve_presets(self.scene) comes immediately after scene-related setup.
🔴 Critical: Missing regression tests
The PR claims tests were added but none are present in the changeset. Given the subtle nature of this bug (silent data loss), a test that instantiates NavigationEnvCfg and asserts:
cfg.scene.contact_forces.update_period == cfg.sim.dtcfg.sim.physics_material.static_friction == 1.0(or whatever the terrain's configured value is)
would prevent regression. This should be added before merge.
🔵 Improvement: navigation_env_cfg.py:21 — Consider documenting the resolve_presets call
The module-level resolve_presets(LOW_LEVEL_ENV_CFG) is a side effect at import time. A brief comment explaining why this is necessary would help future maintainers understand that this isn't incidental but required for correctness when LOW_LEVEL_ENV_CFG attributes are referenced in class defaults.
Greptile SummaryThis PR fixes two bugs introduced by the Newton preset system:
Confidence Score: 4/5Safe to merge for the current codebase; the physics_material ordering is a future-proofing concern, not a current defect. All remaining findings are P2: the physics_material ordering issue is latent (physics_material is a concrete RigidBodyMaterialCfg today, not a PresetCfg), so no current breakage. The core fixes are correct and match the established pattern. navigation_env_cfg.py — the ordering of physics_material assignment relative to resolve_presets(self.scene) Important Files Changed
Sequence DiagramsequenceDiagram
participant Module as Module Import
participant LLCFG as LOW_LEVEL_ENV_CFG
participant NavCfg as NavigationEnvCfg
participant Scene as self.scene
participant Sim as self.sim
Module->>LLCFG: AnymalCFlatEnvCfg()
Module->>LLCFG: resolve_presets(LOW_LEVEL_ENV_CFG)
Note over LLCFG: All PresetCfg wrappers resolved
Module->>NavCfg: class definition uses LOW_LEVEL_ENV_CFG.scene
NavCfg->>NavCfg: __post_init__()
NavCfg->>Sim: sim.physics_material = scene.terrain.physics_material
Note over Sim: Assigned BEFORE resolve_presets(scene)
NavCfg->>Scene: resolve_presets(self.scene)
Note over Scene: Remaining PresetCfg nodes resolved
NavCfg->>Scene: contact_forces.update_period = sim.dt
Reviews (1): Last reviewed commit: "Fixes navigation env config for PresetCf..." | Re-trigger Greptile |
| self.sim.dt = LOW_LEVEL_ENV_CFG.sim.dt | ||
| self.sim.render_interval = LOW_LEVEL_ENV_CFG.decimation | ||
| self.sim.physics_material = self.scene.terrain.physics_material | ||
| self.decimation = LOW_LEVEL_ENV_CFG.decimation * 10 | ||
| self.episode_length_s = self.commands.pose_command.resampling_time_range[1] | ||
|
|
||
| # Resolve any PresetCfg wrappers in the scene so that update_period | ||
| # is set on the actual sensor config rather than the wrapper (which | ||
| # would be discarded by a later resolve_presets call). | ||
| resolve_presets(self.scene) |
There was a problem hiding this comment.
physics_material assigned before presets are resolved
self.sim.physics_material is assigned from self.scene.terrain.physics_material on line 142, before resolve_presets(self.scene) is called on line 149. If terrain.physics_material is ever wrapped in a PresetCfg (possible as the preset system expands), the copied value in self.sim.physics_material will be an unresolved wrapper and won't be patched by the subsequent resolve_presets(self.scene) call (which only walks self.scene, not self.sim). Swapping the order to resolve first, then assign, is safer and more consistent with the stated intent of this fix.
| self.sim.dt = LOW_LEVEL_ENV_CFG.sim.dt | |
| self.sim.render_interval = LOW_LEVEL_ENV_CFG.decimation | |
| self.sim.physics_material = self.scene.terrain.physics_material | |
| self.decimation = LOW_LEVEL_ENV_CFG.decimation * 10 | |
| self.episode_length_s = self.commands.pose_command.resampling_time_range[1] | |
| # Resolve any PresetCfg wrappers in the scene so that update_period | |
| # is set on the actual sensor config rather than the wrapper (which | |
| # would be discarded by a later resolve_presets call). | |
| resolve_presets(self.scene) | |
| self.sim.dt = LOW_LEVEL_ENV_CFG.sim.dt | |
| self.sim.render_interval = LOW_LEVEL_ENV_CFG.decimation | |
| self.decimation = LOW_LEVEL_ENV_CFG.decimation * 10 | |
| self.episode_length_s = self.commands.pose_command.resampling_time_range[1] | |
| # Resolve any PresetCfg wrappers in the scene so that update_period | |
| # is set on the actual sensor config rather than the wrapper (which | |
| # would be discarded by a later resolve_presets call). | |
| resolve_presets(self.scene) | |
| self.sim.physics_material = self.scene.terrain.physics_material |
…ime side effect - Move resolve_presets(self.scene) before physics_material assignment so that if terrain ever becomes a PresetCfg, it is resolved first. - Add regression tests verifying update_period, physics_material, and full preset resolution for both NavigationEnvCfg and _PLAY variant. - Add comment on module-level resolve_presets(LOW_LEVEL_ENV_CFG) call explaining why the import-time side effect is required.
Removes unused pytest import and fixes import ordering in test file.
Description
The navigation environment configuration was broken after the Newton preset system was introduced (#4794, #5014). The
LOW_LEVEL_ENV_CFGcontained unresolvedPresetCfgwrappers (e.g.VelocityEnvContactSensorCfgfor contact forces,preset()for actuator armature) which caused two issues:update_periodsilently lost: Settingupdate_periodon aPresetCfgwrapper in__post_init__worked (as a dynamic attribute), but was discarded whenresolve_presets()later replaced the wrapper with the actualContactSensorCfg. The resolved config retained the defaultupdate_period=0.0instead of the intended0.005.sim.physics_materialnot propagated: The navigation env's__post_init__did not copy the terrain's physics material tosim.physics_material, resulting in default friction values (0.5/0.5/average) instead of the terrain's configured values (1.0/1.0/multiply).Fix
resolve_presets()onLOW_LEVEL_ENV_CFGat module import time so allPresetCfgwrappers (contact sensor, actuator armature, etc.) are resolved before they are referenced byNavigationEnvCfgdefaults.resolve_presets(self.scene)in__post_init__so that any remainingPresetCfgnodes in the deep-copied scene are resolved beforeupdate_periodis assigned.sim.physics_materialfrom the terrain, matching the pattern used byLocomotionVelocityRoughEnvCfg.Type of change
Checklist
./isaaclab.sh --formatconfig/extension.tomlfile