fix(robocasa): restrict obj_registries to lightwheel by default

CloseFridge (and most kitchen tasks) crashed at reset with
`ValueError: Probabilities contain NaN` coming out of
`sample_kitchen_object_helper`. RoboCasa's upstream default
`obj_registries=("objaverse", "lightwheel")` normalizes per-registry
candidate counts as probabilities; when a sampled category has zero
mjcf paths in every configured registry (because the objaverse asset
pack isn't on disk — ~30GB, skipped by our Docker build), the 0/0
divide yields NaNs and `rng.choice` raises.

- Add `obj_registries: list[str] = ["lightwheel"]` to `RoboCasaEnv`
  config; thread it through `create_robocasa_envs`, `_make_env_fns`,
  and the gym.Env wrapper to the underlying `RoboCasaGymEnv` (which
  forwards to `create_env` → `robosuite.make` → kitchen env).
- Default matches what `download_kitchen_assets --type objs_lw`
  actually ships, so the env works out of the box without a 30GB
  objaverse download.
- Document the override (`--env.obj_registries='[objaverse,lightwheel]'`)
  for users who have downloaded the full asset set.

Made-with: Cursor
This commit is contained in:
Pepijn
2026-04-17 12:06:30 +01:00
parent 90819482f5
commit 81ee2952a3
3 changed files with 39 additions and 2 deletions
+13 -1
View File
@@ -32,7 +32,13 @@ After following the LeRobot installation instructions:
```bash ```bash
pip install -e ".[robocasa]" pip install -e ".[robocasa]"
python -m robocasa.scripts.setup_macros python -m robocasa.scripts.setup_macros
python -m robocasa.scripts.download_kitchen_assets # Lightweight assets only (lightwheel registry, ~2GB). Enough for the
# default env out of the box.
python -m robocasa.scripts.download_kitchen_assets --type tex fixtures_lw objs_lw
# Optional: full objaverse/aigen registries (~30GB) for richer object
# variety. If you download these, pass them via `--env.obj_registries`
# at eval/train time (see below).
# python -m robocasa.scripts.download_kitchen_assets --type objaverse
``` ```
<Tip> <Tip>
@@ -44,6 +50,12 @@ export MUJOCO_GL=egl # for headless servers (HPC, cloud)
</Tip> </Tip>
By default the env samples objects only from the `lightwheel` registry (the one shipped by `--type objs_lw`), which avoids a `Probabilities contain NaN` crash when the objaverse/aigen packs are absent. If you've downloaded the full asset set, enable it with:
```bash
--env.obj_registries='[objaverse,lightwheel]'
```
## Policy inputs and outputs ## Policy inputs and outputs
**Observations** (raw RoboCasa camera names are preserved verbatim): **Observations** (raw RoboCasa camera names are preserved verbatim):
+7
View File
@@ -508,6 +508,12 @@ class RoboCasaEnv(EnvConfig):
observation_height: int = 256 observation_height: int = 256
observation_width: int = 256 observation_width: int = 256
split: str | None = None split: str | None = None
# Object-mesh registries to sample from. Upstream default is
# ("objaverse", "lightwheel"), but objaverse is ~30GB and the CI image
# only ships the lightwheel pack. Override to include objaverse once
# you've run `python -m robocasa.scripts.download_kitchen_assets
# --type objaverse` locally.
obj_registries: list[str] = field(default_factory=lambda: ["lightwheel"])
features: dict[str, PolicyFeature] = field( features: dict[str, PolicyFeature] = field(
default_factory=lambda: {ACTION: PolicyFeature(type=FeatureType.ACTION, shape=(12,))} default_factory=lambda: {ACTION: PolicyFeature(type=FeatureType.ACTION, shape=(12,))}
) )
@@ -557,6 +563,7 @@ class RoboCasaEnv(EnvConfig):
gym_kwargs=self.gym_kwargs, gym_kwargs=self.gym_kwargs,
env_cls=env_cls, env_cls=env_cls,
episode_length=self.episode_length, episode_length=self.episode_length,
obj_registries=tuple(self.obj_registries),
) )
+19 -1
View File
@@ -44,6 +44,16 @@ DEFAULT_CAMERAS = [
"robot0_agentview_right", "robot0_agentview_right",
] ]
# Object-mesh registries to sample from. RoboCasa's upstream default is
# ("objaverse", "lightwheel"), but the objaverse pack is huge (~30GB) and
# most users — including our CI image — only download the lightwheel pack
# (`--type objs_lw` in `download_kitchen_assets`). When a sampled object
# category has zero candidates in every registry, robocasa crashes with
# `ValueError: Probabilities contain NaN` (0/0 divide in the probability
# normalization). Restricting to registries that are actually on disk
# avoids the NaN and matches what the asset download provides.
DEFAULT_OBJ_REGISTRIES: tuple[str, ...] = ("lightwheel",)
# Task-group shortcuts accepted as `--env.task`. When the user passes one of # Task-group shortcuts accepted as `--env.task`. When the user passes one of
# these names, we expand it to the upstream RoboCasa task list and auto-set # these names, we expand it to the upstream RoboCasa task list and auto-set
# the dataset split. Individual task names (optionally comma-separated) still # the dataset split. Individual task names (optionally comma-separated) still
@@ -132,6 +142,7 @@ class RoboCasaEnv(gym.Env):
observation_height: int = 256, observation_height: int = 256,
split: str | None = None, split: str | None = None,
episode_length: int | None = None, episode_length: int | None = None,
obj_registries: Sequence[str] = DEFAULT_OBJ_REGISTRIES,
): ):
super().__init__() super().__init__()
self.task = task self.task = task
@@ -140,6 +151,7 @@ class RoboCasaEnv(gym.Env):
self.observation_width = observation_width self.observation_width = observation_width
self.observation_height = observation_height self.observation_height = observation_height
self.split = split self.split = split
self.obj_registries = tuple(obj_registries)
self.camera_name = _parse_camera_names(camera_name) self.camera_name = _parse_camera_names(camera_name)
@@ -197,12 +209,14 @@ class RoboCasaEnv(gym.Env):
# RoboCasaGymEnv defaults split="test", which create_env rejects # RoboCasaGymEnv defaults split="test", which create_env rejects
# (only None/"all"/"pretrain"/"target" are valid). Always pass a # (only None/"all"/"pretrain"/"target" are valid). Always pass a
# valid value so we don't hit that default. # valid value so we don't hit that default. Extra kwargs are
# forwarded to the underlying kitchen env via create_env/robosuite.make.
self._env = RoboCasaGymEnv( self._env = RoboCasaGymEnv(
env_name=self.task, env_name=self.task,
camera_widths=self.observation_width, camera_widths=self.observation_width,
camera_heights=self.observation_height, camera_heights=self.observation_height,
split=self.split if self.split is not None else "all", split=self.split if self.split is not None else "all",
obj_registries=self.obj_registries,
) )
ep_meta = self._env.env.get_ep_meta() ep_meta = self._env.env.get_ep_meta()
@@ -286,6 +300,7 @@ def _make_env_fns(
observation_height: int, observation_height: int,
split: str | None, split: str | None,
episode_length: int | None, episode_length: int | None,
obj_registries: Sequence[str],
) -> list[Callable[[], RoboCasaEnv]]: ) -> list[Callable[[], RoboCasaEnv]]:
"""Build n_envs factory callables for a single task.""" """Build n_envs factory callables for a single task."""
@@ -299,6 +314,7 @@ def _make_env_fns(
observation_height=observation_height, observation_height=observation_height,
split=split, split=split,
episode_length=episode_length, episode_length=episode_length,
obj_registries=obj_registries,
**kwargs, **kwargs,
) )
@@ -312,6 +328,7 @@ def create_robocasa_envs(
camera_name: str | Sequence[str] = ",".join(DEFAULT_CAMERAS), camera_name: str | Sequence[str] = ",".join(DEFAULT_CAMERAS),
env_cls: Callable[[Sequence[Callable[[], Any]]], Any] | None = None, env_cls: Callable[[Sequence[Callable[[], Any]]], Any] | None = None,
episode_length: int | None = None, episode_length: int | None = None,
obj_registries: Sequence[str] = DEFAULT_OBJ_REGISTRIES,
) -> dict[str, dict[int, Any]]: ) -> dict[str, dict[int, Any]]:
"""Create vectorized RoboCasa365 environments with a consistent return shape. """Create vectorized RoboCasa365 environments with a consistent return shape.
@@ -362,6 +379,7 @@ def create_robocasa_envs(
observation_height=observation_height, observation_height=observation_height,
split=split, split=split,
episode_length=episode_length, episode_length=episode_length,
obj_registries=obj_registries,
) )
if is_async: if is_async: