Skip to content

fix(terrain): eval-mode env origins for OBJ terrains - #185

Open
tkevinbest wants to merge 1 commit into
mainfrom
dev/tkbest/eval-obj-terrain-origins
Open

fix(terrain): eval-mode env origins for OBJ terrains#185
tkevinbest wants to merge 1 commit into
mainfrom
dev/tkbest/eval-obj-terrain-origins

Conversation

@tkevinbest

@tkevinbest tkevinbest commented Aug 10, 2026

Copy link
Copy Markdown

Fixes an AttributeError crash at env init when evaluating a policy on an OBJ (load_obj) terrain — e.g. a stairs-climbing policy on a fitted-box mesh.

Terrain spawn origins are computed one of two ways depending on terrain type: procedural terrains store them in Terrain._env_origins, while OBJ terrains never populate that attribute and instead derive per-tile origins from the loaded mesh via _get_load_obj_env_origin_grid(). Separately, TerrainLocomotion._get_env_origins() has two modes: the training branch (randomize_tiles=True) scatters robots across tiles, and the eval branch (randomize_tiles=False) places every robot at tile (0, 0) for deterministic evaluation.

The training branch already fetched origins the right way through sample_env_origins(), which special-cases OBJ terrains. The eval branch predates OBJ-terrain support and reached for self.terrain._env_origins[0, 0] directly — an attribute that doesn't exist for OBJ terrains — so any OBJ-terrain eval crashed on the first _get_env_origins() call.

The fix introduces one accessor and routes both modes through it:

  • Adds a Terrain.env_origin_grid property (simulator/shared/terrain.py) that returns the [num_rows, num_cols, 3] per-tile origin grid for either terrain type — _get_load_obj_env_origin_grid() for OBJ, _env_origins for procedural.
  • Points both sample_env_origins() and the eval branch in locomotion.py at the property, so eval handles OBJ terrains exactly the way training already does.

Notes for reviewers:

  • No behavior change for procedural terrains. The property returns the same _env_origins array the old code used, so existing (non-OBJ) training and eval runs are unaffected.
  • Shapes line up at both call sites. Both terrain types yield a [num_rows, num_cols, 3] grid, so the eval branch's [0, 0] (→ one 3-vector) and sample_env_origins()'s fancy index (→ [num_robots, 3]) both work. The procedural grid is float64 and the OBJ grid float32, but both call sites wrap the result in torch.from_numpy(...).to(torch.float), so the dtype difference is normalized away.
  • No other call site reads the grid directly. The only external readers were the eval branch (now fixed) and sample_env_origins() (now routed); other _env_origins references are unrelated per-env tensors on different objects.

Verified end-to-end: an OBJ-terrain eval now boots, loads the fitted-box mesh, and records a rollout instead of crashing at init.

TerrainLocomotion._get_env_origins()'s eval branch (randomize_tiles=False) read
self.terrain._env_origins directly, but OBJ (load_obj) terrains never populate that
attribute — their per-tile origins come from _get_load_obj_env_origin_grid(). The
training branch already handled this via sample_env_origins(), but the eval branch
predates OBJ support and was never updated, so evaluating any OBJ-terrain policy
(e.g. a stairs-climbing WBT policy) crashed with AttributeError at env init.

Add a Terrain.env_origin_grid property that returns the right grid for both terrain
types, route sample_env_origins() and the eval branch through it. Verified end-to-end:
a g1 stairs WBT eval now boots, loads the fitted-box mesh, and records a rollout.
@tkevinbest
tkevinbest force-pushed the dev/tkbest/eval-obj-terrain-origins branch from 28ef8f0 to 0d05fa1 Compare August 10, 2026 20:54
@tkevinbest
tkevinbest marked this pull request as ready for review August 10, 2026 21:03
@tkevinbest
tkevinbest requested a review from Juyue August 10, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant