AmanC007 commited on
Commit
822fa6d
·
verified ·
1 Parent(s): 834ff34

Upload folder using huggingface_hub

Browse files
code/snow_rl/snow_env.py CHANGED
@@ -26,6 +26,7 @@ from typing import Any
26
 
27
  import jax
28
  import jax.numpy as jnp
 
29
  from ml_collections import config_dict
30
  from mujoco import mjx
31
  from mujoco_playground._src import mjx_env
@@ -60,6 +61,16 @@ SNOW_CONTACT_FORCE_N = 20.0
60
  # grip or sink through -- while printing "nefc overflow" and continuing to train.
61
  # Playground's stock value is 90. 128 is the next valid size above the observed 93-94 peak.
62
  NJMAX = 128
 
 
 
 
 
 
 
 
 
 
63
  # Uncertainty the belief map attaches to one contact observation. The estimator's own
64
  # ensemble spread is only weakly informative (corr with true error +0.35), so a fixed
65
  # conservative value is more honest than pretending the spread is calibrated.
@@ -85,6 +96,11 @@ def default_config() -> config_dict.ConfigDict:
85
  cfg.reward_config.scales.snow_stumble = -1.0
86
  cfg.reward_config.scales.snow_flat_efficiency = -0.5
87
  cfg.reward_config.scales.snow_overload = -0.4
 
 
 
 
 
88
  cfg.snow = config_dict.create(
89
  enable_forces=True,
90
  # Zeroing this blanks the estimator block in the observation while leaving snow
@@ -98,6 +114,10 @@ def default_config() -> config_dict.ConfigDict:
98
  false_safe_rate=-1.0, # <0 means "use the calibrated point-estimate rate"
99
  terrain_bank_size=TERRAIN_BANK_SIZE,
100
  terrain_seed=0,
 
 
 
 
101
  # Curriculum: 1.0 is full difficulty (0-25 cm). Lower values shrink every regime's
102
  # depth range so an early stage trains on snow the policy can actually cope with.
103
  depth_scale=1.0,
@@ -124,6 +144,14 @@ class SnowJoystick(joystick.Joystick):
124
 
125
  def _post_init(self) -> None:
126
  super()._post_init()
 
 
 
 
 
 
 
 
127
  self._terrain_cfg = TERRAIN_CFG
128
  rate = self._config.snow.false_safe_rate
129
  self._est_params = estimator.load_params(
 
26
 
27
  import jax
28
  import jax.numpy as jnp
29
+ import numpy as np
30
  from ml_collections import config_dict
31
  from mujoco import mjx
32
  from mujoco_playground._src import mjx_env
 
61
  # grip or sink through -- while printing "nefc overflow" and continuing to train.
62
  # Playground's stock value is 90. 128 is the next valid size above the observed 93-94 peak.
63
  NJMAX = 128
64
+ # Slope. Everything before this was level-ground walking, which is a real gap for a
65
+ # mountaineering project: on the flat, losing a foothold means falling over; on a slope it
66
+ # means sliding. The source project's terrain generator had a slope term (+/-0.25) that was
67
+ # dropped when the field was ported to JAX, because our snow is a force field over a flat
68
+ # MuJoCo plane rather than geometry.
69
+ #
70
+ # Rather than tilt the ground mesh, tilt GRAVITY. A uniform slope is exactly equivalent to
71
+ # rotating the gravity vector, it costs nothing in the physics, and it keeps the snow force
72
+ # field (which is defined against a flat substrate) valid without reworking terrain.py.
73
+ SLOPE_RAD = 0.0
74
  # Uncertainty the belief map attaches to one contact observation. The estimator's own
75
  # ensemble spread is only weakly informative (corr with true error +0.35), so a fixed
76
  # conservative value is more honest than pretending the spread is calibrated.
 
96
  cfg.reward_config.scales.snow_stumble = -1.0
97
  cfg.reward_config.scales.snow_flat_efficiency = -0.5
98
  cfg.reward_config.scales.snow_overload = -0.4
99
+ # Playground's stock njmax is 90 constraint rows; a dynamic G1 gait needs 93-94 and
100
+ # MuJoCo SILENTLY DROPS contacts past the limit. This line has been deleted twice by
101
+ # index-based edits to the reward block above -- if you rewrite those weights, check it
102
+ # survived. `make_snow_env()._config.njmax` should read 128, not 90.
103
+ cfg.njmax = NJMAX
104
  cfg.snow = config_dict.create(
105
  enable_forces=True,
106
  # Zeroing this blanks the estimator block in the observation while leaving snow
 
114
  false_safe_rate=-1.0, # <0 means "use the calibrated point-estimate rate"
115
  terrain_bank_size=TERRAIN_BANK_SIZE,
116
  terrain_seed=0,
117
+ # Uphill slope in radians. 0.20 rad ~ 11.5 deg, a realistic snow slope; avalanche
118
+ # terrain starts around 0.5 rad (30 deg). Applied by rotating gravity, so positive
119
+ # values mean the robot walks uphill along +x.
120
+ slope_rad=SLOPE_RAD,
121
  # Curriculum: 1.0 is full difficulty (0-25 cm). Lower values shrink every regime's
122
  # depth range so an early stage trains on snow the policy can actually cope with.
123
  depth_scale=1.0,
 
144
 
145
  def _post_init(self) -> None:
146
  super()._post_init()
147
+ slope = float(self._config.snow.slope_rad)
148
+ if slope != 0.0:
149
+ # Rotate gravity about +y: the robot walking along +x is then walking uphill.
150
+ g = float(np.linalg.norm(self._mj_model.opt.gravity))
151
+ tilted = np.array([g * np.sin(slope), 0.0, -g * np.cos(slope)])
152
+ self._mj_model.opt.gravity[:] = tilted
153
+ self._mjx_model = self._mjx_model.replace(opt=self._mjx_model.opt.replace(
154
+ gravity=jnp.asarray(tilted)))
155
  self._terrain_cfg = TERRAIN_CFG
156
  rate = self._config.snow.false_safe_rate
157
  self._est_params = estimator.load_params(
code/snow_rl/terrain.py CHANGED
@@ -156,7 +156,8 @@ def generate(key: jax.Array, cfg: TerrainConfig = DEFAULT_CONFIG,
156
  return SnowField(depth, bearing, stiffness, damping, void, regime)
157
 
158
 
159
- def crossing_strip(cfg: TerrainConfig = DEFAULT_CONFIG) -> SnowField:
 
160
  """Deterministic flat -> shallow -> deep corridor for Step 6 evaluation.
161
 
162
  Fixed and seedless so every eval run crosses identical ground.
@@ -180,9 +181,14 @@ def crossing_strip(cfg: TerrainConfig = DEFAULT_CONFIG) -> SnowField:
180
  # the corridor and a discontinuous jump in the sinkage force.
181
  shallow = smoothstep(0.28, 0.38, x)
182
  deep = smoothstep(0.61, 0.71, x)
183
- depth = 0.005 + (0.070 - 0.005) * shallow + (0.190 - 0.070) * deep
 
 
 
 
 
184
  stiffness = jnp.broadcast_to(
185
- 28_000.0 + (12_000.0 - 28_000.0) * shallow + (3_000.0 - 12_000.0) * deep,
186
  (cfg.n_rows, cfg.n_cols),
187
  )
188
  depth = jnp.broadcast_to(depth, (cfg.n_rows, cfg.n_cols))
 
156
  return SnowField(depth, bearing, stiffness, damping, void, regime)
157
 
158
 
159
+ def crossing_strip(cfg: TerrainConfig = DEFAULT_CONFIG,
160
+ max_depth_m: float = 0.190) -> SnowField:
161
  """Deterministic flat -> shallow -> deep corridor for Step 6 evaluation.
162
 
163
  Fixed and seedless so every eval run crosses identical ground.
 
181
  # the corridor and a discontinuous jump in the sinkage force.
182
  shallow = smoothstep(0.28, 0.38, x)
183
  deep = smoothstep(0.61, 0.71, x)
184
+ mid = 0.005 + (max_depth_m - 0.005) * 0.37
185
+ depth = 0.005 + (mid - 0.005) * shallow + (max_depth_m - mid) * deep
186
+ # stiffness falls with depth, as in the generated terrain
187
+ frac = jnp.clip(max_depth_m / 0.190, 0.0, 1.0)
188
+ deep_k = 28_000.0 + (3_000.0 - 28_000.0) * frac
189
+ mid_k = 28_000.0 + (12_000.0 - 28_000.0) * frac
190
  stiffness = jnp.broadcast_to(
191
+ 28_000.0 + (mid_k - 28_000.0) * shallow + (deep_k - mid_k) * deep,
192
  (cfg.n_rows, cfg.n_cols),
193
  )
194
  depth = jnp.broadcast_to(depth, (cfg.n_rows, cfg.n_cols))