clean-up
Browse files
env.py
CHANGED
|
@@ -24,10 +24,8 @@ import logging
|
|
| 24 |
import os
|
| 25 |
import sys
|
| 26 |
from pathlib import Path
|
| 27 |
-
from typing import Any
|
| 28 |
|
| 29 |
import gymnasium as gym
|
| 30 |
-
import yaml
|
| 31 |
|
| 32 |
from lerobot.envs.configs import EnvConfig
|
| 33 |
|
|
@@ -39,39 +37,38 @@ DEFAULT_CONFIG_FILE = "configs/config.yaml"
|
|
| 39 |
def _download_and_import(filename: str):
|
| 40 |
"""Download file from Hub and import as module."""
|
| 41 |
from huggingface_hub import hf_hub_download
|
|
|
|
| 42 |
local_path = hf_hub_download(repo_id=HUB_REPO_ID, filename=filename)
|
| 43 |
module_dir = os.path.dirname(local_path)
|
| 44 |
-
|
| 45 |
# Add directory to sys.path so modules can import each other
|
| 46 |
if module_dir not in sys.path:
|
| 47 |
sys.path.insert(0, module_dir)
|
| 48 |
-
|
| 49 |
module_name = filename.replace(".py", "")
|
| 50 |
-
|
| 51 |
# Read file content and replace relative imports with absolute imports
|
| 52 |
-
with open(local_path
|
| 53 |
content = f.read()
|
| 54 |
-
|
| 55 |
# Replace relative imports (e.g., "from .errors" -> "from errors")
|
| 56 |
content = content.replace("from .errors import", "from errors import")
|
| 57 |
content = content.replace("from .isaaclab_env_wrapper import", "from isaaclab_env_wrapper import")
|
| 58 |
-
|
| 59 |
# Create module and execute modified content
|
| 60 |
-
module = importlib.util.module_from_spec(
|
| 61 |
-
importlib.util.spec_from_file_location(module_name, local_path)
|
| 62 |
-
)
|
| 63 |
sys.modules[module_name] = module
|
| 64 |
-
|
| 65 |
# Compile and execute the modified code
|
| 66 |
code = compile(content, local_path, "exec")
|
| 67 |
-
exec(code, module.__dict__)
|
| 68 |
-
|
| 69 |
return module
|
| 70 |
|
| 71 |
|
| 72 |
try:
|
| 73 |
-
from .isaaclab_env_wrapper import IsaacLabEnvWrapper, cleanup_isaaclab
|
| 74 |
from .errors import IsaacLabArenaCameraKeyError, IsaacLabArenaStateKeyError
|
|
|
|
| 75 |
except ImportError:
|
| 76 |
_errors = _download_and_import("errors.py")
|
| 77 |
_isaaclab_wrapper = _download_and_import("isaaclab_env_wrapper.py")
|
|
@@ -151,7 +148,7 @@ ENVIRONMENT_ALIASES: dict[str, str] = {
|
|
| 151 |
"kitchen_pnp": (
|
| 152 |
f"{ISAACLAB_ARENA_ENV_MODULE}.kitchen_pick_and_place_environment.KitchenPickAndPlaceEnvironment"
|
| 153 |
),
|
| 154 |
-
"press_button":
|
| 155 |
}
|
| 156 |
|
| 157 |
|
|
@@ -175,8 +172,6 @@ def _find_config_file(config_path: str | Path | None = None) -> Path | None:
|
|
| 175 |
Returns:
|
| 176 |
Path to config file, or None if not found (uses defaults).
|
| 177 |
"""
|
| 178 |
-
module_dir = Path(__file__).parent
|
| 179 |
-
|
| 180 |
search_paths = []
|
| 181 |
|
| 182 |
# Explicit path from argument
|
|
@@ -204,6 +199,7 @@ def _find_config_file(config_path: str | Path | None = None) -> Path | None:
|
|
| 204 |
# This is needed when env.py is loaded from HF cache (only env.py is downloaded)
|
| 205 |
try:
|
| 206 |
from huggingface_hub import hf_hub_download
|
|
|
|
| 207 |
logging.info(f"Downloading config from Hub: {HUB_REPO_ID}/{DEFAULT_CONFIG_FILE}")
|
| 208 |
hub_config_path = hf_hub_download(
|
| 209 |
repo_id=HUB_REPO_ID,
|
|
@@ -215,6 +211,7 @@ def _find_config_file(config_path: str | Path | None = None) -> Path | None:
|
|
| 215 |
|
| 216 |
raise FileNotFoundError("config.yaml not found and no configuration provided.")
|
| 217 |
|
|
|
|
| 218 |
def _create_isaaclab_env(config: dict, n_envs: int) -> dict[str, dict[int, gym.vector.VectorEnv]]:
|
| 219 |
"""Create IsaacLab Arena environment from configuration.
|
| 220 |
|
|
@@ -270,9 +267,11 @@ def _create_isaaclab_env(config: dict, n_envs: int) -> dict[str, dict[int, gym.v
|
|
| 270 |
camera_keys = tuple(k.strip() for k in (config.get("camera_keys") or "").split(",") if k.strip())
|
| 271 |
try:
|
| 272 |
validate_config(
|
| 273 |
-
raw_env,
|
|
|
|
|
|
|
| 274 |
config.get("state_dim", 54),
|
| 275 |
-
config.get("action_dim", 36)
|
| 276 |
)
|
| 277 |
except (IsaacLabArenaCameraKeyError, IsaacLabArenaStateKeyError, ValueError) as e:
|
| 278 |
logging.error(f"Validation failed: {e}")
|
|
@@ -303,9 +302,8 @@ def _create_isaaclab_env(config: dict, n_envs: int) -> dict[str, dict[int, gym.v
|
|
| 303 |
|
| 304 |
def make_env(
|
| 305 |
n_envs: int = 1,
|
| 306 |
-
use_async_envs: bool = False,
|
| 307 |
cfg: EnvConfig | None = None,
|
| 308 |
-
# **kwargs: Any,
|
| 309 |
) -> dict[str, dict[int, gym.vector.VectorEnv]]:
|
| 310 |
"""Create IsaacLab Arena environments (EnvHub-compatible API).
|
| 311 |
|
|
@@ -316,7 +314,7 @@ def make_env(
|
|
| 316 |
Args:
|
| 317 |
n_envs: Number of parallel environments (default: 1).
|
| 318 |
use_async_envs: Ignored for IsaacLab (GPU-based batched execution).
|
| 319 |
-
|
| 320 |
- environment: Environment name or alias (e.g., "gr1_microwave")
|
| 321 |
- headless: Whether to run headless (default: True)
|
| 322 |
- enable_cameras: Enable camera rendering (default: False)
|
|
@@ -338,7 +336,7 @@ def make_env(
|
|
| 338 |
if n_envs < 1:
|
| 339 |
raise ValueError("`n_envs` must be at least 1")
|
| 340 |
|
| 341 |
-
if not hasattr(cfg,
|
| 342 |
raise ValueError(
|
| 343 |
"No 'environment' specified. Pass it via kwargs or create "
|
| 344 |
"configs/config.yaml with environment settings."
|
|
@@ -370,25 +368,8 @@ def make_env(
|
|
| 370 |
"camera_keys": cfg.camera_keys or "", # Pass empty string for no cameras
|
| 371 |
"task": cfg.task,
|
| 372 |
}
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
# if yaml_path is not None:
|
| 377 |
-
# logging.info(f"Loading config from: {yaml_path}")
|
| 378 |
-
# with open(yaml_path) as f:
|
| 379 |
-
# config = yaml.safe_load(f) or {}
|
| 380 |
-
# else:
|
| 381 |
-
# config = {}
|
| 382 |
-
|
| 383 |
-
# Apply any runtime overrides (highest priority)
|
| 384 |
-
# config.update(kwargs)
|
| 385 |
-
|
| 386 |
-
logging.info(
|
| 387 |
-
f"EnvHub make_env: environment={config.get('environment')}, n_envs={n_envs}"
|
| 388 |
-
)
|
| 389 |
-
logging.info(
|
| 390 |
-
f"Config: headless={config.get('headless')}, "
|
| 391 |
-
f"enable_cameras={config.get('enable_cameras')}"
|
| 392 |
-
)
|
| 393 |
|
| 394 |
return _create_isaaclab_env(config, n_envs)
|
|
|
|
| 24 |
import os
|
| 25 |
import sys
|
| 26 |
from pathlib import Path
|
|
|
|
| 27 |
|
| 28 |
import gymnasium as gym
|
|
|
|
| 29 |
|
| 30 |
from lerobot.envs.configs import EnvConfig
|
| 31 |
|
|
|
|
| 37 |
def _download_and_import(filename: str):
|
| 38 |
"""Download file from Hub and import as module."""
|
| 39 |
from huggingface_hub import hf_hub_download
|
| 40 |
+
|
| 41 |
local_path = hf_hub_download(repo_id=HUB_REPO_ID, filename=filename)
|
| 42 |
module_dir = os.path.dirname(local_path)
|
| 43 |
+
|
| 44 |
# Add directory to sys.path so modules can import each other
|
| 45 |
if module_dir not in sys.path:
|
| 46 |
sys.path.insert(0, module_dir)
|
| 47 |
+
|
| 48 |
module_name = filename.replace(".py", "")
|
| 49 |
+
|
| 50 |
# Read file content and replace relative imports with absolute imports
|
| 51 |
+
with open(local_path) as f:
|
| 52 |
content = f.read()
|
| 53 |
+
|
| 54 |
# Replace relative imports (e.g., "from .errors" -> "from errors")
|
| 55 |
content = content.replace("from .errors import", "from errors import")
|
| 56 |
content = content.replace("from .isaaclab_env_wrapper import", "from isaaclab_env_wrapper import")
|
| 57 |
+
|
| 58 |
# Create module and execute modified content
|
| 59 |
+
module = importlib.util.module_from_spec(importlib.util.spec_from_file_location(module_name, local_path))
|
|
|
|
|
|
|
| 60 |
sys.modules[module_name] = module
|
| 61 |
+
|
| 62 |
# Compile and execute the modified code
|
| 63 |
code = compile(content, local_path, "exec")
|
| 64 |
+
exec(code, module.__dict__) # noqa: S102
|
| 65 |
+
|
| 66 |
return module
|
| 67 |
|
| 68 |
|
| 69 |
try:
|
|
|
|
| 70 |
from .errors import IsaacLabArenaCameraKeyError, IsaacLabArenaStateKeyError
|
| 71 |
+
from .isaaclab_env_wrapper import IsaacLabEnvWrapper, cleanup_isaaclab
|
| 72 |
except ImportError:
|
| 73 |
_errors = _download_and_import("errors.py")
|
| 74 |
_isaaclab_wrapper = _download_and_import("isaaclab_env_wrapper.py")
|
|
|
|
| 148 |
"kitchen_pnp": (
|
| 149 |
f"{ISAACLAB_ARENA_ENV_MODULE}.kitchen_pick_and_place_environment.KitchenPickAndPlaceEnvironment"
|
| 150 |
),
|
| 151 |
+
"press_button": f"{ISAACLAB_ARENA_ENV_MODULE}.press_button_environment.PressButtonEnvironment",
|
| 152 |
}
|
| 153 |
|
| 154 |
|
|
|
|
| 172 |
Returns:
|
| 173 |
Path to config file, or None if not found (uses defaults).
|
| 174 |
"""
|
|
|
|
|
|
|
| 175 |
search_paths = []
|
| 176 |
|
| 177 |
# Explicit path from argument
|
|
|
|
| 199 |
# This is needed when env.py is loaded from HF cache (only env.py is downloaded)
|
| 200 |
try:
|
| 201 |
from huggingface_hub import hf_hub_download
|
| 202 |
+
|
| 203 |
logging.info(f"Downloading config from Hub: {HUB_REPO_ID}/{DEFAULT_CONFIG_FILE}")
|
| 204 |
hub_config_path = hf_hub_download(
|
| 205 |
repo_id=HUB_REPO_ID,
|
|
|
|
| 211 |
|
| 212 |
raise FileNotFoundError("config.yaml not found and no configuration provided.")
|
| 213 |
|
| 214 |
+
|
| 215 |
def _create_isaaclab_env(config: dict, n_envs: int) -> dict[str, dict[int, gym.vector.VectorEnv]]:
|
| 216 |
"""Create IsaacLab Arena environment from configuration.
|
| 217 |
|
|
|
|
| 267 |
camera_keys = tuple(k.strip() for k in (config.get("camera_keys") or "").split(",") if k.strip())
|
| 268 |
try:
|
| 269 |
validate_config(
|
| 270 |
+
raw_env,
|
| 271 |
+
state_keys,
|
| 272 |
+
camera_keys,
|
| 273 |
config.get("state_dim", 54),
|
| 274 |
+
config.get("action_dim", 36),
|
| 275 |
)
|
| 276 |
except (IsaacLabArenaCameraKeyError, IsaacLabArenaStateKeyError, ValueError) as e:
|
| 277 |
logging.error(f"Validation failed: {e}")
|
|
|
|
| 302 |
|
| 303 |
def make_env(
|
| 304 |
n_envs: int = 1,
|
| 305 |
+
use_async_envs: bool = False, # noqa: ARG001
|
| 306 |
cfg: EnvConfig | None = None,
|
|
|
|
| 307 |
) -> dict[str, dict[int, gym.vector.VectorEnv]]:
|
| 308 |
"""Create IsaacLab Arena environments (EnvHub-compatible API).
|
| 309 |
|
|
|
|
| 314 |
Args:
|
| 315 |
n_envs: Number of parallel environments (default: 1).
|
| 316 |
use_async_envs: Ignored for IsaacLab (GPU-based batched execution).
|
| 317 |
+
cfg: Configuration object with environment parameters. Required keys:
|
| 318 |
- environment: Environment name or alias (e.g., "gr1_microwave")
|
| 319 |
- headless: Whether to run headless (default: True)
|
| 320 |
- enable_cameras: Enable camera rendering (default: False)
|
|
|
|
| 336 |
if n_envs < 1:
|
| 337 |
raise ValueError("`n_envs` must be at least 1")
|
| 338 |
|
| 339 |
+
if not hasattr(cfg, "environment") or cfg.environment is None:
|
| 340 |
raise ValueError(
|
| 341 |
"No 'environment' specified. Pass it via kwargs or create "
|
| 342 |
"configs/config.yaml with environment settings."
|
|
|
|
| 368 |
"camera_keys": cfg.camera_keys or "", # Pass empty string for no cameras
|
| 369 |
"task": cfg.task,
|
| 370 |
}
|
| 371 |
+
|
| 372 |
+
logging.info(f"EnvHub make_env: environment={config.get('environment')}, n_envs={n_envs}")
|
| 373 |
+
logging.info(f"Config: headless={config.get('headless')}, enable_cameras={config.get('enable_cameras')}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
|
| 375 |
return _create_isaaclab_env(config, n_envs)
|