openral-sim 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openral_sim/__init__.py +67 -0
- openral_sim/_assets.py +322 -0
- openral_sim/_deps.py +1943 -0
- openral_sim/_quantization.py +819 -0
- openral_sim/_sidecar_common.py +295 -0
- openral_sim/_video.py +334 -0
- openral_sim/_website_video.py +221 -0
- openral_sim/backends/__init__.py +64 -0
- openral_sim/backends/aloha.py +215 -0
- openral_sim/backends/depth_camera.py +320 -0
- openral_sim/backends/isaac_sim.py +669 -0
- openral_sim/backends/libero.py +434 -0
- openral_sim/backends/maniskill3.py +496 -0
- openral_sim/backends/metaworld.py +163 -0
- openral_sim/backends/openarm_robosuite/__init__.py +28 -0
- openral_sim/backends/openarm_robosuite/_assets.py +554 -0
- openral_sim/backends/openarm_robosuite/env.py +907 -0
- openral_sim/backends/pusht.py +182 -0
- openral_sim/backends/rlbench.py +347 -0
- openral_sim/backends/robocasa.py +1579 -0
- openral_sim/backends/robotwin.py +522 -0
- openral_sim/backends/simpler_env.py +453 -0
- openral_sim/backends/so100_robosuite/__init__.py +37 -0
- openral_sim/backends/so100_robosuite/_assets.py +620 -0
- openral_sim/backends/so100_robosuite/env.py +299 -0
- openral_sim/backends/so100_robosuite/model.py +193 -0
- openral_sim/backends/so100_robosuite/policy.py +188 -0
- openral_sim/backends/so101_box/__init__.py +21 -0
- openral_sim/backends/so101_box/_assets.py +603 -0
- openral_sim/backends/so101_box/env.py +633 -0
- openral_sim/backends/tabletop_push/__init__.py +13 -0
- openral_sim/backends/tabletop_push/_assets.py +420 -0
- openral_sim/backends/tabletop_push/env.py +553 -0
- openral_sim/backends/vlabench.py +206 -0
- openral_sim/benchmark.py +841 -0
- openral_sim/cli.py +876 -0
- openral_sim/factory.py +77 -0
- openral_sim/policies/__init__.py +34 -0
- openral_sim/policies/_policy_loading.py +132 -0
- openral_sim/policies/_processors.py +69 -0
- openral_sim/policies/_video_capture.py +119 -0
- openral_sim/policies/act.py +596 -0
- openral_sim/policies/diffusion.py +241 -0
- openral_sim/policies/gr00t.py +481 -0
- openral_sim/policies/mock.py +216 -0
- openral_sim/policies/molmoact2.py +762 -0
- openral_sim/policies/openvla.py +847 -0
- openral_sim/policies/pi05.py +951 -0
- openral_sim/policies/rlbench_3dda.py +235 -0
- openral_sim/policies/rldx.py +1945 -0
- openral_sim/policies/robots.py +125 -0
- openral_sim/policies/smolvla.py +638 -0
- openral_sim/policies/xvla.py +266 -0
- openral_sim/policy.py +67 -0
- openral_sim/policy_deps.py +249 -0
- openral_sim/py.typed +0 -0
- openral_sim/registry.py +135 -0
- openral_sim/rollout.py +231 -0
- openral_sim/sidecar.py +448 -0
- openral_sim/sim_runner.py +1335 -0
- openral_sim-0.1.0.dist-info/METADATA +33 -0
- openral_sim-0.1.0.dist-info/RECORD +63 -0
- openral_sim-0.1.0.dist-info/WHEEL +4 -0
openral_sim/__init__.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
r"""openral sim runner — swappable (robot x scene x task x VLA) for rSkill validation.
|
|
2
|
+
|
|
3
|
+
Typical usage::
|
|
4
|
+
|
|
5
|
+
from openral_sim import SimRunner
|
|
6
|
+
|
|
7
|
+
# ``SimRunner`` consumes the runtime-composed ``SimEnvironment``
|
|
8
|
+
# (scene + task + VLA). The on-disk YAML is a ``SimScene`` (scene +
|
|
9
|
+
# task, no VLA); the CLI composes the ``SimEnvironment`` from a
|
|
10
|
+
# ``SimScene`` + an rSkill manifest. See ``openral sim run`` and
|
|
11
|
+
# :func:`openral_sim.cli._load_or_build_env` for the canonical
|
|
12
|
+
# compose path.
|
|
13
|
+
env_cfg: SimEnvironment = ... # composed by the CLI
|
|
14
|
+
runner = SimRunner(env_cfg)
|
|
15
|
+
runner.activate()
|
|
16
|
+
runner.run(max_ticks=env_cfg.n_episodes * ((env_cfg.task.max_steps or 1000) + 1))
|
|
17
|
+
for episode in runner.episode_results:
|
|
18
|
+
print(episode.success, episode.steps, episode.mean_step_latency_ms)
|
|
19
|
+
runner.deactivate()
|
|
20
|
+
|
|
21
|
+
CLI::
|
|
22
|
+
|
|
23
|
+
openral sim run --config scenes/benchmark/libero_spatial.yaml \
|
|
24
|
+
--rskill smolvla-libero
|
|
25
|
+
openral sim run --robot franka_panda --scene libero_spatial \
|
|
26
|
+
--task libero_spatial/0 \
|
|
27
|
+
--rskill smolvla-libero
|
|
28
|
+
openral benchmark run --suite libero_spatial \
|
|
29
|
+
--rskill smolvla-libero
|
|
30
|
+
|
|
31
|
+
The sim package itself depends only on ``openral-core``,
|
|
32
|
+
``openral-runner``, and ``openral-rskill``. Physics backends
|
|
33
|
+
(LIBERO, MetaWorld, ...) are imported lazily by the registered adapters
|
|
34
|
+
so installing this package never pulls heavyweight ML deps.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
# Trigger built-in policy + backend registration (LIBERO, MetaWorld, mock,
|
|
40
|
+
# smolvla, …). Importing the two subpackages runs their `_register_*`
|
|
41
|
+
# side effects.
|
|
42
|
+
from openral_sim._video import save_episode_mp4
|
|
43
|
+
from openral_sim.backends import _register_backends as _register_backends
|
|
44
|
+
from openral_sim.benchmark import default_output_path, run_benchmark
|
|
45
|
+
from openral_sim.factory import make_env, make_policy
|
|
46
|
+
from openral_sim.policies import _register_policies as _register_policies
|
|
47
|
+
from openral_sim.policy import PolicyAdapter
|
|
48
|
+
from openral_sim.registry import POLICIES, ROBOTS, SCENES
|
|
49
|
+
from openral_sim.rollout import EpisodeResult, SimRollout
|
|
50
|
+
from openral_sim.sim_runner import SimRunner
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"POLICIES",
|
|
54
|
+
"ROBOTS",
|
|
55
|
+
"SCENES",
|
|
56
|
+
"EpisodeResult",
|
|
57
|
+
"PolicyAdapter",
|
|
58
|
+
"SimRollout",
|
|
59
|
+
"SimRunner",
|
|
60
|
+
"default_output_path",
|
|
61
|
+
"make_env",
|
|
62
|
+
"make_policy",
|
|
63
|
+
"run_benchmark",
|
|
64
|
+
"save_episode_mp4",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
__version__ = "0.1.0"
|
openral_sim/_assets.py
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""Lazy asset-fetch helpers for sim backends with large CC-BY downloads.
|
|
2
|
+
|
|
3
|
+
Today the only consumer is the RoboCasa adapter; the module
|
|
4
|
+
is named generically so a future MuJoCo backend that ships its own
|
|
5
|
+
~GB asset bundle can reuse the same readiness-sentinel + license-banner
|
|
6
|
+
pattern without re-inventing it.
|
|
7
|
+
|
|
8
|
+
Conventions
|
|
9
|
+
-----------
|
|
10
|
+
- Asset caches live under ``$OPENRAL_CACHE_HOME`` (defaults to
|
|
11
|
+
``~/.cache/openral/``), mirroring the rSkill cache convention in
|
|
12
|
+
``openral_rskill.loader``.
|
|
13
|
+
- Each backend gets its own subdirectory (``<cache_home>/robocasa/``).
|
|
14
|
+
- A readiness sentinel file (``.openral-ready``) marks "assets
|
|
15
|
+
fully unpacked"; the helper short-circuits on subsequent runs.
|
|
16
|
+
- A Rich license banner surfaces the upstream license + URL + target
|
|
17
|
+
path + size *before* asking the user to confirm.
|
|
18
|
+
- An env-var bypass (``OPENRAL_ALLOW_ROBOCASA_ASSETS=1`` for
|
|
19
|
+
RoboCasa) skips the prompt for CI.
|
|
20
|
+
|
|
21
|
+
Refusal raises :class:`ROSConfigError` with the manual-fetch command so
|
|
22
|
+
users can authorise the download out-of-band.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
import typer
|
|
33
|
+
from openral_core.exceptions import ROSConfigError
|
|
34
|
+
from rich.console import Console
|
|
35
|
+
from rich.panel import Panel
|
|
36
|
+
|
|
37
|
+
# ── Cache layout ──────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
_DEFAULT_CACHE_HOME = Path.home() / ".cache" / "openral"
|
|
41
|
+
_READY_SENTINEL = ".openral-ready"
|
|
42
|
+
|
|
43
|
+
_ROBOCASA_ALLOW_ENV = "OPENRAL_ALLOW_ROBOCASA_ASSETS"
|
|
44
|
+
_ROBOCASA_ASSETS_SIZE_GB = 11 # upstream README says ~10-11 GB depending on version
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _cache_home() -> Path:
|
|
48
|
+
"""Resolve the openral cache root from env or its default."""
|
|
49
|
+
raw = os.environ.get("OPENRAL_CACHE_HOME")
|
|
50
|
+
return Path(raw) if raw else _DEFAULT_CACHE_HOME
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _display_robocasa_license_banner(target: Path) -> None:
|
|
54
|
+
"""Print a Rich license panel before the typer.confirm() prompt.
|
|
55
|
+
|
|
56
|
+
Separate function so unit tests can monkeypatch the prompt without
|
|
57
|
+
suppressing the user-visible banner (the banner is a UX
|
|
58
|
+
requirement, not implementation detail).
|
|
59
|
+
"""
|
|
60
|
+
Console().print(
|
|
61
|
+
Panel.fit(
|
|
62
|
+
(
|
|
63
|
+
"[bold]RoboCasa kitchen assets[/bold]\n"
|
|
64
|
+
"License: [bold]CC-BY-4.0[/bold] "
|
|
65
|
+
"(https://creativecommons.org/licenses/by/4.0/)\n"
|
|
66
|
+
f"Target: {target}\n"
|
|
67
|
+
f"Approx. ~{_ROBOCASA_ASSETS_SIZE_GB} GB on disk\n"
|
|
68
|
+
"\n"
|
|
69
|
+
"By continuing you accept the upstream RoboCasa CC-BY-4.0\n"
|
|
70
|
+
"license for the kitchen asset pack. Derivative artefacts\n"
|
|
71
|
+
"(videos, traces) must carry attribution. To skip this\n"
|
|
72
|
+
f"prompt in CI export {_ROBOCASA_ALLOW_ENV}=1."
|
|
73
|
+
),
|
|
74
|
+
title="RoboCasa asset download (first-use)",
|
|
75
|
+
border_style="yellow",
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _detect_robocasa_variant() -> str:
|
|
81
|
+
"""Return ``"kitchen"`` or ``"gr1_tabletop"`` based on the installed robocasa.
|
|
82
|
+
|
|
83
|
+
The two python packages share the name ``robocasa`` so a host
|
|
84
|
+
installs ONE or the OTHER. We pick the variant by which download
|
|
85
|
+
script the package ships:
|
|
86
|
+
|
|
87
|
+
* Kitchen (github.com/robocasa/robocasa) — ``download_kitchen_assets``.
|
|
88
|
+
* GR1 tabletop fork (github.com/robocasa/robocasa-gr1-tabletop-tasks)
|
|
89
|
+
— ``download_tabletop_assets`` (plus the kitchen one as a sibling
|
|
90
|
+
since the fork is a soft fork of robocasa).
|
|
91
|
+
|
|
92
|
+
Detection is purely filesystem-based so we don't trigger robocasa's
|
|
93
|
+
own import-time version assertions. If neither script is present
|
|
94
|
+
we default to ``"kitchen"`` -- the historical behaviour -- and the
|
|
95
|
+
subsequent subprocess call will surface a typed ImportError.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
import robocasa # type: ignore[import-not-found,import-untyped,unused-ignore]
|
|
99
|
+
except ImportError:
|
|
100
|
+
return "kitchen"
|
|
101
|
+
scripts = Path(robocasa.__file__).parent / "scripts"
|
|
102
|
+
if (scripts / "download_tabletop_assets.py").is_file():
|
|
103
|
+
return "gr1_tabletop"
|
|
104
|
+
return "kitchen"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def ensure_robocasa_assets() -> Path: # noqa: PLR0915 # reason: orchestrates two variants (kitchen + gr1) each with a short-circuit + a download subprocess path; splitting hurts readability more than the length does
|
|
108
|
+
"""Make sure the RoboCasa assets are on disk; download if needed.
|
|
109
|
+
|
|
110
|
+
Handles both robocasa variants -- the upstream kitchen package and
|
|
111
|
+
the GR1 tabletop fork -- by detecting which is installed and
|
|
112
|
+
invoking the matching download script. The version asserts are
|
|
113
|
+
relaxed in the editable clone at provision time
|
|
114
|
+
(``_deps._relax_robocasa_version_asserts_step``), so no version
|
|
115
|
+
spoof is needed here.
|
|
116
|
+
|
|
117
|
+
The first call triggers a Rich license banner + ``typer.confirm()``
|
|
118
|
+
prompt unless ``OPENRAL_ALLOW_ROBOCASA_ASSETS=1`` is set. On
|
|
119
|
+
confirm we run the variant's download script and touch the
|
|
120
|
+
readiness sentinel. Subsequent calls are silent.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Path to the ``<cache_home>/robocasa/`` directory.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
ROSConfigError: When the user refuses the prompt OR when the
|
|
127
|
+
upstream downloader fails (with the exact subprocess
|
|
128
|
+
stderr embedded so the user can debug).
|
|
129
|
+
"""
|
|
130
|
+
# Variant-scoped sentinel. A previous shared `<cache>/robocasa/.openral-ready`
|
|
131
|
+
# was incorrect: the kitchen and GR1 variants ship different `models/assets/`
|
|
132
|
+
# trees and live in different `import robocasa` paths, so a sentinel
|
|
133
|
+
# touched by the GR1 short-circuit (line ~152) silently masked a
|
|
134
|
+
# missing kitchen asset bundle on the next swap to the kitchen
|
|
135
|
+
# backend — and vice versa. Per-variant cache dirs decouple them.
|
|
136
|
+
variant = _detect_robocasa_variant()
|
|
137
|
+
target = _cache_home() / f"robocasa_{variant}"
|
|
138
|
+
sentinel = target / _READY_SENTINEL
|
|
139
|
+
if sentinel.is_file():
|
|
140
|
+
return target
|
|
141
|
+
|
|
142
|
+
# GR1 fork: the user runs the upstream
|
|
143
|
+
# `python robocasa/scripts/download_tabletop_assets.py -y` once at
|
|
144
|
+
# install time per the fork's README (because that script does a
|
|
145
|
+
# sibling import `from download_groot_assets import …` that only
|
|
146
|
+
# resolves when run from inside the scripts/ directory -- it does
|
|
147
|
+
# NOT survive `python -m` invocation). Detect already-downloaded
|
|
148
|
+
# assets in the editable install's models/assets/objects/ and
|
|
149
|
+
# short-circuit with a sentinel touch so subsequent runs are silent.
|
|
150
|
+
if variant == "gr1_tabletop":
|
|
151
|
+
try:
|
|
152
|
+
import robocasa # type: ignore[import-not-found,import-untyped,unused-ignore]
|
|
153
|
+
|
|
154
|
+
assert robocasa.__file__ is not None
|
|
155
|
+
robocasa_dir = Path(robocasa.__file__).parent
|
|
156
|
+
objects_dir = robocasa_dir / "models" / "assets" / "objects"
|
|
157
|
+
required_registries = ("objaverse", "sketchfab", "lightwheel")
|
|
158
|
+
if objects_dir.is_dir() and all(
|
|
159
|
+
(objects_dir / registry).is_dir() for registry in required_registries
|
|
160
|
+
):
|
|
161
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
162
|
+
sentinel.touch()
|
|
163
|
+
return target
|
|
164
|
+
except ImportError:
|
|
165
|
+
# fall through; the deps path will reinstall robocasa and
|
|
166
|
+
# this function gets called again on the next env build.
|
|
167
|
+
raise ROSConfigError(
|
|
168
|
+
"RoboCasa GR1 tabletop adapter requires the editable "
|
|
169
|
+
"fork clone; openral_sim._deps.ensure_backend_deps "
|
|
170
|
+
"('robocasa_gr1') installs it. Re-run the same command "
|
|
171
|
+
"and accept the deps-install prompt."
|
|
172
|
+
) from None
|
|
173
|
+
|
|
174
|
+
# Drive the upstream downloader as a subprocess with the
|
|
175
|
+
# script's parent dir as cwd (the upstream script does a
|
|
176
|
+
# sibling import `from download_groot_assets import …` that
|
|
177
|
+
# only resolves when invoked from inside scripts/ -- it does
|
|
178
|
+
# NOT survive `python -m`). Bypass the prompt with the same
|
|
179
|
+
# env-var that gates the kitchen path.
|
|
180
|
+
bypass_gr1 = (
|
|
181
|
+
os.environ.get(_ROBOCASA_ALLOW_ENV) == "1"
|
|
182
|
+
or os.environ.get("OPENRAL_AUTO_INSTALL_DEPS") == "1"
|
|
183
|
+
)
|
|
184
|
+
if not bypass_gr1:
|
|
185
|
+
_display_robocasa_license_banner(target)
|
|
186
|
+
if not typer.confirm("Download RoboCasa GR1 tabletop assets now?", default=False):
|
|
187
|
+
raise ROSConfigError(
|
|
188
|
+
"RoboCasa GR1 tabletop assets not downloaded. Either "
|
|
189
|
+
f"set {_ROBOCASA_ALLOW_ENV}=1 (or "
|
|
190
|
+
"OPENRAL_AUTO_INSTALL_DEPS=1) and re-run, or fetch "
|
|
191
|
+
"them manually:\n"
|
|
192
|
+
f" cd {robocasa_dir.parent} && uv run python "
|
|
193
|
+
"robocasa/scripts/download_tabletop_assets.py -y"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
scripts_dir = robocasa_dir / "scripts"
|
|
197
|
+
try:
|
|
198
|
+
subprocess.run(
|
|
199
|
+
[sys.executable, "download_tabletop_assets.py", "-y"],
|
|
200
|
+
cwd=str(scripts_dir),
|
|
201
|
+
check=True,
|
|
202
|
+
)
|
|
203
|
+
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
|
|
204
|
+
raise ROSConfigError(
|
|
205
|
+
f"RoboCasa GR1 asset download failed: {exc}. Re-run "
|
|
206
|
+
f"manually:\n cd {robocasa_dir.parent} && uv run python "
|
|
207
|
+
"robocasa/scripts/download_tabletop_assets.py -y"
|
|
208
|
+
) from exc
|
|
209
|
+
|
|
210
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
211
|
+
sentinel.touch()
|
|
212
|
+
return target
|
|
213
|
+
|
|
214
|
+
# Kitchen variant: short-circuit ONLY when every downloaded bundle is
|
|
215
|
+
# on disk. The editable install path (`_deps._robocasa_kitchen_plan`
|
|
216
|
+
# → clone + `uv pip install -e`) ships the static skeleton
|
|
217
|
+
# (``arenas/empty_kitchen_arena.xml``, ``box_links/...json``) from the
|
|
218
|
+
# cloned source, but the heavyweight content (~11 GB) ships
|
|
219
|
+
# separately via ``robocasa.scripts.download_kitchen_assets``'s Box
|
|
220
|
+
# URLs and lands under the dirs enumerated in that script's
|
|
221
|
+
# ``DOWNLOAD_ASSET_REGISTRY``. Per-task object sampling in
|
|
222
|
+
# ``kitchen_object_utils.sample_kitchen_object`` reads the default
|
|
223
|
+
# ``obj_registries=("objaverse", "lightwheel")``, and the AI-gen
|
|
224
|
+
# category set is also referenced by many tasks — so a partial
|
|
225
|
+
# install (e.g. only ``objects/lightwheel/``) reads "ready" but later
|
|
226
|
+
# divides by zero candidates in the sampler and surfaces as
|
|
227
|
+
# ``ValueError: probabilities contain NaN`` at first ``env.reset()``.
|
|
228
|
+
# Require every non-source download target to be non-empty.
|
|
229
|
+
try:
|
|
230
|
+
import robocasa # type: ignore[import-not-found,import-untyped,unused-ignore]
|
|
231
|
+
|
|
232
|
+
assert robocasa.__file__ is not None
|
|
233
|
+
robocasa_dir = Path(robocasa.__file__).parent
|
|
234
|
+
kitchen_arena = robocasa_dir / "models" / "assets" / "arenas" / "empty_kitchen_arena.xml"
|
|
235
|
+
box_links_assets = (
|
|
236
|
+
robocasa_dir / "models" / "assets" / "box_links" / "box_links_assets.json"
|
|
237
|
+
)
|
|
238
|
+
# Downloaded bundles, matching DOWNLOAD_ASSET_REGISTRY keys in
|
|
239
|
+
# robocasa.scripts.download_kitchen_assets. Each must be a
|
|
240
|
+
# non-empty directory.
|
|
241
|
+
assets_root = robocasa_dir / "models" / "assets"
|
|
242
|
+
downloaded_bundles = (
|
|
243
|
+
assets_root / "textures",
|
|
244
|
+
assets_root / "generative_textures",
|
|
245
|
+
assets_root / "fixtures",
|
|
246
|
+
assets_root / "objects" / "objaverse",
|
|
247
|
+
assets_root / "objects" / "aigen_objs",
|
|
248
|
+
assets_root / "objects" / "lightwheel",
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def _populated(p: Path) -> bool:
|
|
252
|
+
return p.is_dir() and any(p.iterdir())
|
|
253
|
+
|
|
254
|
+
if (
|
|
255
|
+
kitchen_arena.is_file()
|
|
256
|
+
and box_links_assets.is_file()
|
|
257
|
+
and all(_populated(p) for p in downloaded_bundles)
|
|
258
|
+
):
|
|
259
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
260
|
+
sentinel.touch()
|
|
261
|
+
return target
|
|
262
|
+
except ImportError:
|
|
263
|
+
pass
|
|
264
|
+
|
|
265
|
+
# ``OPENRAL_AUTO_INSTALL_DEPS=1`` (used by ``openral deploy sim``
|
|
266
|
+
# for CI-style runs) implies acceptance of the RoboCasa asset
|
|
267
|
+
# license + download. The license banner still prints to stderr
|
|
268
|
+
# so the operator has a record of what was downloaded.
|
|
269
|
+
bypass = (
|
|
270
|
+
os.environ.get(_ROBOCASA_ALLOW_ENV) == "1"
|
|
271
|
+
or os.environ.get("OPENRAL_AUTO_INSTALL_DEPS") == "1"
|
|
272
|
+
)
|
|
273
|
+
if not bypass:
|
|
274
|
+
_display_robocasa_license_banner(target)
|
|
275
|
+
if not typer.confirm("Download RoboCasa assets now?", default=False):
|
|
276
|
+
script = (
|
|
277
|
+
"robocasa.scripts.download_tabletop_assets"
|
|
278
|
+
if variant == "gr1_tabletop"
|
|
279
|
+
else "robocasa.scripts.download_kitchen_assets"
|
|
280
|
+
)
|
|
281
|
+
raise ROSConfigError(
|
|
282
|
+
"RoboCasa assets not downloaded. Either set "
|
|
283
|
+
f"{_ROBOCASA_ALLOW_ENV}=1 (or OPENRAL_AUTO_INSTALL_DEPS=1) "
|
|
284
|
+
f"and re-run, or fetch them manually with: "
|
|
285
|
+
f"`uv run python -m {script}`"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
289
|
+
# The upstream download script prompts on stdin when called
|
|
290
|
+
# directly, so we drive it as a subprocess with stdin confirmation
|
|
291
|
+
# pre-baked. The script writes assets to its site-package-internal
|
|
292
|
+
# `models/assets/` directory (not `target`); we touch the sentinel
|
|
293
|
+
# under `target` afterwards as a readiness marker.
|
|
294
|
+
#
|
|
295
|
+
# robocasa's download scripts ``import robocasa``, which used to hard-assert
|
|
296
|
+
# exact mujoco/numpy/robosuite micro versions at import. The install plan now
|
|
297
|
+
# relaxes those asserts in the editable clone at provision time
|
|
298
|
+
# (``_deps._relax_robocasa_version_asserts_step``), so the download runs on
|
|
299
|
+
# the workspace's real versions with NO version spoof -- a plain ``runpy``
|
|
300
|
+
# shim suffices. Only the procedural ``download_*_assets`` target differs by
|
|
301
|
+
# variant (kitchen vs the GR1 tabletop fork).
|
|
302
|
+
if variant == "gr1_tabletop":
|
|
303
|
+
script_hint = "robocasa.scripts.download_tabletop_assets"
|
|
304
|
+
else:
|
|
305
|
+
script_hint = "robocasa.scripts.download_kitchen_assets"
|
|
306
|
+
shim = f'import runpy; runpy.run_module("{script_hint}", run_name="__main__")'
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
subprocess.run(
|
|
310
|
+
[sys.executable, "-c", shim],
|
|
311
|
+
input="y\n",
|
|
312
|
+
text=True,
|
|
313
|
+
check=True,
|
|
314
|
+
)
|
|
315
|
+
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
|
|
316
|
+
raise ROSConfigError(
|
|
317
|
+
f"RoboCasa asset download failed: {exc}. Run "
|
|
318
|
+
f"`uv run python -m {script_hint}` manually and re-run the sim."
|
|
319
|
+
) from exc
|
|
320
|
+
|
|
321
|
+
sentinel.touch()
|
|
322
|
+
return target
|