Skip to content

Commit 249103f

Browse files
authored
fix(libero): declare robots=["franka"] on the 9 robotless libero_pick tasks (#788)
9 of the 10 `libero_pick_*` "pick up X and place it in the basket" tasks omitted `robots=["franka"]` from their ScenarioCfg (only libero_pick_butter had it), so they instantiated with an empty robot list. A pick task with no arm is doubly broken: (1) nothing can move the object, so the DetectedChecker/RelativeBboxDetector can never fire → eval silently scores 0%; (2) `LiberoBaseTask._get_initial_states` loads a franka-keyed trajectory (`franka_v2.pkl.gz`) via `get_traj(traj, scenario.robots[0], ...)`, which on an empty robot list hits the `else None` path and silently fails to apply the demo init states. The "robots may be empty (perception-only)" guard in libero_base is what made both failures silent rather than a hard error. Fix: add `robots=["franka"]` to the 9 missing ScenarioCfgs, mirroring the correct sibling butter. `"franka"` resolves to FrankaCfg (mjcf present) and matches the franka-keyed trajectories. Also fixes a latent typo in alphabet_soup (`max_max_episode_steps` → `max_episode_steps`, which silently failed to override the base horizon). Edits preserve the files' CRLF endings so the diff stays surgical. Scope: complete for the libero_pick_* family. libero_90 already declares the robot; native_libero/native_liberoplus intentionally use robots=[] (the arm is baked into the vendored robosuite MJCF); the *_single.py stubs are empty. Test: new `test_all_libero_pick_tasks_have_a_robot` asserts every libero_pick_* declares a non-empty robot list (red before the fix on any file that omits it). `tests/test_libero_fixes.py` 3 passed; the libero test trio 9 passed, 3 skipped. Reviewed by 3 fresh-context agents.
1 parent f62a968 commit 249103f

10 files changed

Lines changed: 59 additions & 15 deletions

roboverse_pack/tasks/libero/libero_pick_alphabet_soup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ class LiberoPickAlphabetSoupTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/butter/urdf/butter.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/butter/mjcf/butter.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon
74-
max_max_episode_steps = 250
75+
max_episode_steps = 250
7576
task_desc = "Pick the alphabet soup and place it in the basket"
7677
checker = DetectedChecker(
7778
obj_name="alphabet_soup",

roboverse_pack/tasks/libero/libero_pick_bbq_sauce.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickBbqSauceTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/cream_cheese/urdf/cream_cheese.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/cream_cheese/mjcf/cream_cheese.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_chocolate_pudding.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickChocolatePuddingCfg(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/alphabet_soup/urdf/alphabet_soup.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/alphabet_soup/mjcf/alphabet_soup.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273
objects = [
7374
RigidObjCfg(

roboverse_pack/tasks/libero/libero_pick_cream_cheese.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickCreamCheeseTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/orange_juice/urdf/orange_juice.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/orange_juice/mjcf/orange_juice.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_ketchup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickKetchupTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/milk/urdf/milk.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/milk/mjcf/milk.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_milk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickMilkTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/chocolate_pudding/urdf/chocolate_pudding.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/chocolate_pudding/mjcf/chocolate_pudding.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_orange_juice.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickOrangeJuiceCfg(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/salad_dressing/urdf/salad_dressing.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/salad_dressing/mjcf/salad_dressing.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_salad_dressing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickSaladDressingTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/tomato_sauce/urdf/tomato_sauce.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/tomato_sauce/mjcf/tomato_sauce.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

roboverse_pack/tasks/libero/libero_pick_tomato_sauce.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class LiberoPickTomatoSauceTask(LiberoBaseTask):
6767
urdf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/bbq_sauce/urdf/bbq_sauce.urdf",
6868
mjcf_path="roboverse_data/assets/libero/COMMON/stable_hope_objects/bbq_sauce/mjcf/bbq_sauce.xml",
6969
),
70-
]
70+
],
71+
robots=["franka"],
7172
)
7273

7374
# task horizon

tests/test_libero_fixes.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
1-
"""Regression test (backend-free) for Libero90BaseTask._get_initial_states hardening.
1+
"""Regression tests (backend-free) for the libero task fixes.
22
3-
The method must degrade to None (handler defaults) when the trajectory is
4-
missing/empty or the scenario is robotless, matching the already-hardened
5-
LiberoBaseTask. Previously it indexed ``scenario.robots[0]`` and called get_traj
6-
with no guard, so those cases crashed.
3+
Covers two independent hardening fixes:
4+
5+
* ``Libero90BaseTask._get_initial_states`` must degrade to None (handler
6+
defaults) when the trajectory is missing/empty or the scenario is robotless,
7+
matching the already-hardened ``LiberoBaseTask``. Previously it indexed
8+
``scenario.robots[0]`` and called get_traj with no guard, so those cases
9+
crashed.
10+
* Every ``libero_pick_*`` task must declare ``robots=["franka"]``. 9 of 10
11+
omitted it, so they instantiated with an empty robot list — a robotless pick
12+
task can never succeed and eval scores a silent 0%.
713
"""
814

915
from __future__ import annotations
1016

17+
import pathlib
18+
1119
import pytest
1220

21+
_LIBERO = pathlib.Path(__file__).resolve().parents[1] / "roboverse_pack" / "tasks" / "libero"
22+
1323

1424
@pytest.mark.general
1525
def test_libero_90_get_initial_states_degrades_gracefully(monkeypatch):
@@ -44,3 +54,28 @@ def _raise(*a, **k):
4454
# 3. get_traj returns empty → None (empty guard before len())
4555
monkeypatch.setattr(mod, "get_traj", lambda *a, **k: ([], None, None))
4656
assert t._get_initial_states() is None
57+
58+
59+
@pytest.mark.general
60+
def test_all_libero_pick_tasks_have_a_robot():
61+
"""Every ``libero_pick_*`` task is a "pick up X and place in basket" task and
62+
therefore MUST declare a robot arm. Previously 9 of 10 omitted
63+
``robots=["franka"]`` (only butter had it), so the scenario instantiated with
64+
an empty robot list — a robotless pick task can never succeed and eval scores
65+
a silent 0%. This pins every sibling to declare a robot.
66+
"""
67+
import importlib
68+
69+
pick_files = sorted(_LIBERO.glob("libero_pick_*.py"))
70+
assert pick_files, "no libero_pick_* task files found"
71+
missing = []
72+
for f in pick_files:
73+
mod = importlib.import_module(f"roboverse_pack.tasks.libero.{f.stem}")
74+
# the task class defines a class-level ScenarioCfg
75+
for obj in vars(mod).values():
76+
scen = getattr(obj, "scenario", None)
77+
if scen is not None and hasattr(scen, "robots"):
78+
if not scen.robots:
79+
missing.append(f.stem)
80+
break
81+
assert not missing, f"libero_pick tasks with no robot (robotless pick can never succeed): {missing}"

0 commit comments

Comments
 (0)