Some checks failed
nightly / Test against latest dependencies (py3.10) (push) Has been cancelled
nightly / Test against latest dependencies (py3.13) (push) Has been cancelled
tests / tests (3.13, locked) (push) Has been cancelled
tests / tests (3.13, unlocked) (push) Has been cancelled
tests / pyright (3.10) (push) Has been cancelled
tests / lint-format (push) Has been cancelled
tests / tests (3.10, locked) (push) Has been cancelled
tests / tests (3.11, locked) (push) Has been cancelled
tests / tests (3.12, locked) (push) Has been cancelled
tests / pyright (3.11) (push) Has been cancelled
tests / pyright (3.12) (push) Has been cancelled
tests / pyright (3.13) (push) Has been cancelled
tests / ty-check (3.10) (push) Has been cancelled
tests / ty-check (3.11) (push) Has been cancelled
tests / ty-check (3.12) (push) Has been cancelled
tests / ty-check (3.13) (push) Has been cancelled
tests / stubs (push) Has been cancelled
tests / smoke-test (push) Has been cancelled
Docker / check_paths (push) Has been cancelled
docs / build (push) Has been cancelled
Docker / build (push) Has been cancelled
Upstream: https://github.com/michaelgillett/mjlab Upstream-Commit: c19f713c415a699a79d71cd96aa13c3104a05047 Upstream-Branch: main
200 lines
6.9 KiB
Python
200 lines
6.9 KiB
Python
"""Tests specific to velocity tasks."""
|
|
|
|
import pytest
|
|
|
|
from mjlab.asset_zoo.robots import G1_ACTION_SCALE, GO1_ACTION_SCALE
|
|
from mjlab.envs.mdp.actions import JointPositionActionCfg
|
|
from mjlab.tasks.registry import list_tasks, load_env_cfg
|
|
from mjlab.tasks.velocity.mdp import UniformVelocityCommandCfg
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def velocity_task_ids() -> list[str]:
|
|
"""Get all velocity task IDs."""
|
|
return [t for t in list_tasks() if "Velocity" in t]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def g1_velocity_task_ids(velocity_task_ids: list[str]) -> list[str]:
|
|
"""Get all G1 velocity task IDs."""
|
|
return [t for t in velocity_task_ids if "G1" in t]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def go1_velocity_task_ids(velocity_task_ids: list[str]) -> list[str]:
|
|
"""Get all Go1 velocity task IDs."""
|
|
return [t for t in velocity_task_ids if "Go1" in t]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def rough_velocity_task_ids(velocity_task_ids: list[str]) -> list[str]:
|
|
"""Get all rough terrain velocity task IDs."""
|
|
return [t for t in velocity_task_ids if "Rough" in t]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def flat_velocity_task_ids(velocity_task_ids: list[str]) -> list[str]:
|
|
"""Get all flat terrain velocity task IDs."""
|
|
return [t for t in velocity_task_ids if "Flat" in t]
|
|
|
|
|
|
def test_velocity_tasks_have_twist_command(velocity_task_ids: list[str]) -> None:
|
|
"""All velocity tasks should have a velocity command."""
|
|
for task_id in velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert "twist" in cfg.commands, f"Task {task_id} missing 'twist' command"
|
|
|
|
twist_cmd = cfg.commands["twist"]
|
|
assert isinstance(twist_cmd, UniformVelocityCommandCfg), (
|
|
f"Task {task_id} twist command is not UniformVelocityCommandCfg"
|
|
)
|
|
|
|
|
|
def test_g1_velocity_has_required_sensors(g1_velocity_task_ids: list[str]) -> None:
|
|
"""G1 velocity tasks should have feet/ground and self collision sensors."""
|
|
for task_id in g1_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert cfg.scene.sensors is not None, f"Task {task_id} has no sensors"
|
|
|
|
sensor_names = {s.name for s in cfg.scene.sensors}
|
|
assert "feet_ground_contact" in sensor_names, (
|
|
f"Task {task_id} missing feet_ground_contact sensor"
|
|
)
|
|
assert "self_collision" in sensor_names, (
|
|
f"Task {task_id} missing self_collision sensor"
|
|
)
|
|
|
|
|
|
def test_go1_velocity_has_required_sensors(go1_velocity_task_ids: list[str]) -> None:
|
|
"""Go1 velocity tasks should have feet/ground and collision sensors."""
|
|
for task_id in go1_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert cfg.scene.sensors is not None, f"Task {task_id} has no sensors"
|
|
|
|
sensor_names = {s.name for s in cfg.scene.sensors}
|
|
assert "feet_ground_contact" in sensor_names, (
|
|
f"Task {task_id} missing feet_ground_contact sensor"
|
|
)
|
|
if "Rough" in task_id:
|
|
for name in (
|
|
"self_collision",
|
|
"thigh_ground_touch",
|
|
"shank_ground_touch",
|
|
"trunk_ground_touch",
|
|
):
|
|
assert name in sensor_names, f"Task {task_id} missing {name} sensor"
|
|
|
|
|
|
def test_flat_velocity_tasks_have_plane_terrain(
|
|
flat_velocity_task_ids: list[str],
|
|
) -> None:
|
|
"""Flat velocity tasks should have terrain_type='plane' and no terrain_generator."""
|
|
for task_id in flat_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert cfg.scene.terrain is not None, f"Task {task_id} has no terrain config"
|
|
assert cfg.scene.terrain.terrain_type == "plane", (
|
|
f"Task {task_id} terrain_type={cfg.scene.terrain.terrain_type}, expected 'plane'"
|
|
)
|
|
assert cfg.scene.terrain.terrain_generator is None, (
|
|
f"Task {task_id} has terrain_generator, expected None for flat terrain"
|
|
)
|
|
|
|
|
|
def test_rough_velocity_tasks_have_generator_terrain(
|
|
rough_velocity_task_ids: list[str],
|
|
) -> None:
|
|
"""Rough velocity tasks should have generator terrain."""
|
|
for task_id in rough_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert cfg.scene.terrain is not None, f"Task {task_id} has no terrain config"
|
|
assert cfg.scene.terrain.terrain_type == "generator", (
|
|
f"Task {task_id} terrain_type={cfg.scene.terrain.terrain_type}, "
|
|
"expected 'generator'"
|
|
)
|
|
assert cfg.scene.terrain.terrain_generator is not None, (
|
|
f"Task {task_id} has no terrain_generator, expected one for rough terrain"
|
|
)
|
|
|
|
|
|
def test_rough_velocity_training_has_curriculum_enabled() -> None:
|
|
"""Rough velocity training tasks should have terrain curriculum enabled."""
|
|
rough_training_tasks = [
|
|
"Mjlab-Velocity-Rough-Unitree-G1",
|
|
"Mjlab-Velocity-Rough-Unitree-Go1",
|
|
]
|
|
|
|
for task_id in rough_training_tasks:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert cfg.scene.terrain is not None, f"Task {task_id} has no terrain config"
|
|
assert cfg.scene.terrain.terrain_generator is not None, (
|
|
f"Task {task_id} has no terrain_generator"
|
|
)
|
|
assert cfg.scene.terrain.terrain_generator.curriculum is True, (
|
|
f"Task {task_id} curriculum={cfg.scene.terrain.terrain_generator.curriculum}, "
|
|
"expected True"
|
|
)
|
|
|
|
|
|
def test_rough_velocity_play_has_curriculum_disabled() -> None:
|
|
"""Rough velocity play tasks should have terrain curriculum disabled."""
|
|
rough_training_tasks = [
|
|
"Mjlab-Velocity-Rough-Unitree-G1",
|
|
"Mjlab-Velocity-Rough-Unitree-Go1",
|
|
]
|
|
|
|
for task_id in rough_training_tasks:
|
|
cfg = load_env_cfg(task_id, play=True)
|
|
|
|
assert cfg.scene.terrain is not None, (
|
|
f"Task {task_id} (play mode) has no terrain config"
|
|
)
|
|
assert cfg.scene.terrain.terrain_generator is not None, (
|
|
f"Task {task_id} (play mode) has no terrain_generator"
|
|
)
|
|
assert cfg.scene.terrain.terrain_generator.curriculum is False, (
|
|
f"Task {task_id} (play mode) curriculum={cfg.scene.terrain.terrain_generator.curriculum}, "
|
|
"expected False"
|
|
)
|
|
|
|
|
|
def test_g1_velocity_has_correct_action_scale(g1_velocity_task_ids: list[str]) -> None:
|
|
"""G1 velocity tasks should use G1_ACTION_SCALE."""
|
|
for task_id in g1_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert "joint_pos" in cfg.actions, f"Task {task_id} missing 'joint_pos' action"
|
|
|
|
joint_pos_action = cfg.actions["joint_pos"]
|
|
assert isinstance(joint_pos_action, JointPositionActionCfg), (
|
|
f"Task {task_id} joint_pos action is not JointPositionActionCfg"
|
|
)
|
|
|
|
assert joint_pos_action.scale == G1_ACTION_SCALE, (
|
|
f"Task {task_id} action scale mismatch, expected G1_ACTION_SCALE"
|
|
)
|
|
|
|
|
|
def test_go1_velocity_has_correct_action_scale(
|
|
go1_velocity_task_ids: list[str],
|
|
) -> None:
|
|
"""Go1 velocity tasks should use GO1_ACTION_SCALE."""
|
|
for task_id in go1_velocity_task_ids:
|
|
cfg = load_env_cfg(task_id)
|
|
|
|
assert "joint_pos" in cfg.actions, f"Task {task_id} missing 'joint_pos' action"
|
|
|
|
joint_pos_action = cfg.actions["joint_pos"]
|
|
assert isinstance(joint_pos_action, JointPositionActionCfg), (
|
|
f"Task {task_id} joint_pos action is not JointPositionActionCfg"
|
|
)
|
|
|
|
assert joint_pos_action.scale == GO1_ACTION_SCALE, (
|
|
f"Task {task_id} action scale mismatch, expected GO1_ACTION_SCALE"
|
|
)
|