Upstream: https://github.com/pollen-robotics/microduck_rl Upstream-Commit: d424a0c899f6b33cbd3daeb279913134349c0b63 Upstream-Branch: develop
106 lines
4.4 KiB
Python
106 lines
4.4 KiB
Python
from mjlab_microduck.tasks.microduck_roller_slope_env_cfg import (
|
|
make_microduck_roller_slope_env_cfg,
|
|
)
|
|
from mjlab_microduck.tasks.slope_terrain import FlatRampTerrainCfg
|
|
|
|
|
|
def test_terrain_is_flat_ramp_generator():
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert cfg.scene.terrain.terrain_type == "generator"
|
|
gen = cfg.scene.terrain.terrain_generator
|
|
assert gen is not None and gen.curriculum is True
|
|
assert any(isinstance(st, FlatRampTerrainCfg) for st in gen.sub_terrains.values())
|
|
|
|
|
|
def test_command_is_neutralised():
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
cmd = cfg.commands["twist"]
|
|
assert cmd.rel_standing_envs == 1.0
|
|
assert cmd.rel_heading_envs == 0.0
|
|
assert cmd.ranges.lin_vel_x == (0.0, 0.0)
|
|
assert cmd.ranges.lin_vel_y == (0.0, 0.0)
|
|
if getattr(cmd.ranges, "ang_vel_z", None) is not None:
|
|
assert cmd.ranges.ang_vel_z == (0.0, 0.0)
|
|
|
|
|
|
def test_rolling_entry_no_base_push():
|
|
# élan donné en ROULEMENT (reset_rolling_entry), pas en poussée de base
|
|
# (base seule + roues immobiles = à-coup de patinage). Donc reset_base ne
|
|
# met aucune vitesse de base.
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert cfg.events["reset_base"].params["velocity_range"] == {}
|
|
assert "reset_rolling_entry" in cfg.events
|
|
lo, hi = cfg.events["reset_rolling_entry"].params["speed_range"]
|
|
assert 0.0 < lo <= hi <= 0.6
|
|
|
|
|
|
def test_has_heading_hold_reward():
|
|
# aller droit : maintien du yaw de spawn
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert "heading_hold" in cfg.rewards
|
|
assert cfg.rewards["heading_hold"].weight > 0.0
|
|
|
|
|
|
def test_balance_rewards_no_fixed_pose():
|
|
# équilibre libre : upright/alive/glisse présents, mais PAS de pose fixe
|
|
# imposée (il doit pouvoir bouger son centre de gravité pour tenir la pente).
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
for name in ("upright", "alive", "feet_flat", "wheel_glide", "neck_joint_pos_l2"):
|
|
assert name in cfg.rewards
|
|
assert "standing_pose" not in cfg.rewards
|
|
assert "standing_pose_l1" not in cfg.rewards
|
|
|
|
|
|
def test_has_wheel_glide_reward_not_base_speed():
|
|
# "se laisser glisser" = rouler (roues), pas récompenser la vitesse de base
|
|
# (qu'il atteignait en courant). wheel_glide présent, descent_speed absent.
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert "wheel_glide" in cfg.rewards
|
|
assert cfg.rewards["wheel_glide"].weight > 0.0
|
|
assert "descent_speed" not in cfg.rewards
|
|
|
|
|
|
def test_no_roller_skating_rewards_survive():
|
|
# les rewards de PATINAGE du roller ne doivent pas survivre (heading_hold est
|
|
# ré-ajouté volontairement pour aller droit, donc pas dans cette liste).
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
for name in ("wheel_speed", "braking", "skating_air_time", "glide", "forward_lean"):
|
|
assert name not in cfg.rewards
|
|
|
|
|
|
def test_spawn_yaw_faces_downhill():
|
|
# yaw fixe à 0 : toujours face au bas de la pente (+x), pas le -pi/+pi hérité
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert cfg.events["reset_base"].params["pose_range"]["yaw"] == (0.0, 0.0)
|
|
|
|
|
|
def test_void_termination_present_no_edge_termination():
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert "fell_into_void" in cfg.terminations
|
|
assert "fell_over" in cfg.terminations
|
|
# plus de terminaison « bord de terrain » (remplacée par le plat de sortie)
|
|
assert "reached_bottom" not in cfg.terminations
|
|
assert "out_of_terrain_bounds" not in cfg.terminations
|
|
|
|
|
|
def test_obs_nan_policy_sanitize():
|
|
# obs assainies : un NaN de contact rare ne doit pas tuer l'entraînement
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
assert cfg.observations["actor"].nan_policy == "sanitize"
|
|
assert cfg.observations["critic"].nan_policy == "sanitize"
|
|
|
|
|
|
def test_curriculum_present_and_starts_gentle():
|
|
# curriculum doux->raide : démarre sur la rampe la plus douce, promotion active
|
|
cfg = make_microduck_roller_slope_env_cfg() # play=False (entraînement)
|
|
assert "terrain_levels" in cfg.curriculum
|
|
assert cfg.scene.terrain.max_init_terrain_level == 0
|
|
|
|
|
|
def test_terrain_tile_fits_geometry():
|
|
# la tuile doit contenir plat + rampe_max + sortie
|
|
cfg = make_microduck_roller_slope_env_cfg()
|
|
gen = cfg.scene.terrain.terrain_generator
|
|
st = next(iter(gen.sub_terrains.values()))
|
|
assert st.flat_length + st.ramp_length_range[1] + st.runout_length <= gen.size[0]
|