env_assembly_bench / hud_env.py
lukasskellijs's picture
Update hud_env module purge
f5f7b14 verified
Raw
History Blame Contribute Delete
4.29 kB
"""HUD environment that loads assembly_bench from EnvHub (Hub download path).
Standard HUD robot flow: ``env.gym(make_env)`` derives the contract/capability
and serves over the robot WebSocket. ``make_env`` pulls this repo from the Hub
(the same way LeRobot EnvHub does), then builds the Isaac Lab Arena sim.
Serve (isaac conda, GPU)::
OMNI_KIT_ACCEPT_EULA=YES ACCEPT_EULA=Y PRIVACY_CONSENT=Y \\
python -m hud.environment.server hud_env.py --port 8765
Scene config is the factory signature (``variant`` / ``num_envs`` / …); episodic
args (seed) go through ``sim.reset``.
"""
from __future__ import annotations
import importlib.util
import os
import sys
from pathlib import Path
from types import SimpleNamespace
from hud import Environment
HUB = os.environ.get("ASSEMBLY_BENCH_HUB", "lukasskellijs/env_assembly_bench")
# Authored contract next to this file (absolute — cwd-relative would silently drift).
_CONTRACT = Path(__file__).absolute().parent / "contract.json"
def make_env(
variant: str = "peg_round_M1_loose",
num_envs: int = int(os.environ.get("ASSEMBLY_NUM_ENVS", "1")),
embodiment: str = os.environ.get("ASSEMBLY_EMBODIMENT", "droid_abs_joint_pos_softmimic"),
reward: str = os.environ.get("ASSEMBLY_REWARD", "none"),
):
"""Download EnvHub package (if needed) and return the vectorized Arena env."""
from huggingface_hub import snapshot_download
# Fresh-enough Hub snapshot; local checkout of this repo also works when
# ASSEMBLY_BENCH_HUB points at a path... snapshot always hits the Hub id.
root = snapshot_download(repo_id=HUB)
env_py = Path(root) / "env.py"
if not env_py.is_file():
raise FileNotFoundError(f"Hub repo {HUB} missing env.py (got {root})")
# Prefer Hub package over any editable/local assembly_bench install.
if root in sys.path:
sys.path.remove(root)
sys.path.insert(0, root)
for name in list(sys.modules):
if name == "assembly_bench" or name.startswith("assembly_bench."):
del sys.modules[name]
spec = importlib.util.spec_from_file_location("env_assembly_bench_hub_env", env_py)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
# IsaaclabArenaEnv-shaped config (no lerobot import required in the isaac env).
cfg = SimpleNamespace(
environment="assembly_bench",
embodiment=embodiment,
object=None,
mimic=False,
teleop_device=None,
seed=42,
device=os.environ.get("ASSEMBLY_DEVICE", "cuda:0"),
disable_fabric=False,
enable_cameras=True,
headless=True,
enable_pinocchio=False,
episode_length=300, # hub make_env replaces 300 with variant duration
state_dim=15,
action_dim=8,
camera_height=720,
camera_width=1280,
video=False,
video_length=100,
video_interval=200,
state_keys="joint_pos,gripper_pos,eef_pos,eef_quat",
camera_keys="front_cam_rgb,wrist_camera_rgb",
task=None, # filled from variants.instruction
variant=variant,
reward=reward,
hdr="asm_machine_shop",
light_intensity=1500.0,
)
suites = module.make_env(n_envs=num_envs, use_async_envs=False, cfg=cfg)
# {suite: {task_id: VectorEnv}} → the live vectorized env
return next(iter(next(iter(suites.values())).values()))
env = Environment(name="assembly-bench")
sim = env.gym(
make_env,
contract=_CONTRACT,
variant="peg_round_M1_loose",
)
@env.template(id="assembly")
async def assembly(
variant: str = "peg_round_M1_loose",
seed: int = 0,
num_envs: int | None = None,
embodiment: str | None = None,
reward: str | None = None,
):
"""One assembly episode. Env-defining args rebuild the scene when they change."""
reset_kw: dict = {"variant": variant, "seed": seed}
if num_envs is not None:
reset_kw["num_envs"] = num_envs
if embodiment is not None:
reset_kw["embodiment"] = embodiment
if reward is not None:
reset_kw["reward"] = reward
ep = await sim.reset(**reset_kw)
yield {"prompt": ep["prompt"], "robot": {"token": ep["token"]}}
yield await sim.result(token=ep["token"])