Skip to content

Commit 21aba0b

Browse files
geng-haoranclaude
andcommitted
feat(tasks): native LIBERO-plus perturbation tasks (libero-free, bitwise 1:1)
Register 40 representative LIBERO-plus perturbed tasks (5 dims: add/language/ light/table/tb × 4 suites) as first-class MetaSim tasks `libero_plus_native.*`, reusing the base-LIBERO native machinery: load each perturbed compiled model_file on the groundless MujocoHandler, drive it with the robosuite-free native OSC controller, judge success natively from the carried-over BDDL goal. No `import libero` / `import robosuite` at runtime. Closes the two open items from the LIBERO-plus report's honest list: - (3) MetaSim closed-loop blocked (no OSC) -> native OSC steps perturbed scenes inside the handler; - (7) passthrough != metasim-native -> tasks go through ScenarioCfg/Handler/ registry, resolved via get_task_class with libero+robosuite import-blocked. Verified (shared roboverse env, mujoco 3.8): engine bitwise raw-mujoco vs MetaSim dm_control loader 40/40 (Delta=0, per-dim 8/8); native BDDL checker evaluates 40/40; native register + OSC step 5/5 dims with libero+robosuite blocked. Data: research_report .../metasim_1to1/liberoplus{,_native}.json. Tooling: gen_liberoplus.py builds bundles in a dedicated robosuite-1.4 env, lazily extracting only each task's asset files from the 6.4GB assets.zip via HTTP range requests (no full download); verify_liberoplus.py + the smoke test. NativeLiberoEnv refactored to a configurable bundles_root + _remap_model hook (backward compatible; existing libero_native.* unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d578182 commit 21aba0b

168 files changed

Lines changed: 27336 additions & 60 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

roboverse_pack/tasks/libero/_native_util.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ def remap_libero_model(model_file: str, libero_assets: str) -> str:
4141
return xml
4242

4343

44+
def remap_liberoplus_model(model_file: str, libero_assets: str, plus_assets: str) -> str:
45+
"""Rebase a LIBERO-plus perturbed ``model_file`` to local assets.
46+
47+
Same as :func:`remap_libero_model` (robosuite + chiliocosm roots, dm_control-safe)
48+
plus the LIBERO-plus overlay asset root — perturbed scenes embed absolute paths
49+
into ``.../LIBERO-plus/libero/libero/assets`` (light scenes, new-object meshes,
50+
textures). Rebase that root to ``plus_assets`` so the bundle is portable.
51+
"""
52+
xml = remap_libero_model(model_file, libero_assets)
53+
xml = re.sub(r'file="[^"]*?/LIBERO-plus/libero/libero/assets', f'file="{plus_assets}', xml)
54+
return xml
55+
56+
4457
def parse_goal(bddl_text: str) -> list[tuple[str, list[str]]]:
4558
m = re.search(r"\(:goal\s*(.*?)\)\s*\)\s*$", bddl_text, re.S)
4659
block = m.group(1) if m else bddl_text
@@ -69,25 +82,39 @@ def _in_region(model, data, obj: str, region: str) -> bool:
6982
_TURNON_RANGES = {"flat_stove": [0.5, 2.1]}
7083

7184

72-
def _artic_qpos(model, data, base: str):
73-
"""qpos values of the object's articulated (non-free, 1-dof) joints."""
74-
out = []
75-
for j in range(model.njnt):
76-
jn = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_JOINT, j) or ""
77-
if base in jn and model.jnt_type[j] in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE):
78-
out.append(float(data.qpos[model.jnt_qposadr[j]]))
79-
return out
80-
81-
8285
def _region_base(region: str) -> str:
8386
return re.sub(r"_(\w+_)?(region|level)$", "", region)
8487

8588

89+
def _artic_qpos(model, data, region: str):
90+
"""qpos of the articulated (non-free) joint(s) for ``region``.
91+
92+
A multi-drawer cabinet has one joint per drawer (``<obj>_<level>_level``); a
93+
region like ``<obj>_<level>_region`` must target ONLY that drawer's joint, not
94+
every joint on the object. We first try the level-specific joint
95+
(``region`` with ``region``→``level``); if none match we fall back to all of
96+
the object's articulated joints (single-DOF objects: microwave, window, …).
97+
"""
98+
level_joint = re.sub(r"region$", "level", region)
99+
base = _region_base(region)
100+
specific, generic = [], []
101+
for j in range(model.njnt):
102+
if model.jnt_type[j] not in (mujoco.mjtJoint.mjJNT_HINGE, mujoco.mjtJoint.mjJNT_SLIDE):
103+
continue
104+
jn = mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_JOINT, j) or ""
105+
q = float(data.qpos[model.jnt_qposadr[j]])
106+
if level_joint in jn:
107+
specific.append(q)
108+
if base in jn:
109+
generic.append(q)
110+
return specific if specific else generic
111+
112+
86113
def _is_open(model, data, region: str) -> bool:
87114
base = _region_base(region)
88115
cls = next((k for k in _OPEN_RANGES if k in base.lower()), None)
89116
rng, direction = _OPEN_RANGES.get(cls, ([-0.14, -0.14], "lt"))
90-
for q in _artic_qpos(model, data, base):
117+
for q in _artic_qpos(model, data, region):
91118
if (q < max(rng)) if direction == "lt" else (q > min(rng)):
92119
return True
93120
return False
@@ -97,7 +124,7 @@ def _turn_on(model, data, region: str) -> bool:
97124
base = _region_base(region)
98125
cls = next((k for k in _TURNON_RANGES if k in base.lower()), None)
99126
rng = _TURNON_RANGES.get(cls, [0.5, 2.1])
100-
return any(q >= min(rng) for q in _artic_qpos(model, data, base))
127+
return any(q >= min(rng) for q in _artic_qpos(model, data, region))
101128

102129

103130
def _contact(model, data, body_a: int, body_b: int) -> bool:
@@ -127,11 +154,7 @@ def _on(model, data, a: str, b: str) -> bool:
127154
return False
128155
size = model.site_size[sid]
129156
delta = data.site_xmat[sid].reshape(3, 3) @ (data.xpos[bid] - data.site_xpos[sid])
130-
return bool(
131-
size[2] - 0.005 < delta[2] < size[2] + 0.10
132-
and abs(delta[0]) < size[0]
133-
and abs(delta[1]) < size[1]
134-
)
157+
return bool(size[2] - 0.005 < delta[2] < size[2] + 0.10 and abs(delta[0]) < size[0] and abs(delta[1]) < size[1])
135158
ba = _bid(model, a) if _bid(model, a) >= 0 else _bid(model, a + "_main")
136159
bb = _bid(model, b) if _bid(model, b) >= 0 else _bid(model, b + "_main")
137160
if ba < 0 or bb < 0:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[["Turnon", ["flat_stove_1"]], ["On", ["moka_pot_1", "flat_stove_1_cook_region"]]]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"dim": "add", "suite": "libero_10", "bddl": "KITCHEN_SCENE3_turn_on_the_stove_and_put_the_moka_pot_on_it_add_1.bddl", "nq": 31, "nv": 28, "lang": "turn on the stove and put the moka pot on it", "goal": [["Turnon", ["flat_stove_1"]], ["On", ["moka_pot_1", "flat_stove_1_cook_region"]]]}

0 commit comments

Comments
 (0)