diff --git a/docs/sphinx/source/api_reference/tasks/index.md b/docs/sphinx/source/api_reference/tasks/index.md index 1b2a6fa2b..0af0ab05e 100644 --- a/docs/sphinx/source/api_reference/tasks/index.md +++ b/docs/sphinx/source/api_reference/tasks/index.md @@ -2,12 +2,13 @@ Concrete RL tasks split by family: -- **locomotion** — A2, Go1, Go2, Go2w, Go2 + Airbot, and Unitree G1 +- **locomotion** — Go2 and Unitree G1 reference owners - **manipulation** — Allegro in-hand cube and Stewart balance - **motion_tracking** — G1 and X2 whole-body motion tracking Every task is registered into the task `Registry` so it can be selected via `uv run train --algo --task --sim `. +Unitree production variants are documented in `unitree_rl_unilab`. ```{toctree} :maxdepth: 2 diff --git a/docs/sphinx/source/api_reference/tasks/locomotion.md b/docs/sphinx/source/api_reference/tasks/locomotion.md index 8178b983b..bfd233340 100644 --- a/docs/sphinx/source/api_reference/tasks/locomotion.md +++ b/docs/sphinx/source/api_reference/tasks/locomotion.md @@ -6,10 +6,7 @@ :template: autosummary/module.rst :recursive: - unilab.tasks.locomotion.a2 unilab.tasks.locomotion.common unilab.tasks.locomotion.g1 - unilab.tasks.locomotion.go1 unilab.tasks.locomotion.go2 - unilab.tasks.locomotion.go2w ``` diff --git a/docs/sphinx/source/en/0-index.md b/docs/sphinx/source/en/0-index.md index 5d52c8084..6a0a38b68 100644 --- a/docs/sphinx/source/en/0-index.md +++ b/docs/sphinx/source/en/0-index.md @@ -153,12 +153,13 @@ committed benchmark manifest or separate recommendation metadata. | Robot / task family | Algorithm paths with repo evidence | Backend evidence | | --- | --- | --- | -| Go1 joystick | PPO, APPO, TD3 | PPO has tested MuJoCo and Motrix rows. APPO has tested MuJoCo rows and Motrix registered rows. TD3 has a Motrix owner YAML for `go1_joystick_flat`. | | Go2 joystick | PPO, FlashSAC, TD3 | PPO has tested MuJoCo and Motrix rows. FlashSAC has MuJoCo owner YAMLs for `go2_joystick_flat`; TD3 has a Motrix owner YAML for `go2_joystick_flat`. | -| Go2W joystick | PPO | PPO owner YAMLs exist for MuJoCo and Motrix flat/rough variants under `src/unilab/conf/ppo/task/go2w_joystick_*`. | -| G1 locomotion / tracking | PPO, APPO, SAC, TD3 | PPO, APPO, and SAC include committed MuJoCo and Motrix owner YAMLs for G1 tasks; TD3 has a `g1_walk_flat` MuJoCo owner. | +| G1 reference locomotion / tracking | PPO, APPO, SAC, TD3 | PPO, APPO, and SAC include committed MuJoCo and Motrix owner YAMLs for retained G1 tasks; TD3 has a `g1_walk_flat` MuJoCo owner. | | Allegro in-hand | PPO, APPO | PPO and APPO have committed MuJoCo and Motrix owner YAMLs for Allegro in-hand tasks. | +Unitree production task families are maintained in `unitree_rl_unilab` and are +not counted as core repository evidence. + ```{toctree} :hidden: :caption: Documentation diff --git a/docs/sphinx/source/en/2-user_guide/3-backends/0-index.md b/docs/sphinx/source/en/2-user_guide/3-backends/0-index.md index f6abea40e..664f12d50 100644 --- a/docs/sphinx/source/en/2-user_guide/3-backends/0-index.md +++ b/docs/sphinx/source/en/2-user_guide/3-backends/0-index.md @@ -63,8 +63,8 @@ The support matrix is generated from registry, owner YAML, and tests; use it as the current evidence source: {doc}`../../5-reference/5-support_matrix`. ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco -uv run train --algo ppo --task go1_joystick_flat --sim motrix +uv run train --algo ppo --task go2_joystick_flat --sim mujoco +uv run train --algo ppo --task go2_joystick_flat --sim motrix uv run train --algo ppo --task g1_walk_flat --sim isaacsim ``` @@ -92,8 +92,8 @@ The selected owner YAML sets `training.sim_backend` as an identity field. - `--render-mode none` disables playback. ```bash -uv run eval --algo ppo --task go1_joystick_flat --sim mujoco --load-run -1 -uv run eval --algo ppo --task go1_joystick_flat --sim motrix --load-run -1 \ +uv run eval --algo ppo --task go2_joystick_flat --sim mujoco --load-run -1 +uv run eval --algo ppo --task go2_joystick_flat --sim motrix --load-run -1 \ --render-mode record ``` diff --git a/docs/sphinx/source/en/2-user_guide/3-backends/1-mujoco.md b/docs/sphinx/source/en/2-user_guide/3-backends/1-mujoco.md index 3ac63f7e8..d94e01c9f 100644 --- a/docs/sphinx/source/en/2-user_guide/3-backends/1-mujoco.md +++ b/docs/sphinx/source/en/2-user_guide/3-backends/1-mujoco.md @@ -19,7 +19,7 @@ default version pinned by the committed `uv.lock`) plus the ```bash uv run train --algo ppo --task go2_joystick_flat --sim mujoco -uv run train --algo appo --task go1_joystick_flat --sim mujoco training.no_play=true +uv run train --algo appo --task go2_joystick_flat --sim mujoco training.no_play=true uv run train --algo sac --task g1_walk_flat --sim mujoco ``` diff --git a/docs/sphinx/source/en/2-user_guide/3-backends/3-isaacgym.md b/docs/sphinx/source/en/2-user_guide/3-backends/3-isaacgym.md index 69af94326..18f030247 100644 --- a/docs/sphinx/source/en/2-user_guide/3-backends/3-isaacgym.md +++ b/docs/sphinx/source/en/2-user_guide/3-backends/3-isaacgym.md @@ -97,7 +97,7 @@ export UNILAB_BENCHMARK_HSGYM_LIB="$UNILAB_BENCHMARK_HOLOSOMA_DEPS/miniconda3/en Validate the environment with the benchmark script. The benchmark loads robot models from URDF, so you must provide your own URDF model tree -(`go1_description/`, `g1_description/`, ...) and point `--models-root` or +(`go2_description/`, `g1_description/`, ...) and point `--models-root` or `UNILAB_BENCHMARK_MODELS_ROOT` at its root directory: ```bash diff --git a/docs/sphinx/source/en/2-user_guide/4-tasks/0-index.md b/docs/sphinx/source/en/2-user_guide/4-tasks/0-index.md index a211f93e8..563545958 100644 --- a/docs/sphinx/source/en/2-user_guide/4-tasks/0-index.md +++ b/docs/sphinx/source/en/2-user_guide/4-tasks/0-index.md @@ -9,13 +9,13 @@ owner YAMLs under `src/unilab/conf/` and summarized in {doc}`../../5-reference/5 :::{grid-item-card} Locomotion :link: 1-locomotion :link-type: doc -Go1, Go2, Go2W, and G1 walking owners. +Go2 and G1 core reference owners; Unitree production variants are downstream. ::: :::{grid-item-card} Motion tracking :link: 2-motion_tracking :link-type: doc -G1 motion tracking, flips, climbs, wall flips, and box tracking. +G1/X2 motion-tracking reference profiles. ::: :::{grid-item-card} Manipulation diff --git a/docs/sphinx/source/en/2-user_guide/4-tasks/1-locomotion.md b/docs/sphinx/source/en/2-user_guide/4-tasks/1-locomotion.md index 578a54d8a..e76ab2c67 100644 --- a/docs/sphinx/source/en/2-user_guide/4-tasks/1-locomotion.md +++ b/docs/sphinx/source/en/2-user_guide/4-tasks/1-locomotion.md @@ -1,117 +1,28 @@ # Locomotion -Locomotion tasks are registered in `src/unilab/tasks/locomotion/` and -`src/unilab/tasks/motion_tracking/`. The available owner YAMLs under `src/unilab/conf/` -define which algorithm and backend combinations are runnable. +UniLab keeps a small reference/conformance locomotion set and the shared +Manager-Based runtime. Unitree production variants live in the downstream +`unitree_rl_unilab` package. -## Families +## Core reference tasks -- Go1: `go1_joystick_flat`, `go1_joystick_rough` -- Go2: `go2_joystick_flat`, `go2_joystick_rough`, `go2_footstand` -- Go2W: `go2w_joystick_flat`, `go2w_joystick_rough` +- Go2 joystick: `go2_joystick_flat` - G1 walking: `g1_walk_flat`, `g1_walk_rough` -- G1 motion tracking: `g1_motion_tracking`, `g1_flip_tracking`, - `g1_wall_flip_tracking`, `g1_climb_tracking`, `g1_box_tracking` - -## Examples +- G1 motion tracking reference profiles: see {doc}`2-motion_tracking` ```bash uv run train --algo ppo --task go2_joystick_flat --sim mujoco -uv run train --algo ppo --task go2_joystick_rough --sim motrix training.no_play=true -uv run train --algo ppo --task go2_footstand --sim mujoco training.no_play=true -uv run train --algo appo --task g1_motion_tracking --sim mujoco training.no_play=true +uv run train --algo ppo --task g1_walk_flat --sim mujoco uv run train --algo sac --task g1_walk_flat --sim mujoco ``` -Check the support matrix for evidence grade by entrypoint, task owner, and +Check the core support matrix for evidence grade by entrypoint, task owner, and backend: {doc}`../../5-reference/5-support_matrix`. -## Go2 FootStand - -`go2_footstand` is the Go2 front-feet-stand task. Its PPO owner YAMLs -register MuJoCo, Motrix, and Drake; the SAC owner currently targets Drake. - -- Canonical PPO task config: `src/unilab/conf/ppo/task/go2_footstand/base.yaml` -- Backend owners: `src/unilab/conf/ppo/task/go2_footstand/{mujoco,motrix,drake}.yaml` -- Registered env: `Go2FootStand` (MuJoCo, Motrix, and Drake) -- Implementation: `src/unilab/tasks/locomotion/go2/footstand.py` - (task-owned NumPy manager terms on the generic Manager-Based runtime) -- Go2 model XML: `src/unilab/assets/robots/go2/go2.xml` - -```bash -uv run train --algo ppo --task go2_footstand --sim mujoco training.no_play=true -uv run eval --algo ppo --task go2_footstand --sim mujoco --load-run -1 -``` - -### Teacher-Student Pipeline - -The full FootStand recipe is a three-stage teacher-student pipeline; the shipped -`go2_footstand` config corresponds to stage 1 (the teacher PPO entry point): - -1. **Teacher PPO (privileged obs).** The teacher uses privileged observations - (e.g. base linear velocity) that are available in simulation but should not be - relied on directly during real-robot deployment. A power curriculum first lets - the policy learn the front-feet stand under a loose power budget (~400 W), then - gradually tightens it toward ~200 W, so early exploration is not crushed by a - low power limit and the final policy stays near a deployable energy envelope. -2. **Distillation to a deployable student.** The trained teacher is distilled into - a student policy whose inputs keep only on-robot observations (no privileged - information). The goal is to reproduce the teacher's behavior without privileged - obs. -3. **Student RL fine-tune.** The distilled student is fine-tuned with a combined - objective: a reward term similar to the teacher's, plus a teacher-regularization - term that keeps the student from drifting away from the teacher too quickly. - This preserves the stable motion while letting the student adapt to its own - observation inputs and deployment constraints. - -### Observation Layout - -The `Go2FootStand` policy (actor) observation uses 15 history frames of 45 dims -each (`FRAME_OBS_DIM = 45`): - -```text -linvel(3) + gyro(3) + gravity(3) + joint_position_delta(12) + joint_velocity(12) + last_action(12) -``` - -So the policy observation is `45 * 15 = 675`. The value (critic) observation -appends the current-step privileged tail (`PRIVILEGED_OBS_DIM = 49`) -after that history: +## Unitree ecosystem tasks -```text -gyro(3) + accelerometer(3) + linvel(3) + global_angvel(3) + dof_pos(12) + dof_vel(12) + torques(12) + height(1) -``` - -The value observation is therefore `675 + 49 = 724`. - -### Rewards And Terminations - -Defaults come from `src/unilab/conf/ppo/task/go2_footstand/base.yaml`; backend leaves only -override backend-specific terms and tuning. The reward scales -include stand `height`, `orientation`, `rear_feet_contact`, target front-leg angle -(`tar`), `action_rate`, `dof_pos_limits`, `front_leg_motion`, `rear_leg_symmetry`, -`knee_clearance`, `upright_stability`, `stay_still`, `pose`, plus `energy` and -`dof_acc` penalties; `termination` and `penalty_contact` drive the termination / -penalty paths (front-leg / front-body contact, low height, bad orientation, and a -high-energy cutoff in the `footstand` termination term). - -### Tuning Keys - -- `env.observations.policy.terms.frame.history_length`: policy history length - (default `15`). -- `env.terminations.footstand.params.energy_threshold`: high-energy cutoff - (default `200.0`). -- `env.events`: reset and domain-randomization terms. Backend owners explicitly - set unsupported model-field terms to `null`. -- `reward.footstand.params.scales`: stand, contact, motion, and energy weights. - -### Near-Risk Validation - -```bash -uv run pytest tests/envs/locomotion/test_go2_footstand.py tests/config/test_locomotion_params.py -q -``` - -If the Go2 XML changed, at minimum confirm MuJoCo can load the model: - -```bash -uv run python -c "import mujoco; m=mujoco.MjModel.from_xml_path('src/unilab/assets/robots/go2/go2.xml'); print(m.nq, m.nv, m.nu, m.nsensor)" -``` +Unitree production variants are maintained in +[unitree_rl_unilab](https://github.com/unilabsim/unitree_rl_unilab), which +depends only on the published UniLab/UniRL distributions. Its support evidence +and task documentation are owned by that repository and are not part of +UniLab's core support matrix. diff --git a/docs/sphinx/source/en/2-user_guide/4-tasks/2-motion_tracking.md b/docs/sphinx/source/en/2-user_guide/4-tasks/2-motion_tracking.md index 5bc28206c..3c8c5f236 100644 --- a/docs/sphinx/source/en/2-user_guide/4-tasks/2-motion_tracking.md +++ b/docs/sphinx/source/en/2-user_guide/4-tasks/2-motion_tracking.md @@ -21,28 +21,25 @@ configuration entry point; the selected owner is materialized into the shared | --- | --- | --- | --- | | `g1_motion_tracking` | `G1MotionTracking` | `dance1_subject2_part.npz` | `src/unilab/conf/ppo/task/g1_motion_tracking/`, `src/unilab/conf/appo/task/g1_motion_tracking/` | | `g1_flip_tracking` | `G1FlipTracking` | `flip_360_001__A304.npz` | `src/unilab/conf/ppo/task/g1_flip_tracking/`, `src/unilab/conf/appo/task/g1_flip_tracking/` | -| `g1_wall_flip_tracking` | `G1WallFlipTracking` | `flip_from_wall_104__A304.npz` | `src/unilab/conf/ppo/task/g1_wall_flip_tracking/`, `src/unilab/conf/appo/task/g1_wall_flip_tracking/` | | `x2_wall_flip_tracking` | `X2WallFlipTracking` | `tictacflip_6-3_g1format.npz` | `src/unilab/conf/ppo/task/x2_wall_flip_tracking/` | -| `g1_climb_tracking` | `G1ClimbTracking` | `climb_20_z_scale_1.0.npz` | `src/unilab/conf/ppo/task/g1_climb_tracking/`, `src/unilab/conf/appo/task/g1_climb_tracking/` | | `g1_box_tracking` | `G1BoxTracking` | `sub3_largebox_003_boxconverted.npz` | `src/unilab/conf/ppo/task/g1_box_tracking/` | | `g1_wbt_obs` | `G1WBTObs` | `dance1_subject2_part.npz` | `src/unilab/conf/sac/task/g1_wbt_obs/mujoco.yaml` | -The 23-DoF task-owner directories select their matching 23-DoF scene, motion, -entity, and action declarations. Profile differences remain in Hydra. The G1 -identities use the shared manager factory; X2 adds only a cold-path mesh resolver -before delegating to that factory. +Profile differences remain in Hydra. The retained G1 identities use the shared +manager factory; X2 adds only a cold-path mesh resolver before delegating to +that factory. Unitree production wall-flip, climb, deploy, and 23-DoF motion +profiles now live in `unitree_rl_unilab`. ## PPO And APPO PPO owner iteration budgets (the `--sim mujoco` owner YAMLs): `g1_motion_tracking` -runs `algo.max_iterations=15000`; `g1_flip_tracking` and `g1_wall_flip_tracking` -run `20000`; `x2_wall_flip_tracking` runs `9500`. (The Motrix owner YAML for +runs `algo.max_iterations=15000`; `g1_flip_tracking` runs `20000`; and +`x2_wall_flip_tracking` runs `9500`. (The Motrix owner YAML for `g1_flip_tracking` raises this to `30000`.) ```bash uv run train --algo ppo --task g1_motion_tracking --sim mujoco uv run train --algo ppo --task g1_flip_tracking --sim mujoco -uv run train --algo ppo --task g1_wall_flip_tracking --sim mujoco uv run train --algo ppo --task x2_wall_flip_tracking --sim mujoco uv run train --algo ppo --task g1_motion_tracking --sim motrix uv run train --algo appo --task g1_motion_tracking --sim mujoco training.no_play=true diff --git a/docs/sphinx/source/en/2-user_guide/5-domain_randomization/0-index.md b/docs/sphinx/source/en/2-user_guide/5-domain_randomization/0-index.md index 68776d49c..c4f674973 100644 --- a/docs/sphinx/source/en/2-user_guide/5-domain_randomization/0-index.md +++ b/docs/sphinx/source/en/2-user_guide/5-domain_randomization/0-index.md @@ -5,7 +5,7 @@ This page only describes the current domain randomization status of registered t Manager-Based event terms are the only DR declaration path: -- **Manager-Based (Compatible) tasks**: reset / interval randomization is declared through Hydra `events:` manager terms in the owner YAML; reset-lifecycle events sample at reset, interval-lifecycle events perturb between steps. See the `events:` block of `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` for an example. +- **Manager-Based (Compatible) tasks**: reset / interval randomization is declared through Hydra `events:` manager terms in the owner YAML; reset-lifecycle events sample at reset, interval-lifecycle events perturb between steps. See the `events:` block of `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` for an example. The Manager-Based lifecycle is: @@ -31,7 +31,6 @@ These three paths correspond to three lifecycle classes: | Task | Declaration path | Structured form? | reset form | interval form | Code | | --- | --- | --- | --- | --- | --- | -| `Go1JoystickFlat` | Hydra `events:` terms | Yes: owner YAML declares reset/interval events | root-state reset + base mass/COM + `pd_gains` | `push_by_setting_velocity` event | `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` | | `Go2JoystickFlat` | Hydra `events:` terms | Yes: owner YAML declares reset events | root-state reset + `pd_gains` kp/kd | none | `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` | | `G1WalkFlat` | Hydra `events:` terms | Yes: Hydra `EventTermCfg` + Manager-Based reset terms | root-state reset + kp/kd via `pd_gains` | none | `g1/manager_terms.py` | | `G1WalkRough` | Hydra `events:` terms | Yes: same Manager-Based event terms as `G1WalkFlat` | root-state reset + kp/kd via `pd_gains` | none | `g1/manager_terms.py` | @@ -44,7 +43,6 @@ These three paths correspond to three lifecycle classes: | Task | Currently implemented reset domain randomization | Currently implemented interval domain randomization | Default state | | --- | --- | --- | --- | -| `Go1JoystickFlat` | base xy/yaw and base qvel via `reset_root_state_uniform`; command sampling (`UniformVelocityCommandCfg`); base mass via `randomize_rigid_body_mass`; base COM via `randomize_rigid_body_com`; kp/kd via `pd_gains` | `push_by_setting_velocity` interval event | all listed event terms are declared and enabled by default in `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` | | `Go2JoystickFlat` | base xy/yaw and base qvel via `reset_root_state_uniform`; command sampling; kp/kd via `pd_gains` | none | event terms declared and enabled by default in `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` | | `G1WalkFlat` | base xy/yaw and base qvel via `reset_root_state_uniform`; command sampling with a planar dead zone; `gait_phase` sampling; kp/kd randomization via `pd_gains` | none | kp/kd enabled on mujoco owners by default; disabled on motrix/mjwarp owners | | `G1WalkRough` | Same as `G1WalkFlat` (shared owner bases, rough scene) | none | Same defaults as `G1WalkFlat` | @@ -78,11 +76,11 @@ early task unlearnable. ## Interval push Usage Manager-Based tasks configure interval push through the `env.events.push_robot` -term. For example, `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` uses -`push_by_setting_velocity` with a 15-second interval and per-axis velocity ranges. +term. For example, the retained `g1_wbt_obs` owner uses +`push_by_setting_velocity` with interval and per-axis velocity ranges. ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco \ +uv run train --algo sac --task g1_wbt_obs --sim mujoco \ 'env.events.push_robot.interval_range_s=[10.0,10.0]' ``` diff --git a/docs/sphinx/source/en/2-user_guide/5-domain_randomization/1-configuration.md b/docs/sphinx/source/en/2-user_guide/5-domain_randomization/1-configuration.md index 4768f342d..69c19d27f 100644 --- a/docs/sphinx/source/en/2-user_guide/5-domain_randomization/1-configuration.md +++ b/docs/sphinx/source/en/2-user_guide/5-domain_randomization/1-configuration.md @@ -24,19 +24,18 @@ term that calls `randomize_physics_scene_gravity`. ## Interval Push Manager-Based tasks configure interval push through the `env.events.push_robot` -term. For example, `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` uses -`push_by_setting_velocity` with a 15-second interval and per-axis velocity ranges. +term. For example, the retained `g1_wbt_obs` owner uses +`push_by_setting_velocity` with an interval and per-axis velocity ranges. ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco \ +uv run train --algo sac --task g1_wbt_obs --sim mujoco \ 'env.events.push_robot.interval_range_s=[10.0,10.0]' ``` ## Owner-Local Defaults Keep ranges in the task owner YAML when they are part of the task contract. For -example, the rough quadruped family's base mass, center-of-mass, kp/kd, and push -randomization are declared as event terms in the shared base -`src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`. +example, a rough-task family can declare base mass, center-of-mass, kp/kd, and +push randomization as event terms in its shared owner base. For the full current inventory, see {doc}`0-index`. diff --git a/docs/sphinx/source/en/2-user_guide/6-terrain/1-procedural.md b/docs/sphinx/source/en/2-user_guide/6-terrain/1-procedural.md index 151cba5c7..ec3b2bf79 100644 --- a/docs/sphinx/source/en/2-user_guide/6-terrain/1-procedural.md +++ b/docs/sphinx/source/en/2-user_guide/6-terrain/1-procedural.md @@ -1,185 +1,72 @@ # Procedural Terrain +Procedural terrain is a scene-composition capability, not a separate backend +mode. A task owner declares `env.scene.terrain` in Hydra; UniLab validates the +configuration and UniSim's public backend adapters materialize the terrain only +during environment construction. -This page only answers four questions: +## Owner declaration -1. How do I run the rough terrain task that already exists in the current repo? -2. What can and cannot be changed via the Hydra command line? -3. When I want to change the sub-terrain composition, what is the correct entry point? -4. What are the currently known boundaries — not bugs, but constraints? +The core reusable pieces are: -For the underlying contracts (cold-path materialization, registering a new sub-terrain, hfield export), see the source comments in `unisim.backend.mujoco.xml`, `unisim.backend.motrix.scene`, and `unisim.terrain.generator`. +- `unilab.base.scene.SceneCfg` for `terrain` and scene files. +- `unilab.tasks.locomotion.common.rough_manager_terms` for terrain generation, + rough reset, velocity-command, height-scan, and action owner terms. +- `unilab.tasks.locomotion.common.height_scan` for cached height sampling. -## Current Status - -Only one task in the current repo registers and wires up procedural terrain: - -| Task | owner YAML | Backend | Entry Algorithm | Code | -| --- | --- | --- | --- | --- | -| `Go2JoystickRough` | `mujoco.yaml`, `motrix.yaml` | MuJoCo / Motrix | PPO (`train_rsl_rl.py`) | `go2/rough.py` | - -During env construction: - -1. `Go2JoystickRoughCfg` declares a `SceneCfg` whose `model_file` points to `go2.xml`, `fragment_files` brings in the task-level contact sensors and `home` keyframe from `locomotion_task.xml`, and `scene.terrain` declares an hfield named `terrain_hfield` to be generated. -2. The backend scene materializer calls `TerrainGenerator(...)` to produce a backend-agnostic merged height matrix and `terrain_origins`; the terrain generator itself does not depend on MuJoCo or Motrix. -3. The MuJoCo materializer uses `MjSpec.add_hfield(...)` / `worldbody.add_geom(...)` to create the terrain, then uses `MjSpec.attach(...)` to attach the robot spec to the scene, and finally `compile()` produces the `MjModel`. -4. The Motrix materializer uses `motrixsim.msd.World` to create the terrain world, uses `World.attach(...)` to stitch in the robot world and task fragment, and finally `msd.build(...)` produces the `SceneModel`. -5. `go2.xml` is the robot model; `locomotion_task.xml` is the task fragment for rough terrain and contains the contact sensors associated with the terrain `floor` plus the task-level `home` keyframe. -6. The backend instance owns the cold-path scene artifacts until env `close()`; `terrain_origins` is passed back to env via a backend scene attribute, used for spawn / curriculum. - -`step()`, `reset()`, and Manager-Based event terms never read XML or access -asset files; everything terrain-related happens on the cold path. - -## 1. Direct Training - -```bash -# Default single-patch random_rough, critic additionally receives a 17×11 height scan -uv run train --algo ppo --task go2_joystick_rough --sim mujoco -``` - -The Motrix backend uses the same task owner: - -```bash -uv run train --algo ppo --task go2_joystick_rough --sim motrix -``` - -## 2. Overriding Terrain Parameters via Hydra Command Line - -`Go2JoystickRough` explicitly lists a set of override-able fields in `src/unilab/conf/ppo/task/go2_joystick_rough/{mujoco,motrix}.yaml`; these fields allow Hydra struct mode to accept command-line overrides. - -| Field | Purpose | YAML Default | -| --- | --- | --- | -| `env.scene.terrain.generator.seed` | Random seed, `null` means re-randomize each time | `42` | -| `env.scene.terrain.generator.curriculum` | `true`: one column per sub-terrain, difficulty increases along rows; `false`: random sampling by `proportion` | `false` | -| `env.scene.terrain.generator.size` | x/y size of a single terrain patch (meters) | `[8.0, 8.0]` | -| `env.scene.terrain.generator.num_rows` | grid row count (in curriculum mode = number of difficulty levels) | `1` | -| `env.scene.terrain.generator.num_cols` | grid column count (ignored in curriculum mode; column count = `len(sub_terrains)`) | `1` | -| `env.scene.terrain.generator.border_width` | width of the flat border around the grid (meters) | `1.0` | -| `env.scene.terrain.generator.difficulty_range` | difficulty sampling range `[min, max]`, ∈ `[0, 1]` | `[0.0, 1.0]` | -| `env.terrain_scan.enabled` | Whether to concatenate the backend-native height scan to the critic obs | `true` | -| `env.terrain_scan.geom_name` | The hfield geom name sampled by the height scan | `floor` | - -Example: local small-scale smoke + fixed seed + curriculum mode. - -```bash -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ - env.scene.terrain.generator.num_rows=4 \ - env.scene.terrain.generator.num_cols=6 \ - env.scene.terrain.generator.seed=42 \ - env.scene.terrain.generator.curriculum=true \ - algo.num_envs=64 algo.max_iterations=2 training.no_play=true -``` - -Fields not listed in the YAML (e.g. `sub_terrains`) currently **cannot** be overridden from the command line: - -- `sub_terrains` is `dict[str, SubTerrainCfg]`, and `SubTerrainCfg` is an abstract base class; rebuilding subclass types from the command line is not safe. -- The default grids of `terrain_scan.measured_points_x` / `terrain_scan.measured_points_y` are defined by the `Go2JoystickRoughCfg` owner; when the scan layout needs to be changed, adjust it explicitly in the owner cfg and validate `obs_groups_spec` against the critic obs shape. - -## 3. Modifying Sub-terrains - -Sub-terrains are registered in `ALL_TERRAIN_PRESETS` in `unilab.terrains.config`. The 7 sub-terrains mixed by `Go2JoystickRough` by default: - -| Name | Implementation | Description | -| --- | --- | --- | -| `flat` | `HfFlatTerrainCfg` | All-zero heightfield, baseline patch | -| `pyramid_stairs` | `HfPyramidStairsTerrainCfg` | Pyramid-shaped ascending stairs (concentric square rings in the heightfield) | -| `pyramid_stairs_inv` | `HfInvertedPyramidStairsTerrainCfg` | Inverted-pyramid descending stairs | -| `hf_pyramid_slope` | `HfPyramidSlopedTerrainCfg` | Heightfield pyramid slope | -| `hf_pyramid_slope_inv` | `HfPyramidSlopedTerrainCfg(inverted=True)` | Inverted pyramid slope | -| `random_rough` | `HfRandomUniformTerrainCfg` | Random uniform noise heightfield | -| `wave_terrain` | `HfWaveTerrainCfg` | Sine wave heightfield | - -Each has its own difficulty parameters (`step_height_range`, `slope_range`, `noise_range`, etc.); full field definitions are in `heightfield_terrains.py`. All sub-terrains (including `flat` and stairs) are now implemented via hfield, with resolution uniformly controlled by `TerrainGeneratorCfg.horizontal_scale` / `vertical_scale`. - -Built-in compositions are defined in `unilab.terrains.config`, and `Go2JoystickRoughCfg` defines its own owner defaults in `go2/rough.py`: - -- `Go2RoughTerrainCfg`: 1 × 1, by default only samples `random_rough` (proportion `0.2`, the rest of the sub-terrains are kept as configurable profiles but default to proportion `0.0`), random mode. Each env instance receives its own independent cfg object. -- `ROUGH_TERRAINS_CFG`: 10 × 20, 7 sub-terrains mixed by proportion, random mode. Currently kept as a reusable profile; not the default training profile of `Go2JoystickRoughCfg`. -- `STAIRS_TERRAINS_CFG`: 10 × 4, curriculum mode, difficulty goes from flat → easy → moderate → challenging. Not referenced by any task at this time; can be used in custom task configs. - -## 4. Height Scan Observation - -`Go2JoystickRoughEnv` only concatenates the height scan into the `critic` group; the actor obs follows the 45-dimensional rough-task contract. Default scan points are 17 in the x direction and 11 in the y direction, totaling 187 dimensions, so `obs_groups_spec` is: - -| obs group | Dimension | Content | -| --- | ---: | --- | -| `obs` | `45` | actor policy input | -| `critic` | `235` | rough critic 48 dims + height scan 187 dims | - -The height scan's geom/body id and sampling offsets are cached during env init; the hot path only uses the backend-owned scanner created by `create_hfield_scanner(...)` and consumes cached ids / offsets. XML is not parsed and asset metadata is not read in `step()` / `reset()`. - -## 5. Enabling Procedural Terrain in a New Task - -A new task enables procedural terrain through `SceneCfg`. `SceneCfg` lives in `src/unilab/base/scene.py`, and `scene.terrain.generator` uses `TerrainGeneratorCfg`. +For example, an owner can declare a generated terrain without putting terrain +knowledge in the backend: ```yaml env: scene: - model_file: .../robot.xml - fragment_files: - - .../locomotion_task.xml terrain: - kind: hfield hfield_name: terrain_hfield geom_name: floor generator: + _target_: unilab.tasks.locomotion.common.rough_manager_terms.QuadrupedRoughTerrainCfg seed: 42 - size: [8.0, 8.0] - num_rows: 10 - num_cols: 20 - border_width: 20.0 ``` -The env's `__init__` does not need to call the XML materializer directly; hand `scene` over to the backend constructor: +UniLab does not retain a procedural-terrain production owner. The retained +`g1_walk_rough` task uses the static-heightfield form of the same cold-path +scene contract, while generator composition itself is covered by core terrain +and backend materialization tests. -```python -from unilab.base.backend_factory import create_backend +## Materialization boundary -backend = create_backend(..., cfg.scene) -terrain_origins = getattr(backend, "terrain_origins", None) -``` - -Note: `TerrainGenerator.__init__` mutates the passed cfg in place (writing values into each `sub_cfg.size`). If the same `TerrainGeneratorCfg` instance is shared across multiple envs they will pollute each other; you must use `default_factory` or `copy.deepcopy` to ensure each instance gets its own cfg. `Go2JoystickRoughCfg` handles this via `scene.terrain.generator=Go2RoughTerrainCfg()`. +During `registry.make(...)`: -## 6. Visualization and Offline Replay +1. Hydra materializes the selected owner into `ManagerBasedRlEnvCfg`. +2. `create_backend` resolves required robot assets and passes `SceneCfg` to the + selected UniSim backend. +3. The backend's public scene materializer generates the terrain matrix, + origins, hfield, and merged scene model. +4. Entity and height-scanner IDs are cached for reset/step use. -To preview the materialized scene without starting training: +Step and reset never parse robot XML or inspect asset metadata. They consume +cached IDs and public backend capabilities. -```bash -uv run scripts/visualize_task_env.py --task Go2JoystickRough --num_envs 4 -``` +## Example -## 7. Validation +Use the retained rough-scene reference task: ```bash -# Procedural terrain + hfield PNG materializer unit/integration tests -uv run pytest tests/terrains tests/utils/test_xml_utils.py -q - -# Hydra compose + Go2JoystickRoughCfg task owner test -uv run pytest tests/config/test_locomotion_params.py -k rough -q +uv run train --algo sac --task g1_walk_rough --sim mujoco training.no_play=true +``` -# Go2 rough terrain spawn + height scan contract tests -uv run pytest tests/envs/locomotion/test_go2_terrain_spawn.py tests/envs/locomotion/test_go2_rough_height_scan.py -q +Custom owners can tune the terrain grid and seed through Hydra: -# Hydra command-line override + registry deep-merge loop -uv run pytest tests/config/test_locomotion_params.py \ - -k "apply_cfg_overrides or hydra_terrain_override" -q +```text +env.scene.terrain.generator.num_rows=4 +env.scene.terrain.generator.seed=42 +``` -# End-to-end smoke: Hydra command-line override of grid size + seed, 2-iter PPO -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ - env.scene.terrain.generator.num_rows=4 env.scene.terrain.generator.seed=42 \ - algo.max_iterations=2 algo.num_envs=64 +## Core validation -uv run train --algo ppo --task go2_joystick_rough --sim motrix \ - env.scene.terrain.generator.num_rows=4 env.scene.terrain.generator.seed=42 \ - algo.max_iterations=2 algo.num_envs=64 +```bash +uv run pytest tests/terrains tests/utils/test_xml_utils.py -q ``` -## Known Constraints - -- **Both MuJoCo and Motrix materializers have automated smoke coverage**: the MuJoCo path returns `MjModel`, the Motrix path returns `SceneModel`. Production training performance and convergence quality still need to be recorded by independent benchmarks; they are not guaranteed by smoke tests. -- **The MuJoCo assembly path depends on `MjSpec.attach`**: the robot XML, terrain, and task sensor fragment are assembled at the materialization stage and compiled directly into `MjModel`. -- **The Motrix assembly path depends on `motrixsim.msd.World.attach`**: `go2.xml` provides the robot model, and `locomotion_task.xml` is wired in as the task fragment that carries contact sensors and the task-level keyframe. -- **Height scan support goes through `create_hfield_scanner(...)`**: the rough env caches scanner ids and offsets during initialization, then consumes scanner output in observation/reward code without parsing XML on the hot path. -- **`scene.terrain.generator` is a cold-path config**: modifying the generator after env construction does not affect the already materialized scene. To change terrains, the env must be reconstructed (i.e. rerun the training command). -- **`import unilab.terrains` does not depend on mujoco**: `TerrainGenerator.generate()` / `write_png()` is a pure numpy + imageio path. +Core validation also covers the terrain generator and backend materialization +boundary; ecosystem packages own evidence for additional task families. diff --git a/docs/sphinx/source/en/2-user_guide/6-terrain/2-heightfield_import.md b/docs/sphinx/source/en/2-user_guide/6-terrain/2-heightfield_import.md index a15826515..4514f4546 100644 --- a/docs/sphinx/source/en/2-user_guide/6-terrain/2-heightfield_import.md +++ b/docs/sphinx/source/en/2-user_guide/6-terrain/2-heightfield_import.md @@ -2,27 +2,24 @@ Heightfield terrain is configured through `SceneCfg` and the terrain generator, then materialized by the backend on the init path. The committed user-facing -example is `Go2JoystickRough`, with owners in -`src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml` and -`src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml`. +example is the retained `g1_walk_rough` scene. ## Files To Read - `src/unilab/terrains/heightfield_terrains.py` - `unisim.terrain.generator` -- `src/unilab/tasks/locomotion/go2/rough.py` +- `src/unilab/assets/robots/g1/scene_rough.xml` +- `src/unilab/tasks/locomotion/common/height_scan.py` - `unisim.backend.mujoco.xml` - `unisim.backend.motrix.scene` ## Smoke Commands ```bash -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ +uv run train --algo sac --task g1_walk_rough --sim mujoco \ algo.max_iterations=2 \ algo.num_envs=64 \ training.no_play=true - -uv run scripts/visualize_task_env.py --task Go2JoystickRough --backend mujoco --num_envs 4 ``` Height scan IDs and offsets are cached during env initialization; hot paths call diff --git a/docs/sphinx/source/en/2-user_guide/7-tooling/4-scene_export.md b/docs/sphinx/source/en/2-user_guide/7-tooling/4-scene_export.md index a0b1fb348..d849ccded 100644 --- a/docs/sphinx/source/en/2-user_guide/7-tooling/4-scene_export.md +++ b/docs/sphinx/source/en/2-user_guide/7-tooling/4-scene_export.md @@ -9,7 +9,7 @@ For task-level materialization checks, use the script that constructs an env from the registry and owner config: ```bash -uv run scripts/visualize_task_env.py --task Go2JoystickRough --backend mujoco --num_envs 4 +uv run scripts/visualize_task_env.py --task G1WalkFlat --backend mujoco --num_envs 4 ``` `tests/test_export_scene.py` covers the export helper, including `scene.xml` diff --git a/docs/sphinx/source/en/2-user_guide/7-tooling/5-robot_import.md b/docs/sphinx/source/en/2-user_guide/7-tooling/5-robot_import.md index 888be3ff6..142f8489d 100644 --- a/docs/sphinx/source/en/2-user_guide/7-tooling/5-robot_import.md +++ b/docs/sphinx/source/en/2-user_guide/7-tooling/5-robot_import.md @@ -44,7 +44,7 @@ where possible. only for position-control owners. - If the robot must preserve torque/motor actuator semantics, later task extension should follow the control pattern in - `src/unilab/tasks/locomotion/go2w/`: keep action interpretation, PD/torque + a motor/torque task owner: keep action interpretation, PD/torque control, and the actuator contract inside the robot owner boundary. - After conversion, `mujoco.viewer` opens automatically to show the converted result and proceed to keyframe adjustment. diff --git a/docs/sphinx/source/en/3-deployment/0-index.md b/docs/sphinx/source/en/3-deployment/0-index.md index 258a12cf1..c7979abcf 100644 --- a/docs/sphinx/source/en/3-deployment/0-index.md +++ b/docs/sphinx/source/en/3-deployment/0-index.md @@ -61,7 +61,7 @@ End-to-end pipeline + go/no-go checklist. :::{grid-item-card} 🐕 Go2 locomotion :link: 1-sim_to_real/3-go2_locomotion :link-type: doc -Joystick, rough terrain, Go2W wheels. +Go2 joystick-flat deployment. ::: :::{grid-item-card} 🤚 Allegro in-hand diff --git a/docs/sphinx/source/en/3-deployment/1-sim_to_real/0-index.md b/docs/sphinx/source/en/3-deployment/1-sim_to_real/0-index.md index f1554b15e..c98dbac2e 100644 --- a/docs/sphinx/source/en/3-deployment/1-sim_to_real/0-index.md +++ b/docs/sphinx/source/en/3-deployment/1-sim_to_real/0-index.md @@ -52,7 +52,7 @@ Motion-tracking deployment notes for the G1 path. :::{grid-item-card} Go2 locomotion :link: 3-go2_locomotion :link-type: doc -Joystick, rough terrain, and Go2W deployment notes. +Go2 joystick-flat deployment notes. ::: :::{grid-item-card} Allegro in-hand diff --git a/docs/sphinx/source/en/3-deployment/1-sim_to_real/1-overview.md b/docs/sphinx/source/en/3-deployment/1-sim_to_real/1-overview.md index 4a79329c8..08c561184 100644 --- a/docs/sphinx/source/en/3-deployment/1-sim_to_real/1-overview.md +++ b/docs/sphinx/source/en/3-deployment/1-sim_to_real/1-overview.md @@ -95,7 +95,7 @@ Humanoid motion tracking deployment, joint clamp ranges, IMU alignment. :link: 3-go2_locomotion :link-type: doc -Joystick + rough terrain policies on Go2 and Go2W. +Joystick-flat policies on Go2. ::: :::{grid-item-card} ✋ Allegro in-hand diff --git a/docs/sphinx/source/en/3-deployment/1-sim_to_real/2-g1_whole_body.md b/docs/sphinx/source/en/3-deployment/1-sim_to_real/2-g1_whole_body.md index fe3f0bf9f..fe0a282a6 100644 --- a/docs/sphinx/source/en/3-deployment/1-sim_to_real/2-g1_whole_body.md +++ b/docs/sphinx/source/en/3-deployment/1-sim_to_real/2-g1_whole_body.md @@ -51,9 +51,6 @@ differ per owner — two G1 examples: - 514 - No state estimation: `motion_anchor_pos_b` and `base_lin_vel` are set to `null`, pelvis IMU, `history_length: 5` on the proprio terms. -* - `src/unilab/conf/ppo/task/g1_motion_tracking_deploy/mujoco.yaml` - - 154 - - Single-step mimic actor layout, per-joint-group `scale` regex map. ``` ::::{admonition} Read the width off the composed config, not off this table @@ -107,8 +104,8 @@ Map actor output as `action * scale + default_angles`, then clamp to the scene's joint range before the target reaches the motor driver. - `scale` is `env.actions.joint_pos.scale`. It may be a **scalar** (`2.0` for - `g1_wbt_obs`) or a **regex → value map** resolved per actuator - (`g1_motion_tracking_deploy` maps joint-name patterns to distinct values). + `g1_wbt_obs`) or a **regex → value map** resolved per actuator. Unitree's + deploy owners map joint-name patterns to distinct values. Reproduce the owner's resolved per-actuator vector exactly — do not average a map, take one entry, or broadcast a scalar over a map owner. - `default_angles` follows from `use_default_offset: true`, i.e. the `stand` diff --git a/docs/sphinx/source/en/3-deployment/1-sim_to_real/3-go2_locomotion.md b/docs/sphinx/source/en/3-deployment/1-sim_to_real/3-go2_locomotion.md index 17600395b..4aaa92b85 100644 --- a/docs/sphinx/source/en/3-deployment/1-sim_to_real/3-go2_locomotion.md +++ b/docs/sphinx/source/en/3-deployment/1-sim_to_real/3-go2_locomotion.md @@ -1,8 +1,7 @@ -# Go2 / Go2W Locomotion Deployment +# Go2 Locomotion Deployment -Joystick-driven locomotion (flat + rough) plus the wheel-legged Go2W -variant. The hardware story for both is similar; this page calls out the -deltas. +This page describes the retained `go2_joystick_flat` reference owner. Unitree +production deployment variants are documented by their ecosystem package. ## Observation contract @@ -26,16 +25,16 @@ deltas. - 3 - operator input * - Joint positions - - 12 (Go2) / 16 (Go2W) + - 12 - encoder * - Joint velocities - - 12 / 16 + - 12 - encoder velocity after the deploy controller's filtering path * - Previous action - - 12 / 16 + - 12 - last policy output * - Foot contact - - 4 (Go2 only) + - 4 - contact sensor or estimated from foot height ``` @@ -46,23 +45,6 @@ owner. If deployment cannot provide the same base-velocity signal, train a variant whose actor observation matches the estimator you can run on the robot. :::: -## Rough terrain caveat - -For `go2_joystick_rough` the policy expects elevated terrain features. On a -flat indoor surface the rough-trained policy will be *more conservative* -than necessary but should still be validated through replay before hardware -bring-up. For deployment on slopes / debris: - -- Choose ground-friction DR ranges from measured deployment surfaces. -- Train with terrain curriculum: see - {doc}`../../2-user_guide/6-terrain/1-procedural`. - -## Go2W wheel ↔ leg dispatch - -Go2W policies output **continuous wheel velocity** for the rear wheel -joints and **position targets** for the legs. The action vector ordering -must match `src/unilab/assets/robots/go2w/`. Verify with `unilab-export-scene`. - ## See also - {doc}`5-onnx_runtime` diff --git a/docs/sphinx/source/en/3-deployment/1-sim_to_real/6-domain_randomization.md b/docs/sphinx/source/en/3-deployment/1-sim_to_real/6-domain_randomization.md index 4ad5adbd8..b03a9b045 100644 --- a/docs/sphinx/source/en/3-deployment/1-sim_to_real/6-domain_randomization.md +++ b/docs/sphinx/source/en/3-deployment/1-sim_to_real/6-domain_randomization.md @@ -44,7 +44,7 @@ range in the task owner only after recording why that range is plausible. Manager-Based tasks declare reset and interval randomization through `env.events` in their owner YAML, executed by the manager lifecycle. See -`src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`. +`src/unilab/conf/sac/task/g1_wbt_obs/mujoco.yaml`. The legacy task-level provider protocol has been removed. The capability boundary is described in @@ -52,10 +52,10 @@ boundary is described in ## Recipe: starting ranges -Use the selected owner YAML as the source of truth. Go2 rough owners compose -`src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`, which declares -base mass, COM, PD gains, and interval push. This excerpt shows its PD-gain -term; evaluate absolute gain ranges together with the robot's control settings. +Use the selected owner YAML as the source of truth. The retained G1 WBT owner +declares base mass, COM, PD gains, encoder bias, and interval push. This +excerpt shows a PD-gain term; evaluate absolute gain ranges together with the +robot's control settings. ```yaml env: diff --git a/docs/sphinx/source/en/3-deployment/3-framework_migration/6-reward_porting.md b/docs/sphinx/source/en/3-deployment/3-framework_migration/6-reward_porting.md index 9e2a7a60c..e9a1145d8 100644 --- a/docs/sphinx/source/en/3-deployment/3-framework_migration/6-reward_porting.md +++ b/docs/sphinx/source/en/3-deployment/3-framework_migration/6-reward_porting.md @@ -8,7 +8,7 @@ entity facade and managers, and return NumPy arrays of shape `(num_envs,)`. The `twist` command below must be defined in the owner's `env.commands`. The tracking and action-rate entries follow -`src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml`; the joint-limit and +`src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml`; the joint-limit and termination entries illustrate existing helpers whose weights need task-specific evaluation. diff --git a/docs/sphinx/source/en/4-developer_guide/1-architecture/4-scene_composition.md b/docs/sphinx/source/en/4-developer_guide/1-architecture/4-scene_composition.md index f16349c92..b76e9fe2f 100644 --- a/docs/sphinx/source/en/4-developer_guide/1-architecture/4-scene_composition.md +++ b/docs/sphinx/source/en/4-developer_guide/1-architecture/4-scene_composition.md @@ -105,11 +105,10 @@ Disallowed on hot paths: The current procedural terrain user-facing path is Go2 rough terrain: -- Task owner: `src/unilab/tasks/locomotion/go2/rough.py` +- Task owner: `src/unilab/tasks/locomotion/g1/manager_terms.py` - Terrain generator: `unisim.terrain.generator` - MuJoCo materializer: `unisim.backend.mujoco.xml` - Motrix materializer: `unisim.backend.motrix.scene` -- Owner YAMLs: `src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml`, - `src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml` +- Owner YAMLs: `src/unilab/conf/sac/task/g1_walk_rough/{mujoco,motrix}.yaml` User instructions are in {doc}`../../2-user_guide/6-terrain/1-procedural`. diff --git a/docs/sphinx/source/en/4-developer_guide/7-motion_assets.md b/docs/sphinx/source/en/4-developer_guide/7-motion_assets.md index f0368e4ed..5a73ec058 100644 --- a/docs/sphinx/source/en/4-developer_guide/7-motion_assets.md +++ b/docs/sphinx/source/en/4-developer_guide/7-motion_assets.md @@ -87,8 +87,9 @@ Alternatively, pre-download into the in-repo directory with `--local-dir` Robot binary meshes and textures (for example `.STL`, `.obj`, and `.png`) are externalized the same way, on the Hugging Face dataset repo [unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots). -The registered robots are a2, allegro_hand, g1, go2, -and x2 (`ROBOT_ASSET_SPECS` in `src/unilab/assets/hub.py`). +The registered core robots are allegro_hand, g1, go2, and x2 +(`ROBOT_ASSET_SPECS` in `src/unilab/assets/hub.py`). Unitree production robot +metadata is resolved by `unitree_rl_unilab`. Their mesh/texture directories download lazily on first use and land under their original paths (for example `src/unilab/assets/robots/g1/assets/` and `robots/g1/textures/` for G1), so the original relative XML paths remain diff --git a/docs/sphinx/source/en/5-reference/5-support_matrix.md b/docs/sphinx/source/en/5-reference/5-support_matrix.md index 75fd336a6..790990207 100644 --- a/docs/sphinx/source/en/5-reference/5-support_matrix.md +++ b/docs/sphinx/source/en/5-reference/5-support_matrix.md @@ -76,67 +76,32 @@ rendering/playback paths remain unsupported. ## Entrypoint x Task Owner -| Entrypoint | Task owner | MuJoCo | mjwarp | Motrix | IsaacGym | IsaacSim | -| --- | --- | --- | --- | --- | --- | --- | -| PPO (torch) | `go1_joystick_flat` (Go1 joystick) | Tested | - | Tested | - | - | -| PPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | -| PPO (torch) | `go2_joystick_rough` (Go2 joystick rough) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Configured | Configured | -| PPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `x2_wall_flip_tracking` (X2 wall flip tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | -| PPO (torch) | `a2_joystick_flat` (a2 joystick flat) | Tested | - | - | - | - | -| PPO (torch) | `allegro_inhand_grasp` (allegro inhand grasp) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_box_tracking` (g1 23dof box tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_climb_tracking` (g1 23dof climb tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_motion_tracking_deploy` (g1 23dof motion tracking deploy) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_23dof_walk_rough` (g1 23dof walk rough) | Tested | - | Registered | - | - | -| PPO (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_box_tracking` (g1 box tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_climb_tracking` (g1 climb tracking) | Tested | - | Tested | - | - | -| PPO (torch) | `g1_motion_tracking_deploy` (g1 motion tracking deploy) | Tested | - | Tested | - | - | -| PPO (torch) | `go1_joystick_rough` (go1 joystick rough) | Tested | - | Tested | - | - | -| PPO (torch) | `go2_footstand` (go2 footstand) | Tested | - | Tested | - | - | -| PPO (torch) | `go2w_joystick_flat` (go2w joystick flat) | Tested | - | Tested | - | - | -| PPO (torch) | `go2w_joystick_rough` (go2w joystick rough) | Tested | - | Tested | - | - | -| PPO (torch) | `stewart_balance` (stewart balance) | Tested | - | Tested | - | - | -| APPO (torch) | `go1_joystick_flat` (Go1 joystick) | Tested | - | Tested | - | - | -| APPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | -| APPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_23dof_climb_tracking` (g1 23dof climb tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Registered | - | - | -| APPO (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Tested | - | - | -| APPO (torch) | `g1_climb_tracking` (g1 climb tracking) | Tested | - | Tested | - | - | -| SAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Tested | Configured | -| SAC (torch) | `g1_walk_rough` (G1 walk rough) | Tested | - | Tested | - | - | -| SAC (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | Configured | Tested | - | - | -| SAC (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Registered | - | - | -| SAC (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Registered | - | - | -| SAC (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Registered | - | - | -| SAC (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | -| SAC (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | -| SAC (torch) | `g1_23dof_walk_rough` (g1 23dof walk rough) | Tested | - | Tested | - | - | -| SAC (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Registered | - | - | -| SAC (torch) | `g1_23dof_wbt_obs` (g1 23dof wbt obs) | Tested | - | Registered | - | - | -| SAC (torch) | `g1_wbt_obs` (g1 wbt obs) | Tested | - | Registered | - | - | -| TD3 (torch) | `go1_joystick_flat` (Go1 joystick) | Registered | - | Tested | - | - | -| TD3 (torch) | `go2_joystick_flat` (Go2 joystick) | Registered | - | Tested | - | - | -| TD3 (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | -| TD3 (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Registered | - | - | -| FlashSAC (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Registered | - | - | -| FlashSAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Configured | Tested | Registered | Registered | -| FlashSAC (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | +| Entrypoint | Task owner | MuJoCo | mjwarp | Motrix | IsaacGym | Genesis | IsaacSim | Newton | SuperDex | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| PPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | - | - | Configured | +| PPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Configured | Configured | Configured | Configured | - | +| PPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `x2_wall_flip_tracking` (X2 wall flip tracking) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `allegro_inhand_grasp` (allegro inhand grasp) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `fr3_joint_target` (fr3 joint target) | - | - | - | - | - | - | - | Configured | +| PPO (torch) | `g1_box_tracking` (g1 box tracking) | Tested | - | Tested | - | - | - | - | - | +| PPO (torch) | `stewart_balance` (stewart balance) | Tested | - | Tested | - | - | - | - | - | +| APPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | - | - | Registered | +| APPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | Registered | Registered | - | +| APPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | - | - | - | +| APPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | - | - | - | +| APPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | - | - | - | +| SAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Tested | Tested | Configured | Tested | - | +| SAC (torch) | `g1_walk_rough` (G1 walk rough) | Tested | - | Tested | - | - | - | - | - | +| SAC (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | Configured | Tested | - | - | - | - | - | +| SAC (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Registered | - | - | - | - | - | +| SAC (torch) | `g1_wbt_obs` (g1 wbt obs) | Tested | - | Registered | - | - | - | - | - | +| TD3 (torch) | `go2_joystick_flat` (Go2 joystick) | Registered | - | Tested | - | - | - | - | Registered | +| TD3 (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | Registered | Registered | - | +| FlashSAC (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Registered | - | - | - | - | Registered | +| FlashSAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Configured | Tested | Registered | Registered | Registered | Registered | - | ## Source Index diff --git a/docs/sphinx/source/zh_CN/0-index.md b/docs/sphinx/source/zh_CN/0-index.md index 3c55e8318..ef4115822 100644 --- a/docs/sphinx/source/zh_CN/0-index.md +++ b/docs/sphinx/source/zh_CN/0-index.md @@ -146,12 +146,12 @@ recommendation 元数据。 | 机器人 / 任务族 | 有仓库证据的算法路径 | 后端证据 | | --- | --- | --- | -| Go1 joystick | PPO、APPO、TD3 | PPO 有已测试的 MuJoCo 与 Motrix 行。APPO 有已测试的 MuJoCo 行和 Motrix registered 行。TD3 有 `go1_joystick_flat` 的 Motrix owner YAML。 | | Go2 joystick | PPO、FlashSAC、TD3 | PPO 有已测试的 MuJoCo 与 Motrix 行。FlashSAC 有 `go2_joystick_flat` 的 MuJoCo owner YAML;TD3 有 `go2_joystick_flat` 的 Motrix owner YAML。 | -| Go2W joystick | PPO | `src/unilab/conf/ppo/task/go2w_joystick_*` 下存在 MuJoCo 与 Motrix flat/rough 变体的 PPO owner YAML。 | -| G1 locomotion / tracking | PPO、APPO、SAC、TD3 | PPO、APPO、SAC 都为 G1 任务提供了已提交的 MuJoCo 与 Motrix owner YAML;TD3 有一个 `g1_walk_flat` 的 MuJoCo owner。 | +| G1 reference locomotion / tracking | PPO、APPO、SAC、TD3 | PPO、APPO、SAC 都为保留的 G1 任务提供了已提交的 MuJoCo 与 Motrix owner YAML;TD3 有一个 `g1_walk_flat` 的 MuJoCo owner。 | | Allegro in-hand | PPO、APPO | PPO 和 APPO 为 Allegro in-hand 任务提供了已提交的 MuJoCo 与 Motrix owner YAML。 | +Unitree production 任务族由 `unitree_rl_unilab` 维护,不计入核心仓库证据。 + ```{toctree} :hidden: :caption: 文档 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/0-index.md b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/0-index.md index 6a435f28c..d1e541ae8 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/0-index.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/0-index.md @@ -61,8 +61,8 @@ UniLab 通过 task owner config 选择仿真器。常规用法下,使用 `--ta {doc}`../../5-reference/5-support_matrix`。 ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco -uv run train --algo ppo --task go1_joystick_flat --sim motrix +uv run train --algo ppo --task go2_joystick_flat --sim mujoco +uv run train --algo ppo --task go2_joystick_flat --sim motrix uv run train --algo ppo --task g1_walk_flat --sim isaacsim ``` @@ -89,8 +89,8 @@ Owner YAML 位置: - `--render-mode none` 禁用回放。 ```bash -uv run eval --algo ppo --task go1_joystick_flat --sim mujoco --load-run -1 -uv run eval --algo ppo --task go1_joystick_flat --sim motrix --load-run -1 \ +uv run eval --algo ppo --task go2_joystick_flat --sim mujoco --load-run -1 +uv run eval --algo ppo --task go2_joystick_flat --sim motrix --load-run -1 \ --render-mode record ``` diff --git a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/1-mujoco.md b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/1-mujoco.md index 16d31f781..1f5bd507f 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/1-mujoco.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/1-mujoco.md @@ -17,7 +17,7 @@ MuJoCo 是已提交 owner 配置中的默认后端路径。其 Python 依赖为 ```bash uv run train --algo ppo --task go2_joystick_flat --sim mujoco -uv run train --algo appo --task go1_joystick_flat --sim mujoco training.no_play=true +uv run train --algo appo --task go2_joystick_flat --sim mujoco training.no_play=true uv run train --algo sac --task g1_walk_flat --sim mujoco ``` diff --git a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/3-isaacgym.md b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/3-isaacgym.md index 9f37da2e8..4792f258c 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/3-backends/3-isaacgym.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/3-backends/3-isaacgym.md @@ -81,7 +81,7 @@ export UNILAB_BENCHMARK_HSGYM_LIB="$UNILAB_BENCHMARK_HOLOSOMA_DEPS/miniconda3/en ## 验证 用 benchmark 脚本验证环境可用。benchmark 从 URDF 加载机器人模型, -URDF 模型树(`go1_description/`、`g1_description/` 等)需自备,通过 +URDF 模型树(`go2_description/`、`g1_description/` 等)需自备,通过 `--models-root` 或 `UNILAB_BENCHMARK_MODELS_ROOT` 指向其根目录: ```bash diff --git a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/0-index.md b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/0-index.md index e1265c0db..27af33ef0 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/0-index.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/0-index.md @@ -9,13 +9,13 @@ :::{grid-item-card} 运动控制 :link: 1-locomotion :link-type: doc -Go1、Go2、Go2W 和 G1 行走 owner。 +Go2 与 G1 核心参考 owner;Unitree production 变体在下游。 ::: :::{grid-item-card} 动作追踪 :link: 2-motion_tracking :link-type: doc -G1 动作追踪、翻转、攀爬、墙面翻转和箱体追踪。 +G1/X2 motion-tracking 参考配置。 ::: :::{grid-item-card} 操作 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/1-locomotion.md b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/1-locomotion.md index 33b1bbb92..39fdd518f 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/1-locomotion.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/1-locomotion.md @@ -1,109 +1,26 @@ -# 运动控制 +# 运动任务 -运动控制任务注册在 `src/unilab/tasks/locomotion/` 和 -`src/unilab/tasks/motion_tracking/` 中。`src/unilab/conf/` 下可用的 owner YAML -定义了哪些算法与后端组合是可运行的。 +UniLab 保留少量 reference/conformance 运动任务以及共享 Manager-Based +runtime。Unitree production 变体由下游 `unitree_rl_unilab` 包维护。 -## 系列 +## 核心参考任务 -- Go1:`go1_joystick_flat`、`go1_joystick_rough` -- Go2:`go2_joystick_flat`、`go2_joystick_rough`、`go2_footstand` -- Go2W:`go2w_joystick_flat`、`go2w_joystick_rough` -- G1 行走:`g1_walk_flat`、`g1_walk_rough` -- G1 动作追踪:`g1_motion_tracking`、`g1_flip_tracking`、 - `g1_wall_flip_tracking`、`g1_climb_tracking`、`g1_box_tracking` - -## 示例 +- Go2 joystick: `go2_joystick_flat` +- G1 walking: `g1_walk_flat`, `g1_walk_rough` +- G1 motion tracking 参考配置:见 {doc}`2-motion_tracking` ```bash uv run train --algo ppo --task go2_joystick_flat --sim mujoco -uv run train --algo ppo --task go2_joystick_rough --sim motrix training.no_play=true -uv run train --algo ppo --task go2_footstand --sim mujoco training.no_play=true -uv run train --algo appo --task g1_motion_tracking --sim mujoco training.no_play=true +uv run train --algo ppo --task g1_walk_flat --sim mujoco uv run train --algo sac --task g1_walk_flat --sim mujoco ``` -查看支持矩阵以了解按 entrypoint、task owner 和 backend 划分的证据分级: +按 entrypoint、task owner 和 backend 查询核心支持矩阵: {doc}`../../5-reference/5-support_matrix`。 -## Go2 FootStand - -`go2_footstand` 是 Go2 前足站立任务。PPO owner YAML 已注册 MuJoCo、 -Motrix 和 Drake;当前 SAC owner 使用 Drake。 - -- PPO canonical 配置:`src/unilab/conf/ppo/task/go2_footstand/base.yaml` -- 后端 owner:`src/unilab/conf/ppo/task/go2_footstand/{mujoco,motrix,drake}.yaml` -- 环境注册名:`Go2FootStand`(MuJoCo、Motrix、Drake) -- 环境实现:`src/unilab/tasks/locomotion/go2/footstand.py` - (通用 Manager-Based runtime 上的 task-owned NumPy manager terms) -- Go2 模型 XML:`src/unilab/assets/robots/go2/go2.xml` - -```bash -uv run train --algo ppo --task go2_footstand --sim mujoco training.no_play=true -uv run eval --algo ppo --task go2_footstand --sim mujoco --load-run -1 -``` - -### 教师-学生训练流程 - -FootStand 的完整流程是三阶段教师-学生 pipeline;当前仓库里的 `go2_footstand` 配置 -对应第一步,也就是教师策略的 PPO 训练入口: - -1. **教师策略训练(特权观测)。** 教师策略可以使用特权观测(例如基座线速度),这些信息 - 在仿真中可直接获得,但实机部署时不应直接依赖。训练时先让策略在较宽松的功率预算下学会 - 前足站立(约 400 W),再通过课程学习逐步收紧到约 200 W,避免一开始就用低功率限制导致 - 探索失败,同时让最终策略更接近可部署的能耗范围。 -2. **学生策略蒸馏。** 把训练好的教师策略蒸馏到可部署的学生策略上,学生输入只保留实机可获得 - 的观测,不依赖特权信息。蒸馏目标是在没有特权观测的条件下尽量复现教师策略的行为。 -3. **学生策略微调。** 蒸馏后的学生策略继续做强化学习微调,使用统一损失目标:一部分来自与 - 教师类似的奖励函数,另一部分来自教师正则项,约束学生策略不要过快偏离教师策略。这样既能 - 保留学到的稳定动作,又能让学生策略适应自己的观测输入和部署约束。 - -### 观测口径 - -`Go2FootStand` 的策略(actor)网络观测使用 15 帧历史,每帧 45 维 -(`FRAME_OBS_DIM = 45`): - -```text -linvel(3) + gyro(3) + gravity(3) + joint_position_delta(12) + joint_velocity(12) + last_action(12) -``` - -因此策略网络观测维度是 `45 * 15 = 675`。价值(critic)网络在这段历史观测后追加当前时刻的 -特权观测尾部(`PRIVILEGED_OBS_DIM = 49`): +## Unitree ecosystem 任务 -```text -gyro(3) + accelerometer(3) + linvel(3) + global_angvel(3) + dof_pos(12) + dof_vel(12) + torques(12) + height(1) -``` - -价值网络观测维度是 `675 + 49 = 724`。 - -### 奖励与终止项 - -默认奖励来自 `src/unilab/conf/ppo/task/go2_footstand/base.yaml`,后端 leaf 只覆盖 -后端专属 term 和调优项。奖励权重包括站立 `height`、 -`orientation`、`rear_feet_contact`、前腿目标角度(`tar`)、`action_rate`、 -`dof_pos_limits`、`front_leg_motion`、`rear_leg_symmetry`、`knee_clearance`、 -`upright_stability`、`stay_still`、`pose`,以及 `energy` 和 `dof_acc` 惩罚; -`termination` 与 `penalty_contact` 驱动终止/惩罚路径(前腿/前身体接触、低高度、坏朝向, -以及 `footstand` termination term 中的高能耗截断)。 - -### 调参提示 - -- `env.observations.policy.terms.frame.history_length`:策略观测历史长度, - 默认为 `15`。 -- `env.terminations.footstand.params.energy_threshold`:高能耗终止阈值, - 默认为 `200.0`。 -- `env.events`:重置和 domain randomization terms;后端 owner 对不支持的 - model-field term 显式设为 `null`。 -- `reward.footstand.params.scales`:站立、接触、运动和能耗权重。 - -### 近风险检查 - -```bash -uv run pytest tests/envs/locomotion/test_go2_footstand.py tests/config/test_locomotion_params.py -q -``` - -如果改过 Go2 XML,至少确认 MuJoCo 能加载模型: - -```bash -uv run python -c "import mujoco; m=mujoco.MjModel.from_xml_path('src/unilab/assets/robots/go2/go2.xml'); print(m.nq, m.nv, m.nu, m.nsensor)" -``` +Unitree production 变体维护在 +[unitree_rl_unilab](https://github.com/unilabsim/unitree_rl_unilab),该仓库只依赖 +已发布的 UniLab/UniRL 发行版。其支持证据与任务文档由下游仓库持有,不属于 +UniLab 核心支持矩阵。 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/2-motion_tracking.md b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/2-motion_tracking.md index c4acb0154..a68c82a23 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/2-motion_tracking.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/4-tasks/2-motion_tracking.md @@ -19,27 +19,24 @@ runtime 执行。 | --- | --- | --- | --- | | `g1_motion_tracking` | `G1MotionTracking` | `dance1_subject2_part.npz` | `src/unilab/conf/ppo/task/g1_motion_tracking/`, `src/unilab/conf/appo/task/g1_motion_tracking/` | | `g1_flip_tracking` | `G1FlipTracking` | `flip_360_001__A304.npz` | `src/unilab/conf/ppo/task/g1_flip_tracking/`, `src/unilab/conf/appo/task/g1_flip_tracking/` | -| `g1_wall_flip_tracking` | `G1WallFlipTracking` | `flip_from_wall_104__A304.npz` | `src/unilab/conf/ppo/task/g1_wall_flip_tracking/`, `src/unilab/conf/appo/task/g1_wall_flip_tracking/` | | `x2_wall_flip_tracking` | `X2WallFlipTracking` | `tictacflip_6-3_g1format.npz` | `src/unilab/conf/ppo/task/x2_wall_flip_tracking/` | -| `g1_climb_tracking` | `G1ClimbTracking` | `climb_20_z_scale_1.0.npz` | `src/unilab/conf/ppo/task/g1_climb_tracking/`, `src/unilab/conf/appo/task/g1_climb_tracking/` | | `g1_box_tracking` | `G1BoxTracking` | `sub3_largebox_003_boxconverted.npz` | `src/unilab/conf/ppo/task/g1_box_tracking/` | | `g1_wbt_obs` | `G1WBTObs` | `dance1_subject2_part.npz` | `src/unilab/conf/sac/task/g1_wbt_obs/mujoco.yaml` | -23-DoF task owner 目录选择对应的 23-DoF 场景、motion、entity 与 action 声明。 -profile 差异全部留在 Hydra 中。G1 identity 使用共享 manager factory;X2 只在委托给 -该 factory 前增加一层冷路径 mesh resolver。 +profile 差异留在 Hydra 中。保留的 G1 identity 使用共享 manager factory;X2 只在 +委托给该 factory 前增加一层冷路径 mesh resolver。Unitree 的 wall flip、climb、 +deploy 与 23-DoF motion production profile 现在位于 `unitree_rl_unilab`。 ## PPO 与 APPO PPO owner 迭代预算(`--sim mujoco` owner YAML):`g1_motion_tracking` 为 -`algo.max_iterations=15000`;`g1_flip_tracking` 和 `g1_wall_flip_tracking` 为 -`20000`;`x2_wall_flip_tracking` 为 `9500`。(`g1_flip_tracking` 的 Motrix owner +`algo.max_iterations=15000`;`g1_flip_tracking` 为 `20000`; +`x2_wall_flip_tracking` 为 `9500`。(`g1_flip_tracking` 的 Motrix owner YAML 将其提到 `30000`。) ```bash uv run train --algo ppo --task g1_motion_tracking --sim mujoco uv run train --algo ppo --task g1_flip_tracking --sim mujoco -uv run train --algo ppo --task g1_wall_flip_tracking --sim mujoco uv run train --algo ppo --task x2_wall_flip_tracking --sim mujoco uv run train --algo ppo --task g1_motion_tracking --sim motrix uv run train --algo appo --task g1_motion_tracking --sim mujoco training.no_play=true diff --git a/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/0-index.md b/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/0-index.md index 1c8433d20..fa8b5eda5 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/0-index.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/0-index.md @@ -5,7 +5,7 @@ Manager-Based event term 是唯一 DR 声明路径: -- **Manager-Based(Compatible)任务**:reset / interval 随机化通过 owner YAML 中的 Hydra `events:` manager term 声明;reset 生命周期的 event 在 reset 时采样,interval 生命周期的 event 在 step 之间施加扰动。例如 `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` 的 `events:` 段。 +- **Manager-Based(Compatible)任务**:reset / interval 随机化通过 owner YAML 中的 Hydra `events:` manager term 声明;reset 生命周期的 event 在 reset 时采样,interval 生命周期的 event 在 step 之间施加扰动。例如 `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` 的 `events:` 段。 @@ -27,7 +27,6 @@ Manager-Based event term 是唯一 DR 声明路径: | Task | 声明路径 | 结构化形式? | reset 形式 | interval 形式 | Code | | --- | --- | --- | --- | --- | --- | -| `Go1JoystickFlat` | Hydra `events:` term | 是:owner YAML 声明 reset/interval event | root-state reset + base mass/COM + `pd_gains` | `push_by_setting_velocity` event | `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` | | `Go2JoystickFlat` | Hydra `events:` term | 是:owner YAML 声明 reset event | root-state reset + `pd_gains` kp/kd | 无 | `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` | | `G1WalkFlat` | Hydra `events:` term | 是:Hydra `EventTermCfg` + Manager-Based reset term | root-state reset + 经 `pd_gains` 的 kp/kd | 无 | `g1/manager_terms.py` | | `G1WalkRough` | Hydra `events:` term | 是:与 `G1WalkFlat` 相同的 Manager-Based event term | root-state reset + 经 `pd_gains` 的 kp/kd | 无 | `g1/manager_terms.py` | @@ -40,7 +39,6 @@ Manager-Based event term 是唯一 DR 声明路径: | Task | 当前已实现的 reset 域随机化 | 当前已实现的 interval 域随机化 | 默认状态 | | --- | --- | --- | --- | -| `Go1JoystickFlat` | 经 `reset_root_state_uniform` 的 base xy/yaw 与 base qvel;command 采样(`UniformVelocityCommandCfg`);经 `randomize_rigid_body_mass` 的 base mass;经 `randomize_rigid_body_com` 的 base COM;经 `pd_gains` 的 kp/kd | `push_by_setting_velocity` interval event | 上述 event term 全部在 `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` 中默认声明并启用 | | `Go2JoystickFlat` | 经 `reset_root_state_uniform` 的 base xy/yaw 与 base qvel;command 采样;经 `pd_gains` 的 kp/kd | 无 | event term 在 `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml` 中默认声明并启用 | | `G1WalkFlat` | 经 `reset_root_state_uniform` 的 base xy/yaw 与 base qvel;带平面死区的 command 采样;`gait_phase` 采样;经 `pd_gains` 的 kp/kd 随机化 | 无 | mujoco owner 默认启用 kp/kd;motrix/mjwarp owner 默认禁用 | | `G1WalkRough` | 与 `G1WalkFlat` 相同(共享 owner base,rough 场景) | 无 | 与 `G1WalkFlat` 相同的默认值 | @@ -71,11 +69,10 @@ fail closed。建议从较小倾斜范围开始,避免早期训练任务不可 ## Interval push 用法 Manager-Based 任务通过 `env.events.push_robot` term 配置周期推扰。例如, -`src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` 使用 -`push_by_setting_velocity`,间隔为 15 秒,并按轴声明速度范围。 +保留的 `g1_wbt_obs` owner 使用 `push_by_setting_velocity`,并按轴声明速度范围。 ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco \ +uv run train --algo sac --task g1_wbt_obs --sim mujoco \ 'env.events.push_robot.interval_range_s=[10.0,10.0]' ``` diff --git a/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/1-configuration.md b/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/1-configuration.md index 52c936234..48ddd924d 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/1-configuration.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/5-domain_randomization/1-configuration.md @@ -22,18 +22,17 @@ Backend 支持通过 `unisim.backend.base` 显式声明。所选 backend 未声 ## Interval Push Manager-Based 任务通过 `env.events.push_robot` term 配置周期推扰。例如, -`src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml` 使用 -`push_by_setting_velocity`,间隔为 15 秒,并按轴声明速度范围。 +保留的 `g1_wbt_obs` owner 使用 `push_by_setting_velocity`,并按轴声明速度范围。 ```bash -uv run train --algo ppo --task go1_joystick_flat --sim mujoco \ +uv run train --algo sac --task g1_wbt_obs --sim mujoco \ 'env.events.push_robot.interval_range_s=[10.0,10.0]' ``` ## Owner 本地默认值 当取值范围是任务 contract 的一部分时,将其保留在 task owner YAML 中。例如, -rough 四足家族的 base mass、质心、kp/kd 和 push 随机化作为 event term 声明在 -共享 base `src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`。 +rough 任务族可以把 base mass、质心、kp/kd 和 push 随机化作为 event term +声明在自己的共享 owner base 中。 完整当前清单见 {doc}`0-index`。 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/1-procedural.md b/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/1-procedural.md index 252d93da3..b41fb1e6d 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/1-procedural.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/1-procedural.md @@ -1,184 +1,69 @@ # 程序化地形 -本页只回答四个问题: +程序化地形是 scene composition 能力,不是独立的 backend 模式。task owner +在 Hydra 中声明 `env.scene.terrain`;UniLab 校验配置,UniSim 的公开 backend +adapter 只在环境构建阶段物化地形。 -1. 如何运行当前仓库中已经存在的崎岖地形任务? -2. 哪些内容可以、哪些内容不能通过 Hydra 命令行修改? -3. 当我想修改子地形组成时,正确的入口是什么? -4. 当前已知的边界是什么——这些不是 bug,而是约束? +## Owner 声明 -关于底层 contract(冷路径实例化、注册新的子地形、hfield 导出),参见 `unisim.backend.mujoco.xml`、`unisim.backend.motrix.scene` 和 `unisim.terrain.generator` 中的源码注释。 +核心可复用部分包括: -## 当前状态 +- `unilab.base.scene.SceneCfg`:`terrain` 与 scene 文件。 +- `unilab.tasks.locomotion.common.rough_manager_terms`:terrain generator、 + rough reset、velocity command、height scan 与 action owner term。 +- `unilab.tasks.locomotion.common.height_scan`:缓存式高度采样。 -当前仓库中只有一个任务注册并接入了程序化地形: - -| 任务 | owner YAML | 后端 | 入口算法 | 代码 | -| --- | --- | --- | --- | --- | -| `Go2JoystickRough` | `mujoco.yaml`、`motrix.yaml` | MuJoCo / Motrix | PPO (`train_rsl_rl.py`) | `go2/rough.py` | - -在 env 构建过程中: - -1. `Go2JoystickRoughCfg` 声明了一个 `SceneCfg`,其 `model_file` 指向 `go2.xml`,`fragment_files` 从 `locomotion_task.xml` 引入 task 级别的接触传感器和 `home` keyframe,`scene.terrain` 声明了一个名为 `terrain_hfield` 的待生成 hfield。 -2. 后端场景实例化器调用 `TerrainGenerator(...)` 生成一个与后端无关的合并高度矩阵以及 `terrain_origins`;地形生成器本身不依赖 MuJoCo 或 Motrix。 -3. MuJoCo 实例化器使用 `MjSpec.add_hfield(...)` / `worldbody.add_geom(...)` 创建地形,然后用 `MjSpec.attach(...)` 把机器人 spec 附加到场景中,最后通过 `compile()` 生成 `MjModel`。 -4. Motrix 实例化器使用 `motrixsim.msd.World` 创建地形世界,用 `World.attach(...)` 拼接机器人世界和 task fragment,最后通过 `msd.build(...)` 生成 `SceneModel`。 -5. `go2.xml` 是机器人模型;`locomotion_task.xml` 是用于崎岖地形的 task fragment,包含与地形 `floor` 关联的接触传感器以及 task 级别的 `home` keyframe。 -6. 后端实例持有冷路径场景产物,直到 env `close()`;`terrain_origins` 通过一个后端场景属性回传给 env,用于 spawn / curriculum。 - -`step()`、`reset()` 和 Manager-Based event term 永远不会读取 XML 或访问 asset -文件;所有与地形相关的事情都发生在冷路径上。 - -## 1. 直接训练 - -```bash -# 默认使用单 patch 的 random_rough,critic 额外接收一个 17×11 的高度扫描 -uv run train --algo ppo --task go2_joystick_rough --sim mujoco -``` - -Motrix 后端使用相同的任务 owner: - -```bash -uv run train --algo ppo --task go2_joystick_rough --sim motrix -``` - -## 2. 通过 Hydra 命令行覆盖地形参数 - -`Go2JoystickRough` 在 `src/unilab/conf/ppo/task/go2_joystick_rough/{mujoco,motrix}.yaml` 中显式列出了一组可覆盖字段;这些字段允许 Hydra struct 模式接受命令行覆盖。 - -| 字段 | 用途 | YAML 默认值 | -| --- | --- | --- | -| `env.scene.terrain.generator.seed` | 随机种子,`null` 表示每次重新随机化 | `42` | -| `env.scene.terrain.generator.curriculum` | `true`:每个子地形一列,难度沿行递增;`false`:按 `proportion` 随机采样 | `false` | -| `env.scene.terrain.generator.size` | 单个地形 patch 的 x/y 尺寸(米) | `[8.0, 8.0]` | -| `env.scene.terrain.generator.num_rows` | 网格行数(curriculum 模式下 = 难度等级数量) | `1` | -| `env.scene.terrain.generator.num_cols` | 网格列数(curriculum 模式下被忽略;列数 = `len(sub_terrains)`) | `1` | -| `env.scene.terrain.generator.border_width` | 网格周围平坦边界的宽度(米) | `1.0` | -| `env.scene.terrain.generator.difficulty_range` | 难度采样范围 `[min, max]`,∈ `[0, 1]` | `[0.0, 1.0]` | -| `env.terrain_scan.enabled` | 是否将后端原生高度扫描拼接到 critic obs | `true` | -| `env.terrain_scan.geom_name` | 高度扫描采样的 hfield geom 名称 | `floor` | - -示例:本地小规模冒烟 + 固定种子 + curriculum 模式。 - -```bash -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ - env.scene.terrain.generator.num_rows=4 \ - env.scene.terrain.generator.num_cols=6 \ - env.scene.terrain.generator.seed=42 \ - env.scene.terrain.generator.curriculum=true \ - algo.num_envs=64 algo.max_iterations=2 training.no_play=true -``` - -未在 YAML 中列出的字段(例如 `sub_terrains`)目前**无法**从命令行覆盖: - -- `sub_terrains` 是 `dict[str, SubTerrainCfg]`,而 `SubTerrainCfg` 是一个抽象基类;从命令行重建子类类型并不安全。 -- `terrain_scan.measured_points_x` / `terrain_scan.measured_points_y` 的默认网格由 `Go2JoystickRoughCfg` owner 定义;当需要修改扫描布局时,请在 owner cfg 中显式调整,并对照 critic obs 形状验证 `obs_groups_spec`。 - -## 3. 修改子地形 - -子地形在 `unilab.terrains.config` 的 `ALL_TERRAIN_PRESETS` 中注册。`Go2JoystickRough` 默认混合的 7 种子地形: - -| 名称 | 实现 | 描述 | -| --- | --- | --- | -| `flat` | `HfFlatTerrainCfg` | 全零高度场,基线 patch | -| `pyramid_stairs` | `HfPyramidStairsTerrainCfg` | 金字塔形上升台阶(高度场中的同心方环) | -| `pyramid_stairs_inv` | `HfInvertedPyramidStairsTerrainCfg` | 倒金字塔形下降台阶 | -| `hf_pyramid_slope` | `HfPyramidSlopedTerrainCfg` | 高度场金字塔斜坡 | -| `hf_pyramid_slope_inv` | `HfPyramidSlopedTerrainCfg(inverted=True)` | 倒金字塔斜坡 | -| `random_rough` | `HfRandomUniformTerrainCfg` | 随机均匀噪声高度场 | -| `wave_terrain` | `HfWaveTerrainCfg` | 正弦波高度场 | - -每种都有自己的难度参数(`step_height_range`、`slope_range`、`noise_range` 等);完整的字段定义在 `heightfield_terrains.py` 中。所有子地形(包括 `flat` 和台阶)现在都通过 hfield 实现,分辨率统一由 `TerrainGeneratorCfg.horizontal_scale` / `vertical_scale` 控制。 - -内置组合定义在 `unilab.terrains.config` 中,`Go2JoystickRoughCfg` 在 `go2/rough.py` 中定义了自己的 owner 默认值: - -- `Go2RoughTerrainCfg`:1 × 1,默认只采样 `random_rough`(proportion `0.2`,其余子地形作为可配置 profile 保留,但默认 proportion 为 `0.0`),随机模式。每个 env 实例获得自己独立的 cfg 对象。 -- `ROUGH_TERRAINS_CFG`:10 × 20,按 proportion 混合 7 种子地形,随机模式。目前作为可复用 profile 保留;不是 `Go2JoystickRoughCfg` 的默认训练 profile。 -- `STAIRS_TERRAINS_CFG`:10 × 4,curriculum 模式,难度从 flat → easy → moderate → challenging 递增。目前没有任何任务引用它;可以在自定义任务配置中使用。 - -## 4. 高度扫描观测 - -`Go2JoystickRoughEnv` 只把高度扫描拼接到 `critic` group;actor obs 遵循 45 维崎岖任务 contract。默认扫描点在 x 方向 17 个、y 方向 11 个,合计 187 维,因此 `obs_groups_spec` 为: - -| obs group | 维度 | 内容 | -| --- | ---: | --- | -| `obs` | `45` | actor policy 输入 | -| `critic` | `235` | 崎岖 critic 48 维 + 高度扫描 187 维 | - -高度扫描的 geom/body id 和采样偏移在 env init 期间缓存;热路径只使用由 `create_hfield_scanner(...)` 创建的后端持有的 scanner,并消费缓存的 id / 偏移。`step()` / `reset()` 中不解析 XML、不读取 asset 元数据。 - -## 5. 在新任务中启用程序化地形 - -新任务通过 `SceneCfg` 启用程序化地形。`SceneCfg` 位于 `src/unilab/base/scene.py`,`scene.terrain.generator` 使用 `TerrainGeneratorCfg`。 +例如,owner 可以声明生成式 terrain,而不让 backend 感知任务语义: ```yaml env: scene: - model_file: .../robot.xml - fragment_files: - - .../locomotion_task.xml terrain: - kind: hfield hfield_name: terrain_hfield geom_name: floor generator: + _target_: unilab.tasks.locomotion.common.rough_manager_terms.QuadrupedRoughTerrainCfg seed: 42 - size: [8.0, 8.0] - num_rows: 10 - num_cols: 20 - border_width: 20.0 ``` -env 的 `__init__` 不需要直接调用 XML 实例化器;把 `scene` 交给后端构造函数即可: +UniLab 不保留 procedural-terrain production owner。保留的 `g1_walk_rough` +任务使用同一冷路径 scene contract 的静态 heightfield 形式;generator 组合 +本身由核心 terrain 与 backend materialization 测试覆盖。 -```python -from unilab.base.backend_factory import create_backend +## 物化边界 -backend = create_backend(..., cfg.scene) -terrain_origins = getattr(backend, "terrain_origins", None) -``` - -注意:`TerrainGenerator.__init__` 会原地修改传入的 cfg(把值写入每个 `sub_cfg.size`)。如果同一个 `TerrainGeneratorCfg` 实例被多个 env 共享,它们会相互污染;你必须使用 `default_factory` 或 `copy.deepcopy` 来确保每个实例获得自己的 cfg。`Go2JoystickRoughCfg` 通过 `scene.terrain.generator=Go2RoughTerrainCfg()` 处理这一点。 +`registry.make(...)` 期间: -## 6. 可视化与离线回放 +1. Hydra 将选中的 owner 物化为 `ManagerBasedRlEnvCfg`。 +2. `create_backend` 解析所需机器人资产,并将 `SceneCfg` 传给选中的 UniSim + backend。 +3. backend 的公开 scene materializer 生成 terrain matrix、origins、hfield + 与合并后的 scene model。 +4. entity 与 height-scanner ID 被缓存供 reset/step 使用。 -要在不启动训练的情况下预览已实例化的场景: +step 和 reset 不解析机器人 XML,也不检查 asset metadata;它们只消费缓存 +ID 和公开 backend capability。 -```bash -uv run scripts/visualize_task_env.py --task Go2JoystickRough --num_envs 4 -``` +## 示例 -## 7. 验证 +使用保留的 rough-scene reference task: ```bash -# 程序化地形 + hfield PNG 实例化器单元/集成测试 -uv run pytest tests/terrains tests/utils/test_xml_utils.py -q - -# Hydra compose + Go2JoystickRoughCfg 任务 owner 测试 -uv run pytest tests/config/test_locomotion_params.py -k rough -q +uv run train --algo sac --task g1_walk_rough --sim mujoco training.no_play=true +``` -# Go2 崎岖地形 spawn + 高度扫描 contract 测试 -uv run pytest tests/envs/locomotion/test_go2_terrain_spawn.py tests/envs/locomotion/test_go2_rough_height_scan.py -q +自定义 owner 可以通过 Hydra 调整 terrain 网格与 seed: -# Hydra 命令行覆盖 + registry 深度合并环路 -uv run pytest tests/config/test_locomotion_params.py \ - -k "apply_cfg_overrides or hydra_terrain_override" -q +```text +env.scene.terrain.generator.num_rows=4 +env.scene.terrain.generator.seed=42 +``` -# 端到端冒烟:Hydra 命令行覆盖网格尺寸 + 种子,2 次迭代 PPO -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ - env.scene.terrain.generator.num_rows=4 env.scene.terrain.generator.seed=42 \ - algo.max_iterations=2 algo.num_envs=64 +## 核心验证 -uv run train --algo ppo --task go2_joystick_rough --sim motrix \ - env.scene.terrain.generator.num_rows=4 env.scene.terrain.generator.seed=42 \ - algo.max_iterations=2 algo.num_envs=64 +```bash +uv run pytest tests/terrains tests/utils/test_xml_utils.py -q ``` -## 已知约束 - -- **MuJoCo 和 Motrix 实例化器都有自动化冒烟覆盖**:MuJoCo 路径返回 `MjModel`,Motrix 路径返回 `SceneModel`。生产训练性能与收敛质量仍需由独立的 benchmark 记录;冒烟测试不对其作出保证。 -- **MuJoCo 组装路径依赖 `MjSpec.attach`**:机器人 XML、地形和 task 传感器 fragment 在实例化阶段组装,并直接编译为 `MjModel`。 -- **Motrix 组装路径依赖 `motrixsim.msd.World.attach`**:`go2.xml` 提供机器人模型,`locomotion_task.xml` 作为携带接触传感器和 task 级别 keyframe 的 task fragment 被接入。 -- **高度扫描支持通过 `create_hfield_scanner(...)`**:崎岖 env 在初始化期间缓存 scanner id 和偏移,然后在观测/奖励代码中消费 scanner 输出,热路径上不解析 XML。 -- **`scene.terrain.generator` 是冷路径配置**:在 env 构建之后修改 generator 不会影响已经实例化的场景。要更换地形,必须重建 env(即重新运行训练命令)。 -- **`import unilab.terrains` 不依赖 mujoco**:`TerrainGenerator.generate()` / `write_png()` 是纯 numpy + imageio 路径。 +核心验证同时覆盖 terrain generator 与 backend materialization 边界; +额外任务族的证据由 ecosystem 包持有。 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/2-heightfield_import.md b/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/2-heightfield_import.md index ec38bff1e..58971c1c0 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/2-heightfield_import.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/6-terrain/2-heightfield_import.md @@ -1,24 +1,23 @@ # 高度场导入 -高度场地形通过 `SceneCfg` 和地形生成器进行配置,然后在 init 路径上由后端实例化。已提交的面向用户的示例是 `Go2JoystickRough`,其 owner 位于 `src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml` 和 `src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml`。 +高度场地形通过 `SceneCfg` 和地形生成器进行配置,然后在 init 路径上由后端实例化。已提交的面向用户示例是保留的 `g1_walk_rough` 场景。 ## 需要阅读的文件 - `src/unilab/terrains/heightfield_terrains.py` - `unisim.terrain.generator` -- `src/unilab/tasks/locomotion/go2/rough.py` +- `src/unilab/assets/robots/g1/scene_rough.xml` +- `src/unilab/tasks/locomotion/common/height_scan.py` - `unisim.backend.mujoco.xml` - `unisim.backend.motrix.scene` ## 冒烟命令 ```bash -uv run train --algo ppo --task go2_joystick_rough --sim mujoco \ +uv run train --algo sac --task g1_walk_rough --sim mujoco \ algo.max_iterations=2 \ algo.num_envs=64 \ training.no_play=true - -uv run scripts/visualize_task_env.py --task Go2JoystickRough --backend mujoco --num_envs 4 ``` 高度扫描的 ID 和偏移在 env 初始化期间缓存;热路径调用后端高度 scanner contract,而不是解析 XML 或 asset 元数据。 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/4-scene_export.md b/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/4-scene_export.md index 5cd1275b4..44694a8b6 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/4-scene_export.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/4-scene_export.md @@ -5,7 +5,7 @@ 对于 task 级别的实例化检查,请使用从 registry 和 owner config 构造 env 的脚本: ```bash -uv run scripts/visualize_task_env.py --task Go2JoystickRough --backend mujoco --num_envs 4 +uv run scripts/visualize_task_env.py --task G1WalkFlat --backend mujoco --num_envs 4 ``` `tests/test_export_scene.py` 覆盖了导出辅助逻辑,包括 `scene.xml` 的创建、可重新加载性以及 zip 输出。 diff --git a/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/5-robot_import.md b/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/5-robot_import.md index cd3787a30..d922ab81a 100644 --- a/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/5-robot_import.md +++ b/docs/sphinx/source/zh_CN/2-user_guide/7-tooling/5-robot_import.md @@ -36,7 +36,7 @@ visual mesh 作为 collision mesh,尽量把碰撞体简化为 box / capsule / - 默认自动导入会把 actuator 写成 `position`,这只适合位置控制 owner。 - 如果机器人必须保留 torque/motor actuator 语义,后续扩展任务时,需要参考 - `src/unilab/tasks/locomotion/go2w/` 的控制方式,把 action 解释、PD/力矩控制和 + motor/torque 任务 owner 的控制方式,把 action 解释、PD/力矩控制和 actuator contract 放在机器人 owner 的控制边界内。 - 转换完成后,会自动弹出 `mujoco.viewer` 可视化界面展示转换结果,并进行下一步调整 Keyframe。 diff --git a/docs/sphinx/source/zh_CN/3-deployment/0-index.md b/docs/sphinx/source/zh_CN/3-deployment/0-index.md index 43200024f..df6b053bc 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/0-index.md +++ b/docs/sphinx/source/zh_CN/3-deployment/0-index.md @@ -60,7 +60,7 @@ :::{grid-item-card} 🐕 Go2 运动 :link: 1-sim_to_real/3-go2_locomotion :link-type: doc -摇杆、崎岖地形、Go2W 轮足。 +Go2 joystick-flat 部署。 ::: :::{grid-item-card} 🤚 Allegro 手内操作 diff --git a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/0-index.md b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/0-index.md index 647c1fefe..4b247f475 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/0-index.md +++ b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/0-index.md @@ -51,7 +51,7 @@ G1 路线的运动跟踪部署说明。 :::{grid-item-card} Go2 运动 :link: 3-go2_locomotion :link-type: doc -摇杆、崎岖地形与 Go2W 的部署说明。 +Go2 joystick-flat 部署说明。 ::: :::{grid-item-card} Allegro 手内操作 diff --git a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/1-overview.md b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/1-overview.md index a90ed9097..5e4d5d93f 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/1-overview.md +++ b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/1-overview.md @@ -83,7 +83,7 @@ flowchart LR :link: 3-go2_locomotion :link-type: doc -Go2 与 Go2W 上的摇杆 + 崎岖地形策略。 +Go2 上的摇杆平地策略。 ::: :::{grid-item-card} ✋ Allegro 手内操作 diff --git a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/2-g1_whole_body.md b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/2-g1_whole_body.md index d1ced945e..52b6dc9d7 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/2-g1_whole_body.md +++ b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/2-g1_whole_body.md @@ -48,9 +48,6 @@ uv run eval --algo ppo --task g1_motion_tracking --sim motrix --load-run -1 - 514 - 无状态估计:`motion_anchor_pos_b` 与 `base_lin_vel` 置为 `null`,使用 pelvis IMU,proprio 项带 `history_length: 5`。 -* - `src/unilab/conf/ppo/task/g1_motion_tracking_deploy/mujoco.yaml` - - 154 - - 单步 mimic actor 布局,按关节分组的 `scale` 正则映射。 ``` ::::{admonition} 观测宽度应从 composed config 读取,而不是照抄本表 @@ -101,8 +98,8 @@ motion command 在观测项之前贡献参考关节位置与速度(`29 + 29` 之前钳制到场景的关节范围内。 - `scale` 即 `env.actions.joint_pos.scale`。它可能是**标量**(`g1_wbt_obs` 为 - `2.0`),也可能是按 actuator 解析的**正则 → 数值映射** - (`g1_motion_tracking_deploy` 把关节名模式映射到不同数值)。必须原样复现 owner + `2.0`),也可能是按 actuator 解析的**正则 → 数值映射**(Unitree deploy owner + 把关节名模式映射到不同数值)。必须原样复现 owner 解析后的逐 actuator 向量——不要对映射取平均、取其中一项,也不要把标量广播到 映射型 owner 上。 - `default_angles` 由 `use_default_offset: true` 决定,即 owner 场景中 `stand` diff --git a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/3-go2_locomotion.md b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/3-go2_locomotion.md index 7ff50ed7d..618f10d2a 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/3-go2_locomotion.md +++ b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/3-go2_locomotion.md @@ -1,7 +1,7 @@ -# Go2 / Go2W 运动部署 +# Go2 运动部署 -摇杆驱动的运动(平地 + 崎岖)以及轮足式的 Go2W 变体。两者的硬件流程相似;本页指出 -其中的差异。 +本页描述保留的 `go2_joystick_flat` reference owner。Unitree production 部署 +变体由对应 ecosystem 包文档维护。 ## 观测契约 @@ -9,56 +9,41 @@ :header-rows: 1 :widths: 30 15 55 -* - 分组 - - 维度 - - 硬件上的来源 -* - 基座线速度 +* - Group + - Dim + - 硬件来源 +* - Base linear velocity - 3 - - 状态估计器(在 IMU + 腿部里程计上的 KF);不是原始积分 -* - 基座角速度 + - 状态估计器(IMU + 足端里程计 KF);不要使用原始积分 +* - Base angular velocity - 3 - IMU 陀螺仪 -* - 投影重力 +* - Projected gravity - 3 - - IMU 朝向 -* - 摇杆指令 (vx, vy, ωz) + - IMU 姿态 +* - Joystick command (vx, vy, ωz) - 3 - - 操作员输入 -* - 关节位置 - - 12(Go2)/ 16(Go2W) + - 操作者输入 +* - Joint positions + - 12 - 编码器 -* - 关节速度 - - 12 / 16 - - 经过部署控制器滤波路径后的编码器速度 -* - 上一步动作 - - 12 / 16 - - 上一次策略输出 -* - 足端接触 - - 4(仅 Go2) - - 接触传感器,或由足端高度估计 +* - Joint velocities + - 12 + - 部署控制器滤波后的编码器速度 +* - Previous action + - 12 + - 上一步策略输出 +* - Foot contact + - 4 + - 接触传感器或由足端高度估计 ``` ::::{admonition} 状态估计器注意事项 :class: warning -策略是针对所选环境 owner 发出的观测项训练的。如果部署无法提供同样的基座速度信号, -请训练一个变体,使其 actor 观测与你能在机器人上运行的估计器相匹配。 +策略训练时使用所选 env owner 声明的观测 term。如果部署侧无法提供相同的 +base-velocity 信号,请训练 actor 观测与机器人可用估计器匹配的变体。 :::: -## 崎岖地形注意事项 - -对于 `go2_joystick_rough`,策略期望存在抬升的地形特征。在平坦的室内地面上,按崎岖 -地形训练的策略会比必要时*更加保守*,但在硬件上机前仍应通过回放进行验证。对于在 -斜坡 / 碎屑上的部署: - -- 从实测的部署表面选取地面摩擦的 DR 范围。 -- 用地形课程训练:见 - {doc}`../../2-user_guide/6-terrain/1-procedural`。 - -## Go2W 轮 ↔ 腿分派 - -Go2W 策略为后轮关节输出**连续轮速**,并为腿部输出**位置目标**。动作向量的顺序必须 -与 `src/unilab/assets/robots/go2w/` 匹配。用 `unilab-export-scene` 验证。 - ## 另请参阅 - {doc}`5-onnx_runtime` diff --git a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/6-domain_randomization.md b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/6-domain_randomization.md index 7724b62e9..a3775621a 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/6-domain_randomization.md +++ b/docs/sphinx/source/zh_CN/3-deployment/1-sim_to_real/6-domain_randomization.md @@ -42,17 +42,16 @@ Manager-Based 任务在 owner YAML 的 `env.events` 中声明 reset 与 interval 随机化,由 manager 生命周期执行。示例见 -`src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`。 +`src/unilab/conf/sac/task/g1_wbt_obs/mujoco.yaml`。 legacy 任务级 provider 协议已移除。能力边界见 {doc}`../../4-developer_guide/2-contracts/4-dr_contract`。 ## 配方:起始范围 -以所选 owner YAML 为准。Go2 rough owner 组合 -`src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml`,其中声明基座质量、 -质心、PD 增益和周期推扰。以下是该共享 owner 的 PD 增益片段;绝对增益范围应 -与机器人的控制参数一起评估。 +以所选 owner YAML 为准。保留的 G1 WBT owner 声明基座质量、质心、PD 增益、 +编码器偏置和周期推扰。以下是一个 PD 增益片段;绝对增益范围应与机器人的 +控制参数一起评估。 ```yaml env: diff --git a/docs/sphinx/source/zh_CN/3-deployment/3-framework_migration/6-reward_porting.md b/docs/sphinx/source/zh_CN/3-deployment/3-framework_migration/6-reward_porting.md index 304e4819f..d35f4100c 100644 --- a/docs/sphinx/source/zh_CN/3-deployment/3-framework_migration/6-reward_porting.md +++ b/docs/sphinx/source/zh_CN/3-deployment/3-framework_migration/6-reward_porting.md @@ -7,7 +7,7 @@ Manager-Based reward 接收 env,通过 entity facade 和各 manager 读取批 ## 跟踪、平滑与关节限制 以下示例的 `twist` command 必须由 owner 的 `env.commands` 定义。 -跟踪与动作平滑项参考 `src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml`; +跟踪与动作平滑项参考 `src/unilab/conf/ppo/task/go2_joystick_flat/base.yaml`; 关节限制与终止项展示现有 helper 的配置方式,权重应按任务评估。 ```yaml diff --git a/docs/sphinx/source/zh_CN/4-developer_guide/1-architecture/4-scene_composition.md b/docs/sphinx/source/zh_CN/4-developer_guide/1-architecture/4-scene_composition.md index 68b9fe6d8..76f0b5abd 100644 --- a/docs/sphinx/source/zh_CN/4-developer_guide/1-architecture/4-scene_composition.md +++ b/docs/sphinx/source/zh_CN/4-developer_guide/1-architecture/4-scene_composition.md @@ -98,11 +98,10 @@ materializer。 当前面向用户的程序化地形路径是 Go2 崎岖地形: -- Task owner:`src/unilab/tasks/locomotion/go2/rough.py` +- Task owner:`src/unilab/tasks/locomotion/g1/manager_terms.py` - 地形生成器:`unisim.terrain.generator` - MuJoCo materializer:`unisim.backend.mujoco.xml` - Motrix materializer:`unisim.backend.motrix.scene` -- Owner YAML:`src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml`、 - `src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml` +- Owner YAML:`src/unilab/conf/sac/task/g1_walk_rough/{mujoco,motrix}.yaml` 用户使用说明见 {doc}`../../2-user_guide/6-terrain/1-procedural`。 diff --git a/docs/sphinx/source/zh_CN/4-developer_guide/7-motion_assets.md b/docs/sphinx/source/zh_CN/4-developer_guide/7-motion_assets.md index a391d4c6d..aa56fa864 100644 --- a/docs/sphinx/source/zh_CN/4-developer_guide/7-motion_assets.md +++ b/docs/sphinx/source/zh_CN/4-developer_guide/7-motion_assets.md @@ -80,8 +80,9 @@ env: 机器人二进制网格和纹理(例如 `.STL`、`.obj`、`.png`)采用相同方式外置, 托管在 Hugging Face 数据集仓库 [unilabsim/unilab-robots](https://huggingface.co/datasets/unilabsim/unilab-robots)。 -已注册的机器人为 a2、allegro_hand、g1、go2、 -x2(见 `src/unilab/assets/hub.py` 的 `ROBOT_ASSET_SPECS`)。它们的 +核心已注册机器人为 allegro_hand、g1、go2、x2(见 +`src/unilab/assets/hub.py` 的 `ROBOT_ASSET_SPECS`)。Unitree production +机器人元数据由 `unitree_rl_unilab` 解析。它们的 mesh/纹理目录在首次使用时按需下载,落盘到原始路径(例如 G1 的 `src/unilab/assets/robots/g1/assets/` 与 `robots/g1/textures/`),因此 XML 中的 原始相对路径保持有效。这些目录通过 `pyproject.toml` 的 diff --git a/docs/sphinx/source/zh_CN/4-developer_guide/9-sim2sim_contract_status.md b/docs/sphinx/source/zh_CN/4-developer_guide/9-sim2sim_contract_status.md index 4c61f1c78..85143018e 100644 --- a/docs/sphinx/source/zh_CN/4-developer_guide/9-sim2sim_contract_status.md +++ b/docs/sphinx/source/zh_CN/4-developer_guide/9-sim2sim_contract_status.md @@ -28,21 +28,20 @@ uv run scripts/audit_sim2sim_contracts.py | Task | 判定 | 分歧 | |---|---|---| -| allegro_inhand · allegro_inhand_grasp · g1_climb_tracking · g1_motion_tracking · g1_wall_flip_tracking · go1_joystick_rough · go2_footstand · go2_handstand · go2_joystick_flat · go2_joystick_rough · go2w_joystick_flat · go2w_joystick_rough | ✅ | 无 | +| allegro_inhand · allegro_inhand_grasp · g1_motion_tracking · go2_handstand · go2_joystick_flat | ✅ | 无 | | g1_box_tracking | ❌ | `empirical_normalization` false↔true;`obs_groups` critic 组差异 | | g1_flip_tracking | ❌ | `empirical_normalization` true↔false;`obs_groups`;`action_scale` 29 维↔默认 0.25;`sampling_mode` 两后端运行时同为 `start`(无害) | | g1_walk_flat | ❌ | `env.actions.joint_pos.scale` 0.25↔0.5;`empirical_normalization` false↔true;`obs_groups` | -| go1_joystick_flat | ❌ | `empirical_normalization` false↔true | -| g1_motion_tracking_deploy | ⚪ | 仅 mujoco | ## `src/unilab/conf/appo/task/` | Task | 判定 | 分歧 | |---|---|---| -| allegro_inhand · g1_climb_tracking · g1_motion_tracking · go2_joystick_flat | ✅ | 无 | +| allegro_inhand · g1_motion_tracking · go2_joystick_flat | ✅ | 无 | | g1_flip_tracking | ❌ | `action_scale` 29 维↔默认 0.25;`sampling_mode` 同为 `start`(无害) | -| g1_wall_flip_tracking | ❌ | `action_scale` 29 维↔默认 0.25;`sampling_mode` `start`↔默认 `adaptive` | -| g1_walk_flat · go1_joystick_flat | ⚪ | 仅 mujoco | +| g1_walk_flat | ⚪ | 仅 mujoco | + +已迁移的 Unitree owner 由 `unitree_rl_unilab` 自行维护 contract audit;核心状态表不再声称覆盖它们。 ## 其它配置树 diff --git a/docs/sphinx/source/zh_CN/5-reference/5-support_matrix.md b/docs/sphinx/source/zh_CN/5-reference/5-support_matrix.md index 42b44203c..35722ba4b 100644 --- a/docs/sphinx/source/zh_CN/5-reference/5-support_matrix.md +++ b/docs/sphinx/source/zh_CN/5-reference/5-support_matrix.md @@ -61,66 +61,30 @@ uv run scripts/generate_support_matrix.py --write | Entrypoint | Task owner | MuJoCo | mjwarp | Motrix | IsaacGym | Genesis | IsaacSim | Newton | SuperDex | |------------|------------|--------|--------|--------|----------|---------|----------|--------|----------| -| PPO (torch) | `go1_joystick_flat` (Go1 joystick) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | - | - | Configured | -| PPO (torch) | `go2_joystick_rough` (Go2 joystick rough) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Configured | Configured | Configured | Configured | - | | PPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `x2_wall_flip_tracking` (X2 wall flip tracking) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `a2_joystick_flat` (a2 joystick flat) | Tested | - | - | - | - | - | - | - | | PPO (torch) | `allegro_inhand_grasp` (allegro inhand grasp) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `fr3_joint_target` (fr3 joint target) | - | - | - | - | - | - | - | Configured | -| PPO (torch) | `g1_23dof_box_tracking` (g1 23dof box tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_climb_tracking` (g1 23dof climb tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_motion_tracking_deploy` (g1 23dof motion tracking deploy) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_23dof_walk_rough` (g1 23dof walk rough) | Tested | - | Registered | - | - | - | - | - | -| PPO (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `g1_box_tracking` (g1 box tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_climb_tracking` (g1 climb tracking) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `g1_motion_tracking_deploy` (g1 motion tracking deploy) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `go1_joystick_rough` (go1 joystick rough) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `go2_footstand` (go2 footstand) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `go2w_joystick_flat` (go2w joystick flat) | Tested | - | Tested | - | - | - | - | - | -| PPO (torch) | `go2w_joystick_rough` (go2w joystick rough) | Tested | - | Tested | - | - | - | - | - | | PPO (torch) | `stewart_balance` (stewart balance) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `go1_joystick_flat` (Go1 joystick) | Tested | - | Tested | - | - | - | - | - | | APPO (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Tested | - | - | - | - | Registered | | APPO (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | Registered | Registered | - | | APPO (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | - | Tested | - | - | - | - | - | | APPO (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Tested | - | - | - | - | - | | APPO (torch) | `allegro_inhand` (Allegro in-hand) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_23dof_climb_tracking` (g1 23dof climb tracking) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Registered | - | - | - | - | - | -| APPO (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Tested | - | - | - | - | - | -| APPO (torch) | `g1_climb_tracking` (g1 climb tracking) | Tested | - | Tested | - | - | - | - | - | | SAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Tested | Tested | Tested | Tested | Configured | Tested | - | | SAC (torch) | `g1_walk_rough` (G1 walk rough) | Tested | - | Tested | - | - | - | - | - | | SAC (torch) | `g1_motion_tracking` (G1 motion tracking) | Tested | Configured | Tested | - | - | - | - | - | | SAC (torch) | `g1_flip_tracking` (G1 flip tracking) | Tested | - | Registered | - | - | - | - | - | -| SAC (torch) | `g1_wall_flip_tracking` (G1 wall flip tracking) | Tested | - | Registered | - | - | - | - | - | -| SAC (torch) | `g1_23dof_flip_tracking` (g1 23dof flip tracking) | Tested | - | Registered | - | - | - | - | - | -| SAC (torch) | `g1_23dof_motion_tracking` (g1 23dof motion tracking) | Tested | - | Tested | - | - | - | - | - | -| SAC (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | - | - | - | -| SAC (torch) | `g1_23dof_walk_rough` (g1 23dof walk rough) | Tested | - | Tested | - | - | - | - | - | -| SAC (torch) | `g1_23dof_wall_flip_tracking` (g1 23dof wall flip tracking) | Tested | - | Registered | - | - | - | - | - | -| SAC (torch) | `g1_23dof_wbt_obs` (g1 23dof wbt obs) | Tested | - | Registered | - | - | - | - | - | | SAC (torch) | `g1_wbt_obs` (g1 wbt obs) | Tested | - | Registered | - | - | - | - | - | -| TD3 (torch) | `go1_joystick_flat` (Go1 joystick) | Registered | - | Tested | - | - | - | - | - | | TD3 (torch) | `go2_joystick_flat` (Go2 joystick) | Registered | - | Tested | - | - | - | - | Registered | | TD3 (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Registered | Registered | Registered | Registered | Registered | Registered | - | -| TD3 (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Registered | - | - | - | - | - | | FlashSAC (torch) | `go2_joystick_flat` (Go2 joystick) | Tested | - | Registered | - | - | - | - | Registered | | FlashSAC (torch) | `g1_walk_flat` (G1 walk flat) | Tested | Configured | Tested | Registered | Registered | Registered | Registered | - | -| FlashSAC (torch) | `g1_23dof_walk_flat` (g1 23dof walk flat) | Tested | - | Tested | - | - | - | - | - | ### Source Index diff --git a/pyproject.toml b/pyproject.toml index 0b1b0568c..8e63ba820 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,11 +10,9 @@ build-backend = "uv_build" # SUPERDEX_ROBOT_ASSET_SPECS in src/unilab/assets/hub.py. source-exclude = [ "/src/unilab/assets/bots", - "/src/unilab/assets/robots/a2/assets", "/src/unilab/assets/robots/allegro_hand/assets", "/src/unilab/assets/robots/g1/assets", "/src/unilab/assets/robots/g1/textures", - "/src/unilab/assets/robots/go1/assets", "/src/unilab/assets/robots/go2/assets", "/src/unilab/assets/robots/x2/meshes", ] diff --git a/scripts/benchmark/benchmark_drake_performance.py b/scripts/benchmark/benchmark_drake_performance.py index b1bc44c27..f53ffc7bd 100644 --- a/scripts/benchmark/benchmark_drake_performance.py +++ b/scripts/benchmark/benchmark_drake_performance.py @@ -95,11 +95,6 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: def _task_specs() -> dict[str, TaskSpec]: - def go1_cfg() -> Any: - from unilab.envs import ManagerBasedRlEnvCfg - - return ManagerBasedRlEnvCfg() - def manager_env() -> Callable[..., Any]: from unilab.envs import make_manager_based_rl_env @@ -111,7 +106,6 @@ def go2_cfg() -> Any: return ManagerBasedRlEnvCfg() return { - "go1_joystick_flat": TaskSpec(go1_cfg, manager_env), "go2_joystick_flat": TaskSpec(go2_cfg, manager_env), } @@ -321,7 +315,7 @@ def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--tasks", - default="go1_joystick_flat,go2_joystick_flat", + default="go2_joystick_flat", help="Comma-separated task ids with committed Drake YAML owners.", ) parser.add_argument("--backends", default="drake,mujoco", help="Comma-separated backends.") diff --git a/scripts/benchmark/core/task_names.py b/scripts/benchmark/core/task_names.py index 88e0f15e3..c23b12347 100644 --- a/scripts/benchmark/core/task_names.py +++ b/scripts/benchmark/core/task_names.py @@ -15,13 +15,6 @@ class LocomotionTaskSpec: _TASK_SPECS = { - "go1_joystick_flat": LocomotionTaskSpec( - owner_task_id="go1_joystick_flat", - env_task_name="Go1JoystickFlat", - display_name="go1_joystick_flat", - config_cls=ManagerBasedRlEnvCfg, - model_file="src/unilab/assets/robots/go1/scene_flat.xml", - ), "go2_joystick_flat": LocomotionTaskSpec( owner_task_id="go2_joystick_flat", env_task_name="Go2JoystickFlat", diff --git a/scripts/benchmark/env/benchmark_env_step.py b/scripts/benchmark/env/benchmark_env_step.py index d9d807600..51700ced4 100644 --- a/scripts/benchmark/env/benchmark_env_step.py +++ b/scripts/benchmark/env/benchmark_env_step.py @@ -13,7 +13,7 @@ scripts/benchmark/env/benchmark_env_step.py task=g1_walk_flat/mjwarp # Override bench params: - uv run scripts/benchmark/env/benchmark_env_step.py task=go1_joystick_flat/mujoco num_envs=4096 num_steps=500 + uv run scripts/benchmark/env/benchmark_env_step.py task=go2_joystick_flat/mujoco num_envs=4096 num_steps=500 # Save to custom locations: uv run scripts/benchmark/env/benchmark_env_step.py --out-json tmp/env_step.json --plot-dir tmp/env_step_plots @@ -223,12 +223,6 @@ def _materialize_g1_rough_benchmark_scene() -> str: return str(output_path) -def _go1_cfg(backend: str, config_overrides: list[str]) -> Any: - from unilab.envs import ManagerBasedRlEnvCfg - - return _ppo_owner_yaml_cfg("go1_joystick_flat", backend, ManagerBasedRlEnvCfg, config_overrides) - - def _manager_env_cls() -> Callable[..., Any]: from unilab.envs import make_manager_based_rl_env @@ -241,34 +235,6 @@ def _go2_cfg(backend: str, config_overrides: list[str]) -> Any: return _ppo_owner_yaml_cfg("go2_joystick_flat", backend, ManagerBasedRlEnvCfg, config_overrides) -def _go2_rough_cfg(backend: str, config_overrides: list[str]) -> Any: - from unilab.envs import ManagerBasedRlEnvCfg - - return _ppo_owner_yaml_cfg( - "go2_joystick_rough", backend, ManagerBasedRlEnvCfg, config_overrides - ) - - -def _go2w_cfg(backend: str, config_overrides: list[str]) -> Any: - from unilab.envs import ManagerBasedRlEnvCfg - - return _ppo_owner_yaml_cfg( - "go2w_joystick_flat", backend, ManagerBasedRlEnvCfg, config_overrides - ) - - -def _go2w_rough_cfg(backend: str, config_overrides: list[str]) -> Any: - from unilab.envs import ManagerBasedRlEnvCfg - - return _ppo_owner_yaml_cfg( - "go2w_joystick_rough", backend, ManagerBasedRlEnvCfg, config_overrides - ) - - -def _go2w_env_cls() -> Callable[..., Any]: - return _manager_env_cls() - - def _g1_flat_cfg(backend: str, config_overrides: list[str]) -> Any: from unilab.envs import ManagerBasedRlEnvCfg @@ -299,13 +265,6 @@ def _g1_walk_env_cls() -> type: TASK_CONFIGS: dict[str, TaskConfig] = { - "go1": TaskConfig( - task_id="go1_joystick_flat", - env_name="Go1JoystickFlat", - cfg_factory=_go1_cfg, - env_cls_factory=_manager_env_cls, - backends=("mujoco", "motrix", "mjwarp"), - ), "go2": TaskConfig( task_id="go2_joystick_flat", env_name="Go2JoystickFlat", @@ -313,27 +272,6 @@ def _g1_walk_env_cls() -> type: env_cls_factory=_manager_env_cls, backends=("mujoco", "motrix", "mjwarp"), ), - "go2_rough": TaskConfig( - task_id="go2_joystick_rough", - env_name="Go2JoystickRough", - cfg_factory=_go2_rough_cfg, - env_cls_factory=_manager_env_cls, - backends=("mujoco", "motrix"), - ), - "go2w": TaskConfig( - task_id="go2w_joystick_flat", - env_name="Go2WJoystickFlat", - cfg_factory=_go2w_cfg, - env_cls_factory=_go2w_env_cls, - backends=("mujoco", "motrix", "mjwarp"), - ), - "go2w_rough": TaskConfig( - task_id="go2w_joystick_rough", - env_name="Go2WJoystickRough", - cfg_factory=_go2w_rough_cfg, - env_cls_factory=_manager_env_cls, - backends=("mujoco", "motrix"), - ), "g1": TaskConfig( task_id="g1_walk_flat", env_name="G1WalkFlat", @@ -364,15 +302,10 @@ def _g1_walk_env_cls() -> type: DEFAULT_WARMUP_STEPS = 5 TASK_COLORS = { - "go1": "#4C78A8", "go2": "#54A24B", - "go2_rough": "#8CD17D", "g1": "#F58518", "g1_mt": "#B279A2", "g1_rough": "#E45756", - "go2w": "#72B7B2", - "go2w_rough": "#499894", - "go2w_rough_tiles": "#499894", } BACKEND_STYLES = { "mujoco": {"marker": "o", "linestyle": "-", "hatch": "//"}, @@ -488,7 +421,7 @@ def _matching_task_config(task_path: str) -> TaskConfig | None: def _resolve_task_and_backend(hydra_overrides: list[str]) -> tuple[str, TaskConfig, str]: """Resolve the benchmark owner selected by ``task=/``.""" - task_key = "go1" + task_key = "go2" task_config = TASK_CONFIGS[task_key] sim_backend: str | None = None @@ -716,17 +649,13 @@ def _print_single_report(result: dict[str, Any]) -> None: def _short_task_label(task_name: str) -> str: - """Shorten 'Go1JoystickFlat' → 'go1'.""" + """Shorten canonical registry names for benchmark plot labels.""" name = task_name.lower() if "motiontracking" in name: return "g1_mt" if "rough" in name and name.startswith("g1"): return "g1_rough" - if name.startswith("go2w") and "roughtiles" in name: - return "go2w_rough_tiles" - if name.startswith("go2w"): - return "go2w" - for prefix in ("go1", "go2", "g1"): + for prefix in ("go2", "g1"): if name.startswith(prefix): return prefix return task_name[:8] diff --git a/scripts/benchmark/env/benchmark_postprocess.py b/scripts/benchmark/env/benchmark_postprocess.py index 4f7468cec..1b5aff3bd 100644 --- a/scripts/benchmark/env/benchmark_postprocess.py +++ b/scripts/benchmark/env/benchmark_postprocess.py @@ -35,7 +35,7 @@ def ensure_registries() -> None: OUTPUT_JSON = OUTPUT_DIR / "latest_postprocess_benchmark.json" OUTPUT_PNG = OUTPUT_DIR / "latest_postprocess_latency.png" TORCH_DEVICE = "mps" -OWNER_TASK_ID = "go1_joystick_flat" +OWNER_TASK_ID = "go2_joystick_flat" ENV_TASK_NAME = locomotion_env_name(OWNER_TASK_ID) diff --git a/scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py b/scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py index be5e94e1f..9c917c99d 100644 --- a/scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py +++ b/scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py @@ -19,7 +19,7 @@ uv run scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py uv run scripts/benchmark/physics/benchmark_mujoco_backend_step_detail.py \ - --tasks go1_joystick_flat,go2_joystick_flat,g1_walk_flat \ + --tasks go2_joystick_flat,g1_walk_flat \ --env-nums 256,512,1024,2048,4096,8192 \ --nsteps 1,2,3,4 @@ -87,7 +87,6 @@ def _load_helper_module(module_name: str, relative_path: str): ) TASK_COLORS = { - "go1_joystick_flat": "#4C78A8", "go2_joystick_flat": "#54A24B", "g1_walk_flat": "#F58518", } diff --git a/scripts/benchmark/physics/benchmark_mujoco_rollout_model_sharing.py b/scripts/benchmark/physics/benchmark_mujoco_rollout_model_sharing.py index cf349e34d..61e607b64 100644 --- a/scripts/benchmark/physics/benchmark_mujoco_rollout_model_sharing.py +++ b/scripts/benchmark/physics/benchmark_mujoco_rollout_model_sharing.py @@ -50,7 +50,6 @@ DEFAULT_ROBOT_XMLS = { - "go1": Path("src/unilab/assets/robots/go1/scene_flat.xml"), "go2": Path("src/unilab/assets/robots/go2/scene_flat.xml"), "g1": Path("src/unilab/assets/robots/g1/scene_flat.xml"), } diff --git a/scripts/benchmark/physics/benchmark_physics_step_genesis.py b/scripts/benchmark/physics/benchmark_physics_step_genesis.py index 2cab889e8..b45d92d5a 100644 --- a/scripts/benchmark/physics/benchmark_physics_step_genesis.py +++ b/scripts/benchmark/physics/benchmark_physics_step_genesis.py @@ -3,7 +3,7 @@ Benchmark Genesis physics execution. Benchmarks Genesis across current locomotion owner task ids -(go1_joystick_flat/go2_joystick_flat/g1_walk_flat) and outputs JSON + plots +(go2_joystick_flat/g1_walk_flat) and outputs JSON + plots aligned with scripts/benchmark/physics/benchmark_physics_step_mj_step.py. Legacy env names remain accepted as aliases. diff --git a/scripts/benchmark/physics/benchmark_physics_step_isaacgym.py b/scripts/benchmark/physics/benchmark_physics_step_isaacgym.py index 57de6bb90..9c4660ec7 100644 --- a/scripts/benchmark/physics/benchmark_physics_step_isaacgym.py +++ b/scripts/benchmark/physics/benchmark_physics_step_isaacgym.py @@ -2,7 +2,7 @@ """ Benchmark Isaac Gym physics execution using URDF assets. -Benchmarks Isaac Gym across go1/go2/g1 locomotion robots and outputs JSON + plots +Benchmarks Isaac Gym across go2/g1 locomotion robots and outputs JSON + plots aligned with scripts/benchmark/physics/benchmark_physics_step_mj_step.py. Run without creating any new environment: @@ -107,13 +107,6 @@ class BenchRecord: TASK_SPECS = { - "go1_joystick_flat": TaskSpec( - owner_task_id="go1_joystick_flat", - display_name="go1_joystick_flat", - asset_root=DEFAULT_MODELS_ROOT, - asset_file="go1_description/urdf/go1.urdf", - initial_height=0.40, - ), "go2_joystick_flat": TaskSpec( owner_task_id="go2_joystick_flat", display_name="go2_joystick_flat", @@ -130,16 +123,12 @@ class BenchRecord: ), } TASK_ALIASES = { - "Go1JoystickFlat": "go1_joystick_flat", "Go2JoystickFlat": "go2_joystick_flat", "G1WalkFlat": "g1_walk_flat", - "task=go1_joystick_flat/isaacgym": "go1_joystick_flat", "task=go2_joystick_flat/isaacgym": "go2_joystick_flat", "task=g1_walk_flat/isaacgym": "g1_walk_flat", - "go1_joystick_flat/isaacgym": "go1_joystick_flat", "go2_joystick_flat/isaacgym": "go2_joystick_flat", "g1_walk_flat/isaacgym": "g1_walk_flat", - "go1": "go1_joystick_flat", "go2": "go2_joystick_flat", "g1": "g1_walk_flat", } @@ -437,7 +426,7 @@ def main(): "--models-root", type=str, default=str(DEFAULT_MODELS_ROOT), - help="Root containing go1_description/go2_description/g1_description URDFs", + help="Root containing go2_description/g1_description URDFs", ) parser.add_argument("--tasks", type=str, default=",".join(DEFAULT_TASK_IDS)) parser.add_argument( diff --git a/scripts/benchmark/physics/benchmark_physics_step_isaacsim.py b/scripts/benchmark/physics/benchmark_physics_step_isaacsim.py index 8c4852791..bd752ff55 100644 --- a/scripts/benchmark/physics/benchmark_physics_step_isaacsim.py +++ b/scripts/benchmark/physics/benchmark_physics_step_isaacsim.py @@ -75,13 +75,6 @@ class BenchRecord: TASK_SPECS: Dict[str, TaskSpec] = { - "go1_joystick_flat": TaskSpec( - owner_task_id="go1_joystick_flat", - display_name="go1_joystick_flat", - usd_file="go1_description/go1.usd", - articulation_root_prim="base", - initial_height=0.40, - ), "go2_joystick_flat": TaskSpec( owner_task_id="go2_joystick_flat", display_name="go2_joystick_flat", @@ -98,10 +91,8 @@ class BenchRecord: ), } TASK_ALIASES = { - "Go1JoystickFlat": "go1_joystick_flat", "Go2JoystickFlat": "go2_joystick_flat", "G1WalkFlat": "g1_walk_flat", - "go1": "go1_joystick_flat", "go2": "go2_joystick_flat", "g1": "g1_walk_flat", **{f"task={task}/isaacsim": task for task in TASK_SPECS}, @@ -568,7 +559,7 @@ def main() -> None: "--usd-root", type=str, default=str(DEFAULT_USD_ROOT), - help="Directory containing go1/go2/g1 USD assets", + help="Directory containing go2/g1 USD assets", ) parser.add_argument("--tasks", type=str, default=",".join(DEFAULT_TASK_IDS)) parser.add_argument( diff --git a/scripts/benchmark/physics/benchmark_physics_step_mj_step.py b/scripts/benchmark/physics/benchmark_physics_step_mj_step.py index 77c58e26c..ce48d7141 100644 --- a/scripts/benchmark/physics/benchmark_physics_step_mj_step.py +++ b/scripts/benchmark/physics/benchmark_physics_step_mj_step.py @@ -5,7 +5,7 @@ Benchmarks mujoco.rollout with the configured thread count. Sweeps batch sizes across current locomotion owner task ids -(go1_joystick_flat/go2_joystick_flat/g1_walk_flat). +(go2_joystick_flat/g1_walk_flat). Legacy env names remain accepted as aliases. """ @@ -58,8 +58,8 @@ class BenchRecord: DEFAULT_TASK_IDS = canonical_locomotion_task_ids() DEFAULT_BATCH_SIZES = [2**k for k in range(8, 15)] # 256 .. 16384 -TASK_ALPHA = {"go1_joystick_flat": 0.75, "go2_joystick_flat": 0.9, "g1_walk_flat": 1.0} -TASK_HATCH = {"go1_joystick_flat": "//", "go2_joystick_flat": "\\\\", "g1_walk_flat": "xx"} +TASK_ALPHA = {"go2_joystick_flat": 0.9, "g1_walk_flat": 1.0} +TASK_HATCH = {"go2_joystick_flat": "\\\\", "g1_walk_flat": "xx"} def _keyframe0_state_and_ctrl(model: Any) -> tuple[np.ndarray, np.ndarray]: diff --git a/scripts/benchmark/physics/benchmark_physics_step_mujoco_warp.py b/scripts/benchmark/physics/benchmark_physics_step_mujoco_warp.py index 699829b37..accf06a58 100644 --- a/scripts/benchmark/physics/benchmark_physics_step_mujoco_warp.py +++ b/scripts/benchmark/physics/benchmark_physics_step_mujoco_warp.py @@ -3,7 +3,7 @@ Benchmark MuJoCo Warp physics execution. Benchmarks mujoco_warp across current locomotion owner task ids -(go1_joystick_flat/go2_joystick_flat/g1_walk_flat) and outputs JSON + plots +(go2_joystick_flat/g1_walk_flat) and outputs JSON + plots aligned with scripts/benchmark/physics/benchmark_physics_step_mj_step.py. Legacy env names remain accepted as aliases. @@ -81,7 +81,6 @@ class BenchRecord: DEFAULT_TASK_IDS = canonical_locomotion_task_ids() DEFAULT_BATCH_SIZES = [2**k for k in range(8, 15)] # 256 .. 16384 DEFAULT_NJMAX_BY_TASK = { - "go1_joystick_flat": 100, "go2_joystick_flat": 100, "g1_walk_flat": 256, } diff --git a/scripts/tools/capture_mujoco_drift_baseline.py b/scripts/tools/capture_mujoco_drift_baseline.py index c01947619..938f4edbc 100644 --- a/scripts/tools/capture_mujoco_drift_baseline.py +++ b/scripts/tools/capture_mujoco_drift_baseline.py @@ -37,7 +37,7 @@ # Single task / smoke run: uv run scripts/tools/capture_mujoco_drift_baseline.py \ - --tasks go2w_joystick_flat/mujoco --steps 50 --output /tmp/drift_smoke + --tasks go2_joystick_flat/mujoco --steps 50 --output /tmp/drift_smoke # Determinism check: run twice into different dirs, compare array contents. """ @@ -73,11 +73,10 @@ CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" DEFAULT_OUTPUT_DIR = ROOT_DIR / "scripts" / "tools" / "drift_baseline" / "before" -# Default tasks: Go2WJoystickFlat exercises the per-substep state-feedback -# control path (Go2WMixedAction via SimBackend.set_pre_step_control), the -# highest-risk surface for the executor swap; Go2JoystickFlat covers the plain -# position-action path on the same robot family. -DEFAULT_TASKS = ("go2w_joystick_flat/mujoco", "go2_joystick_flat/mujoco") +# Default task: the retained Go2JoystickFlat owner covers the plain +# position-action path. Wheeled-leg drift evidence now belongs to the Unitree +# downstream repository. +DEFAULT_TASKS = ("go2_joystick_flat/mujoco",) # Executor determinism contract: pin the pool worker count via cpu_ids so # every run steps an identical partition. Recorded in metadata for the AFTER diff --git a/scripts/tools/drift_baseline/after/Go2WJoystickFlat.metadata.json b/scripts/tools/drift_baseline/after/Go2WJoystickFlat.metadata.json deleted file mode 100644 index 2d1308713..000000000 --- a/scripts/tools/drift_baseline/after/Go2WJoystickFlat.metadata.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "task_name": "Go2WJoystickFlat", - "hydra_task_path": "go2w_joystick_flat/mujoco", - "sim_backend": "mujoco", - "num_envs": 8, - "num_steps": 300, - "seed": 42, - "action_seed": 1234, - "action_generator": "make_action_sequence: default_rng(action_seed) iid uniform(-1, 1); envs i%4==3 hold a seeded +/-1 vector for the first half, negated after", - "cpu_ids": [ - 0, - 1, - 2, - 3 - ], - "sim_dt": 0.005, - "ctrl_dt": 0.02, - "obs_groups_spec": { - "obs": 53, - "critic": 72 - }, - "action_dim": 16, - "git_commit": "fc64b6ae8b06eae89badc36cbc309d61e8f363af", - "package_versions": { - "mujoco": "3.11.0", - "mjbatch": "0.1.0", - "unisim-core": "1.2.0", - "numpy": "2.4.4" - }, - "timestamp_utc": "2026-09-11T17:43:31.120882+00:00", - "array_sha256": { - "reward": "b5ea168ca93c3280f4f461d32f8e21d5a0445f5962276236ff04710b8cc24c22", - "terminated": "1b4fa292d26b5857652ffa862089156a03091bb14d82fc107d3ec9bcebc4c866", - "truncated": "a0ee989ed2a0a2e3626520afa4032e06144865c8c8f6357293c9f4cd2069eaf2", - "qpos": "185ae7ba7075296515e3ea0da4dc7ec8806e4d5eea69ae49b95fafeacbf368f4", - "qvel": "a66798bf2ab1f9828f01540e4b2b8c0643246fe519907e0df3aacd2f8ec940ce", - "obs/critic": "b2d6f68504ab0ef62dd44671b4c3e4e0cfad04a480073760d58029fffbfed59e", - "obs/obs": "fa658e25ded3bc88704edb7b2827f7d37aa2fdd2b0a47af1798c940e5d800ef4", - "actions": "4c2df924382b83d34cb56a188cb966c23d27d30fd4c8a6973e5d92bc6e7e7a8f", - "obs_init/critic": "149379b215c40beb65da5e4301e064a3e92f39a112a2783fec577dfc8c34518d", - "obs_init/obs": "d4b73148fbb776fd7912c20dbd84fd3c0e8cdf9757868b8e30b5b92e406b8e72", - "qpos_init": "924ca2ab30273642e3a284c0b57718bb61df707e3df00b7d32792826b074db81", - "qvel_init": "c50170fa7c86bb5bc265f44bfe0d21e86d5f112feeab31725641b981d1e42c54" - } -} diff --git a/scripts/tools/drift_baseline/after/Go2WJoystickFlat.npz b/scripts/tools/drift_baseline/after/Go2WJoystickFlat.npz deleted file mode 100644 index bfeb8e49d..000000000 Binary files a/scripts/tools/drift_baseline/after/Go2WJoystickFlat.npz and /dev/null differ diff --git a/scripts/tools/drift_baseline/before/Go2WJoystickFlat.metadata.json b/scripts/tools/drift_baseline/before/Go2WJoystickFlat.metadata.json deleted file mode 100644 index 8cacf0a5c..000000000 --- a/scripts/tools/drift_baseline/before/Go2WJoystickFlat.metadata.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "task_name": "Go2WJoystickFlat", - "hydra_task_path": "go2w_joystick_flat/mujoco", - "sim_backend": "mujoco", - "num_envs": 8, - "num_steps": 300, - "seed": 42, - "action_seed": 1234, - "action_generator": "make_action_sequence: default_rng(action_seed) iid uniform(-1, 1); envs i%4==3 hold a seeded +/-1 vector for the first half, negated after", - "cpu_ids": [ - 0, - 1, - 2, - 3 - ], - "chunk_size": 2, - "adaptive_chunk_size": false, - "sim_dt": 0.005, - "ctrl_dt": 0.02, - "obs_groups_spec": { - "obs": 53, - "critic": 72 - }, - "action_dim": 16, - "git_commit": "db1a6e5b3dbe4dd096b16a517837f2d46dba8164", - "package_versions": { - "mujoco": "3.11.0", - "mujoco-uni-runtime": "0.5.0", - "unisim-core": "1.2.0", - "numpy": "2.4.4" - }, - "timestamp_utc": "2026-09-11T15:32:47.470709+00:00", - "array_sha256": { - "reward": "469cd45dcd4efd4af7d549b7b339c062a444de8d55ee311316f867831851da09", - "terminated": "1b4fa292d26b5857652ffa862089156a03091bb14d82fc107d3ec9bcebc4c866", - "truncated": "a0ee989ed2a0a2e3626520afa4032e06144865c8c8f6357293c9f4cd2069eaf2", - "qpos": "fb4e78b67a0e26df9a483f0c15ba72883c3226ddc6e4988c9277cfcbf99b98e9", - "qvel": "d68d669c9efb7a5a269cc672d70a29229e16276f3573ad16ffbee9240701cfb0", - "obs/critic": "f7445001580e6fe5499c80b01bd07751309b632e621c1fd191bf0fb857cf355d", - "obs/obs": "ec7b82b63128e7ab85d7da08eaabbcab72b41b20f381c4574b58bf7450bc97c1", - "actions": "4c2df924382b83d34cb56a188cb966c23d27d30fd4c8a6973e5d92bc6e7e7a8f", - "obs_init/critic": "149379b215c40beb65da5e4301e064a3e92f39a112a2783fec577dfc8c34518d", - "obs_init/obs": "d4b73148fbb776fd7912c20dbd84fd3c0e8cdf9757868b8e30b5b92e406b8e72", - "qpos_init": "924ca2ab30273642e3a284c0b57718bb61df707e3df00b7d32792826b074db81", - "qvel_init": "c50170fa7c86bb5bc265f44bfe0d21e86d5f112feeab31725641b981d1e42c54" - } -} diff --git a/scripts/tools/drift_baseline/before/Go2WJoystickFlat.npz b/scripts/tools/drift_baseline/before/Go2WJoystickFlat.npz deleted file mode 100644 index fdebe46fb..000000000 Binary files a/scripts/tools/drift_baseline/before/Go2WJoystickFlat.npz and /dev/null differ diff --git a/scripts/tools/drift_baseline/drift_report.md b/scripts/tools/drift_baseline/drift_report.md index 575c5f326..0c5f82773 100644 --- a/scripts/tools/drift_baseline/drift_report.md +++ b/scripts/tools/drift_baseline/drift_report.md @@ -27,22 +27,3 @@ Both captures use the identical configuration: 8 envs, 300 steps, env seed 42, a First divergence step (any array): **1** -## Go2WJoystickFlat - -| array | shape | max abs diff | mean abs diff | ref max abs | first divergence step | max abs diff at first divergence | -|---|---|---|---|---|---| -| `actions` | (300, 8, 16) | 0.000000e+00 | 0.000000e+00 | 1.000000e+00 | -1 | 0.000000e+00 | -| `obs/critic` | (300, 8, 72) | 3.289003e+01 | 1.981591e-01 | 4.543000e+01 | 0 | 5.564094e-05 | -| `obs/obs` | (300, 8, 53) | 1.065044e+01 | 8.987349e-02 | 2.687317e+01 | 0 | 5.564094e-05 | -| `obs_init/critic` | (8, 72) | 0.000000e+00 | 0.000000e+00 | 1.000000e+00 | -1 | 0.000000e+00 | -| `obs_init/obs` | (8, 53) | 0.000000e+00 | 0.000000e+00 | 1.000000e+00 | -1 | 0.000000e+00 | -| `qpos` | (300, 8, 23) | 1.096748e+00 | 2.048076e-02 | 1.769883e+01 | 0 | 2.784654e-07 | -| `qpos_init` | (8, 23) | 0.000000e+00 | 0.000000e+00 | 1.500000e+00 | -1 | 0.000000e+00 | -| `qvel` | (300, 8, 22) | 1.065044e+01 | 2.105295e-01 | 2.687317e+01 | 0 | 5.564094e-05 | -| `qvel_init` | (8, 22) | 0.000000e+00 | 0.000000e+00 | 5.306464e-01 | -1 | 0.000000e+00 | -| `reward` | (300, 8) | 8.046474e-02 | 4.191729e-03 | 7.397851e-01 | 0 | 1.490116e-08 | -| `terminated` | (300, 8) | 0.000000e+00 | 0.000000e+00 | 1.000000e+00 | -1 | 0.000000e+00 | -| `truncated` | (300, 8) | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | -1 | 0.000000e+00 | - -First divergence step (any array): **0** - diff --git a/scripts/tools/drift_baseline/training_smoke_1554.md b/scripts/tools/drift_baseline/training_smoke_1554.md index f1cf2b045..76faf20a3 100644 --- a/scripts/tools/drift_baseline/training_smoke_1554.md +++ b/scripts/tools/drift_baseline/training_smoke_1554.md @@ -1,24 +1,19 @@ # Training smoke — mjbatch executor validation (#1554) Short rsl_rl PPO runs on the mujoco backend (RTX 4090, local integration -branches: mjbatch fork + unisim adapter), exercising both action paths: +branches: mjbatch fork + unisim adapter), exercising the retained plain +position-action path: - `Go2JoystickFlat` — plain position-action path. -- `Go2WJoystickFlat` — wheeled-leg task; its mixed action runs through - `SimBackend.set_pre_step_control`, i.e. mjbatch's native per-substep - callback (slimmed to `fn(k, state, ctrl)` by the post-swap ablation; this - smoke ran against the pre-ablation build with `callback_sensordata=False`). -Both runs: `algo.num_envs=32 algo.max_iterations=100 algo.seed=42`, zero -NaN/Inf, playback video rendered after training. +The run used `algo.num_envs=32 algo.max_iterations=100 algo.seed=42`, with +zero NaN/Inf and playback video rendered after training. ## Commands ```bash uv run train --algo ppo --task go2_joystick_flat --sim mujoco -- \ algo.num_envs=32 algo.max_iterations=100 algo.seed=42 -uv run train --algo ppo --task go2w_joystick_flat --sim mujoco -- \ - algo.num_envs=32 algo.max_iterations=100 algo.seed=42 ``` (Executed with `UV_NO_SYNC=1` and the local mjbatch/unisim checkouts @@ -29,10 +24,3 @@ sentinel.) - `Train/mean_reward`: 0.4275 (iter 0) → 17.96 (iter 99), monotone-ish, no NaN. - 100 iterations, ~0.07 s/iteration, playback video rendered. - -## Go2WJoystickFlat (logs/rsl_rl_ppo/Go2WJoystickFlat/2026-09-12_01-45-37_mujoco) - -- `Train/mean_reward`: 1.3125 (iter 0) → 42.99 (iter 99), monotone-ish, no NaN. -- run_summary: 99 completed iterations, 76,800 env steps, - ~8,662 env-steps/s, final_mean_reward 42.99, mean_episode_length ~780 - (ctrl steps; no early termination mass), playback video rendered. diff --git a/scripts/tools/setup_isaacgym_env.sh b/scripts/tools/setup_isaacgym_env.sh index cb0fb3410..ff29ee4c3 100755 --- a/scripts/tools/setup_isaacgym_env.sh +++ b/scripts/tools/setup_isaacgym_env.sh @@ -204,7 +204,7 @@ cat </isaacgym)默认从 ~/.unilab/isaacgym 自动发现运行时; diff --git a/scripts/tools/support_matrix.py b/scripts/tools/support_matrix.py index e16a20890..80201d02d 100644 --- a/scripts/tools/support_matrix.py +++ b/scripts/tools/support_matrix.py @@ -79,27 +79,21 @@ ) _TASK_ORDER = { - "go1_joystick_flat": 0, - "go2_joystick_flat": 1, - "go2_joystick_rough": 2, - "g1_walk_flat": 3, - "g1_walk_rough": 4, - "g1_motion_tracking": 5, - "g1_flip_tracking": 6, - "g1_wall_flip_tracking": 7, - "x2_wall_flip_tracking": 8, - "allegro_inhand": 9, - "allegro_sac": 10, + "go2_joystick_flat": 0, + "g1_walk_flat": 1, + "g1_walk_rough": 2, + "g1_motion_tracking": 3, + "g1_flip_tracking": 4, + "x2_wall_flip_tracking": 5, + "allegro_inhand": 6, + "allegro_sac": 7, } _TASK_LABELS = { - "go1_joystick_flat": "Go1 joystick", "go2_joystick_flat": "Go2 joystick", - "go2_joystick_rough": "Go2 joystick rough", "g1_walk_flat": "G1 walk flat", "g1_walk_rough": "G1 walk rough", "g1_motion_tracking": "G1 motion tracking", "g1_flip_tracking": "G1 flip tracking", - "g1_wall_flip_tracking": "G1 wall flip tracking", "x2_wall_flip_tracking": "X2 wall flip tracking", "allegro_inhand": "Allegro in-hand", "allegro_sac": "Allegro SAC in-hand", diff --git a/scripts/visualize_task_env.py b/scripts/visualize_task_env.py index 7e6617956..b9a2e2489 100644 --- a/scripts/visualize_task_env.py +++ b/scripts/visualize_task_env.py @@ -15,8 +15,8 @@ Usage: uv run scripts/visualize_task_env.py --task Go2JoystickFlat - uv run scripts/visualize_task_env.py --task Go2JoystickRough --num_envs 16 - uv run scripts/visualize_task_env.py --task Go1JoystickFlat --backend motrix --num_envs 4 + uv run scripts/visualize_task_env.py --task G1WalkFlat --num_envs 16 + uv run scripts/visualize_task_env.py --task Go2JoystickFlat --backend motrix --num_envs 4 """ # pyright: reportAttributeAccessIssue=false @@ -98,7 +98,7 @@ def _parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace: "--task", type=str, default="Go2JoystickFlat", - help="Registered task name (e.g. Go2JoystickFlat, Go2JoystickRough, Go1JoystickFlat).", + help="Registered task name (e.g. Go2JoystickFlat, G1WalkFlat).", ) parser.add_argument( "--backend", diff --git a/src/unilab/assets/hub.py b/src/unilab/assets/hub.py index c3846fc68..c56653485 100644 --- a/src/unilab/assets/hub.py +++ b/src/unilab/assets/hub.py @@ -37,16 +37,12 @@ # label only feed the ``unilab-pull-assets`` summary line; resolution keys # off the marker file. ROBOT_ASSET_SPECS: dict[str, tuple[tuple[str, str, str, str], ...]] = { - "a2": (("robots/a2/assets", "a2/base_link.STL", "**/*.STL", "STL"),), "allegro_hand": (("robots/allegro_hand/assets", "base_link.stl", "**/*", "asset"),), "g1": ( ("robots/g1/assets", "head_link.STL", "**/*", "asset"), ("robots/g1/textures", "floor.png", "*.png", "PNG"), ), - "go1": (("robots/go1/assets", "trunk.stl", "*.stl", "STL"),), "go2": (("robots/go2/assets", "base_0.obj", "**/*", "asset"),), - # go2w points its meshdir at ``../go2/assets``. - "go2w": (("robots/go2/assets", "base_0.obj", "**/*", "asset"),), "x2": (("robots/x2/meshes", "pelvis.STL", "*.STL", "STL"),), } diff --git a/src/unilab/assets/robots/a2/a2.xml b/src/unilab/assets/robots/a2/a2.xml deleted file mode 100644 index 92a6ccb15..000000000 --- a/src/unilab/assets/robots/a2/a2.xml +++ /dev/null @@ -1,234 +0,0 @@ - - - diff --git a/src/unilab/assets/robots/a2/scene_flat.xml b/src/unilab/assets/robots/a2/scene_flat.xml deleted file mode 100644 index 11e1fc5f4..000000000 --- a/src/unilab/assets/robots/a2/scene_flat.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/g1_23dof.xml b/src/unilab/assets/robots/g1/g1_23dof.xml deleted file mode 100644 index 44a468a35..000000000 --- a/src/unilab/assets/robots/g1/g1_23dof.xml +++ /dev/null @@ -1,316 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/g1/g1_23dof_sphere_hand.xml b/src/unilab/assets/robots/g1/g1_23dof_sphere_hand.xml deleted file mode 100644 index 50c7d6c43..000000000 --- a/src/unilab/assets/robots/g1/g1_23dof_sphere_hand.xml +++ /dev/null @@ -1,317 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1.xml b/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1.xml deleted file mode 100644 index 2089f96dc..000000000 --- a/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1_23dof.xml b/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1_23dof.xml deleted file mode 100644 index 609e432be..000000000 --- a/src/unilab/assets/robots/g1/scene_climb_20_z_scale_1_23dof.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_flat_23dof.xml b/src/unilab/assets/robots/g1/scene_flat_23dof.xml deleted file mode 100644 index 7660b53e2..000000000 --- a/src/unilab/assets/robots/g1/scene_flat_23dof.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_flat_23dof_with_largebox.xml b/src/unilab/assets/robots/g1/scene_flat_23dof_with_largebox.xml deleted file mode 100644 index 363be01d0..000000000 --- a/src/unilab/assets/robots/g1/scene_flat_23dof_with_largebox.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml b/src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml deleted file mode 100644 index 8040ab8a3..000000000 --- a/src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_flat_with_wall.xml b/src/unilab/assets/robots/g1/scene_flat_with_wall.xml deleted file mode 100644 index bf8bb9a60..000000000 --- a/src/unilab/assets/robots/g1/scene_flat_with_wall.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/g1/scene_rough_23dof.xml b/src/unilab/assets/robots/g1/scene_rough_23dof.xml deleted file mode 100644 index 98d1774b7..000000000 --- a/src/unilab/assets/robots/g1/scene_rough_23dof.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/go1/go1.xml b/src/unilab/assets/robots/go1/go1.xml deleted file mode 100644 index a7b09610c..000000000 --- a/src/unilab/assets/robots/go1/go1.xml +++ /dev/null @@ -1,252 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/go1/go1_mujoco.xml b/src/unilab/assets/robots/go1/go1_mujoco.xml deleted file mode 100644 index e124fb656..000000000 --- a/src/unilab/assets/robots/go1/go1_mujoco.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/go1/locomotion_task.xml b/src/unilab/assets/robots/go1/locomotion_task.xml deleted file mode 100644 index 9a5edc303..000000000 --- a/src/unilab/assets/robots/go1/locomotion_task.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/go1/scene_flat.xml b/src/unilab/assets/robots/go1/scene_flat.xml deleted file mode 100644 index 4902f9d59..000000000 --- a/src/unilab/assets/robots/go1/scene_flat.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/assets/robots/go2w/go2w.xml b/src/unilab/assets/robots/go2w/go2w.xml deleted file mode 100644 index 3c8dd98bc..000000000 --- a/src/unilab/assets/robots/go2w/go2w.xml +++ /dev/null @@ -1,353 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/go2w/go2w_mujoco.xml b/src/unilab/assets/robots/go2w/go2w_mujoco.xml deleted file mode 100644 index 558691e10..000000000 --- a/src/unilab/assets/robots/go2w/go2w_mujoco.xml +++ /dev/null @@ -1,356 +0,0 @@ - - - - diff --git a/src/unilab/assets/robots/go2w/locomotion_task.xml b/src/unilab/assets/robots/go2w/locomotion_task.xml deleted file mode 100644 index 2e8cb0b0c..000000000 --- a/src/unilab/assets/robots/go2w/locomotion_task.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/src/unilab/assets/robots/go2w/scene_flat.xml b/src/unilab/assets/robots/go2w/scene_flat.xml deleted file mode 100644 index 214e04174..000000000 --- a/src/unilab/assets/robots/go2w/scene_flat.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/unilab/cli.py b/src/unilab/cli.py index 6d705d4e2..926eb2bae 100644 --- a/src/unilab/cli.py +++ b/src/unilab/cli.py @@ -86,7 +86,7 @@ def _override_key(override: str) -> str: def _check_task_name(task: str) -> None: if TASK_NAME_PATTERN.fullmatch(task) is None: raise SystemExit( - "--task must be a registry task name such as `go1_joystick`; " + "--task must be a registry task name such as `go2_joystick`; " "do not include slashes, dots, or path separators." ) diff --git a/src/unilab/conf/appo/config.yaml b/src/unilab/conf/appo/config.yaml index 6334e39b7..1c26e7753 100644 --- a/src/unilab/conf/appo/config.yaml +++ b/src/unilab/conf/appo/config.yaml @@ -1,6 +1,6 @@ defaults: - _self_ - - task: go1_joystick_flat/mujoco + - task: go2_joystick_flat/mujoco algo: algo: appo @@ -51,7 +51,7 @@ algo: enable_compile: false training: - task_name: Go1JoystickFlat + task_name: Go2JoystickFlat device: null collector_device: null logger: tensorboard diff --git a/src/unilab/conf/appo/task/g1_23dof_climb_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_23dof_climb_tracking/motrix.yaml deleted file mode 100644 index ae708bf1d..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_climb_tracking/motrix.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_climb_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking23Dof - sim_backend: motrix diff --git a/src/unilab/conf/appo/task/g1_23dof_climb_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_23dof_climb_tracking/mujoco.yaml deleted file mode 100644 index 3586affd7..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_climb_tracking/mujoco.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 20000 - save_interval: 500 - algorithm: - adaptive_kl_factor: 1.2 - adaptive_lr_factor: 1.1 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_climb_20_z_scale_1_23dof.xml - sim_dt: 0.005 - max_episode_seconds: 15.0 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - commands: - motion: - params: - motion_file: motions/g1/climb_20_z_scale_1.0_23dof.npz - sampling_mode: adaptive - truncate_on_clip_end: false - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.3} - ee_body_pos: - params: - command_name: motion - threshold: 0.3 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 - action_rate_l2: - weight: -0.005 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} diff --git a/src/unilab/conf/appo/task/g1_23dof_flip_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_23dof_flip_tracking/motrix.yaml deleted file mode 100644 index a600df907..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_flip_tracking/motrix.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_flip_tracking/mujoco - - _self_ - -training: - task_name: G1FlipTracking23Dof - sim_backend: motrix - -algo: - algorithm: - adaptive_kl_factor: 2.0 - adaptive_lr_factor: 1.5 - enable_compile: true diff --git a/src/unilab/conf/appo/task/g1_23dof_flip_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_23dof_flip_tracking/mujoco.yaml deleted file mode 100644 index 6798916ca..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1FlipTracking23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - steps_per_env: 24 - max_iterations: 3500 - save_interval: 500 - algorithm: - entropy_coef: 0.005 - num_learning_epochs: 10 - num_mini_batches: 8 - desired_kl: 0.01 - adaptive_kl_factor: 1.2 - adaptive_lr_factor: 1.1 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - sim_dt: 0.005 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - commands: - motion: - params: - motion_file: motions/g1/flip_360_001__A304_23dof.npz - sampling_mode: start - truncate_on_clip_end: true - pose_range: &zero_pose - x: [0.0, 0.0] - y: [0.0, 0.0] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - velocity_range: *zero_pose - joint_position_range: [0.0, 0.0] - terminations: - motion_clip_end: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_clip_end - time_out: true - params: {command_name: motion} - anchor_pos: - params: {command_name: motion, threshold: 0.5} - anchor_ori: - params: - command_name: motion - threshold: 1.0e9 - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - ee_body_pos: - params: - command_name: motion - threshold: 0.5 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - action_rate_l2: - weight: -0.005 diff --git a/src/unilab/conf/appo/task/g1_23dof_motion_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_23dof_motion_tracking/motrix.yaml deleted file mode 100644 index 9d8ecf00d..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_motion_tracking/motrix.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTracking23Dof - sim_backend: motrix diff --git a/src/unilab/conf/appo/task/g1_23dof_motion_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_23dof_motion_tracking/mujoco.yaml deleted file mode 100644 index 8605feb92..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_motion_tracking/mujoco.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTracking23Dof - sim_backend: mujoco - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: &g1_23dof_joints - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: *g1_23dof_joints - body_names: &tracked_bodies_23dof - - pelvis - - left_hip_roll_link - - left_knee_link - - left_ankle_roll_link - - right_hip_roll_link - - right_knee_link - - right_ankle_roll_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - left_wrist_roll_rubber_hand - - right_shoulder_roll_link - - right_elbow_link - - right_wrist_roll_rubber_hand - commands: - motion: - params: - motion_file: motions/g1/dance1_subject2_part_23dof.npz - body_names: *tracked_bodies_23dof - terminations: - ee_body_pos: - params: - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand diff --git a/src/unilab/conf/appo/task/g1_23dof_walk_flat/base.yaml b/src/unilab/conf/appo/task/g1_23dof_walk_flat/base.yaml deleted file mode 100644 index 66c3da41e..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_walk_flat/base.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# @package _global_ -# Canonical G1 23-DoF walk Manager-Based task declaration (APPO owners; mirrors the PPO base). -# Inherits the 29-DoF flat contract and swaps the scene to the 23-DoF model -# (no waist roll/pitch, no wrist pitch/yaw) with the 23-entry pose weights. -defaults: - - /task/g1_walk_flat/base - - _self_ - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - -reward: - pose: - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/appo/task/g1_23dof_walk_flat/mujoco.yaml b/src/unilab/conf/appo/task/g1_23dof_walk_flat/mujoco.yaml deleted file mode 100644 index aa34c3339..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_walk_flat/mujoco.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# @package _global_ -# MuJoCo APPO owner: inherits the shared 23-DoF flat Manager-Based contract -# from base.yaml and only carries backend/algo identity. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: mujoco -algo: - max_iterations: 500 - save_interval: 100 diff --git a/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/motrix.yaml deleted file mode 100644 index 3a43778c1..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/motrix.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_wall_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking23Dof - sim_backend: motrix - replay_queue_size: null - -algo: - steps_per_env: 24 - max_iterations: 5000 - algorithm: - num_learning_epochs: 5 - num_mini_batches: 4 - entropy_coef: 0.01 - desired_kl: 0.01 - enable_compile: true - -env: - actions: - joint_pos: - scale: 0.25 - -reward: - motion_body_pos: - weight: 1.0 - motion_body_ori: - weight: 1.0 - motion_ee_body_pos_z: null - action_rate_l2: - weight: -0.1 diff --git a/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index a140546c1..000000000 --- a/src/unilab/conf/appo/task/g1_23dof_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking23Dof - sim_backend: mujoco - replay_queue_size: 5 - -algo: - steps_per_env: 20 - max_iterations: 7000 - algorithm: - num_learning_epochs: 6 - desired_kl: 0.008 - adaptive_kl_factor: 2.0 - adaptive_lr_factor: 1.5 - enable_compile: true - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304_23dof.npz diff --git a/src/unilab/conf/appo/task/g1_climb_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_climb_tracking/motrix.yaml deleted file mode 100644 index 01a98604a..000000000 --- a/src/unilab/conf/appo/task/g1_climb_tracking/motrix.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_climb_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking - sim_backend: motrix diff --git a/src/unilab/conf/appo/task/g1_climb_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_climb_tracking/mujoco.yaml deleted file mode 100644 index 8d15fff57..000000000 --- a/src/unilab/conf/appo/task/g1_climb_tracking/mujoco.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 20000 - save_interval: 500 - algorithm: - adaptive_kl_factor: 1.2 - adaptive_lr_factor: 1.1 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_climb_20_z_scale_1.xml - sim_dt: 0.005 - max_episode_seconds: 15.0 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - "waist_(roll|pitch)_joint": 0.43857731392336724 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - ".*_wrist_(pitch|yaw)_joint": 0.07450087032950714 - commands: - motion: - params: - motion_file: motions/g1/climb_20_z_scale_1.0.npz - sampling_mode: adaptive - truncate_on_clip_end: false - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.3} - ee_body_pos: - params: - command_name: motion - threshold: 0.3 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_yaw_link - - right_wrist_yaw_link - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 - action_rate_l2: - weight: -0.005 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} diff --git a/src/unilab/conf/appo/task/g1_wall_flip_tracking/motrix.yaml b/src/unilab/conf/appo/task/g1_wall_flip_tracking/motrix.yaml deleted file mode 100644 index 3ce1d8cc3..000000000 --- a/src/unilab/conf/appo/task/g1_wall_flip_tracking/motrix.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_wall_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking - sim_backend: motrix - replay_queue_size: null - -algo: - steps_per_env: 24 - max_iterations: 5000 - algorithm: - num_learning_epochs: 5 - num_mini_batches: 4 - entropy_coef: 0.01 - desired_kl: 0.01 - -env: - actions: - joint_pos: - scale: 0.25 - -reward: - motion_body_pos: - weight: 1.0 - motion_body_ori: - weight: 1.0 - motion_ee_body_pos_z: null - action_rate_l2: - weight: -0.1 diff --git a/src/unilab/conf/appo/task/g1_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/appo/task/g1_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index d177ef8b4..000000000 --- a/src/unilab/conf/appo/task/g1_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking - sim_backend: mujoco - replay_queue_size: 5 - -algo: - steps_per_env: 20 - max_iterations: 7000 - algorithm: - num_learning_epochs: 6 - desired_kl: 0.008 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304.npz diff --git a/src/unilab/conf/appo/task/go1_joystick_flat/base.yaml b/src/unilab/conf/appo/task/go1_joystick_flat/base.yaml deleted file mode 100644 index 8a2f3bf57..000000000 --- a/src/unilab/conf/appo/task/go1_joystick_flat/base.yaml +++ /dev/null @@ -1,244 +0,0 @@ -# @package _global_ -# Canonical Go1 flat Manager-Based task declaration. Backend owner leaves inherit -# this file and only override backend/algo tuning or explicitly disabled terms. -env: - scene: - model_file: src/unilab/assets/robots/go1/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: trunk - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - body_names: [trunk] - sim_dt: 0.01 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - actions: - joint_pos: - _target_: unilab.envs.mdp.JointPositionActionCfg - entity_name: robot - actuator_names: [".*"] - scale: 0.25 - use_default_offset: true - commands: - twist: - _target_: unilab.envs.mdp.UniformVelocityCommandCfg - entity_name: robot - resampling_time_range: [20.0, 20.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.0 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - ranges: - lin_vel_x: [-0.6, 1.0] - lin_vel_y: [-0.4, 0.4] - ang_vel_z: [-0.8, 0.8] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - mass_distribution_params: [-1.5, 1.5] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - com_range: - x: [-0.05, 0.05] - y: [0.0, 0.0] - z: [0.0, 0.0] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [35.0, 35.0] - kd_range: [0.5, 0.5] - operation: abs - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [15.0, 15.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.2 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.3 - action_rate: - func: unilab.envs.mdp.action_rate_l2 - weight: -0.005 - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.1 - contact: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_contact - # Legacy Go1 sums four matching feet while this community term returns their mean. - weight: 0.96 - params: - frequency: 2.0 - sensor_names: - - FL_foot_contact - - FR_foot_contact - - RL_foot_contact - - RR_foot_contact - contact_threshold: 0.1 - stance_threshold: 0.6 - swing_feet_z: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_swing_height - weight: 4.0 - params: - frequency: 2.0 - sensor_names: [FL_pos, FR_pos, RL_pos, RR_pos] - target_height: 0.1 - kernel: 0.01 - swing_start: 0.6 diff --git a/src/unilab/conf/appo/task/go1_joystick_flat/motrix.yaml b/src/unilab/conf/appo/task/go1_joystick_flat/motrix.yaml deleted file mode 100644 index d4bb53521..000000000 --- a/src/unilab/conf/appo/task/go1_joystick_flat/motrix.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: motrix -algo: - num_envs: 1024 - steps_per_env: 24 - max_iterations: 300 - actor: - distribution_cfg: - init_std: 0.5 - algorithm: - learning_rate: 5.0e-4 - entropy_coef: 1.0e-3 - desired_kl: 0.008 -env: - commands: - twist: - ranges: - lin_vel_x: [0.5, 0.5] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [0.0, 0.0] - events: - push_robot: null -reward: - action_rate: - weight: -0.015 - action_smooth: - func: unilab.envs.mdp.action_acc_l2 - weight: -0.01 - similar_to_default: - weight: -0.15 - contact: null - swing_feet_z: - weight: 2.0 diff --git a/src/unilab/conf/appo/task/go1_joystick_flat/mujoco.yaml b/src/unilab/conf/appo/task/go1_joystick_flat/mujoco.yaml deleted file mode 100644 index 5443809b6..000000000 --- a/src/unilab/conf/appo/task/go1_joystick_flat/mujoco.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: mujoco -algo: - max_iterations: 150 -reward: - swing_feet_z: null diff --git a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/base.yaml b/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/base.yaml deleted file mode 100644 index c7571348f..000000000 --- a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/base.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# @package _global_ -# Canonical G1 23-DoF walk Manager-Based task declaration (off-policy owners). -# Inherits the 29-DoF off-policy contract and swaps the scene to the 23-DoF -# model (no waist roll/pitch, no wrist pitch/yaw) with 23-entry pose weights. -defaults: - - /task/g1_walk_flat/base - - _self_ - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - -reward: - pose: - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/motrix.yaml b/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/motrix.yaml deleted file mode 100644 index 487f03787..000000000 --- a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/motrix.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# @package _global_ -# FlashSAC Motrix 23-DoF owner: mirrors flashsac/g1_walk_flat/motrix.yaml with -# the 23-DoF contract (algo identity kept, Motrix-direction retuning). -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: motrix -algo: - num_envs: 4096 - learning_starts: 49 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - replay_buffer_n: 256 - tau: 0.05 -env: - events: - # Legacy Motrix owners disable kp/kd randomization. - pd_gains: null -reward: - tracking_lin_vel: - weight: 2.2 - tracking_ang_vel: - weight: 1.8 - penalty_ang_vel_xy: - weight: -1.2 - penalty_orientation: - weight: -12.0 - penalty_action_rate: - weight: -2.5 - pose: - weight: -0.6 - params: - pose_weights: [0.01, 2.0, 5.0, 0.01, 5.0, 5.0, 0.01, 2.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] - penalty_feet_ori: - weight: -5.0 - feet_phase: - weight: 6.0 - params: - tracking_sigma: 0.008 - alive: - weight: 12.0 diff --git a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/mujoco.yaml b/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/mujoco.yaml deleted file mode 100644 index 77e8071ab..000000000 --- a/src/unilab/conf/flashsac/task/g1_23dof_walk_flat/mujoco.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# @package _global_ -# FlashSAC MuJoCo 23-DoF owner: 23-DoF off-policy contract plus the FlashSAC -# algo identity and its reward retuning. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: mujoco -algo: - num_envs: 4096 - learning_starts: 49 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - replay_buffer_n: 256 - tau: 0.05 -reward: - penalty_action_rate: - weight: -5.0 - penalty_feet_ori: - weight: -25.0 - feet_phase: - params: - tracking_sigma: 0.005 - pose: - params: - pose_weights: [0.01, 2.0, 5.0, 0.01, 5.0, 5.0, 0.01, 2.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/ppo/config.yaml b/src/unilab/conf/ppo/config.yaml index c7f5febe2..d46d3c0d6 100644 --- a/src/unilab/conf/ppo/config.yaml +++ b/src/unilab/conf/ppo/config.yaml @@ -1,6 +1,6 @@ defaults: - _self_ - - task: go1_joystick_flat/mujoco + - task: go2_joystick_flat/mujoco algo: algo: ppo @@ -55,7 +55,7 @@ algo: disable_finite_checks: true training: - task_name: Go1JoystickFlat + task_name: Go2JoystickFlat # list[int] | null; null/[] keeps single-device behavior, [d] selects one # CUDA device, and [d0..dN-1] launches one RSL-RL worker per device. # algo.num_envs is per rank; do not set this together with training.device. diff --git a/src/unilab/conf/ppo/task/a2_joystick_flat/base.yaml b/src/unilab/conf/ppo/task/a2_joystick_flat/base.yaml deleted file mode 100644 index 87203212a..000000000 --- a/src/unilab/conf/ppo/task/a2_joystick_flat/base.yaml +++ /dev/null @@ -1,296 +0,0 @@ -# @package _global_ -# Canonical A2 flat Manager-Based task declaration. The MuJoCo owner leaf adds -# only training identity/tuning; all task behavior is declared here for Hydra. -env: - scene: - model_file: src/unilab/assets/robots/a2/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: base_link - joint_names: - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - body_names: [base_link] - geom_names: [floor] - actuator_names: - - FL_hip - - FL_thigh - - FL_calf - - FR_hip - - FR_thigh - - FR_calf - - RL_hip - - RL_thigh - - RL_calf - - RR_hip - - RR_thigh - - RR_calf - sim_dt: 0.01 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - command_name: twist - command_threshold: 0.1 - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - command_name: twist - command_threshold: 0.1 - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - actions: - joint_pos: - _target_: unilab.envs.mdp.JointPositionActionCfg - entity_name: robot - actuator_names: [".*"] - scale: 0.25 - use_default_offset: true - commands: - twist: - _target_: unilab.envs.mdp.UniformVelocityCommandCfg - entity_name: robot - resampling_time_range: [5.0, 5.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.1 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - ranges: - lin_vel_x: [-0.6, 1.0] - lin_vel_y: [-0.4, 0.4] - ang_vel_z: [-0.8, 0.8] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: base_link - mass_distribution_params: [0.0, 8.0] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: base_link - com_range: - x: [-0.08, 0.08] - y: [-0.08, 0.08] - z: [-0.08, 0.08] - foot_friction: - func: unilab.envs.mdp.geom_friction - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - geom_names: floor - ranges: [0.3, 1.6] - operation: scale - axes: [0] - shared_random: true - joint_armature: - func: unilab.envs.mdp.joint_armature - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*" - ranges: [0.9, 1.1] - operation: scale - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - actuator_names: ".*" - kp_range: [0.9, 1.1] - kd_range: [0.9, 1.1] - operation: scale - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [8.0, 8.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.4 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.4 - action_rate: - func: unilab.envs.mdp.action_rate_l2 - weight: -0.02 - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.25 - contact: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_contact - weight: 0.5 - params: - frequency: 2.0 - command_name: twist - command_threshold: 0.1 - sensor_names: [FL_foot_contact, FR_foot_contact, RL_foot_contact, RR_foot_contact] - contact_threshold: 0.1 - stance_threshold: 0.6 - swing_feet_z: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_swing_height - weight: 4.0 - params: - frequency: 2.0 - command_name: twist - command_threshold: 0.1 - sensor_names: [FL_pos, FR_pos, RL_pos, RR_pos] - target_height: 0.1 - kernel: 0.01 - swing_start: 0.6 - stand_still: - func: unilab.tasks.locomotion.common.manager_terms.stand_still_l1 - weight: -4.0 - params: - command_name: twist - command_threshold: 0.1 - hip_deviation: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -1.0 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_hip_joint" - stand_feet_air: - func: unilab.tasks.locomotion.common.manager_terms.feet_air_while_standing - weight: -1.0 - params: - command_name: twist - command_threshold: 0.1 - sensor_names: [FL_foot_contact, FR_foot_contact, RL_foot_contact, RR_foot_contact] - contact_threshold: 0.1 diff --git a/src/unilab/conf/ppo/task/a2_joystick_flat/mujoco.yaml b/src/unilab/conf/ppo/task/a2_joystick_flat/mujoco.yaml deleted file mode 100644 index 8a5f336ca..000000000 --- a/src/unilab/conf/ppo/task/a2_joystick_flat/mujoco.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# @package _global_ -defaults: - - /task/a2_joystick_flat/base - - _self_ - -training: - task_name: A2JoystickFlat - sim_backend: mujoco -algo: - num_envs: 1024 - max_iterations: 500 - empirical_normalization: true - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 1.0e-3 diff --git a/src/unilab/conf/ppo/task/g1_23dof_box_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_box_tracking/motrix.yaml deleted file mode 100644 index c9456f1e4..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_box_tracking/motrix.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_box_tracking/mujoco - - _self_ - -training: - task_name: G1BoxTracking23Dof - sim_backend: motrix - play_env_num: 16 - -algo: - max_iterations: 40000 - empirical_normalization: true - obs_groups: - actor: [actor] - critic: [critic] - algorithm: - entropy_coef: 0.002 - desired_kl: 0.01 - -reward: - motion_global_root_pos: - weight: 1.0 - motion_body_ori: - weight: 1.5 - motion_body_ang_vel: - weight: 1.5 - object_global_ref_position_error_exp: - weight: 4.0 - params: {command_name: motion, std: 0.12} - object_global_ref_orientation_error_exp: - weight: 3.0 - params: {command_name: motion, std: 0.2} - -play_profile: - enabled: true - env: - render_spacing: 2.5 - scene: - enabled: true - source_model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_largebox.xml - ground_texture_file: src/unilab/assets/robots/g1/textures/floor.png - skybox_rgb1: [0.90, 0.90, 0.91] - skybox_rgb2: [0.68, 0.68, 0.70] - ground_texrepeat: [0.25, 0.25] diff --git a/src/unilab/conf/ppo/task/g1_23dof_box_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_box_tracking/mujoco.yaml deleted file mode 100644 index d835ffe06..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_box_tracking/mujoco.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1BoxTracking23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 30000 - save_interval: 500 - obs_groups: - actor: [actor] - algorithm: - entropy_coef: 0.005 - -play_profile: - enabled: false - env: null - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_largebox.xml - entities: - object: - root_body_name: largebox - sim_dt: 0.005 - observations: - actor: - terms: - motion_anchor_pos_b: null - base_lin_vel: null - base_ang_vel: - params: {sensor_name: pelvis_gyro} - critic: - terms: - base_ang_vel: - params: {sensor_name: pelvis_gyro} - object_state: - func: unilab.tasks.motion_tracking.g1.manager_terms.object_state_b - params: {command_name: motion} - commands: - motion: - _target_: unilab.tasks.motion_tracking.g1.manager_terms.BoxMotionCommandCfg - object_entity_name: object - params: - motion_file: motions/g1/sub3_largebox_003_boxconverted_23dof.npz - terminations: - object_pos: - func: unilab.tasks.motion_tracking.g1.manager_terms.bad_object_position - params: {command_name: motion, threshold: 0.25} - object_ori: - func: unilab.tasks.motion_tracking.g1.manager_terms.bad_object_orientation - params: {command_name: motion, threshold: 0.8} - -reward: - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: - command_name: motion - threshold: 0.05 - body_names: - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - object_global_ref_position_error_exp: - func: unilab.tasks.motion_tracking.g1.manager_terms.object_global_position_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.2} - object_global_ref_orientation_error_exp: - func: unilab.tasks.motion_tracking.g1.manager_terms.object_global_orientation_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3} diff --git a/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/motrix.yaml deleted file mode 100644 index ae708bf1d..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/motrix.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_climb_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking23Dof - sim_backend: motrix diff --git a/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/mujoco.yaml deleted file mode 100644 index 99706fa98..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_climb_tracking/mujoco.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 20000 - save_interval: 500 - empirical_normalization: true - obs_groups: - actor: [actor] - critic: [critic] - algorithm: - entropy_coef: 0.005 - desired_kl: 0.01 - -play_profile: - enabled: false - env: null - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_climb_20_z_scale_1_23dof.xml - sim_dt: 0.005 - max_episode_seconds: 15.0 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - commands: - motion: - params: - motion_file: motions/g1/climb_20_z_scale_1.0_23dof.npz - sampling_mode: adaptive - truncate_on_clip_end: false - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.3} - ee_body_pos: - params: - command_name: motion - threshold: 0.3 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 - action_rate_l2: - weight: -0.005 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} diff --git a/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/motrix.yaml deleted file mode 100644 index fe5afd7e6..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/motrix.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_flip_tracking/mujoco - - _self_ - -training: - task_name: G1FlipTracking23Dof - sim_backend: motrix - -algo: - max_iterations: 30000 - empirical_normalization: false - -env: - actions: - joint_pos: - scale: 0.25 - -reward: - motion_global_root_pos: - weight: 1.0 - motion_body_pos: - weight: 1.0 - motion_body_ori: - weight: 1.0 - motion_ee_body_pos_z: null - action_rate_l2: - weight: -0.05 - undesired_contacts: null diff --git a/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/mujoco.yaml deleted file mode 100644 index 5cec48e23..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1FlipTracking23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 20000 - save_interval: 500 - empirical_normalization: true - obs_groups: - actor: [actor] - critic: [critic] - algorithm: - entropy_coef: 0.005 - desired_kl: 0.01 - -play_profile: - enabled: false - env: null - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - sim_dt: 0.005 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - commands: - motion: - params: - motion_file: motions/g1/flip_360_001__A304_23dof.npz - sampling_mode: start - truncate_on_clip_end: false - pose_range: &zero_pose - x: [0.0, 0.0] - y: [0.0, 0.0] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - velocity_range: *zero_pose - joint_position_range: [0.0, 0.0] - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.5} - anchor_ori: - params: - command_name: motion - threshold: 1.0e9 - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - ee_body_pos: - params: - command_name: motion - threshold: 0.5 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - action_rate_l2: - weight: -0.005 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} diff --git a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/motrix.yaml deleted file mode 100644 index 2141c58cf..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/motrix.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTracking23Dof - sim_backend: motrix - play_env_num: 16 - -reward: - motion_global_root_pos: - weight: 1.0 - action_rate_l2: - weight: -0.05 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: - command_name: motion - threshold: 0.05 - body_names: - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -play_profile: - enabled: true - env: - render_spacing: 2.5 diff --git a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/mujoco.yaml deleted file mode 100644 index 8605feb92..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking/mujoco.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTracking23Dof - sim_backend: mujoco - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: &g1_23dof_joints - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: *g1_23dof_joints - body_names: &tracked_bodies_23dof - - pelvis - - left_hip_roll_link - - left_knee_link - - left_ankle_roll_link - - right_hip_roll_link - - right_knee_link - - right_ankle_roll_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - left_wrist_roll_rubber_hand - - right_shoulder_roll_link - - right_elbow_link - - right_wrist_roll_rubber_hand - commands: - motion: - params: - motion_file: motions/g1/dance1_subject2_part_23dof.npz - body_names: *tracked_bodies_23dof - terminations: - ee_body_pos: - params: - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand diff --git a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/motrix.yaml deleted file mode 100644 index 46d82769f..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/motrix.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking_deploy/mujoco - - _self_ - -training: - task_name: G1MotionTracking23DofDeploy - sim_backend: motrix - play_env_num: 16 - -env: - events: - foot_friction: null - push_robot: null - -reward: - motion_global_root_pos: - weight: 1.0 - action_rate_l2: - weight: -0.05 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: - command_name: motion - threshold: 0.05 - body_names: - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -play_profile: - enabled: true - env: - render_spacing: 2.5 diff --git a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/mujoco.yaml deleted file mode 100644 index 0e4667f90..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_motion_tracking_deploy/mujoco.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking_deploy/mujoco - - _self_ - -training: - task_name: G1MotionTracking23DofDeploy - sim_backend: mujoco - -_g1_23dof_deploy_action_scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: &g1_23dof_joints - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: *g1_23dof_joints - body_names: &tracked_bodies_23dof - - pelvis - - left_hip_roll_link - - left_knee_link - - left_ankle_roll_link - - right_hip_roll_link - - right_knee_link - - right_ankle_roll_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - left_wrist_roll_rubber_hand - - right_shoulder_roll_link - - right_elbow_link - - right_wrist_roll_rubber_hand - actions: - joint_pos: - scale: ${_g1_23dof_deploy_action_scale} - commands: - motion: - params: - motion_file: motions/g1/dance1_subject2_part_23dof.npz - body_names: *tracked_bodies_23dof - terminations: - ee_body_pos: - params: - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand diff --git a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/base.yaml b/src/unilab/conf/ppo/task/g1_23dof_walk_flat/base.yaml deleted file mode 100644 index 7489083e8..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/base.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# @package _global_ -# Canonical G1 23-DoF walk Manager-Based task declaration (PPO/APPO owners). -# Inherits the 29-DoF flat contract and swaps the scene to the 23-DoF model -# (no waist roll/pitch, no wrist pitch/yaw) with the 23-entry pose weights. -defaults: - - /task/g1_walk_flat/base - - _self_ - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - -reward: - pose: - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_walk_flat/motrix.yaml deleted file mode 100644 index d8fd852d0..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/motrix.yaml +++ /dev/null @@ -1,118 +0,0 @@ -# @package _global_ -# Motrix owner: inherits the shared 23-DoF flat Manager-Based contract from -# base.yaml, then overrides contract fields for Motrix-specific tuning -# (intentionally non-transferable from MuJoCo; drop overrides to restore parity). -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: motrix -algo: - num_envs: 2048 - max_iterations: 2200 - empirical_normalization: true - obs_groups: - actor: - - policy - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 5.0e-3 -env: - actions: - joint_pos: - scale: 0.5 - commands: - twist: - ranges: - lin_vel_x: [0.4, 0.7] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [0.0, 0.0] - events: - # Legacy Motrix owners disable kp/kd randomization. - pd_gains: null - reset_root_state_uniform: - params: - velocity_range: - x: [-0.05, 0.05] - y: [-0.05, 0.05] - z: [-0.05, 0.05] - roll: [-0.05, 0.05] - pitch: [-0.05, 0.05] - yaw: [-0.05, 0.05] - terminations: - tilt: - params: - max_tilt_deg: 35.0 - base_height: - params: - minimum_height: 0.5 -reward: - tracking_ang_vel: - weight: 0.25 - forward_progress: - func: unilab.tasks.locomotion.g1.manager_terms.forward_progress - weight: 0.0 - params: - command_name: twist - under_speed: - func: unilab.tasks.locomotion.g1.manager_terms.under_speed - weight: -0.2 - params: - command_name: twist - upper_body_pose: - func: unilab.tasks.locomotion.g1.manager_terms.upper_body_pose - weight: -0.05 - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] - penalty_feet_ori: - func: unilab.tasks.locomotion.g1.manager_terms.penalty_feet_ori - weight: 0.0 - feet_phase: - weight: 1.2 - params: - min_forward_speed: 0.05 - feet_phase_contrast: - func: unilab.tasks.locomotion.g1.manager_terms.feet_phase_contrast - weight: 1.5 - params: - frequency: 1.5 - swing_height: 0.09 - tracking_sigma: 0.008 - min_forward_speed: 0.05 - command_name: twist - feet_phase_contact: - func: unilab.tasks.locomotion.g1.manager_terms.feet_phase_contact - weight: 1.0 - params: - frequency: 1.5 - swing_height: 0.09 - tracking_sigma: 0.008 - min_forward_speed: 0.05 - command_name: twist - feet_double_stance: - func: unilab.tasks.locomotion.g1.manager_terms.feet_double_stance - weight: -1.0 - params: - frequency: 1.5 - swing_height: 0.09 - tracking_sigma: 0.008 - min_forward_speed: 0.05 - command_name: twist - ang_vel_xy: - weight: -0.2 - base_height: - weight: -120.0 - params: - target_height: 0.765 - orientation: - weight: -2.5 - action_rate: - weight: -0.005 - pose: - weight: -0.05 diff --git a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_walk_flat/mujoco.yaml deleted file mode 100644 index e8e5776ed..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_walk_flat/mujoco.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# @package _global_ -# MuJoCo owner: inherits the shared 23-DoF flat Manager-Based contract from -# base.yaml and only carries backend/algo identity. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: mujoco -algo: - num_envs: 2048 - max_iterations: 2200 - obs_groups: - actor: - - actor diff --git a/src/unilab/conf/ppo/task/g1_23dof_walk_rough/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_walk_rough/mujoco.yaml deleted file mode 100644 index 9c2856964..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_walk_rough/mujoco.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# @package _global_ -# MuJoCo 23-DoF rough owner: inherits the 23-DoF flat Manager-Based contract, -# swaps the scene to the static-hfield rough XML, and enables the penalty -# curriculum (the only PPO walk owner that carries one). -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofRough - sim_backend: mujoco -algo: - num_envs: 2048 - max_iterations: 2200 - obs_groups: - actor: - - actor -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_rough_23dof.xml - curriculum: - penalty_scaling: - func: unilab.tasks.locomotion.g1.manager_terms.G1PenaltyCurriculum - params: - initial_scale: 0.5 - min_scale: 0.5 - max_scale: 1.0 - level_down_threshold: 150.0 - level_up_threshold: 750.0 - degree: 0.001 - -reward: - # The rough scene XML declares no named foot contact sensors, so the shared - # air-time term inherited from the flat base is explicitly disabled here. - feet_air_time: null diff --git a/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/motrix.yaml deleted file mode 100644 index ca2f0e7be..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/motrix.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_wall_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking23Dof - sim_backend: motrix - play_env_num: 16 - render_spacing: 3.0 - -algo: - max_iterations: 12000 - -env: - motrix_max_iterations: 3 - -play_profile: - enabled: true - env: - render_spacing: 4.0 - scene: - enabled: true - source_model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml - ground_texture_file: src/unilab/assets/robots/g1/textures/floor.png - skybox_rgb1: [0.90, 0.90, 0.91] - skybox_rgb2: [0.68, 0.68, 0.70] - ground_texrepeat: [0.25, 0.25] diff --git a/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index 3f2c7ec81..000000000 --- a/src/unilab/conf/ppo/task/g1_23dof_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking23Dof - sim_backend: mujoco - -play_profile: - enabled: false - env: null - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304_23dof.npz - -reward: - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 diff --git a/src/unilab/conf/ppo/task/g1_climb_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_climb_tracking/motrix.yaml deleted file mode 100644 index 01a98604a..000000000 --- a/src/unilab/conf/ppo/task/g1_climb_tracking/motrix.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_climb_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking - sim_backend: motrix diff --git a/src/unilab/conf/ppo/task/g1_climb_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_climb_tracking/mujoco.yaml deleted file mode 100644 index fd7826eb4..000000000 --- a/src/unilab/conf/ppo/task/g1_climb_tracking/mujoco.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1ClimbTracking - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 1024 - max_iterations: 20000 - save_interval: 500 - empirical_normalization: true - obs_groups: - actor: [actor] - critic: [critic] - algorithm: - entropy_coef: 0.005 - desired_kl: 0.01 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_climb_20_z_scale_1.xml - sim_dt: 0.005 - max_episode_seconds: 15.0 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - "waist_(roll|pitch)_joint": 0.43857731392336724 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - ".*_wrist_(pitch|yaw)_joint": 0.07450087032950714 - commands: - motion: - params: - motion_file: motions/g1/climb_20_z_scale_1.0.npz - sampling_mode: adaptive - truncate_on_clip_end: false - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.3} - ee_body_pos: - params: - command_name: motion - threshold: 0.3 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_yaw_link - - right_wrist_yaw_link - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_body_pos: - weight: 2.0 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 - action_rate_l2: - weight: -0.005 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} - -play_profile: - enabled: true - env: - render_spacing: 2.0 diff --git a/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/motrix.yaml b/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/motrix.yaml deleted file mode 100644 index 9d2fe0e6e..000000000 --- a/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/motrix.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking_deploy/mujoco - - _self_ - -training: - task_name: G1MotionTrackingDeploy - sim_backend: motrix - play_env_num: 16 - -env: - events: - foot_friction: null - push_robot: null - -reward: - motion_global_root_pos: - weight: 1.0 - action_rate_l2: - weight: -0.05 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: - command_name: motion - threshold: 0.05 - body_names: - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -play_profile: - enabled: true - env: - render_spacing: 2.5 diff --git a/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/mujoco.yaml b/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/mujoco.yaml deleted file mode 100644 index 6b8d5ef89..000000000 --- a/src/unilab/conf/ppo/task/g1_motion_tracking_deploy/mujoco.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTrackingDeploy - sim_backend: mujoco - -env: - sim_dt: 0.005 - observations: - actor: - terms: - motion_anchor_pos_b: null - base_lin_vel: null - base_ang_vel: - params: {sensor_name: pelvis_gyro} - critic: - terms: - base_ang_vel: - params: {sensor_name: pelvis_gyro} - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - "waist_(roll|pitch)_joint": 0.43857731392336724 - ".*_(shoulder_(pitch|roll|yaw)|elbow|wrist_roll)_joint": 0.43857731392336724 - ".*_wrist_(pitch|yaw)_joint": 0.07450087032950714 - commands: - motion: - params: - joint_default_position_range: [-0.01, 0.01] - events: - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - body_names: pelvis - mass_distribution_params: [-1.5, 1.5] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - body_names: pelvis - com_range: - x: [-0.025, 0.025] - y: [-0.05, 0.05] - z: [-0.05, 0.05] - foot_friction: - func: unilab.envs.mdp.geom_friction - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - geom_names: ".*" - ranges: [0.3, 1.2] - operation: abs - shared_random: true - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [15.0, 15.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] diff --git a/src/unilab/conf/ppo/task/g1_wall_flip_tracking/motrix.yaml b/src/unilab/conf/ppo/task/g1_wall_flip_tracking/motrix.yaml deleted file mode 100644 index 8fd67bfc7..000000000 --- a/src/unilab/conf/ppo/task/g1_wall_flip_tracking/motrix.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_wall_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking - sim_backend: motrix - play_env_num: 16 - render_spacing: 3.0 - -algo: - max_iterations: 12000 - -env: - motrix_max_iterations: 3 - -play_profile: - enabled: true - env: - render_spacing: 4.0 - scene: - enabled: true - source_model_file: src/unilab/assets/robots/g1/scene_flat_with_wall.xml - ground_texture_file: src/unilab/assets/robots/g1/textures/floor.png - skybox_rgb1: [0.90, 0.90, 0.91] - skybox_rgb2: [0.68, 0.68, 0.70] - ground_texrepeat: [0.25, 0.25] diff --git a/src/unilab/conf/ppo/task/g1_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/ppo/task/g1_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index 082c23fd9..000000000 --- a/src/unilab/conf/ppo/task/g1_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTracking - sim_backend: mujoco - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304.npz - -reward: - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 diff --git a/src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml b/src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml deleted file mode 100644 index 8a2f3bf57..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_flat/base.yaml +++ /dev/null @@ -1,244 +0,0 @@ -# @package _global_ -# Canonical Go1 flat Manager-Based task declaration. Backend owner leaves inherit -# this file and only override backend/algo tuning or explicitly disabled terms. -env: - scene: - model_file: src/unilab/assets/robots/go1/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: trunk - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - body_names: [trunk] - sim_dt: 0.01 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - actions: - joint_pos: - _target_: unilab.envs.mdp.JointPositionActionCfg - entity_name: robot - actuator_names: [".*"] - scale: 0.25 - use_default_offset: true - commands: - twist: - _target_: unilab.envs.mdp.UniformVelocityCommandCfg - entity_name: robot - resampling_time_range: [20.0, 20.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.0 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - ranges: - lin_vel_x: [-0.6, 1.0] - lin_vel_y: [-0.4, 0.4] - ang_vel_z: [-0.8, 0.8] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - mass_distribution_params: [-1.5, 1.5] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - com_range: - x: [-0.05, 0.05] - y: [0.0, 0.0] - z: [0.0, 0.0] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [35.0, 35.0] - kd_range: [0.5, 0.5] - operation: abs - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [15.0, 15.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.2 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.3 - action_rate: - func: unilab.envs.mdp.action_rate_l2 - weight: -0.005 - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.1 - contact: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_contact - # Legacy Go1 sums four matching feet while this community term returns their mean. - weight: 0.96 - params: - frequency: 2.0 - sensor_names: - - FL_foot_contact - - FR_foot_contact - - RL_foot_contact - - RR_foot_contact - contact_threshold: 0.1 - stance_threshold: 0.6 - swing_feet_z: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_swing_height - weight: 4.0 - params: - frequency: 2.0 - sensor_names: [FL_pos, FR_pos, RL_pos, RR_pos] - target_height: 0.1 - kernel: 0.01 - swing_start: 0.6 diff --git a/src/unilab/conf/ppo/task/go1_joystick_flat/drake.yaml b/src/unilab/conf/ppo/task/go1_joystick_flat/drake.yaml deleted file mode 100644 index f1251763b..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_flat/drake.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: drake - play_steps: 500 - play_env_num: 16 - render_spacing: 0.0 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 1024 - num_steps_per_env: 24 - max_iterations: 151 - save_interval: 100 - obs_groups: - actor: - - actor - critic: - - critic - -env: - drake_backend_mode: batch - drake_nthread: 0 - events: - base_mass: null - base_com: null - pd_gains: null - push_robot: null - -reward: - contact: null diff --git a/src/unilab/conf/ppo/task/go1_joystick_flat/motrix.yaml b/src/unilab/conf/ppo/task/go1_joystick_flat/motrix.yaml deleted file mode 100644 index e05a46d7b..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_flat/motrix.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: motrix - play_steps: 500 - play_env_num: 16 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 1024 - max_iterations: 151 - obs_groups: - actor: - - actor - critic: - - critic - empirical_normalization: true - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 1.0e-3 -env: - commands: - twist: - ranges: - lin_vel_x: [0.5, 0.5] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [0.0, 0.0] - events: - # Motrix has no formal root velocity-delta capability; do not fall back to force push. - push_robot: null -reward: - contact: null -play_profile: - enabled: true - env: - render_spacing: 2.0 diff --git a/src/unilab/conf/ppo/task/go1_joystick_flat/mujoco.yaml b/src/unilab/conf/ppo/task/go1_joystick_flat/mujoco.yaml deleted file mode 100644 index 867b319b8..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_flat/mujoco.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: mujoco - play_steps: 500 - play_env_num: 16 - render_spacing: 0.0 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 1024 - max_iterations: 151 - obs_groups: - actor: - - actor - critic: - - critic -play_profile: - enabled: true - env: - render_spacing: 2.0 diff --git a/src/unilab/conf/ppo/task/go1_joystick_rough/motrix.yaml b/src/unilab/conf/ppo/task/go1_joystick_rough/motrix.yaml deleted file mode 100644 index 0af29a93b..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_rough/motrix.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_rough/mujoco - - _self_ - -training: - task_name: Go1JoystickRough - sim_backend: motrix - -algo: - num_envs: 2048 - -env: - render_offset_mode: zero - scene: - model_file: src/unilab/assets/robots/go1/go1.xml - events: - push_robot: null diff --git a/src/unilab/conf/ppo/task/go1_joystick_rough/mujoco.yaml b/src/unilab/conf/ppo/task/go1_joystick_rough/mujoco.yaml deleted file mode 100644 index db1c3e920..000000000 --- a/src/unilab/conf/ppo/task/go1_joystick_rough/mujoco.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# @package _global_ -defaults: - - /task/quadruped_joystick_rough/quadruped - - _self_ - -training: - task_name: Go1JoystickRough - sim_backend: mujoco - play_steps: 500 - play_env_num: 16 - render_spacing: 0.0 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 2048 - num_steps_per_env: 24 - max_iterations: 1000 - empirical_normalization: false - obs_groups: {actor: [actor], critic: [critic]} - policy: {init_noise_std: 1.0} - algorithm: {learning_rate: 1.0e-3, entropy_coef: 1.0e-2} - -env: - sim_dt: 0.005 - scene: - model_file: src/unilab/assets/robots/go1/go1_mujoco.xml - fragment_files: [src/unilab/assets/robots/go1/locomotion_task.xml] - entities: - robot: - root_body_name: trunk - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - body_names: [trunk] - -play_profile: - enabled: true - env: {render_spacing: 2.0} diff --git a/src/unilab/conf/ppo/task/go2_footstand/base.yaml b/src/unilab/conf/ppo/task/go2_footstand/base.yaml deleted file mode 100644 index eafdd6826..000000000 --- a/src/unilab/conf/ppo/task/go2_footstand/base.yaml +++ /dev/null @@ -1,216 +0,0 @@ -# @package _global_ -# Canonical Go2 footstand Manager-Based declaration. Hydra owns every task term; -# backend leaves only select identity, tuning, and supported reset capabilities. -env: - scene: - model_file: src/unilab/assets/robots/go2/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: base - joint_names: - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - body_names: - - base - - FL_hip - - FL_thigh - - FL_calf - - FR_hip - - FR_thigh - - FR_calf - - RL_hip - - RL_thigh - - RL_calf - - RR_hip - - RR_thigh - - RR_calf - geom_names: [floor] - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - sim_dt: 0.004 - ctrl_dt: 0.02 - max_episode_seconds: 10.0 - observations: - policy: - enable_corruption: true - terms: - frame: - func: unilab.tasks.locomotion.go2.footstand.frame_observation - params: - action_name: joint_pos - noise: - _target_: UniformNoiseCfg - n_min: [-0.1, -0.1, -0.1, -0.2, -0.2, -0.2, -0.05, -0.05, -0.05, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - n_max: [0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.05, 0.05, 0.05, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - history_length: 15 - critic: - terms: - frame: - func: unilab.tasks.locomotion.go2.footstand.frame_observation - params: - action_name: joint_pos - history_length: 15 - privileged: - func: unilab.tasks.locomotion.go2.footstand.privileged_observation - params: - action_name: joint_pos - actions: - joint_pos: - _target_: unilab.tasks.locomotion.go2.footstand.FootstandIncrementalActionCfg - entity_name: robot - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - joint_position_limits: - - [-1.0472, 1.0472] - - [-1.5708, 3.4907] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-1.5708, 3.4907] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-0.5236, 4.5379] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-0.5236, 4.5379] - - [-2.7227, -0.83776] - action_scale: 0.3 - clip_actions: 1.0 - kp: 35.0 - kd: 0.5 - simulate_action_latency: false - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - reset_joints: - func: unilab.tasks.locomotion.go2.footstand.FootstandJointReset - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*" - position_offset_range: [-0.05, 0.05] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [35.0, 35.0] - kd_range: [0.5, 0.5] - operation: abs - floor_friction: null - link_mass: null - torso_com: null - joint_armature: null - terminations: - footstand: - func: unilab.tasks.locomotion.go2.footstand.FootstandTermination - params: - action_name: joint_pos - grace_steps: 100 - height_fraction: 0.8 - orientation_threshold: 0.2 - energy_threshold: 200.0 - time_out: - func: unilab.envs.mdp.time_out - time_out: true - policy_observation_group: policy - critic_observation_group: critic - scale_rewards_by_dt: true - -reward: - footstand: - func: unilab.tasks.locomotion.go2.footstand.FootstandReward - weight: 1.0 - params: - state_term_name: footstand - scales: - height: 2.0 - orientation: 2.0 - contact: -1.0 - action_rate: -0.01 - termination: -2.0 - dof_pos_limits: -0.5 - torques: 0.0 - pose: -0.1 - penalty_contact: -0.2 - tar: 0.8 - rear_feet_contact: 0.5 - rear_leg_symmetry: -0.2 - front_leg_motion: -0.05 - upright_stability: -0.2 - knee_clearance: -0.5 - stay_still: -0.1 - energy: -0.003 - dof_acc: -2.5e-7 - soft_joint_pos_limit_factor: 0.9 - knee_height_target: 0.08 - front_feet_min_separation: 0.16 - front_feet_side_margin: 0.04 - rear_hip_abduction_margin: 0.25 - rear_foot_slip_deadband: 0.02 - rear_foot_anchor_radius: 0.03 diff --git a/src/unilab/conf/ppo/task/go2_footstand/drake.yaml b/src/unilab/conf/ppo/task/go2_footstand/drake.yaml deleted file mode 100644 index 3d7c02a40..000000000 --- a/src/unilab/conf/ppo/task/go2_footstand/drake.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# @package _global_ -defaults: - - /task/go2_footstand/base - - _self_ - -training: - task_name: Go2FootStand - sim_backend: drake - -env: - drake_backend_mode: batch - drake_nthread: 0 - events: - # Drake supports the joint-state reset, but not these reset payload fields. - pd_gains: null - floor_friction: null - link_mass: null - torso_com: null - joint_armature: null - -algo: - empirical_normalization: true - num_envs: 4096 - max_iterations: 10000 - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - entropy_coef: 0.005 diff --git a/src/unilab/conf/ppo/task/go2_footstand/motrix.yaml b/src/unilab/conf/ppo/task/go2_footstand/motrix.yaml deleted file mode 100644 index c53005fbd..000000000 --- a/src/unilab/conf/ppo/task/go2_footstand/motrix.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# @package _global_ -defaults: - - /task/go2_footstand/base - - _self_ - -training: - task_name: Go2FootStand - sim_backend: motrix - no_play: true - -env: - events: - reset_joints: - params: - position_offset_range: [-0.02, 0.02] - # Unsupported model-field payloads remain explicitly disabled for Motrix. - floor_friction: null - link_mass: null - torso_com: null - joint_armature: null - -algo: - empirical_normalization: true - num_envs: 4096 - max_iterations: 10000 - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - entropy_coef: 0.005 - -reward: - footstand: - params: - scales: - height: 2.0 - orientation: 3.0 - contact: -1.0 - action_rate: -0.01 - termination: -2.0 - dof_pos_limits: -0.5 - torques: 0.0 - pose: -0.1 - penalty_contact: -0.2 - tar: 1.3 - rear_feet_contact: 0.5 - both_rear_feet_contact: 0.25 - rear_foot_slip: -1.0 - rear_foot_anchor: -0.15 - front_feet_air: 0.0 - balanced_footstand: 0.0 - rear_leg_symmetry: -0.2 - rear_leg_splay: -0.25 - front_leg_motion: -0.06 - front_leg_crossing: -2.0 - upright_stability: -0.2 - knee_clearance: -0.5 - stay_still: -0.12 - energy: -0.003 - dof_acc: -2.5e-7 - front_feet_min_separation: 0.18 - front_feet_side_margin: 0.06 - rear_hip_abduction_margin: 0.25 - rear_foot_slip_deadband: 0.012 - rear_foot_anchor_radius: 0.04 diff --git a/src/unilab/conf/ppo/task/go2_footstand/mujoco.yaml b/src/unilab/conf/ppo/task/go2_footstand/mujoco.yaml deleted file mode 100644 index 8a4b428cc..000000000 --- a/src/unilab/conf/ppo/task/go2_footstand/mujoco.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# @package _global_ -defaults: - - /task/go2_footstand/base - - _self_ - -training: - task_name: Go2FootStand - sim_backend: mujoco - -env: - events: - floor_friction: - func: unilab.envs.mdp.geom_friction - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - geom_names: floor - ranges: [0.4, 1.0] - operation: abs - link_mass: - func: unilab.tasks.locomotion.go2.footstand.FootstandMassRandomization - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: ".*" - torso_body_name: base - link_mass_scale_range: [0.9, 1.1] - torso_added_mass_range: [-1.0, 1.0] - torso_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: base - com_range: - x: [-0.05, 0.05] - y: [-0.05, 0.05] - z: [-0.05, 0.05] - joint_armature: - func: unilab.envs.mdp.joint_armature - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*" - ranges: [1.0, 1.05] - operation: scale - -algo: - empirical_normalization: true - num_envs: 4096 - max_iterations: 10000 - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - entropy_coef: 0.005 diff --git a/src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml b/src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml deleted file mode 100644 index a35a5cbc5..000000000 --- a/src/unilab/conf/ppo/task/go2_joystick_rough/motrix.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# @package _global_ -defaults: - - /task/go2_joystick_rough/mujoco - - _self_ - -training: - task_name: Go2JoystickRough - sim_backend: motrix - -algo: - num_envs: 4096 - -env: - render_offset_mode: zero - scene: - model_file: src/unilab/assets/robots/go2/go2.xml - events: - push_robot: null diff --git a/src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml b/src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml deleted file mode 100644 index 5d3622fdc..000000000 --- a/src/unilab/conf/ppo/task/go2_joystick_rough/mujoco.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# @package _global_ -defaults: - - /task/quadruped_joystick_rough/quadruped - - _self_ - -training: - task_name: Go2JoystickRough - sim_backend: mujoco - play_steps: 500 - play_env_num: 16 - render_spacing: 0.0 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 2048 - num_steps_per_env: 24 - max_iterations: 1500 - empirical_normalization: false - obs_groups: {actor: [actor], critic: [critic]} - policy: {init_noise_std: 1.0} - algorithm: {learning_rate: 1.0e-3, entropy_coef: 1.0e-2} - -env: - sim_dt: 0.002 - scene: - model_file: src/unilab/assets/robots/go2/go2_mujoco.xml - fragment_files: [src/unilab/assets/robots/go2/locomotion_task.xml] - entities: - robot: - root_body_name: base - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - body_names: [base] - -play_profile: - enabled: true - env: {render_spacing: 2.0} diff --git a/src/unilab/conf/ppo/task/go2w_joystick_flat/base.yaml b/src/unilab/conf/ppo/task/go2w_joystick_flat/base.yaml deleted file mode 100644 index 3d057e1ee..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_flat/base.yaml +++ /dev/null @@ -1,263 +0,0 @@ -# @package _global_ -# Canonical Go2W flat Manager-Based task declaration. Backend leaves only own -# backend identity and backend-specific rendering/runtime settings. -env: - scene: - model_file: src/unilab/assets/robots/go2w/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: base_link - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - FR_wheel_joint - - FL_wheel_joint - - RR_wheel_joint - - RL_wheel_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - - FR_wheel - - FL_wheel - - RR_wheel - - RL_wheel - body_names: [base_link] - sim_dt: 0.005 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - leg_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - wheel_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - actions: - func: unilab.envs.mdp.last_action - params: - action_name: motor - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - leg_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - wheel_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - actions: - func: unilab.envs.mdp.last_action - params: - action_name: motor - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - motor_torque: - func: unilab.tasks.locomotion.go2w.manager_terms.motor_torque - params: - action_name: motor - actions: - motor: - _target_: unilab.tasks.locomotion.go2w.manager_terms.Go2WMixedActionCfg - entity_name: robot - actuator_names: [".*"] - leg_action_scale: 0.5 - wheel_action_scale: 10.0 - leg_kp: 50.0 - leg_kd: 1.5 - wheel_kd: 0.5 - clip_actions: 1.0 - simulate_action_latency: false - commands: - twist: - _target_: unilab.tasks.locomotion.go2w.manager_terms.Go2WVelocityCommandCfg - entity_name: robot - resampling_time_range: [20.0, 20.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.0 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - planar_dead_zone: 0.2 - ranges: - lin_vel_x: [0.0, 1.0] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [-1.0, 1.0] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - motor_gains: - func: unilab.tasks.locomotion.go2w.manager_terms.randomize_motor_gains - mode: reset - params: - action_name: motor - kp_multiplier_range: [1.0, 1.0] - kd_multiplier_range: [1.0, 1.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.75 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.4 - orientation: - func: unilab.envs.mdp.flat_orientation_l2 - weight: -2.0 - action_rate: - func: unilab.tasks.locomotion.go2w.manager_terms.clipped_action_rate_l2 - weight: -0.005 - params: - action_name: motor - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.5 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - torques: - func: unilab.tasks.locomotion.go2w.manager_terms.motor_torque_l2 - weight: -0.0002 - params: - action_name: motor - wheel_vel: - func: unilab.envs.mdp.joint_vel_l2 - weight: 0.0 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - alive: - func: unilab.tasks.locomotion.go2w.manager_terms.constant_alive - weight: 0.5 - upward: - func: unilab.tasks.locomotion.go2w.manager_terms.upward_l2 - weight: 1.0 diff --git a/src/unilab/conf/ppo/task/go2w_joystick_flat/drake.yaml b/src/unilab/conf/ppo/task/go2w_joystick_flat/drake.yaml deleted file mode 100644 index ddbbc1bfa..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_flat/drake.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# @package _global_ -defaults: - - /task/go2w_joystick_flat/base - - _self_ - -training: - task_name: Go2WJoystickFlat - sim_backend: drake - -algo: - num_envs: 1024 - max_iterations: 151 - empirical_normalization: true - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 1.0e-3 - -env: - drake_backend_mode: batch - drake_nthread: 0 diff --git a/src/unilab/conf/ppo/task/go2w_joystick_flat/motrix.yaml b/src/unilab/conf/ppo/task/go2w_joystick_flat/motrix.yaml deleted file mode 100644 index 01af0050d..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_flat/motrix.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# @package _global_ -defaults: - - /task/go2w_joystick_flat/base - - _self_ - -training: - task_name: Go2WJoystickFlat - sim_backend: motrix -algo: - num_envs: 1024 - max_iterations: 151 - empirical_normalization: true - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 1.0e-3 -env: - render_offset_mode: zero -play_profile: - enabled: true - env: - render_spacing: 2.0 diff --git a/src/unilab/conf/ppo/task/go2w_joystick_flat/mujoco.yaml b/src/unilab/conf/ppo/task/go2w_joystick_flat/mujoco.yaml deleted file mode 100644 index 3e092334c..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_flat/mujoco.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# @package _global_ -defaults: - - /task/go2w_joystick_flat/base - - _self_ - -training: - task_name: Go2WJoystickFlat - sim_backend: mujoco -algo: - num_envs: 1024 - max_iterations: 151 - empirical_normalization: true - obs_groups: - actor: - - actor - critic: - - critic - policy: - init_noise_std: 0.5 - algorithm: - learning_rate: 3.0e-4 - entropy_coef: 1.0e-3 -play_profile: - enabled: true - env: - render_spacing: 2.0 diff --git a/src/unilab/conf/ppo/task/go2w_joystick_rough/motrix.yaml b/src/unilab/conf/ppo/task/go2w_joystick_rough/motrix.yaml deleted file mode 100644 index 0f4fcbb21..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_rough/motrix.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# @package _global_ -defaults: - - /task/go2w_joystick_rough/mujoco - - _self_ - -training: - task_name: Go2WJoystickRough - sim_backend: motrix - -env: - render_offset_mode: zero - scene: - model_file: src/unilab/assets/robots/go2w/go2w.xml - events: - push_robot: null - -reward: - hip_pos: - weight: -0.5 diff --git a/src/unilab/conf/ppo/task/go2w_joystick_rough/mujoco.yaml b/src/unilab/conf/ppo/task/go2w_joystick_rough/mujoco.yaml deleted file mode 100644 index f0c77718c..000000000 --- a/src/unilab/conf/ppo/task/go2w_joystick_rough/mujoco.yaml +++ /dev/null @@ -1,78 +0,0 @@ -# @package _global_ -defaults: - - /task/quadruped_joystick_rough/go2w - - _self_ - -training: - task_name: Go2WJoystickRough - sim_backend: mujoco - play_steps: 500 - play_env_num: 16 - render_spacing: 0.0 - cam_tracking: true - cam_tracking_env_idx: 0 - cam_tracking_extra_envs: 9 - -interactive: - action_mode: policy - policy_obs_mode: auto - camera_follow_body: true - use_env_visual_model: false - -algo: - num_envs: 2048 - num_steps_per_env: 24 - max_iterations: 1200 - empirical_normalization: false - obs_groups: {actor: [actor], critic: [critic]} - -env: - sim_dt: 0.005 - scene: - model_file: src/unilab/assets/robots/go2w/go2w_mujoco.xml - fragment_files: [src/unilab/assets/robots/go2w/locomotion_task.xml] - terrain: - generator: - horizontal_scale: 0.1 - entities: - robot: - root_body_name: base_link - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - FR_wheel_joint - - FL_wheel_joint - - RR_wheel_joint - - RL_wheel_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - - FR_wheel - - FL_wheel - - RR_wheel - - RL_wheel - body_names: [base_link] - -play_profile: - enabled: true - env: {render_spacing: 2.0} diff --git a/src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml b/src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml deleted file mode 100644 index c916ccd63..000000000 --- a/src/unilab/conf/ppo/task/quadruped_joystick_rough/base.yaml +++ /dev/null @@ -1,152 +0,0 @@ -# @package _global_ -# Shared terrain/reset/command owner for all production rough quadrupeds. -env: - scene: - default_keyframe_name: home - terrain: - hfield_name: terrain_hfield - geom_name: floor - generator: - _target_: unilab.tasks.locomotion.common.rough_manager_terms.QuadrupedRoughTerrainCfg - seed: 42 - curriculum: false - size: [8.0, 8.0] - num_rows: 6 - num_cols: 6 - border_width: 20.0 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - commands: - twist: - _target_: unilab.tasks.locomotion.common.rough_manager_terms.RoughVelocityCommandCfg - entity_name: robot - resampling_time_range: [10.0, 10.0] - heading_command: true - heading_control_stiffness: 0.5 - rel_standing_envs: 0.1 - rel_heading_envs: 1.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - planar_dead_zone: 0.08 - ranges: - lin_vel_x: [-1.0, 1.0] - lin_vel_y: [-1.0, 1.0] - ang_vel_z: [-1.0, 1.0] - heading: [-3.141592653589793, 3.141592653589793] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - terrain_root_state: - func: unilab.tasks.locomotion.common.rough_manager_terms.RoughTerrainReset - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.25, 0.5] - roll: [-3.14, 3.14] - pitch: [-3.14, 3.14] - yaw: [-3.14, 3.14] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - promote_frac: 0.5 - demote_frac: 0.25 - cycle_top_frac: 0.5 - spawn_height_margin: 0.05 - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: ".*" - mass_distribution_params: [-1.0, 3.0] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: ".*" - com_range: - x: [-0.05, 0.05] - y: [0.0, 0.0] - z: [0.0, 0.0] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [17.5, 70.0] - kd_range: [0.25, 1.0] - operation: abs - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [12.5, 12.5] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - terrain_out_of_bounds: - func: unilab.tasks.locomotion.common.rough_manager_terms.RoughTerrainOutOfBounds - time_out: true - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - distance_buffer: 3.0 - curriculum: - terrain_levels: - func: unilab.tasks.locomotion.common.rough_manager_terms.RoughTerrainCurriculum - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 3.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 1.5 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -2.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.05 - action_rate: - func: unilab.envs.mdp.action_rate_l2 - weight: -0.01 diff --git a/src/unilab/conf/ppo/task/quadruped_joystick_rough/go2w.yaml b/src/unilab/conf/ppo/task/quadruped_joystick_rough/go2w.yaml deleted file mode 100644 index 746943680..000000000 --- a/src/unilab/conf/ppo/task/quadruped_joystick_rough/go2w.yaml +++ /dev/null @@ -1,127 +0,0 @@ -# @package _global_ -defaults: - - /task/quadruped_joystick_rough/base - - _self_ - -env: - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: gyro} - scale: 0.25 - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: {sensor_name: upvector} - command: - func: unilab.envs.mdp.generated_commands - params: {command_name: twist} - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - scale: 0.05 - actions: - func: unilab.envs.mdp.last_action - params: {action_name: motor} - critic: - terms: - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: local_linvel} - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: gyro} - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: {sensor_name: upvector} - command: - func: unilab.envs.mdp.generated_commands - params: {command_name: twist} - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - params: {action_name: motor} - height_scan: - func: unilab.tasks.locomotion.common.rough_manager_terms.RoughHeightScan - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - geom_name: floor - vertical_offset: 0.5 - scale: 5.0 - actions: - motor: - _target_: unilab.tasks.locomotion.go2w.manager_terms.Go2WMixedActionCfg - entity_name: robot - actuator_names: [".*"] - leg_action_scale: 0.25 - hip_action_scale: 0.125 - wheel_action_scale: 5.0 - leg_kp: 35.0 - leg_kd: 0.5 - wheel_kd: 0.5 - clip_actions: 100.0 - simulate_action_latency: false - events: - pd_gains: null - motor_gains: - func: unilab.tasks.locomotion.go2w.manager_terms.randomize_motor_gains - mode: reset - params: - action_name: motor - kp_multiplier_range: [0.5, 1.0] - kd_multiplier_range: [0.5, 1.0] - -reward: - orientation: - func: unilab.envs.mdp.flat_orientation_l2 - weight: -2.0 - motor_torque: - func: unilab.tasks.locomotion.go2w.manager_terms.motor_torque_l2 - weight: -2.5e-5 - params: {action_name: motor} - stand_still: - func: unilab.tasks.locomotion.common.manager_terms.stand_still_l1 - weight: -2.0 - params: - command_name: twist - command_threshold: 0.1 - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - hip_pos: - func: unilab.tasks.locomotion.common.rough_manager_terms.joint_deviation_l2 - weight: -2.0 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_hip_joint" - joint_pos_penalty: - func: unilab.tasks.locomotion.common.rough_manager_terms.joint_deviation_l2 - weight: -1.0 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - upward: - func: unilab.tasks.locomotion.go2w.manager_terms.upward_l2 - weight: 1.0 diff --git a/src/unilab/conf/ppo/task/quadruped_joystick_rough/quadruped.yaml b/src/unilab/conf/ppo/task/quadruped_joystick_rough/quadruped.yaml deleted file mode 100644 index a464a98c8..000000000 --- a/src/unilab/conf/ppo/task/quadruped_joystick_rough/quadruped.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# @package _global_ -defaults: - - /task/quadruped_joystick_rough/base - - _self_ - -env: - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: gyro} - scale: 0.25 - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: {sensor_name: upvector} - command: - func: unilab.envs.mdp.generated_commands - params: {command_name: twist} - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - scale: 0.05 - actions: - func: unilab.envs.mdp.last_action - params: {action_name: joint_pos} - critic: - terms: - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: local_linvel} - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: gyro} - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: {sensor_name: upvector} - command: - func: unilab.envs.mdp.generated_commands - params: {command_name: twist} - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - params: {action_name: joint_pos} - height_scan: - func: unilab.tasks.locomotion.common.rough_manager_terms.RoughHeightScan - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - geom_name: floor - vertical_offset: 0.5 - scale: 5.0 - actions: - joint_pos: - _target_: unilab.tasks.locomotion.common.rough_manager_terms.RoughJointPositionActionCfg - entity_name: robot - actuator_names: [".*"] - scale: - ".*_hip_joint": 0.125 - ".*_(thigh|calf)_joint": 0.25 - use_default_offset: true - clip_actions: 100.0 - -reward: - stand_still: - func: unilab.tasks.locomotion.common.manager_terms.stand_still_l1 - weight: -2.0 - params: - command_name: twist - command_threshold: 0.1 - hip_pos: - func: unilab.tasks.locomotion.common.rough_manager_terms.joint_deviation_l2 - weight: -0.5 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_hip_joint" - joint_pos_penalty: - func: unilab.tasks.locomotion.common.rough_manager_terms.joint_deviation_l2 - weight: -1.0 - upward: - func: unilab.tasks.locomotion.go2w.manager_terms.upward_l2 - weight: 1.0 diff --git a/src/unilab/conf/sac/task/g1_23dof_flip_tracking/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_flip_tracking/mujoco.yaml deleted file mode 100644 index 70ce6e8e7..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1FlipTrackingSAC23Dof - sim_backend: mujoco - play_steps: 1000 - -algo: - num_envs: 4096 - max_iterations: 25000 - save_interval: 1000 - gamma: 0.99 - tau: 0.05 - num_atoms: 501 - updates_per_step: 4 - policy_frequency: 2 - algo_params: - alpha_init: 0.005 - target_entropy_ratio: 0.05 - max_grad_norm: 10.0 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - sim_dt: 0.005 - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_wrist_roll_joint": 0.43857731392336724 - commands: - motion: - params: - motion_file: motions/g1/flip_360_001__A304_23dof.npz - sampling_mode: mixed - sampling_start_ratio: 0.1 - truncate_on_clip_end: true - pose_range: &zero_pose - x: [0.0, 0.0] - y: [0.0, 0.0] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - velocity_range: *zero_pose - joint_position_range: [0.0, 0.0] - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.5} - anchor_ori: - params: - command_name: motion - threshold: 1.0e9 - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - ee_body_pos: - params: - command_name: motion - threshold: 0.5 - body_names: &ee_bodies - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.bad_undesired_body_contacts - params: - command_name: motion - threshold: 0.05 - body_names: &undesired_bodies - - pelvis - - left_hip_roll_link - - left_knee_link - - right_hip_roll_link - - right_knee_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - right_shoulder_roll_link - - right_elbow_link - -reward: - motion_global_root_pos: - weight: 0.5 - motion_body_ori: - weight: 1.5 - motion_ee_body_pos_z: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_relative_body_position_z_error_exp - weight: 2.0 - params: {command_name: motion, std: 0.3, body_names: *ee_bodies} - action_rate_l2: - weight: -0.005 - joint_limit: - weight: -10.0 - undesired_contacts: - func: unilab.tasks.motion_tracking.common.manager_terms.undesired_body_contacts - weight: -0.1 - params: {command_name: motion, threshold: 0.05, body_names: *undesired_bodies} diff --git a/src/unilab/conf/sac/task/g1_23dof_motion_tracking/motrix.yaml b/src/unilab/conf/sac/task/g1_23dof_motion_tracking/motrix.yaml deleted file mode 100644 index 735e89be0..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_motion_tracking/motrix.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# @package _global_ -# Motrix is the sim2sim eval owner for MuJoCo-trained WBT checkpoints. -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTrackingSAC23Dof - sim_backend: motrix diff --git a/src/unilab/conf/sac/task/g1_23dof_motion_tracking/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_motion_tracking/mujoco.yaml deleted file mode 100644 index da1338c9e..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_motion_tracking/mujoco.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_motion_tracking/mujoco - - _self_ - -training: - task_name: G1MotionTrackingSAC23Dof - sim_backend: mujoco - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: &g1_23dof_joints - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: *g1_23dof_joints - body_names: &tracked_bodies_23dof - - pelvis - - left_hip_roll_link - - left_knee_link - - left_ankle_roll_link - - right_hip_roll_link - - right_knee_link - - right_ankle_roll_link - - torso_link - - left_shoulder_roll_link - - left_elbow_link - - left_wrist_roll_rubber_hand - - right_shoulder_roll_link - - right_elbow_link - - right_wrist_roll_rubber_hand - actions: - joint_pos: - scale: - ".*_(hip_pitch|hip_yaw)_joint": 0.5475464629911068 - ".*_(hip_roll|knee)_joint": 0.35066146637882434 - ".*_ankle_(pitch|roll)_joint": 0.43857731392336724 - "waist_yaw_joint": 0.5475464629911068 - ".*_(shoulder_(pitch|roll|yaw)|elbow)_joint": 0.43857731392336724 - ".*_wrist_roll_joint": 0.07450087032950714 - commands: - motion: - params: - motion_file: motions/g1/dance1_subject2_part_23dof.npz - body_names: *tracked_bodies_23dof - terminations: - ee_body_pos: - params: - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand diff --git a/src/unilab/conf/sac/task/g1_23dof_walk_flat/base.yaml b/src/unilab/conf/sac/task/g1_23dof_walk_flat/base.yaml deleted file mode 100644 index c7571348f..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_walk_flat/base.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# @package _global_ -# Canonical G1 23-DoF walk Manager-Based task declaration (off-policy owners). -# Inherits the 29-DoF off-policy contract and swaps the scene to the 23-DoF -# model (no waist roll/pitch, no wrist pitch/yaw) with 23-entry pose weights. -defaults: - - /task/g1_walk_flat/base - - _self_ - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - -reward: - pose: - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/sac/task/g1_23dof_walk_flat/motrix.yaml b/src/unilab/conf/sac/task/g1_23dof_walk_flat/motrix.yaml deleted file mode 100644 index 99d75a942..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_walk_flat/motrix.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# @package _global_ -# SAC Motrix 23-DoF owner: keeps DENYLIST parity with the MuJoCo owner and -# retunes reward shaping / disables kp/kd randomization for Motrix. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: motrix -algo: - num_envs: 2048 - learning_starts: 1 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - algo_params: - alpha_init: 0.001 - target_entropy_ratio: 0.0 -env: - events: - # Legacy Motrix owners disable kp/kd randomization. - pd_gains: null -reward: - tracking_lin_vel: - weight: 2.2 - tracking_ang_vel: - weight: 1.8 - penalty_ang_vel_xy: - weight: -1.2 - penalty_orientation: - weight: -12.0 - penalty_action_rate: - weight: -2.5 - pose: - weight: -0.6 - penalty_feet_ori: - weight: -5.0 - feet_phase: - weight: 6.0 - params: - tracking_sigma: 0.008 - alive: - weight: 12.0 diff --git a/src/unilab/conf/sac/task/g1_23dof_walk_flat/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_walk_flat/mujoco.yaml deleted file mode 100644 index d06148b02..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_walk_flat/mujoco.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# @package _global_ -# SAC MuJoCo 23-DoF owner: inherits the 23-DoF off-policy Manager-Based -# contract and only carries backend/algo identity. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: mujoco -algo: - num_envs: 2048 - learning_starts: 10 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - algo_params: - alpha_init: 0.001 - target_entropy_ratio: 0.0 diff --git a/src/unilab/conf/sac/task/g1_23dof_walk_rough/motrix.yaml b/src/unilab/conf/sac/task/g1_23dof_walk_rough/motrix.yaml deleted file mode 100644 index 10899e153..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_walk_rough/motrix.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# @package _global_ -# SAC Motrix 23-DoF rough owner: static-hfield rough scene, Motrix -# sim_dt=0.01, Motrix-direction reward retuning; kp/kd randomization disabled. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofRough - sim_backend: motrix -algo: - num_envs: 2048 - learning_starts: 1 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - algo_params: - alpha_init: 0.001 - target_entropy_ratio: 0.0 -env: - sim_dt: 0.01 - scene: - model_file: src/unilab/assets/robots/g1/scene_rough_23dof.xml - events: - # Legacy Motrix owners disable kp/kd randomization. - pd_gains: null -reward: - tracking_lin_vel: - weight: 2.2 - tracking_ang_vel: - weight: 1.8 - penalty_ang_vel_xy: - weight: -1.2 - penalty_orientation: - weight: -12.0 - penalty_action_rate: - weight: -2.5 - pose: - weight: -0.6 - penalty_feet_ori: - weight: -5.0 - feet_phase: - weight: 6.0 - params: - tracking_sigma: 0.008 - alive: - weight: 12.0 diff --git a/src/unilab/conf/sac/task/g1_23dof_walk_rough/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_walk_rough/mujoco.yaml deleted file mode 100644 index b6b0fb319..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_walk_rough/mujoco.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# @package _global_ -# SAC MuJoCo 23-DoF rough owner: 23-DoF off-policy contract plus the -# static-hfield rough scene. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofRough - sim_backend: mujoco -algo: - num_envs: 2048 - learning_starts: 10 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - algo_params: - alpha_init: 0.001 - target_entropy_ratio: 0.0 -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_rough_23dof.xml diff --git a/src/unilab/conf/sac/task/g1_23dof_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index 0a111f66a..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTrackingSAC23Dof - sim_backend: mujoco - -algo: - algo_params: - target_entropy_ratio: 0.0 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304_23dof.npz - sampling_mode: uniform - sampling_start_ratio: 0.0 - terminations: - anchor_pos: - params: {command_name: motion, threshold: 1.0e9} - ee_body_pos: - params: - command_name: motion - threshold: 1.0e9 - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - undesired_contacts: null - -reward: - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 diff --git a/src/unilab/conf/sac/task/g1_23dof_wbt_obs/mujoco.yaml b/src/unilab/conf/sac/task/g1_23dof_wbt_obs/mujoco.yaml deleted file mode 100644 index dd1022142..000000000 --- a/src/unilab/conf/sac/task/g1_23dof_wbt_obs/mujoco.yaml +++ /dev/null @@ -1,186 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_23dof_motion_tracking/mujoco - - _self_ - -training: - task_name: G1WBTObs23Dof - sim_backend: mujoco - -algo: - num_envs: 4096 - max_iterations: 140000 - save_interval: 1000 - gamma: 0.99 - tau: 0.05 - num_atoms: 501 - updates_per_step: 4 - policy_frequency: 2 - algo_params: - alpha_init: 0.1 - target_entropy_ratio: 0.5 - max_grad_norm: 10.0 - -env: - sim_dt: 0.005 - scene: - entities: - robot: - geom_names: - - left_foot1_collision - - left_foot2_collision - - left_foot3_collision - - left_foot4_collision - - left_foot5_collision - - left_foot6_collision - - left_foot7_collision - - right_foot1_collision - - right_foot2_collision - - right_foot3_collision - - right_foot4_collision - - right_foot5_collision - - right_foot6_collision - - right_foot7_collision - observations: - actor: - terms: - motion_anchor_pos_b: null - motion_anchor_ori_b: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_anchor_ori_b - params: {command_name: motion} - noise: - _target_: unilab.managers._noise.UniformNoiseCfg - n_min: -0.05 - n_max: 0.05 - base_lin_vel: null - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: {sensor_name: pelvis_gyro} - noise: - _target_: unilab.managers._noise.UniformNoiseCfg - n_min: -0.2 - n_max: 0.2 - history_length: 5 - joint_pos: - func: unilab.tasks.motion_tracking.common.manager_terms.motion_joint_pos_rel_biased - params: {command_name: motion} - noise: - _target_: unilab.managers._noise.UniformNoiseCfg - n_min: -0.01 - n_max: 0.01 - history_length: 5 - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - noise: - _target_: unilab.managers._noise.UniformNoiseCfg - n_min: -0.5 - n_max: 0.5 - history_length: 5 - actions: - func: unilab.envs.mdp.last_action - history_length: 5 - critic: - terms: - base_ang_vel: - params: {sensor_name: pelvis_gyro} - actions: - joint_pos: - scale: 2.0 - simulate_action_latency: true - terminations: - anchor_pos: - params: {command_name: motion, threshold: 0.4} - ee_body_pos: - params: - command_name: motion - threshold: 0.5 - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_roll_rubber_hand - - right_wrist_roll_rubber_hand - events: - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - body_names: pelvis - mass_distribution_params: [-1.0, 1.0] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - body_names: pelvis - com_range: - x: [-0.05, 0.05] - y: [-0.05, 0.05] - z: [-0.05, 0.05] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [0.9, 1.1] - kd_range: [0.85, 1.15] - operation: scale - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - actuator_names: ".*" - foot_friction: - func: unilab.envs.mdp.geom_friction - mode: reset - params: - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - geom_names: "^(left|right)_foot[1-7]_collision$" - ranges: [0.3, 1.2] - operation: abs - shared_random: true - encoder_bias: - func: unilab.envs.mdp.randomize_encoder_bias - mode: reset - params: - bias_range: [-0.01, 0.01] - asset_cfg: - _target_: unilab.managers.SceneEntityCfg - name: robot - joint_names: ".*" - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [4.0, 4.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - -reward: - motion_global_root_ori: - weight: 1.0 - motion_body_pos: - weight: 1.0 - action_rate_l2: - weight: -0.1 - joint_limit: - weight: -5.0 - joint_acc_l2: - func: unilab.tasks.motion_tracking.g1.manager_terms.joint_acc_l2 - weight: -2.5e-7 - joint_torque_l2: - func: unilab.tasks.motion_tracking.g1.manager_terms.joint_torque_l2 - weight: -1.0e-5 - params: {action_name: joint_pos} diff --git a/src/unilab/conf/sac/task/g1_wall_flip_tracking/mujoco.yaml b/src/unilab/conf/sac/task/g1_wall_flip_tracking/mujoco.yaml deleted file mode 100644 index 68ddd8efd..000000000 --- a/src/unilab/conf/sac/task/g1_wall_flip_tracking/mujoco.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# @package _global_ -defaults: - - /task/g1_flip_tracking/mujoco - - _self_ - -training: - task_name: G1WallFlipTrackingSAC - sim_backend: mujoco - -algo: - algo_params: - target_entropy_ratio: 0.0 - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_with_wall.xml - commands: - motion: - params: - motion_file: motions/g1/flip_from_wall_104__A304.npz - sampling_mode: uniform - sampling_start_ratio: 0.0 - terminations: - anchor_pos: - params: {command_name: motion, threshold: 1.0e9} - ee_body_pos: - params: - command_name: motion - threshold: 1.0e9 - body_names: - - left_ankle_roll_link - - right_ankle_roll_link - - left_wrist_yaw_link - - right_wrist_yaw_link - undesired_contacts: null - -reward: - motion_joint_pos: - weight: 0.5 - motion_joint_vel: - weight: 0.25 diff --git a/src/unilab/conf/sac/task/go2_footstand/base.yaml b/src/unilab/conf/sac/task/go2_footstand/base.yaml deleted file mode 100644 index 250f5d950..000000000 --- a/src/unilab/conf/sac/task/go2_footstand/base.yaml +++ /dev/null @@ -1,216 +0,0 @@ -# @package _global_ -# Canonical Go2 footstand Manager-Based declaration for off-policy training. -# Keep this task surface aligned with the PPO owner; Hydra remains the sole entry. -env: - scene: - model_file: src/unilab/assets/robots/go2/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: base - joint_names: - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - body_names: - - base - - FL_hip - - FL_thigh - - FL_calf - - FR_hip - - FR_thigh - - FR_calf - - RL_hip - - RL_thigh - - RL_calf - - RR_hip - - RR_thigh - - RR_calf - geom_names: [floor] - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - sim_dt: 0.004 - ctrl_dt: 0.02 - max_episode_seconds: 10.0 - observations: - policy: - enable_corruption: true - terms: - frame: - func: unilab.tasks.locomotion.go2.footstand.frame_observation - params: - action_name: joint_pos - noise: - _target_: UniformNoiseCfg - n_min: [-0.1, -0.1, -0.1, -0.2, -0.2, -0.2, -0.05, -0.05, -0.05, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -0.01, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - n_max: [0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.05, 0.05, 0.05, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - history_length: 15 - critic: - terms: - frame: - func: unilab.tasks.locomotion.go2.footstand.frame_observation - params: - action_name: joint_pos - history_length: 15 - privileged: - func: unilab.tasks.locomotion.go2.footstand.privileged_observation - params: - action_name: joint_pos - actions: - joint_pos: - _target_: unilab.tasks.locomotion.go2.footstand.FootstandIncrementalActionCfg - entity_name: robot - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - joint_position_limits: - - [-1.0472, 1.0472] - - [-1.5708, 3.4907] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-1.5708, 3.4907] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-0.5236, 4.5379] - - [-2.7227, -0.83776] - - [-1.0472, 1.0472] - - [-0.5236, 4.5379] - - [-2.7227, -0.83776] - action_scale: 0.3 - clip_actions: 1.0 - kp: 35.0 - kd: 0.5 - simulate_action_latency: false - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - reset_joints: - func: unilab.tasks.locomotion.go2.footstand.FootstandJointReset - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*" - position_offset_range: [-0.05, 0.05] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [35.0, 35.0] - kd_range: [0.5, 0.5] - operation: abs - floor_friction: null - link_mass: null - torso_com: null - joint_armature: null - terminations: - footstand: - func: unilab.tasks.locomotion.go2.footstand.FootstandTermination - params: - action_name: joint_pos - grace_steps: 100 - height_fraction: 0.8 - orientation_threshold: 0.2 - energy_threshold: 200.0 - time_out: - func: unilab.envs.mdp.time_out - time_out: true - policy_observation_group: policy - critic_observation_group: critic - scale_rewards_by_dt: true - -reward: - footstand: - func: unilab.tasks.locomotion.go2.footstand.FootstandReward - weight: 1.0 - params: - state_term_name: footstand - scales: - height: 2.0 - orientation: 2.0 - contact: -1.0 - action_rate: -0.01 - termination: -2.0 - dof_pos_limits: -0.5 - torques: 0.0 - pose: -0.1 - penalty_contact: -0.2 - tar: 0.8 - rear_feet_contact: 0.5 - rear_leg_symmetry: -0.2 - front_leg_motion: -0.05 - upright_stability: -0.2 - knee_clearance: -0.5 - stay_still: -0.1 - energy: -0.003 - dof_acc: -2.5e-7 - soft_joint_pos_limit_factor: 0.9 - knee_height_target: 0.08 - front_feet_min_separation: 0.16 - front_feet_side_margin: 0.04 - rear_hip_abduction_margin: 0.25 - rear_foot_slip_deadband: 0.02 - rear_foot_anchor_radius: 0.03 diff --git a/src/unilab/conf/sac/task/go2_footstand/drake.yaml b/src/unilab/conf/sac/task/go2_footstand/drake.yaml deleted file mode 100644 index 3c9fd8b7c..000000000 --- a/src/unilab/conf/sac/task/go2_footstand/drake.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# @package _global_ -defaults: - - /task/go2_footstand/base - - _self_ - -training: - task_name: Go2FootStand - sim_backend: drake - no_play: true - play_steps: 400 - play_env_num: 1 - play_render_mode: record - -algo: - algo_log_name: fast_sac_drake - num_envs: 4096 - batch_size: 1024 - replay_buffer_n: 512 - updates_per_step: 2 - learning_starts: 2 - max_iterations: 300 - save_interval: 100 - actor_hidden_dim: 256 - critic_hidden_dim: 512 - obs_normalization: true - use_layer_norm: true - algo_params: - alpha_init: 0.005 - target_entropy_ratio: 0.0 - use_compile: false - -env: - drake_backend_mode: batch - drake_nthread: 20 - events: - # Drake keeps the task joint reset and rejects unsupported payload fields. - pd_gains: null - floor_friction: null - link_mass: null - torso_com: null - joint_armature: null diff --git a/src/unilab/conf/sac/task/go2w_joystick_flat/base.yaml b/src/unilab/conf/sac/task/go2w_joystick_flat/base.yaml deleted file mode 100644 index 3d057e1ee..000000000 --- a/src/unilab/conf/sac/task/go2w_joystick_flat/base.yaml +++ /dev/null @@ -1,263 +0,0 @@ -# @package _global_ -# Canonical Go2W flat Manager-Based task declaration. Backend leaves only own -# backend identity and backend-specific rendering/runtime settings. -env: - scene: - model_file: src/unilab/assets/robots/go2w/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: base_link - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - - FR_wheel_joint - - FL_wheel_joint - - RR_wheel_joint - - RL_wheel_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - - FR_wheel - - FL_wheel - - RR_wheel - - RL_wheel - body_names: [base_link] - sim_dt: 0.005 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - leg_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - wheel_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - actions: - func: unilab.envs.mdp.last_action - params: - action_name: motor - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - leg_joint_pos: - func: unilab.envs.mdp.joint_pos_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - leg_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - wheel_joint_vel: - func: unilab.envs.mdp.joint_vel_rel - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - actions: - func: unilab.envs.mdp.last_action - params: - action_name: motor - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - motor_torque: - func: unilab.tasks.locomotion.go2w.manager_terms.motor_torque - params: - action_name: motor - actions: - motor: - _target_: unilab.tasks.locomotion.go2w.manager_terms.Go2WMixedActionCfg - entity_name: robot - actuator_names: [".*"] - leg_action_scale: 0.5 - wheel_action_scale: 10.0 - leg_kp: 50.0 - leg_kd: 1.5 - wheel_kd: 0.5 - clip_actions: 1.0 - simulate_action_latency: false - commands: - twist: - _target_: unilab.tasks.locomotion.go2w.manager_terms.Go2WVelocityCommandCfg - entity_name: robot - resampling_time_range: [20.0, 20.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.0 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - planar_dead_zone: 0.2 - ranges: - lin_vel_x: [0.0, 1.0] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [-1.0, 1.0] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - motor_gains: - func: unilab.tasks.locomotion.go2w.manager_terms.randomize_motor_gains - mode: reset - params: - action_name: motor - kp_multiplier_range: [1.0, 1.0] - kd_multiplier_range: [1.0, 1.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.75 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.4 - orientation: - func: unilab.envs.mdp.flat_orientation_l2 - weight: -2.0 - action_rate: - func: unilab.tasks.locomotion.go2w.manager_terms.clipped_action_rate_l2 - weight: -0.005 - params: - action_name: motor - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.5 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_(hip|thigh|calf)_joint" - torques: - func: unilab.tasks.locomotion.go2w.manager_terms.motor_torque_l2 - weight: -0.0002 - params: - action_name: motor - wheel_vel: - func: unilab.envs.mdp.joint_vel_l2 - weight: 0.0 - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - joint_names: ".*_wheel_joint" - alive: - func: unilab.tasks.locomotion.go2w.manager_terms.constant_alive - weight: 0.5 - upward: - func: unilab.tasks.locomotion.go2w.manager_terms.upward_l2 - weight: 1.0 diff --git a/src/unilab/conf/sac/task/go2w_joystick_flat/drake.yaml b/src/unilab/conf/sac/task/go2w_joystick_flat/drake.yaml deleted file mode 100644 index 644465051..000000000 --- a/src/unilab/conf/sac/task/go2w_joystick_flat/drake.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# @package _global_ -defaults: - - /task/go2w_joystick_flat/base - - _self_ - -training: - task_name: Go2WJoystickFlat - sim_backend: drake - no_play: true - play_steps: 400 - play_env_num: 1 - play_render_mode: record - -algo: - algo_log_name: fast_sac_drake - num_envs: 512 - batch_size: 1024 - replay_buffer_n: 512 - updates_per_step: 2 - learning_starts: 2 - max_iterations: 300 - save_interval: 100 - actor_hidden_dim: 256 - critic_hidden_dim: 512 - obs_normalization: true - use_layer_norm: true - algo_params: - alpha_init: 0.005 - target_entropy_ratio: 0.0 - use_compile: false - -env: - drake_backend_mode: batch - drake_nthread: 20 diff --git a/src/unilab/conf/td3/task/g1_23dof_walk_flat/base.yaml b/src/unilab/conf/td3/task/g1_23dof_walk_flat/base.yaml deleted file mode 100644 index c7571348f..000000000 --- a/src/unilab/conf/td3/task/g1_23dof_walk_flat/base.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# @package _global_ -# Canonical G1 23-DoF walk Manager-Based task declaration (off-policy owners). -# Inherits the 29-DoF off-policy contract and swaps the scene to the 23-DoF -# model (no waist roll/pitch, no wrist pitch/yaw) with 23-entry pose weights. -defaults: - - /task/g1_walk_flat/base - - _self_ - -env: - scene: - model_file: src/unilab/assets/robots/g1/scene_flat_23dof.xml - entities: - robot: - joint_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - actuator_names: - - left_hip_pitch_joint - - left_hip_roll_joint - - left_hip_yaw_joint - - left_knee_joint - - left_ankle_pitch_joint - - left_ankle_roll_joint - - right_hip_pitch_joint - - right_hip_roll_joint - - right_hip_yaw_joint - - right_knee_joint - - right_ankle_pitch_joint - - right_ankle_roll_joint - - waist_yaw_joint - - left_shoulder_pitch_joint - - left_shoulder_roll_joint - - left_shoulder_yaw_joint - - left_elbow_joint - - left_wrist_roll_joint - - right_shoulder_pitch_joint - - right_shoulder_roll_joint - - right_shoulder_yaw_joint - - right_elbow_joint - - right_wrist_roll_joint - -reward: - pose: - params: - pose_weights: [0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 0.01, 1.0, 5.0, 0.01, 5.0, 5.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0] diff --git a/src/unilab/conf/td3/task/g1_23dof_walk_flat/mujoco.yaml b/src/unilab/conf/td3/task/g1_23dof_walk_flat/mujoco.yaml deleted file mode 100644 index 52c728a45..000000000 --- a/src/unilab/conf/td3/task/g1_23dof_walk_flat/mujoco.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# @package _global_ -# TD3 MuJoCo 23-DoF owner: inherits the 23-DoF off-policy Manager-Based -# contract and only carries backend/algo identity. -defaults: - - /task/g1_23dof_walk_flat/base - - _self_ - -training: - task_name: G1Walk23DofFlat - sim_backend: mujoco -algo: - max_iterations: 100000 diff --git a/src/unilab/conf/td3/task/go1_joystick_flat/base.yaml b/src/unilab/conf/td3/task/go1_joystick_flat/base.yaml deleted file mode 100644 index 8a2f3bf57..000000000 --- a/src/unilab/conf/td3/task/go1_joystick_flat/base.yaml +++ /dev/null @@ -1,244 +0,0 @@ -# @package _global_ -# Canonical Go1 flat Manager-Based task declaration. Backend owner leaves inherit -# this file and only override backend/algo tuning or explicitly disabled terms. -env: - scene: - model_file: src/unilab/assets/robots/go1/scene_flat.xml - default_keyframe_name: home - entities: - robot: - root_body_name: trunk - joint_names: - - FR_hip_joint - - FR_thigh_joint - - FR_calf_joint - - FL_hip_joint - - FL_thigh_joint - - FL_calf_joint - - RR_hip_joint - - RR_thigh_joint - - RR_calf_joint - - RL_hip_joint - - RL_thigh_joint - - RL_calf_joint - actuator_names: - - FR_hip - - FR_thigh - - FR_calf - - FL_hip - - FL_thigh - - FL_calf - - RR_hip - - RR_thigh - - RR_calf - - RL_hip - - RL_thigh - - RL_calf - body_names: [trunk] - sim_dt: 0.01 - ctrl_dt: 0.02 - max_episode_seconds: 20.0 - observations: - policy: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - critic: - terms: - base_ang_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: gyro - projected_gravity: - func: unilab.envs.mdp.projected_gravity_from_sensor - params: - sensor_name: upvector - joint_pos: - func: unilab.envs.mdp.joint_pos_rel - joint_vel: - func: unilab.envs.mdp.joint_vel_rel - actions: - func: unilab.envs.mdp.last_action - command: - func: unilab.envs.mdp.generated_commands - params: - command_name: twist - gait_phase: - func: unilab.tasks.locomotion.common.manager_terms.quadruped_gait_phase - params: - frequency: 2.0 - base_lin_vel: - func: unilab.envs.mdp.builtin_sensor - params: - sensor_name: local_linvel - actions: - joint_pos: - _target_: unilab.envs.mdp.JointPositionActionCfg - entity_name: robot - actuator_names: [".*"] - scale: 0.25 - use_default_offset: true - commands: - twist: - _target_: unilab.envs.mdp.UniformVelocityCommandCfg - entity_name: robot - resampling_time_range: [20.0, 20.0] - heading_command: false - heading_control_stiffness: 0.5 - rel_standing_envs: 0.0 - rel_heading_envs: 0.0 - rel_world_envs: 0.0 - rel_forward_envs: 0.0 - init_velocity_prob: 0.0 - ranges: - lin_vel_x: [-0.6, 1.0] - lin_vel_y: [-0.4, 0.4] - ang_vel_z: [-0.8, 0.8] - events: - reset_scene_to_default: - func: unilab.envs.mdp.reset_scene_to_default - mode: reset - reset_root_state_uniform: - func: unilab.envs.mdp.reset_root_state_uniform - mode: reset - params: - pose_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [0.0, 0.0] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [-3.141592653589793, 3.141592653589793] - velocity_range: - x: [-0.5, 0.5] - y: [-0.5, 0.5] - z: [-0.5, 0.5] - roll: [-0.5, 0.5] - pitch: [-0.5, 0.5] - yaw: [-0.5, 0.5] - base_mass: - func: unilab.envs.mdp.randomize_rigid_body_mass - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - mass_distribution_params: [-1.5, 1.5] - operation: add - recompute_inertia: false - base_com: - func: unilab.envs.mdp.randomize_rigid_body_com - mode: reset - params: - asset_cfg: - _target_: SceneEntityCfg - name: robot - body_names: trunk - com_range: - x: [-0.05, 0.05] - y: [0.0, 0.0] - z: [0.0, 0.0] - pd_gains: - func: unilab.envs.mdp.pd_gains - mode: reset - params: - kp_range: [35.0, 35.0] - kd_range: [0.5, 0.5] - operation: abs - push_robot: - func: unilab.envs.mdp.push_by_setting_velocity - mode: interval - interval_range_s: [15.0, 15.0] - is_global_time: true - params: - velocity_range: - x: [-1.0, 1.0] - y: [-1.0, 1.0] - z: [-0.5, 0.5] - roll: [0.0, 0.0] - pitch: [0.0, 0.0] - yaw: [0.0, 0.0] - terminations: - time_out: - func: unilab.envs.mdp.time_out - time_out: true - bad_orientation: - func: unilab.envs.mdp.bad_orientation - params: - limit_angle: 1.0471975511965976 - policy_observation_group: policy - critic_observation_group: critic - -reward: - tracking_lin_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_lin_vel_xy_exp - weight: 1.0 - params: - std: 0.5 - command_name: twist - tracking_ang_vel: - func: unilab.tasks.locomotion.common.manager_terms.track_ang_vel_z_exp - weight: 0.2 - params: - std: 0.5 - command_name: twist - lin_vel_z: - func: unilab.tasks.locomotion.common.manager_terms.lin_vel_z_l2 - weight: -5.0 - ang_vel_xy: - func: unilab.tasks.locomotion.common.manager_terms.ang_vel_xy_l2 - weight: -0.1 - base_height: - func: unilab.tasks.locomotion.common.manager_terms.base_height_l2 - weight: -100.0 - params: - target_height: 0.3 - action_rate: - func: unilab.envs.mdp.action_rate_l2 - weight: -0.005 - similar_to_default: - func: unilab.tasks.locomotion.common.manager_terms.joint_deviation_l1 - weight: -0.1 - contact: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_contact - # Legacy Go1 sums four matching feet while this community term returns their mean. - weight: 0.96 - params: - frequency: 2.0 - sensor_names: - - FL_foot_contact - - FR_foot_contact - - RL_foot_contact - - RR_foot_contact - contact_threshold: 0.1 - stance_threshold: 0.6 - swing_feet_z: - func: unilab.tasks.locomotion.common.manager_terms.feet_phase_swing_height - weight: 4.0 - params: - frequency: 2.0 - sensor_names: [FL_pos, FR_pos, RL_pos, RR_pos] - target_height: 0.1 - kernel: 0.01 - swing_start: 0.6 diff --git a/src/unilab/conf/td3/task/go1_joystick_flat/motrix.yaml b/src/unilab/conf/td3/task/go1_joystick_flat/motrix.yaml deleted file mode 100644 index fb408b50b..000000000 --- a/src/unilab/conf/td3/task/go1_joystick_flat/motrix.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# @package _global_ -defaults: - - /task/go1_joystick_flat/base - - _self_ - -training: - task_name: Go1JoystickFlat - sim_backend: motrix -algo: - num_envs: 1024 - learning_starts: 10 - max_iterations: 5000 - save_interval: 1000 - updates_per_step: 8 - batch_size: 8192 - replay_buffer_n: 1024 -env: - commands: - twist: - ranges: - lin_vel_x: [0.5, 0.5] - lin_vel_y: [0.0, 0.0] - ang_vel_z: [0.0, 0.0] - events: - push_robot: null -reward: - contact: null diff --git a/src/unilab/demo.py b/src/unilab/demo.py index 202092adf..2c045aa6d 100644 --- a/src/unilab/demo.py +++ b/src/unilab/demo.py @@ -26,7 +26,6 @@ class DemoSpec: DEMO_REGISTRY: dict[str, DemoSpec] = { "dance": DemoSpec(algo="ppo", task="g1_motion_tracking", sim="motrix", entry="eval"), - "wallflip": DemoSpec(algo="ppo", task="g1_wall_flip_tracking", sim="motrix", entry="eval"), "boxtracking": DemoSpec(algo="ppo", task="g1_box_tracking", sim="motrix", entry="eval"), "teaser": DemoSpec(algo="", task="", sim="", entry="teaser"), } diff --git a/src/unilab/scripts/play_interactive.py b/src/unilab/scripts/play_interactive.py index b11b78258..16b83cd42 100644 --- a/src/unilab/scripts/play_interactive.py +++ b/src/unilab/scripts/play_interactive.py @@ -9,7 +9,7 @@ uv run python -m unilab.scripts.play_interactive --algo ppo --task go2_joystick_flat --sim mujoco # Policy playback and keyboard command control - uv run python -m unilab.scripts.play_interactive --algo ppo --task go2_joystick_rough --sim mujoco \ + uv run python -m unilab.scripts.play_interactive --algo ppo --task go2_joystick_flat --sim mujoco \ interactive.action_mode=policy interactive.keyboard=true # Show target bodies / reward debug overlays diff --git a/src/unilab/tasks/__init__.py b/src/unilab/tasks/__init__.py index 4357620d7..d5166ceb6 100644 --- a/src/unilab/tasks/__init__.py +++ b/src/unilab/tasks/__init__.py @@ -6,11 +6,8 @@ """ __unilab_registry_modules__ = ( - "unilab.tasks.locomotion.go1", "unilab.tasks.locomotion.go2", - "unilab.tasks.locomotion.go2w", "unilab.tasks.locomotion.g1", - "unilab.tasks.locomotion.a2", "unilab.tasks.manipulation.allegro_inhand", "unilab.tasks.manipulation.stewart", "unilab.tasks.manipulation.fr3", diff --git a/src/unilab/tasks/locomotion/a2/__init__.py b/src/unilab/tasks/locomotion/a2/__init__.py deleted file mode 100644 index e078a7e20..000000000 --- a/src/unilab/tasks/locomotion/a2/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import joystick as joystick - -__all__ = ["joystick"] diff --git a/src/unilab/tasks/locomotion/a2/joystick.py b/src/unilab/tasks/locomotion/a2/joystick.py deleted file mode 100644 index f5b22df20..000000000 --- a/src/unilab/tasks/locomotion/a2/joystick.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Hydra-owned A2 flat Manager-Based production registration.""" - -from unilab.base import registry -from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env - -registry.register_env_config("A2JoystickFlat", ManagerBasedRlEnvCfg) -registry.register_env("A2JoystickFlat", make_manager_based_rl_env, sim_backend="mujoco") diff --git a/src/unilab/tasks/locomotion/common/height_scan.py b/src/unilab/tasks/locomotion/common/height_scan.py index a557e8f8f..ac9555d6f 100644 --- a/src/unilab/tasks/locomotion/common/height_scan.py +++ b/src/unilab/tasks/locomotion/common/height_scan.py @@ -1,7 +1,7 @@ """Shared height-scan and terrain-bound helpers for rough locomotion tasks. These functions and the ``HeightScanConfig`` dataclass are consumed by Go2, -Go2W, Go1, and G1 rough environments — anywhere the policy / critic ingests +Height-scan environments — anywhere the policy / critic ingests a forward-looking height grid sampled from a procedural heightfield. Each helper mirrors the original implementation that lived inline in diff --git a/src/unilab/tasks/locomotion/common/manager_terms.py b/src/unilab/tasks/locomotion/common/manager_terms.py index b496f006a..7d4a786c5 100644 --- a/src/unilab/tasks/locomotion/common/manager_terms.py +++ b/src/unilab/tasks/locomotion/common/manager_terms.py @@ -1,6 +1,6 @@ """Shared Manager-Based terms and term bases for the locomotion families. -The equations come from UniLab's existing Go1/Go2 joystick tasks and are reused +The equations come from UniLab's quadruped joystick tasks and are reused by quadruped and biped owners alike. The adaptation uses community ``func + params`` terms, NumPy, and the base-owned sensor facade. Reward terms that read named XML sensors live in ``sensor_reward_terms.py`` and build on the diff --git a/src/unilab/tasks/locomotion/common/rough_manager_terms.py b/src/unilab/tasks/locomotion/common/rough_manager_terms.py index 76520e666..01d9b8568 100644 --- a/src/unilab/tasks/locomotion/common/rough_manager_terms.py +++ b/src/unilab/tasks/locomotion/common/rough_manager_terms.py @@ -100,7 +100,7 @@ def _rough_sub_terrains() -> dict[str, SubTerrainCfg]: @dataclass(kw_only=True) class QuadrupedRoughTerrainCfg(TerrainGeneratorCfg): - """Shared seven-terrain production generator for Go1, Go2, and Go2W.""" + """Shared seven-terrain production generator for quadruped rough owners.""" seed: int | None = 42 curriculum: bool = False diff --git a/src/unilab/tasks/locomotion/g1/__init__.py b/src/unilab/tasks/locomotion/g1/__init__.py index 1f30247f2..362637e16 100644 --- a/src/unilab/tasks/locomotion/g1/__init__.py +++ b/src/unilab/tasks/locomotion/g1/__init__.py @@ -18,14 +18,6 @@ registry.register_env("G1WalkRough", make_g1_walk_env, sim_backend="mujoco") registry.register_env("G1WalkRough", make_g1_walk_env, sim_backend="motrix") -registry.register_env_config("G1Walk23DofFlat", ManagerBasedRlEnvCfg) -registry.register_env("G1Walk23DofFlat", make_g1_walk_env, sim_backend="mujoco") -registry.register_env("G1Walk23DofFlat", make_g1_walk_env, sim_backend="motrix") - -registry.register_env_config("G1Walk23DofRough", ManagerBasedRlEnvCfg) -registry.register_env("G1Walk23DofRough", make_g1_walk_env, sim_backend="mujoco") -registry.register_env("G1Walk23DofRough", make_g1_walk_env, sim_backend="motrix") - __all__ = [ "G1WalkManagerBasedEnv", "make_g1_walk_env", diff --git a/src/unilab/tasks/locomotion/go1/__init__.py b/src/unilab/tasks/locomotion/go1/__init__.py deleted file mode 100644 index 3c5413d39..000000000 --- a/src/unilab/tasks/locomotion/go1/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Hydra-owned Manager-Based Go1 production registrations.""" - -from unilab.base import registry -from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env - -registry.register_env_config("Go1JoystickFlat", ManagerBasedRlEnvCfg) -registry.register_env("Go1JoystickFlat", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go1JoystickFlat", make_manager_based_rl_env, sim_backend="motrix") -registry.register_env("Go1JoystickFlat", make_manager_based_rl_env, sim_backend="drake") - -registry.register_env_config("Go1JoystickRough", ManagerBasedRlEnvCfg) -registry.register_env("Go1JoystickRough", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go1JoystickRough", make_manager_based_rl_env, sim_backend="motrix") - -__all__: list[str] = [] diff --git a/src/unilab/tasks/locomotion/go2/__init__.py b/src/unilab/tasks/locomotion/go2/__init__.py index 74744878b..752e89339 100644 --- a/src/unilab/tasks/locomotion/go2/__init__.py +++ b/src/unilab/tasks/locomotion/go2/__init__.py @@ -3,16 +3,10 @@ from unilab.base import registry from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env -from . import footstand as footstand - registry.register_env_config("Go2JoystickFlat", ManagerBasedRlEnvCfg) registry.register_env("Go2JoystickFlat", make_manager_based_rl_env, sim_backend="mujoco") registry.register_env("Go2JoystickFlat", make_manager_based_rl_env, sim_backend="motrix") registry.register_env("Go2JoystickFlat", make_manager_based_rl_env, sim_backend="drake") registry.register_env("Go2JoystickFlat", make_manager_based_rl_env, sim_backend="superdex") -registry.register_env_config("Go2JoystickRough", ManagerBasedRlEnvCfg) -registry.register_env("Go2JoystickRough", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go2JoystickRough", make_manager_based_rl_env, sim_backend="motrix") - -__all__ = ["footstand"] +__all__: list[str] = [] diff --git a/src/unilab/tasks/locomotion/go2/footstand.py b/src/unilab/tasks/locomotion/go2/footstand.py deleted file mode 100644 index 4cbbb6fa8..000000000 --- a/src/unilab/tasks/locomotion/go2/footstand.py +++ /dev/null @@ -1,1076 +0,0 @@ -"""Hydra-owned Manager-Based terms for the Go2 footstand task. - -The task keeps its historical NumPy observation, action, reward, termination, -and reset semantics while using only the public manager/entity facade. -""" - -from __future__ import annotations - -from dataclasses import dataclass -from numbers import Real -from typing import TYPE_CHECKING, Any, Protocol, cast - -import numpy as np - -from unilab.base import registry -from unilab.dtype_config import get_global_dtype -from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env -from unilab.managers import ActionTerm, ActionTermCfg, ManagerTermBase, ManagerTermBaseCfg -from unilab.managers.scene_entity_config import SceneEntityCfg -from unilab.utils.rotation import np_quat_apply, np_quat_apply_inverse - -if TYPE_CHECKING: - from unilab.base.entity import Entity - from unilab.managers._types import ManagerBasedRlEnv, ManagerSensorView - from unilab.managers.action_manager import ActionManager - from unilab.managers.termination_manager import TerminationManager - - class _FootstandEnv(ManagerBasedRlEnv, Protocol): - @property - def common_step_counter(self) -> int: ... - - @property - def action_manager(self) -> ActionManager: ... - - @property - def termination_manager(self) -> TerminationManager: ... - - -NUM_ACTIONS = 12 -FRAME_OBS_DIM = 45 -PRIVILEGED_OBS_DIM = 49 - -_WORLD_GRAVITY = np.asarray([0.0, 0.0, -1.0], dtype=np.float32) -_BODY_FORWARD = np.asarray([1.0, 0.0, 0.0], dtype=np.float32) -_TARGET_HEIGHT = 0.53 -_CONTACT_THRESHOLD = 0.1 -_STAND_HEIGHT_FRACTION = 0.8 -_STAND_ORIENTATION_THRESHOLD = 0.5 - -_FRONT_FEET = np.asarray([0, 1], dtype=np.intp) -_REAR_FEET = np.asarray([2, 3], dtype=np.intp) -_FRONT_LEGS = np.arange(0, 6, dtype=np.intp) -_REAR_LEGS = np.arange(6, 12, dtype=np.intp) -_REAR_HIPS = np.asarray([6, 9], dtype=np.intp) -_REAR_LEFT = np.asarray([6, 7, 8], dtype=np.intp) -_REAR_RIGHT = np.asarray([9, 10, 11], dtype=np.intp) -_REAR_MIRROR_SIGNS = np.asarray([-1.0, 1.0, 1.0], dtype=np.float32) -_FRONT_LEG_TARGET = np.asarray([0.0, 1.82, -1.16, 0.0, 1.82, -1.16], dtype=np.float32) - -_TRACKED_BODY_NAMES = ( - "FL_thigh", - "FR_thigh", - "FL_calf", - "FR_calf", - "RL_calf", - "RR_calf", -) -_FRONT_LEFT_BODY_INDICES = np.asarray([0, 2], dtype=np.intp) -_FRONT_RIGHT_BODY_INDICES = np.asarray([1, 3], dtype=np.intp) -_KNEE_BODY_INDICES = np.asarray([2, 3, 4, 5], dtype=np.intp) - -_SENSOR_SPECS = ( - ("local_linvel", 3), - ("gyro", 3), - ("upvector", 3), - ("global_position", 3), - ("accelerometer", 3), - ("global_angvel", 3), - ("FL_foot_contact", 1), - ("FR_foot_contact", 1), - ("RL_foot_contact", 1), - ("RR_foot_contact", 1), - ("FL_pos", 3), - ("FR_pos", 3), - ("RL_pos", 3), - ("RR_pos", 3), - ("base1_contact", 1), - ("base2_contact", 1), - ("base3_contact", 1), - ("RL_hip_contact", 1), - ("RR_hip_contact", 1), - ("RL_thigh_contact", 1), - ("RR_thigh_contact", 1), - ("RL_calf_contact1", 1), - ("RL_calf_contact2", 1), - ("RR_calf_contact1", 1), - ("RR_calf_contact2", 1), - ("FL_hip_contact", 1), - ("FR_hip_contact", 1), - ("FL_thigh_contact", 1), - ("FR_thigh_contact", 1), - ("FL_calf_contact1", 1), - ("FL_calf_contact2", 1), - ("FR_calf_contact1", 1), - ("FR_calf_contact2", 1), -) -_FOOT_CONTACT_NAMES = tuple(name for name, _ in _SENSOR_SPECS[6:10]) -_FOOT_POSITION_NAMES = tuple(name for name, _ in _SENSOR_SPECS[10:14]) -_TERMINATION_CONTACT_NAMES = tuple(name for name, _ in _SENSOR_SPECS[14:25]) -_PENALTY_CONTACT_NAMES = tuple(name for name, _ in _SENSOR_SPECS[25:33]) - - -def _real( - term: str, - name: str, - value: Any, - *, - minimum: float | None = None, - strict_minimum: bool = False, -) -> float: - if isinstance(value, (bool, np.bool_)) or not isinstance(value, Real): - raise TypeError(f"{term} {name} must be a real number") - result = float(value) - if not np.isfinite(result): - raise ValueError(f"{term} {name} must be finite") - if minimum is not None and (result <= minimum if strict_minimum else result < minimum): - relation = "greater than" if strict_minimum else "at least" - raise ValueError(f"{term} {name} must be {relation} {minimum}") - return result - - -def _pair( - term: str, - name: str, - value: Any, - *, - minimum: float | None = None, -) -> tuple[float, float]: - if isinstance(value, (str, bytes)) or not isinstance(value, (tuple, list)): - raise TypeError(f"{term} {name} must be a two-value range") - if len(value) != 2: - raise ValueError(f"{term} {name} must contain two values") - lower = _real(term, f"{name}[0]", value[0], minimum=minimum) - upper = _real(term, f"{name}[1]", value[1], minimum=minimum) - if lower > upper: - raise ValueError(f"{term} {name} lower bound {lower} exceeds upper bound {upper}") - return lower, upper - - -def _name(term: str, field: str, value: Any) -> str: - if not isinstance(value, str) or not value: - raise ValueError(f"{term} {field} must be a non-empty string") - return value - - -def _env_ids(env: ManagerBasedRlEnv, env_ids: np.ndarray | slice | None) -> np.ndarray: - if env_ids is None: - return np.arange(env.num_envs, dtype=np.int32) - if isinstance(env_ids, slice): - return np.arange(env.num_envs, dtype=np.int32)[env_ids] - return np.asarray(env_ids, dtype=np.int32) - - -@dataclass(kw_only=True) -class FootstandIncrementalActionCfg(ActionTermCfg): - """Incremental position action in the historical actuator/policy order.""" - - actuator_names: tuple[str, ...] | list[str] - joint_names: tuple[str, ...] | list[str] - joint_position_limits: tuple[tuple[float, float], ...] | list[list[float]] - action_scale: float = 0.3 - clip_actions: float = 1.0 - kp: float = 35.0 - kd: float = 0.5 - simulate_action_latency: bool = False - - def build(self, env: ManagerBasedRlEnv) -> FootstandIncrementalAction: - return FootstandIncrementalAction(self, env) - - -class FootstandIncrementalAction(ActionTerm): - """Integrate clipped policy deltas and write position targets each substep.""" - - cfg: FootstandIncrementalActionCfg - _entity: Entity - - def __init__(self, cfg: FootstandIncrementalActionCfg, env: ManagerBasedRlEnv): - super().__init__(cfg, env) - term = type(self).__name__ - if cfg.clip is not None: - raise NotImplementedError(f"{term} does not support actuator-name clip") - for field_name, patterns in ( - ("actuator_names", cfg.actuator_names), - ("joint_names", cfg.joint_names), - ): - if isinstance(patterns, (str, bytes)) or not isinstance(patterns, (tuple, list)): - raise TypeError(f"{term} {field_name} must be an ordered sequence of patterns") - if len(patterns) != NUM_ACTIONS: - raise ValueError(f"{term} requires {NUM_ACTIONS} ordered {field_name} patterns") - self._scale = _real(term, "action_scale", cfg.action_scale, minimum=0.0) - self._clip_actions = _real( - term, "clip_actions", cfg.clip_actions, minimum=0.0, strict_minimum=True - ) - self._kp = _real(term, "kp", cfg.kp, minimum=0.0) - self._kd = _real(term, "kd", cfg.kd, minimum=0.0) - if not isinstance(cfg.simulate_action_latency, bool): - raise TypeError(f"{term} simulate_action_latency must be bool") - - actuator_ids: list[int] = [] - joint_ids: list[int] = [] - actuator_names: list[str] = [] - joint_names: list[str] = [] - for actuator_pattern, joint_pattern in zip( - cfg.actuator_names, cfg.joint_names, strict=True - ): - if not isinstance(actuator_pattern, str) or not actuator_pattern: - raise ValueError(f"{term} actuator patterns must be non-empty strings") - if not isinstance(joint_pattern, str) or not joint_pattern: - raise ValueError(f"{term} joint patterns must be non-empty strings") - found_actuator_ids, found_actuator_names = self._entity.find_actuators( - (actuator_pattern,), preserve_order=True - ) - found_joint_ids, found_joint_names = self._entity.find_joints( - (joint_pattern,), preserve_order=True - ) - if len(found_actuator_ids) != 1 or len(found_joint_ids) != 1: - raise ValueError( - f"{term} patterns actuator={actuator_pattern!r}, joint={joint_pattern!r} " - "must each resolve exactly once; " - f"got actuators={found_actuator_names}, joints={found_joint_names}" - ) - actuator_ids.append(found_actuator_ids[0]) - joint_ids.append(found_joint_ids[0]) - actuator_names.extend(found_actuator_names) - joint_names.extend(found_joint_names) - if len(set(actuator_ids)) != NUM_ACTIONS or len(set(joint_ids)) != NUM_ACTIONS: - raise ValueError(f"{term} actuator-to-joint mapping must be one-to-one") - if set(joint_ids) != set(range(self._entity.num_joints)): - raise ValueError(f"{term} must control every declared Go2 joint exactly once") - - self._actuator_ids = np.asarray(actuator_ids, dtype=np.intp) - self._joint_ids = np.asarray(joint_ids, dtype=np.intp) - self._actuator_ids.setflags(write=False) - self._joint_ids.setflags(write=False) - self._actuator_names = tuple(actuator_names) - self._joint_names = tuple(joint_names) - - try: - selected_ranges = np.asarray(cfg.joint_position_limits, dtype=get_global_dtype()) - except (TypeError, ValueError) as exc: - raise TypeError(f"{term} joint_position_limits must be numeric") from exc - if selected_ranges.shape != (NUM_ACTIONS, 2): - raise ValueError(f"{term} joint_position_limits must have shape ({NUM_ACTIONS}, 2)") - if not np.isfinite(selected_ranges).all(): - raise ValueError(f"{term} joint_position_limits must be finite") - if np.any(selected_ranges[:, 0] >= selected_ranges[:, 1]): - raise ValueError(f"{term} joint_position_limits must have lower < upper") - self._target_lower = np.asarray(selected_ranges[:, 0], dtype=get_global_dtype()) - self._target_upper = np.asarray(selected_ranges[:, 1], dtype=get_global_dtype()) - self._joint_lower = np.empty((NUM_ACTIONS,), dtype=get_global_dtype()) - self._joint_upper = np.empty_like(self._joint_lower) - self._joint_lower[self._joint_ids] = self._target_lower - self._joint_upper[self._joint_ids] = self._target_upper - - dtype = get_global_dtype() - shape = (env.num_envs, NUM_ACTIONS) - self._raw_action = np.zeros(shape, dtype=dtype) - self._previous_raw_action = np.zeros_like(self._raw_action) - self._target = np.asarray( - self._entity.data.joint_pos[:, self._joint_ids], dtype=dtype - ).copy() - self._state = FootstandState(cast("_FootstandEnv", env), self) - - @property - def action_dim(self) -> int: - return NUM_ACTIONS - - @property - def raw_action(self) -> np.ndarray: - return self._raw_action - - @property - def previous_raw_action(self) -> np.ndarray: - return self._previous_raw_action - - @property - def target(self) -> np.ndarray: - return self._target - - @property - def joint_ids(self) -> np.ndarray: - return self._joint_ids - - @property - def joint_names(self) -> tuple[str, ...]: - return self._joint_names - - @property - def actuator_names(self) -> tuple[str, ...]: - return self._actuator_names - - @property - def joint_lower(self) -> np.ndarray: - return self._joint_lower - - @property - def joint_upper(self) -> np.ndarray: - return self._joint_upper - - @property - def state(self) -> FootstandState: - return self._state - - @property - def entity(self) -> Entity: - return self._entity - - @property - def estimated_torque(self) -> np.ndarray: - return self._state.torques - - def process_actions(self, actions: np.ndarray) -> None: - if not isinstance(actions, np.ndarray): - raise TypeError(f"expected np.ndarray actions, got {type(actions).__name__}") - if actions.shape != self._raw_action.shape: - raise ValueError(f"expected action shape {self._raw_action.shape}, got {actions.shape}") - if not np.isfinite(actions).all(): - raise ValueError("received NaN or Inf actions") - self._previous_raw_action[:] = self._raw_action - np.clip(actions, -self._clip_actions, self._clip_actions, out=self._raw_action) - executed = ( - self._previous_raw_action if self.cfg.simulate_action_latency else self._raw_action - ) - self._target += self._scale * executed - np.clip(self._target, self._target_lower, self._target_upper, out=self._target) - - def apply_actions(self) -> None: - self._entity.set_joint_position_target(self._target, joint_ids=self._joint_ids) - - def estimate_torque( - self, joint_pos: np.ndarray, joint_vel: np.ndarray, out: np.ndarray - ) -> None: - out.fill(0.0) - selected_pos = joint_pos[:, self._joint_ids] - selected_vel = joint_vel[:, self._joint_ids] - out[:, self._joint_ids] = self._kp * (self._target - selected_pos) - self._kd * selected_vel - - def reset(self, env_ids: np.ndarray | slice | None = None) -> None: - ids = _env_ids(self._env, env_ids) - self._raw_action[ids] = 0.0 - self._previous_raw_action[ids] = 0.0 - joint_pos = self._entity.data.joint_pos - self._target[ids] = joint_pos[ids][:, self._joint_ids] - self._state.reset(ids) - - -class FootstandState: - """One per-control-step snapshot shared by termination, reward, and observations.""" - - def __init__(self, env: _FootstandEnv, action: FootstandIncrementalAction): - self._env = env - self._action = action - self._entity = action.entity - names = tuple(name for name, _ in _SENSOR_SPECS) - self._sensor_view: ManagerSensorView = env.scene.bind_sensor_data(names) - expected_dims = tuple(width for _, width in _SENSOR_SPECS) - if self._sensor_view.dimensions != expected_dims: - raise ValueError( - "Footstand named-sensor dimensions differ from the task contract: " - f"expected={expected_dims}, got={self._sensor_view.dimensions}" - ) - offsets = np.cumsum((0, *expected_dims), dtype=np.intp) - self._sensor_slices = { - name: slice(int(offsets[index]), int(offsets[index + 1])) - for index, (name, _) in enumerate(_SENSOR_SPECS) - } - tracked_ids, tracked_names = self._entity.find_bodies( - _TRACKED_BODY_NAMES, preserve_order=True - ) - if tuple(tracked_names) != _TRACKED_BODY_NAMES: - raise ValueError( - f"Footstand tracked body order differs from the task contract: {tracked_names}" - ) - self._tracked_body_ids = np.asarray(tracked_ids, dtype=np.intp) - self._tracked_body_ids.setflags(write=False) - - dtype = get_global_dtype() - num_envs = env.num_envs - self.linvel = np.zeros((num_envs, 3), dtype=dtype) - self.gyro = np.zeros_like(self.linvel) - self.gravity = np.broadcast_to(_WORLD_GRAVITY, (num_envs, 3)).astype(dtype, copy=True) - self.upvector = -self.gravity.copy() - self.accelerometer = np.zeros_like(self.linvel) - self.global_angvel = np.zeros_like(self.linvel) - self.root_pos = np.zeros_like(self.linvel) - self.root_quat = np.zeros((num_envs, 4), dtype=dtype) - self.root_quat[:, 0] = 1.0 - self.root_linvel_w = np.zeros_like(self.linvel) - self.root_angvel_w = np.zeros_like(self.linvel) - self.joint_pos = np.asarray(self._entity.data.default_joint_pos, dtype=dtype).copy() - self.joint_vel = np.zeros_like(self.joint_pos) - self.qacc = np.zeros_like(self.joint_pos) - self.torques = np.zeros_like(self.joint_pos) - self.height = np.zeros((num_envs,), dtype=dtype) - self.orientation = np.zeros((num_envs,), dtype=dtype) - self.foot_contact = np.zeros((num_envs, 4), dtype=np.bool_) - self.foot_pos = np.zeros((num_envs, 4, 3), dtype=dtype) - self.termination_contact = np.zeros((num_envs,), dtype=np.bool_) - self.penalty_contact = np.zeros((num_envs,), dtype=np.bool_) - self.tracked_body_pos = np.zeros((num_envs, len(_TRACKED_BODY_NAMES), 3), dtype=dtype) - self.rear_speed = np.zeros((num_envs, 2), dtype=dtype) - self.rear_anchor_drift = np.zeros((num_envs, 2), dtype=dtype) - self.rear_anchor_contact = np.zeros((num_envs, 2), dtype=np.bool_) - self._last_foot_pos = np.zeros_like(self.foot_pos) - self._rear_anchor_pos = np.zeros((num_envs, 2, 2), dtype=dtype) - self._last_counter = int(env.common_step_counter) - - @property - def last_counter(self) -> int: - return self._last_counter - - @property - def default_joint_pos(self) -> np.ndarray: - return self._entity.data.default_joint_pos - - @property - def action(self) -> FootstandIncrementalAction: - return self._action - - def _sensor(self, values: np.ndarray, name: str) -> np.ndarray: - return values[:, self._sensor_slices[name]] - - def _capture(self) -> dict[str, np.ndarray]: - dtype = get_global_dtype() - sensors = np.asarray(self._sensor_view.read(), dtype=dtype) - root_quat = np.asarray(self._entity.data.root_link_quat_w, dtype=dtype) - gravity_w = np.broadcast_to(_WORLD_GRAVITY, (self._env.num_envs, 3)) - gravity = np.asarray(np_quat_apply_inverse(root_quat, gravity_w), dtype=dtype) - forward_w = np_quat_apply( - root_quat, np.broadcast_to(_BODY_FORWARD, (self._env.num_envs, 3)) - ) - orientation = np.asarray(np.square(0.5 * forward_w[:, 2] + 0.5), dtype=dtype) - foot_contact = ( - np.concatenate([self._sensor(sensors, name) for name in _FOOT_CONTACT_NAMES], axis=1) - > _CONTACT_THRESHOLD - ) - foot_pos = np.stack([self._sensor(sensors, name) for name in _FOOT_POSITION_NAMES], axis=1) - termination_contact = np.any( - np.concatenate( - [self._sensor(sensors, name) for name in _TERMINATION_CONTACT_NAMES], axis=1 - ), - axis=1, - ) - penalty_contact = np.any( - np.concatenate( - [self._sensor(sensors, name) for name in _PENALTY_CONTACT_NAMES], axis=1 - ), - axis=1, - ) - return { - "linvel": self._sensor(sensors, "local_linvel"), - "gyro": self._sensor(sensors, "gyro"), - "gravity": gravity, - "upvector": self._sensor(sensors, "upvector"), - "accelerometer": self._sensor(sensors, "accelerometer"), - "global_angvel": self._sensor(sensors, "global_angvel"), - "root_pos": np.asarray(self._entity.data.root_link_pos_w, dtype=dtype), - "root_quat": root_quat, - "root_linvel_w": np.asarray(self._entity.data.root_link_lin_vel_w, dtype=dtype), - "root_angvel_w": np.asarray(self._entity.data.root_link_ang_vel_w, dtype=dtype), - "joint_pos": np.asarray(self._entity.data.joint_pos, dtype=dtype), - "joint_vel": np.asarray(self._entity.data.joint_vel, dtype=dtype), - "height": self._sensor(sensors, "global_position")[:, 2], - "orientation": orientation, - "foot_contact": foot_contact, - "foot_pos": foot_pos, - "termination_contact": termination_contact, - "penalty_contact": penalty_contact, - "tracked_body_pos": np.asarray( - self._entity.data.body_link_pos_w[:, self._tracked_body_ids], dtype=dtype - ), - } - - def reset(self, env_ids: np.ndarray) -> None: - values = self._capture() - self.linvel[env_ids] = values["linvel"][env_ids] - self.gyro[env_ids] = values["gyro"][env_ids] - self.gravity[env_ids] = values["gravity"][env_ids] - self.upvector[env_ids] = values["upvector"][env_ids] - self.accelerometer[env_ids] = values["accelerometer"][env_ids] - self.global_angvel[env_ids] = values["global_angvel"][env_ids] - self.root_pos[env_ids] = values["root_pos"][env_ids] - self.root_quat[env_ids] = values["root_quat"][env_ids] - self.root_linvel_w[env_ids] = values["root_linvel_w"][env_ids] - self.root_angvel_w[env_ids] = values["root_angvel_w"][env_ids] - self.joint_pos[env_ids] = values["joint_pos"][env_ids] - self.joint_vel[env_ids] = values["joint_vel"][env_ids] - self.height[env_ids] = values["height"][env_ids] - self.orientation[env_ids] = values["orientation"][env_ids] - self.foot_contact[env_ids] = values["foot_contact"][env_ids] - self.foot_pos[env_ids] = values["foot_pos"][env_ids] - self.termination_contact[env_ids] = values["termination_contact"][env_ids] - self.penalty_contact[env_ids] = values["penalty_contact"][env_ids] - self.tracked_body_pos[env_ids] = values["tracked_body_pos"][env_ids] - self.qacc[env_ids] = 0.0 - torque = np.empty_like(self.torques) - self._action.estimate_torque(self.joint_pos, self.joint_vel, torque) - self.torques[env_ids] = torque[env_ids] - self._last_foot_pos[env_ids] = self.foot_pos[env_ids] - self.rear_speed[env_ids] = 0.0 - self._rear_anchor_pos[env_ids] = self.foot_pos[env_ids][:, _REAR_FEET, :2] - self.rear_anchor_contact[env_ids] = False - self.rear_anchor_drift[env_ids] = 0.0 - self._last_counter = int(self._env.common_step_counter) - - def snapshot(self, env: _FootstandEnv) -> FootstandState: - counter = int(env.common_step_counter) - if counter == self._last_counter: - return self - if counter != self._last_counter + 1: - raise RuntimeError( - "FootstandState missed a control-step update: " - f"last={self._last_counter}, current={counter}" - ) - values = self._capture() - new_joint_vel = values["joint_vel"] - np.subtract(new_joint_vel, self.joint_vel, out=self.qacc) - self.qacc /= env.step_dt - - new_foot_pos = values["foot_pos"] - rear_delta = new_foot_pos[:, _REAR_FEET, :2] - self._last_foot_pos[:, _REAR_FEET, :2] - self.rear_speed[:] = np.linalg.norm(rear_delta / env.step_dt, axis=2) - - standing = (values["height"] >= _TARGET_HEIGHT * _STAND_HEIGHT_FRACTION) & ( - values["orientation"] >= _STAND_ORIENTATION_THRESHOLD - ) - anchor_contact = values["foot_contact"][:, _REAR_FEET] & standing[:, None] - rear_xy = new_foot_pos[:, _REAR_FEET, :2] - new_contact = anchor_contact & ~self.rear_anchor_contact - self._rear_anchor_pos[new_contact] = rear_xy[new_contact] - self.rear_anchor_contact[:] = anchor_contact - self.rear_anchor_drift[:] = np.linalg.norm(rear_xy - self._rear_anchor_pos, axis=2) - - self.linvel[:] = values["linvel"] - self.gyro[:] = values["gyro"] - self.gravity[:] = values["gravity"] - self.upvector[:] = values["upvector"] - self.accelerometer[:] = values["accelerometer"] - self.global_angvel[:] = values["global_angvel"] - self.root_pos[:] = values["root_pos"] - self.root_quat[:] = values["root_quat"] - self.root_linvel_w[:] = values["root_linvel_w"] - self.root_angvel_w[:] = values["root_angvel_w"] - self.joint_pos[:] = values["joint_pos"] - self.joint_vel[:] = values["joint_vel"] - self.height[:] = values["height"] - self.orientation[:] = values["orientation"] - self.foot_contact[:] = values["foot_contact"] - self.foot_pos[:] = values["foot_pos"] - self.termination_contact[:] = values["termination_contact"] - self.penalty_contact[:] = values["penalty_contact"] - self.tracked_body_pos[:] = values["tracked_body_pos"] - self._action.estimate_torque(self.joint_pos, self.joint_vel, self.torques) - self._last_foot_pos[:] = self.foot_pos - self._last_counter = counter - return self - - def frame(self, env: _FootstandEnv) -> np.ndarray: - self.snapshot(env) - return np.concatenate( - ( - self.linvel, - self.gyro, - self.gravity, - self.joint_pos - self.default_joint_pos, - self.joint_vel, - self._action.previous_raw_action, - ), - axis=1, - dtype=get_global_dtype(), - ) - - def privileged(self, env: _FootstandEnv) -> np.ndarray: - self.snapshot(env) - return np.concatenate( - ( - self.gyro, - self.accelerometer, - self.linvel, - self.global_angvel, - self.joint_pos, - self.joint_vel, - self.torques, - self.height[:, None], - ), - axis=1, - dtype=get_global_dtype(), - ) - - -def _action(env: _FootstandEnv, action_name: str) -> FootstandIncrementalAction: - name = _name("Footstand manager term", "action_name", action_name) - try: - action = env.action_manager.get_term(name) - except KeyError as exc: - raise KeyError(f"Footstand action term {name!r} is unavailable") from exc - if not isinstance(action, FootstandIncrementalAction): - raise TypeError( - f"Footstand action term {name!r} must be FootstandIncrementalAction, " - f"got {type(action).__name__}" - ) - return action - - -def frame_observation(env: _FootstandEnv, action_name: str) -> np.ndarray: - return _action(env, action_name).state.frame(env) - - -def privileged_observation(env: _FootstandEnv, action_name: str) -> np.ndarray: - return _action(env, action_name).state.privileged(env) - - -class FootstandTermination(ManagerTermBase): - """Aggregate the historical non-timeout termination state before rewards.""" - - def __init__(self, cfg: ManagerTermBaseCfg, env: ManagerBasedRlEnv): - super().__init__(env) - task_env = cast("_FootstandEnv", env) - term = type(self).__name__ - allowed = { - "action_name", - "grace_steps", - "height_fraction", - "orientation_threshold", - "energy_threshold", - } - unknown = sorted(set(cfg.params) - allowed) - if unknown: - raise TypeError(f"{term} received unsupported parameters: {unknown}") - self._state = _action( - task_env, _name(term, "action_name", cfg.params.get("action_name")) - ).state - grace = cfg.params.get("grace_steps") - if isinstance(grace, (bool, np.bool_)) or not isinstance(grace, (int, np.integer)): - raise TypeError(f"{term} grace_steps must be an integer") - if int(grace) < 0: - raise ValueError(f"{term} grace_steps must be non-negative") - self._grace_steps = int(grace) - self._height_fraction = _real( - term, "height_fraction", cfg.params.get("height_fraction"), minimum=0.0 - ) - self._orientation_threshold = _real( - term, "orientation_threshold", cfg.params.get("orientation_threshold"), minimum=0.0 - ) - self._energy_threshold = _real( - term, "energy_threshold", cfg.params.get("energy_threshold"), minimum=0.0 - ) - self.terminated = np.zeros(env.num_envs, dtype=np.bool_) - self._last_counter = int(task_env.common_step_counter) - - @property - def state(self) -> FootstandState: - return self._state - - @property - def last_counter(self) -> int: - return self._last_counter - - def reset(self, env_ids: np.ndarray | slice | None = None) -> None: - self.terminated[_env_ids(self._env, env_ids)] = False - self._last_counter = int(cast("_FootstandEnv", self._env).common_step_counter) - - def __call__(self, env: _FootstandEnv, **params: Any) -> np.ndarray: - del params - state = self._state.snapshot(env) - previous_steps = np.maximum(env.episode_length_buf - 1, 0) - grace_elapsed = previous_steps >= self._grace_steps - low_height = state.height < _TARGET_HEIGHT * self._height_fraction - bad_orientation = state.orientation < self._orientation_threshold - pose_failure = grace_elapsed & (low_height | bad_orientation) - energy = np.sum(np.abs(state.torques) * np.abs(state.joint_vel), axis=1) - energy_failure = energy > self._energy_threshold - upside_down = state.upvector[:, 2] < -0.25 - self.terminated[:] = np.logical_or.reduce( - (state.termination_contact, upside_down, energy_failure, pose_failure) - ) - self._last_counter = int(env.common_step_counter) - return self.terminated - - -def _termination(env: _FootstandEnv, state_term_name: str) -> FootstandTermination: - name = _name("Footstand reward", "state_term_name", state_term_name) - state_term = env.termination_manager.get_term_cfg(name).func - if not isinstance(state_term, FootstandTermination): - raise TypeError( - f"Footstand termination term {name!r} must be FootstandTermination, " - f"got {type(state_term).__name__}" - ) - if state_term.last_counter != int(env.common_step_counter): - raise RuntimeError( - f"Footstand termination state {name!r} was not computed for control step " - f"{env.common_step_counter}" - ) - return state_term - - -class FootstandReward(ManagerTermBase): - """Historical positive-clipped reward aggregate backed by one state snapshot.""" - - _REWARD_NAMES = frozenset( - { - "height", - "contact", - "orientation", - "oritentation", - "action_rate", - "termination", - "dof_pos_limits", - "torques", - "pose", - "penalty_contact", - "tar", - "rear_feet_contact", - "both_rear_feet_contact", - "rear_foot_slip", - "rear_foot_anchor", - "front_feet_air", - "balanced_footstand", - "rear_leg_symmetry", - "rear_leg_splay", - "front_leg_motion", - "front_feet_crossing", - "front_leg_crossing", - "upright_stability", - "knee_clearance", - "stay_still", - "energy", - "dof_acc", - } - ) - - def __init__(self, cfg: ManagerTermBaseCfg, env: ManagerBasedRlEnv): - super().__init__(env) - task_env = cast("_FootstandEnv", env) - term = type(self).__name__ - allowed = { - "state_term_name", - "scales", - "soft_joint_pos_limit_factor", - "knee_height_target", - "front_feet_min_separation", - "front_feet_side_margin", - "rear_hip_abduction_margin", - "rear_foot_slip_deadband", - "rear_foot_anchor_radius", - } - unknown = sorted(set(cfg.params) - allowed) - if unknown: - raise TypeError(f"{term} received unsupported parameters: {unknown}") - self._state_term_name = _name(term, "state_term_name", cfg.params.get("state_term_name")) - scales = cfg.params.get("scales") - if not isinstance(scales, dict) or not scales: - raise TypeError(f"{term} scales must be a non-empty mapping") - unknown_rewards = sorted(set(scales) - self._REWARD_NAMES) - if unknown_rewards: - raise ValueError(f"{term} scales contains unknown rewards: {unknown_rewards}") - self._scales = { - name: _real(term, f"scales.{name}", value) for name, value in scales.items() - } - self._soft_limit_factor = _real( - term, - "soft_joint_pos_limit_factor", - cfg.params.get("soft_joint_pos_limit_factor"), - minimum=0.0, - ) - self._knee_height_target = _real( - term, "knee_height_target", cfg.params.get("knee_height_target"), minimum=0.0 - ) - self._front_min_separation = _real( - term, - "front_feet_min_separation", - cfg.params.get("front_feet_min_separation"), - minimum=0.0, - ) - self._front_side_margin = _real( - term, - "front_feet_side_margin", - cfg.params.get("front_feet_side_margin"), - minimum=0.0, - ) - self._rear_hip_margin = _real( - term, - "rear_hip_abduction_margin", - cfg.params.get("rear_hip_abduction_margin"), - minimum=0.0, - ) - self._rear_slip_deadband = _real( - term, - "rear_foot_slip_deadband", - cfg.params.get("rear_foot_slip_deadband"), - minimum=0.0, - ) - self._rear_anchor_radius = _real( - term, - "rear_foot_anchor_radius", - cfg.params.get("rear_foot_anchor_radius"), - minimum=0.0, - strict_minimum=True, - ) - state_term = _termination(task_env, self._state_term_name) - action = state_term.state.action - centers = (action.joint_lower + action.joint_upper) / 2.0 - widths = action.joint_upper - action.joint_lower - self._soft_lower = centers - 0.5 * widths * self._soft_limit_factor - self._soft_upper = centers + 0.5 * widths * self._soft_limit_factor - - @staticmethod - def _standing(state: FootstandState) -> np.ndarray: - return ( - (state.height >= _TARGET_HEIGHT * _STAND_HEIGHT_FRACTION) - & (state.orientation >= _STAND_ORIENTATION_THRESHOLD) - ).astype(get_global_dtype(), copy=False) - - def _value( - self, - name: str, - state_term: FootstandTermination, - state: FootstandState, - ) -> np.ndarray: - dtype = get_global_dtype() - standing = self._standing(state) - default = state.default_joint_pos - if name == "height": - return np.asarray(np.exp(-np.abs(_TARGET_HEIGHT - state.height) / 0.1), dtype=dtype) - if name == "contact": - return np.any(state.foot_contact[:, _FRONT_FEET], axis=1).astype(dtype) - if name in ("orientation", "oritentation"): - return state.orientation - if name == "action_rate": - action = state.action - return np.sum(np.square(action.raw_action - action.previous_raw_action), axis=1) - if name == "termination": - return state_term.terminated.astype(dtype) - if name == "dof_pos_limits": - below = np.clip(self._soft_lower - state.joint_pos, 0.0, None) - above = np.clip(state.joint_pos - self._soft_upper, 0.0, None) - return np.sum(below + above, axis=1) - if name == "torques": - return np.sum(np.square(state.torques), axis=1) - if name == "pose": - return np.sum( - np.square(state.joint_pos[:, _REAR_LEGS] - default[:, _REAR_LEGS]), axis=1 - ) - if name == "penalty_contact": - return state.penalty_contact.astype(dtype) - if name == "tar": - error = np.sum(np.square(state.joint_pos[:, _FRONT_LEGS] - _FRONT_LEG_TARGET), axis=1) - height_mask = (state.height >= _TARGET_HEIGHT * _STAND_HEIGHT_FRACTION).astype(dtype) - return np.asarray(np.exp(-error) * height_mask, dtype=dtype) - if name == "rear_feet_contact": - return np.mean(state.foot_contact[:, _REAR_FEET], axis=1, dtype=dtype) - if name == "both_rear_feet_contact": - return np.all(state.foot_contact[:, _REAR_FEET], axis=1).astype(dtype) - if name == "rear_foot_slip": - slip = np.square(np.clip(state.rear_speed - self._rear_slip_deadband, 0.0, None)) - slip *= state.foot_contact[:, _REAR_FEET] - return np.mean(slip, axis=1, dtype=dtype) - if name == "rear_foot_anchor": - drift = np.square( - np.clip(state.rear_anchor_drift - self._rear_anchor_radius, 0.0, None) - / self._rear_anchor_radius - ) - drift *= state.rear_anchor_contact - return np.mean(drift, axis=1, dtype=dtype) - if name == "front_feet_air": - return (~np.any(state.foot_contact[:, _FRONT_FEET], axis=1)).astype(dtype) - if name == "balanced_footstand": - support = np.all(state.foot_contact[:, _REAR_FEET], axis=1) - support &= ~np.any(state.foot_contact[:, _FRONT_FEET], axis=1) - return support.astype(dtype) * standing - if name == "rear_leg_symmetry": - mirrored = state.joint_pos[:, _REAR_RIGHT] * _REAR_MIRROR_SIGNS - cost = np.mean(np.square(state.joint_pos[:, _REAR_LEFT] - mirrored), axis=1) - return cost * (1.0 - standing) - if name == "rear_leg_splay": - error = state.joint_pos[:, _REAR_HIPS] - default[:, _REAR_HIPS] - splay = np.clip(np.abs(error) - self._rear_hip_margin, 0.0, None) - return np.mean(np.square(splay), axis=1) * standing - if name == "front_leg_motion": - return np.mean(np.square(state.joint_vel[:, _FRONT_LEGS]), axis=1) * standing - if name in ("front_feet_crossing", "front_leg_crossing"): - return self._front_crossing(state) - if name == "upright_stability": - cost = np.sum(np.square(state.root_linvel_w), axis=1) - cost += 0.25 * np.sum(np.square(state.root_angvel_w), axis=1) - return cost * standing - if name == "knee_clearance": - target = max(self._knee_height_target, 1.0e-6) - height = state.tracked_body_pos[:, _KNEE_BODY_INDICES, 2] - return np.mean(np.square(np.clip(target - height, 0.0, None) / target), axis=1) - if name == "stay_still": - return np.sum(np.square(state.root_linvel_w[:, :2]), axis=1) + np.square( - state.root_angvel_w[:, 2] - ) - if name == "energy": - return np.sum(np.abs(state.joint_vel) * np.abs(state.torques), axis=1) - if name == "dof_acc": - return np.sum(np.square(state.qacc), axis=1) - raise RuntimeError(f"Footstand reward dispatch is incomplete for {name!r}") - - def _front_crossing(self, state: FootstandState) -> np.ndarray: - left = np.concatenate( - ( - state.foot_pos[:, [0], :], - state.tracked_body_pos[:, _FRONT_LEFT_BODY_INDICES, :], - ), - axis=1, - ) - right = np.concatenate( - ( - state.foot_pos[:, [1], :], - state.tracked_body_pos[:, _FRONT_RIGHT_BODY_INDICES, :], - ), - axis=1, - ) - points = np.concatenate((left, right), axis=1) - relative = (points - state.root_pos[:, None, :]).reshape(-1, 3) - quaternions = np.repeat(state.root_quat, points.shape[1], axis=0) - body_points = np_quat_apply_inverse(quaternions, relative).reshape( - state.root_pos.shape[0], points.shape[1], 3 - ) - left_y = body_points[:, : left.shape[1], 1] - right_y = body_points[:, left.shape[1] :, 1] - left_error = np.clip(self._front_side_margin - left_y, 0.0, None) - right_error = np.clip(right_y + self._front_side_margin, 0.0, None) - separation_error = np.clip(self._front_min_separation - (left_y - right_y), 0.0, None) - return np.mean( - np.square(left_error) + np.square(right_error) + np.square(separation_error), axis=1 - ) - - def __call__(self, env: _FootstandEnv, **params: Any) -> np.ndarray: - del params - state_term = _termination(env, self._state_term_name) - state = state_term.state - reward = np.zeros((env.num_envs,), dtype=get_global_dtype()) - for name, scale in self._scales.items(): - if scale != 0.0: - reward += scale * self._value(name, state_term, state) - max_rate = 10000.0 / env.step_dt - return np.clip(reward, 0.0, max_rate) - - -class FootstandJointReset(ManagerTermBase): - """Reset all Go2 joints to the home pose plus a uniform offset.""" - - def __init__(self, cfg: ManagerTermBaseCfg, env: ManagerBasedRlEnv): - super().__init__(env) - term = type(self).__name__ - if set(cfg.params) != {"asset_cfg", "position_offset_range"}: - raise ValueError( - f"{term} requires exactly asset_cfg and position_offset_range parameters" - ) - asset_cfg = cfg.params["asset_cfg"] - if not isinstance(asset_cfg, SceneEntityCfg): - raise TypeError(f"{term} asset_cfg must be SceneEntityCfg") - self._entity = cast("Entity", env.scene[asset_cfg.name]) - self._joint_ids = asset_cfg.joint_ids - selected = self._entity.data.default_joint_pos[:, self._joint_ids] - if selected.shape != (env.num_envs, NUM_ACTIONS): - raise ValueError(f"{term} requires exactly {NUM_ACTIONS} selected joints") - self._range = _pair(term, "position_offset_range", cfg.params["position_offset_range"]) - - def __call__( - self, - env: ManagerBasedRlEnv, - env_ids: np.ndarray | None, - **params: Any, - ) -> None: - del params - ids = _env_ids(env, env_ids) - position = np.array(self._entity.data.default_joint_pos[ids][:, self._joint_ids], copy=True) - position += env.rng.uniform(*self._range, size=position.shape) - velocity = np.array(self._entity.data.default_joint_vel[ids][:, self._joint_ids], copy=True) - self._entity.write_joint_state_to_sim( - np.asarray(position, dtype=get_global_dtype()), - np.asarray(velocity, dtype=get_global_dtype()), - joint_ids=self._joint_ids, - env_ids=ids, - ) - - -class FootstandMassRandomization(ManagerTermBase): - """Compose all-link mass scaling and torso additive mass in one reset write.""" - - def __init__(self, cfg: ManagerTermBaseCfg, env: ManagerBasedRlEnv): - super().__init__(env) - term = type(self).__name__ - allowed = { - "asset_cfg", - "torso_body_name", - "link_mass_scale_range", - "torso_added_mass_range", - } - if set(cfg.params) != allowed: - raise ValueError(f"{term} requires parameters {sorted(allowed)}") - asset_cfg = cfg.params["asset_cfg"] - if not isinstance(asset_cfg, SceneEntityCfg): - raise TypeError(f"{term} asset_cfg must be SceneEntityCfg") - self._entity = cast("Entity", env.scene[asset_cfg.name]) - self._body_ids, self._default_mass = self._entity.bind_body_mass_write( - asset_cfg.body_ids, term_name="footstand_mass" - ) - torso_name = _name(term, "torso_body_name", cfg.params["torso_body_name"]) - torso_ids, _ = self._entity.find_bodies((torso_name,)) - if len(torso_ids) != 1: - raise ValueError(f"{term} torso_body_name must resolve exactly one body") - selected = np.flatnonzero(self._body_ids == torso_ids[0]) - if selected.size != 1: - raise ValueError(f"{term} torso body must be included in asset_cfg") - self._torso_index = int(selected[0]) - self._scale_range = _pair( - term, "link_mass_scale_range", cfg.params["link_mass_scale_range"], minimum=0.0 - ) - self._added_range = _pair( - term, "torso_added_mass_range", cfg.params["torso_added_mass_range"] - ) - - def __call__( - self, - env: ManagerBasedRlEnv, - env_ids: np.ndarray | None, - **params: Any, - ) -> None: - del params - ids = _env_ids(env, env_ids) - default_mass = ( - self._default_mass[ids] if self._default_mass.ndim == 2 else self._default_mass[None, :] - ) - if default_mass.shape[0] != ids.size: - default_mass = np.broadcast_to( - default_mass, - (ids.size, *default_mass.shape[1:]), - ) - scale = env.rng.uniform(*self._scale_range, size=default_mass.shape) - mass = default_mass * scale - mass[:, self._torso_index] += env.rng.uniform(*self._added_range, size=ids.size) - if np.any(mass <= 0.0): - raise ValueError("FootstandMassRandomization produced a non-positive body mass") - self._entity.write_body_mass_to_sim( - mass, - body_ids=self._body_ids, - env_ids=ids, - term_name="footstand_mass", - ) - - -registry.register_env_config("Go2FootStand", ManagerBasedRlEnvCfg) -registry.register_env("Go2FootStand", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go2FootStand", make_manager_based_rl_env, sim_backend="motrix") -registry.register_env("Go2FootStand", make_manager_based_rl_env, sim_backend="drake") - - -__all__ = [ - "FRAME_OBS_DIM", - "NUM_ACTIONS", - "PRIVILEGED_OBS_DIM", - "FootstandIncrementalAction", - "FootstandIncrementalActionCfg", - "FootstandJointReset", - "FootstandMassRandomization", - "FootstandReward", - "FootstandState", - "FootstandTermination", - "frame_observation", - "privileged_observation", -] diff --git a/src/unilab/tasks/locomotion/go2w/__init__.py b/src/unilab/tasks/locomotion/go2w/__init__.py deleted file mode 100644 index 2c908918d..000000000 --- a/src/unilab/tasks/locomotion/go2w/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Hydra-owned Manager-Based Go2W production registrations.""" - -from unilab.base import registry -from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env - -registry.register_env_config("Go2WJoystickFlat", ManagerBasedRlEnvCfg) -registry.register_env("Go2WJoystickFlat", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go2WJoystickFlat", make_manager_based_rl_env, sim_backend="motrix") -registry.register_env("Go2WJoystickFlat", make_manager_based_rl_env, sim_backend="drake") - -registry.register_env_config("Go2WJoystickRough", ManagerBasedRlEnvCfg) -registry.register_env("Go2WJoystickRough", make_manager_based_rl_env, sim_backend="mujoco") -registry.register_env("Go2WJoystickRough", make_manager_based_rl_env, sim_backend="motrix") - -__all__: list[str] = [] diff --git a/src/unilab/tasks/locomotion/go2w/base.py b/src/unilab/tasks/locomotion/go2w/base.py deleted file mode 100644 index d4912a879..000000000 --- a/src/unilab/tasks/locomotion/go2w/base.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import numpy as np - -LEG_JOINT_SENSOR_PREFIXES: tuple[str, ...] = ( - "FR_hip", - "FR_thigh", - "FR_calf", - "FL_hip", - "FL_thigh", - "FL_calf", - "RR_hip", - "RR_thigh", - "RR_calf", - "RL_hip", - "RL_thigh", - "RL_calf", -) -WHEEL_JOINT_SENSOR_PREFIXES: tuple[str, ...] = ("FR_wheel", "FL_wheel", "RR_wheel", "RL_wheel") -JOINT_SENSOR_PREFIXES: tuple[str, ...] = LEG_JOINT_SENSOR_PREFIXES + WHEEL_JOINT_SENSOR_PREFIXES - -NUM_LEG_ACTIONS = len(LEG_JOINT_SENSOR_PREFIXES) -NUM_WHEEL_ACTIONS = len(WHEEL_JOINT_SENSOR_PREFIXES) -NUM_GO2W_ACTIONS = len(JOINT_SENSOR_PREFIXES) - - -def compute_go2w_motor_ctrl( - policy_ctrl: np.ndarray, - joint_pos: np.ndarray, - joint_vel: np.ndarray, - leg_kp: np.ndarray, - leg_kd: np.ndarray, - wheel_kd: np.ndarray, - ctrl_lower: np.ndarray, - ctrl_upper: np.ndarray, - out: np.ndarray, -) -> np.ndarray: - """Convert Go2W owner-level controls into motor actuator torques. - - Hot path: shapes/dtypes are validated by the owning env at init/reset. - """ - leg_out = out[:, :NUM_LEG_ACTIONS] - np.subtract(policy_ctrl[:, :NUM_LEG_ACTIONS], joint_pos[:, :NUM_LEG_ACTIONS], out=leg_out) - np.multiply(leg_out, leg_kp, out=leg_out) - leg_out -= leg_kd * joint_vel[:, :NUM_LEG_ACTIONS] - wheel_out = out[:, NUM_LEG_ACTIONS:] - np.subtract(policy_ctrl[:, NUM_LEG_ACTIONS:], joint_vel[:, NUM_LEG_ACTIONS:], out=wheel_out) - np.multiply(wheel_out, wheel_kd, out=wheel_out) - np.clip(out, ctrl_lower, ctrl_upper, out=out) - return out - - -__all__ = [ - "JOINT_SENSOR_PREFIXES", - "LEG_JOINT_SENSOR_PREFIXES", - "NUM_GO2W_ACTIONS", - "NUM_LEG_ACTIONS", - "NUM_WHEEL_ACTIONS", - "WHEEL_JOINT_SENSOR_PREFIXES", - "compute_go2w_motor_ctrl", -] diff --git a/src/unilab/tasks/locomotion/go2w/manager_terms.py b/src/unilab/tasks/locomotion/go2w/manager_terms.py deleted file mode 100644 index 92364feda..000000000 --- a/src/unilab/tasks/locomotion/go2w/manager_terms.py +++ /dev/null @@ -1,362 +0,0 @@ -"""Manager-Based terms owned by the Go2W flat task.""" - -from __future__ import annotations - -import math -from dataclasses import dataclass -from numbers import Real -from typing import TYPE_CHECKING, Any, ClassVar, cast - -import numpy as np - -from unilab.dtype_config import get_global_dtype -from unilab.envs.mdp.commands.velocity_command import ( - UniformVelocityCommand, - UniformVelocityCommandCfg, -) -from unilab.managers import ActionTerm, ActionTermCfg -from unilab.managers.scene_entity_config import SceneEntityCfg -from unilab.tasks.locomotion.go2w.base import ( - NUM_GO2W_ACTIONS, - NUM_LEG_ACTIONS, - NUM_WHEEL_ACTIONS, - compute_go2w_motor_ctrl, -) - -if TYPE_CHECKING: - from unilab.base.entity import Entity - from unilab.managers._types import ManagerBasedRlEnv - - -_HIP_INDICES = np.asarray([0, 3, 6, 9], dtype=np.intp) -_DEFAULT_ASSET_CFG = SceneEntityCfg("robot") - - -def _real( - value: Any, - *, - label: str, - minimum: float | None = None, - strict_minimum: bool = False, -) -> float: - if isinstance(value, (bool, np.bool_)) or not isinstance(value, Real): - raise TypeError(f"{label} must be a real number, got {type(value).__name__}") - result = float(value) - if not math.isfinite(result): - raise ValueError(f"{label} must be finite") - if minimum is not None and (result <= minimum if strict_minimum else result < minimum): - relation = "greater than" if strict_minimum else "at least" - raise ValueError(f"{label} must be {relation} {minimum}") - return result - - -def _range(value: Any, *, label: str) -> tuple[float, float]: - if not isinstance(value, (tuple, list)) or len(value) != 2: - raise TypeError(f"{label} must be a two-value range") - lower = _real(value[0], label=f"{label} lower", minimum=0.0) - upper = _real(value[1], label=f"{label} upper", minimum=0.0) - if lower > upper: - raise ValueError(f"{label} lower {lower} exceeds upper {upper}") - return lower, upper - - -@dataclass(kw_only=True) -class Go2WMixedActionCfg(ActionTermCfg): - """Configure the Go2W leg-position and wheel-velocity motor action.""" - - actuator_names: tuple[str, ...] | list[str] - leg_action_scale: float = 0.25 - hip_action_scale: float | None = None - wheel_action_scale: float = 10.0 - leg_kp: float = 35.0 - leg_kd: float = 0.5 - wheel_kd: float = 0.5 - clip_actions: float = 1.0 - simulate_action_latency: bool = False - - def build(self, env: ManagerBasedRlEnv) -> Go2WMixedAction: - return Go2WMixedAction(self, env) - - -class Go2WMixedAction(ActionTerm): - """Convert one community action term into Go2W motor torques per substep.""" - - requires_substep_state_feedback: ClassVar[bool] = True - cfg: Go2WMixedActionCfg - _entity: Entity - - def __init__(self, cfg: Go2WMixedActionCfg, env: ManagerBasedRlEnv): - self._validate_cfg(cfg) - super().__init__(cfg=cfg, env=env) - actuator_ids, actuator_names = self._entity.find_actuators(cfg.actuator_names) - joint_ids, joint_names = self._entity.find_joints_by_actuator_names(cfg.actuator_names) - if len(actuator_ids) != NUM_GO2W_ACTIONS or len(joint_ids) != NUM_GO2W_ACTIONS: - raise ValueError( - "Go2WMixedAction requires exactly " - f"{NUM_GO2W_ACTIONS} actuators and target joints; received " - f"actuators={actuator_names}, joints={joint_names}" - ) - self._actuator_ids = np.asarray(actuator_ids, dtype=np.intp) - self._joint_ids = np.asarray(joint_ids, dtype=np.intp) - self._actuator_ids.setflags(write=False) - self._joint_ids.setflags(write=False) - - dtype = get_global_dtype() - shape = (self.num_envs, NUM_GO2W_ACTIONS) - self._raw_action = np.zeros(shape, dtype=dtype) - self._previous_raw_action = np.zeros_like(self._raw_action) - self._processed_action = np.zeros_like(self._raw_action) - self._motor_torque = np.zeros_like(self._raw_action) - - self._leg_action_scale = np.full( - (NUM_LEG_ACTIONS,), float(cfg.leg_action_scale), dtype=dtype - ) - if cfg.hip_action_scale is not None: - self._leg_action_scale[_HIP_INDICES] = float(cfg.hip_action_scale) - self._base_leg_kp = np.full((NUM_LEG_ACTIONS,), float(cfg.leg_kp), dtype=dtype) - self._base_leg_kd = np.full((NUM_LEG_ACTIONS,), float(cfg.leg_kd), dtype=dtype) - self._leg_kp = np.broadcast_to(self._base_leg_kp, (self.num_envs, NUM_LEG_ACTIONS)).copy() - self._leg_kd = np.broadcast_to(self._base_leg_kd, (self.num_envs, NUM_LEG_ACTIONS)).copy() - self._wheel_kd = np.full( - (self.num_envs, NUM_WHEEL_ACTIONS), float(cfg.wheel_kd), dtype=dtype - ) - - ctrl_range = self._entity.data.actuator_ctrl_range[self._actuator_ids] - expected_range_shape = (NUM_GO2W_ACTIONS, 2) - if ctrl_range.shape != expected_range_shape: - raise ValueError( - "Go2WMixedAction actuator control range must have shape " - f"{expected_range_shape}, got {ctrl_range.shape}" - ) - self._ctrl_lower = np.asarray(ctrl_range[:, 0], dtype=dtype) - self._ctrl_upper = np.asarray(ctrl_range[:, 1], dtype=dtype) - - @staticmethod - def _validate_cfg(cfg: Go2WMixedActionCfg) -> None: - if not isinstance(cfg.simulate_action_latency, bool): - raise TypeError("Go2WMixedActionCfg simulate_action_latency must be bool") - for name, value in ( - ("leg_action_scale", cfg.leg_action_scale), - ("wheel_action_scale", cfg.wheel_action_scale), - ("leg_kp", cfg.leg_kp), - ("leg_kd", cfg.leg_kd), - ("wheel_kd", cfg.wheel_kd), - ("clip_actions", cfg.clip_actions), - ): - _real( - value, - label=f"Go2WMixedActionCfg {name}", - minimum=0.0, - strict_minimum=name == "clip_actions", - ) - if cfg.hip_action_scale is not None: - _real( - cfg.hip_action_scale, - label="Go2WMixedActionCfg hip_action_scale", - minimum=0.0, - ) - - @property - def action_dim(self) -> int: - return NUM_GO2W_ACTIONS - - @property - def raw_action(self) -> np.ndarray: - """Clipped policy action, matching the legacy observable action buffer.""" - return self._raw_action - - @property - def previous_raw_action(self) -> np.ndarray: - return self._previous_raw_action - - @property - def processed_action(self) -> np.ndarray: - return self._processed_action - - @property - def motor_torque(self) -> np.ndarray: - return self._motor_torque - - @property - def leg_kp(self) -> np.ndarray: - return self._leg_kp - - @property - def leg_kd(self) -> np.ndarray: - return self._leg_kd - - def process_actions(self, actions: np.ndarray) -> None: - if not isinstance(actions, np.ndarray): - raise TypeError(f"Go2WMixedAction expected np.ndarray, got {type(actions).__name__}") - if actions.shape != self._raw_action.shape: - raise ValueError( - f"Go2WMixedAction expected action shape {self._raw_action.shape}, " - f"got {actions.shape}" - ) - if not np.isfinite(actions).all(): - raise ValueError("Go2WMixedAction received NaN or Inf actions") - - self._previous_raw_action[:] = self._raw_action - np.clip( - actions, - -float(self.cfg.clip_actions), - float(self.cfg.clip_actions), - out=self._raw_action, - ) - executed = ( - self._previous_raw_action if self.cfg.simulate_action_latency else self._raw_action - ) - np.multiply( - executed[:, :NUM_LEG_ACTIONS], - self._leg_action_scale, - out=self._processed_action[:, :NUM_LEG_ACTIONS], - ) - self._processed_action[:, :NUM_LEG_ACTIONS] += self._entity.data.default_joint_pos[ - :, self._joint_ids[:NUM_LEG_ACTIONS] - ] - np.multiply( - executed[:, NUM_LEG_ACTIONS:], - float(self.cfg.wheel_action_scale), - out=self._processed_action[:, NUM_LEG_ACTIONS:], - ) - - def apply_actions(self) -> None: - joint_pos = self._entity.data.joint_pos[:, self._joint_ids] - joint_vel = self._entity.data.joint_vel[:, self._joint_ids] - compute_go2w_motor_ctrl( - self._processed_action, - joint_pos, - joint_vel, - self._leg_kp, - self._leg_kd, - self._wheel_kd, - self._ctrl_lower, - self._ctrl_upper, - self._motor_torque, - ) - self._entity.data.write_ctrl(self._motor_torque, actuator_ids=self._actuator_ids) - - def set_motor_gain_multipliers( - self, - env_ids: np.ndarray, - kp_multiplier: np.ndarray, - kd_multiplier: np.ndarray, - ) -> None: - expected = (len(env_ids), 1) - if kp_multiplier.shape != expected or kd_multiplier.shape != expected: - raise ValueError( - "Go2WMixedAction motor gain multipliers must have shape " - f"{expected}, got kp={kp_multiplier.shape}, kd={kd_multiplier.shape}" - ) - self._leg_kp[env_ids] = self._base_leg_kp * kp_multiplier - self._leg_kd[env_ids] = self._base_leg_kd * kd_multiplier - - def reset(self, env_ids: np.ndarray | slice | None = None) -> None: - if env_ids is None: - env_ids = slice(None) - self._raw_action[env_ids] = 0.0 - self._previous_raw_action[env_ids] = 0.0 - self._processed_action[env_ids] = 0.0 - self._motor_torque[env_ids] = 0.0 - - -@dataclass(kw_only=True) -class Go2WVelocityCommandCfg(UniformVelocityCommandCfg): - """Velocity command with the legacy Go2W planar dead zone.""" - - planar_dead_zone: float = 0.2 - - def build(self, env: ManagerBasedRlEnv) -> Go2WVelocityCommand: - return Go2WVelocityCommand(self, env) - - -class Go2WVelocityCommand(UniformVelocityCommand): - cfg: Go2WVelocityCommandCfg # pyright: ignore[reportIncompatibleVariableOverride] - - def __init__(self, cfg: Go2WVelocityCommandCfg, env: ManagerBasedRlEnv): - self._planar_dead_zone = _real( - cfg.planar_dead_zone, - label="Go2WVelocityCommandCfg planar_dead_zone", - minimum=0.0, - ) - super().__init__(cfg, env) - - def _resample_command(self, env_ids: np.ndarray) -> None: - super()._resample_command(env_ids) - planar = self.vel_command_b[env_ids, :2] - moving = np.linalg.norm(planar, axis=1) > self._planar_dead_zone - self.vel_command_b[env_ids, :2] = planar * moving[:, None] - - -def _action(env: ManagerBasedRlEnv, action_name: str) -> Go2WMixedAction: - if not isinstance(action_name, str) or not action_name: - raise ValueError("Go2W manager term action_name must be a non-empty string") - try: - term = env.action_manager.get_term(action_name) - except KeyError as exc: - raise KeyError(f"Go2W action term '{action_name}' is unavailable") from exc - if not isinstance(term, Go2WMixedAction): - raise TypeError( - f"Go2W action term '{action_name}' must be Go2WMixedAction, got {type(term).__name__}" - ) - return term - - -def randomize_motor_gains( - env: ManagerBasedRlEnv, - env_ids: np.ndarray | None, - action_name: str, - kp_multiplier_range: tuple[float, float] | list[float], - kd_multiplier_range: tuple[float, float] | list[float], -) -> None: - """Sample owner-level motor gains without mutating backend actuator models.""" - ids = ( - np.arange(env.num_envs, dtype=np.int32) - if env_ids is None - else np.asarray(env_ids, dtype=np.int32) - ) - kp_range = _range(kp_multiplier_range, label="randomize_motor_gains kp_multiplier_range") - kd_range = _range(kd_multiplier_range, label="randomize_motor_gains kd_multiplier_range") - shape = (len(ids), 1) - kp = env.rng.uniform(*kp_range, size=shape).astype(get_global_dtype(), copy=False) - kd = env.rng.uniform(*kd_range, size=shape).astype(get_global_dtype(), copy=False) - _action(env, action_name).set_motor_gain_multipliers(ids, kp, kd) - - -def motor_torque(env: ManagerBasedRlEnv, action_name: str) -> np.ndarray: - return _action(env, action_name).motor_torque - - -def motor_torque_l2(env: ManagerBasedRlEnv, action_name: str) -> np.ndarray: - return np.sum(np.square(motor_torque(env, action_name)), axis=1) - - -def clipped_action_rate_l2(env: ManagerBasedRlEnv, action_name: str) -> np.ndarray: - action = _action(env, action_name) - return np.sum(np.square(action.raw_action - action.previous_raw_action), axis=1) - - -def upward_l2( - env: ManagerBasedRlEnv, - asset_cfg: SceneEntityCfg = _DEFAULT_ASSET_CFG, -) -> np.ndarray: - asset = cast("Entity", env.scene[asset_cfg.name]) - return np.square(1.0 - asset.data.projected_gravity_b[:, 2]) - - -def constant_alive(env: ManagerBasedRlEnv) -> np.ndarray: - return np.ones((env.num_envs,), dtype=get_global_dtype()) - - -__all__ = [ - "Go2WMixedAction", - "Go2WMixedActionCfg", - "Go2WVelocityCommand", - "Go2WVelocityCommandCfg", - "clipped_action_rate_l2", - "constant_alive", - "motor_torque", - "motor_torque_l2", - "randomize_motor_gains", - "upward_l2", -] diff --git a/src/unilab/tasks/migration_matrix.py b/src/unilab/tasks/migration_matrix.py index 0e190ad3c..b2ec4f844 100644 --- a/src/unilab/tasks/migration_matrix.py +++ b/src/unilab/tasks/migration_matrix.py @@ -26,69 +26,41 @@ class TaskMigrationRecord: _MBA_TASKS = frozenset( { - "A2JoystickFlat", "AllegroInhandRotation", "AllegroInhandRotationGrasp", # #1534 starts directly on the canonical manager runtime; no legacy seam. "FR3JointTarget", - "Go1JoystickFlat", - "Go2FootStand", "Go2JoystickFlat", - "Go2WJoystickFlat", "StewartBalance", } ) -_ROUGH_TASKS = frozenset( - { - "Go1JoystickRough", - "Go2JoystickRough", - "Go2WJoystickRough", - } -) - _G1_LOCOMOTION_TASKS = frozenset( { "G1WalkFlat", "G1WalkRough", - "G1Walk23DofFlat", - "G1Walk23DofRough", } ) _MOTION_CORE_TASKS = frozenset( { "G1MotionTracking", - "G1MotionTracking23Dof", - "G1MotionTracking23DofDeploy", - "G1MotionTrackingDeploy", "G1MotionTrackingSAC", - "G1MotionTrackingSAC23Dof", } ) _MOTION_TASKS = frozenset( { "G1BoxTracking", - "G1BoxTracking23Dof", - "G1ClimbTracking", - "G1ClimbTracking23Dof", "G1FlipTracking", - "G1FlipTracking23Dof", "G1FlipTrackingSAC", - "G1FlipTrackingSAC23Dof", - "G1WallFlipTracking", - "G1WallFlipTracking23Dof", - "G1WallFlipTrackingSAC", - "G1WallFlipTrackingSAC23Dof", "G1WBTObs", - "G1WBTObs23Dof", "X2WallFlipTracking", } ) PRODUCTION_TASK_NAMES = frozenset( - _MBA_TASKS | _ROUGH_TASKS | _G1_LOCOMOTION_TASKS | _MOTION_CORE_TASKS | _MOTION_TASKS + _MBA_TASKS | _G1_LOCOMOTION_TASKS | _MOTION_CORE_TASKS | _MOTION_TASKS ) @@ -108,21 +80,6 @@ def migration_record(task_name: str) -> TaskMigrationRecord: "Hydra owner YAML materializes the canonical NumPy Manager-Based runtime.", "Keep the manager contract and regression evidence current.", ) - if task_name in _ROUGH_TASKS: - return TaskMigrationRecord( - task_name, - "quadruped_rough", - "Compatible", - "complete", - "Hydra owners materialize shared terrain, height-scan, reset, and curriculum manager terms on the canonical runtime.", - "Keep the shared rough-family contract and both backend owners in sync. " - "Known intentional divergence from the legacy rough env (recorded 2026-08): " - "the legacy reward terms feet_gait, feet_air_time(+variance), " - "feet_contact_without_cmd, feet_height_body, feet_slide, contact_forces, " - "undesired_contacts, joint_mirror, joint_power, joint_torques_l2, " - "joint_acc_l2(+wheel) have no manager port and are not part of the " - "manager-based rough reward set.", - ) if task_name in _G1_LOCOMOTION_TASKS: return TaskMigrationRecord( task_name, diff --git a/src/unilab/tasks/motion_tracking/g1/__init__.py b/src/unilab/tasks/motion_tracking/g1/__init__.py index faa2f43af..10e488009 100644 --- a/src/unilab/tasks/motion_tracking/g1/__init__.py +++ b/src/unilab/tasks/motion_tracking/g1/__init__.py @@ -7,25 +7,11 @@ G1_MOTION_TASKS = ( "G1MotionTracking", - "G1MotionTrackingDeploy", - "G1MotionTracking23Dof", - "G1MotionTracking23DofDeploy", "G1MotionTrackingSAC", - "G1MotionTrackingSAC23Dof", "G1BoxTracking", - "G1BoxTracking23Dof", - "G1ClimbTracking", - "G1ClimbTracking23Dof", "G1FlipTracking", - "G1FlipTracking23Dof", "G1FlipTrackingSAC", - "G1FlipTrackingSAC23Dof", - "G1WallFlipTracking", - "G1WallFlipTracking23Dof", - "G1WallFlipTrackingSAC", - "G1WallFlipTrackingSAC23Dof", "G1WBTObs", - "G1WBTObs23Dof", ) for _task_name in G1_MOTION_TASKS: diff --git a/tests/assets/test_hub.py b/tests/assets/test_hub.py index 3746812e7..a4695e72f 100644 --- a/tests/assets/test_hub.py +++ b/tests/assets/test_hub.py @@ -246,12 +246,9 @@ def test_robot_asset_specs_cover_hf_hosted_robots(): from unilab.assets.hub import ROBOT_ASSET_SPECS expected = { - "a2", "allegro_hand", "g1", - "go1", "go2", - "go2w", "x2", } assert set(ROBOT_ASSET_SPECS) == expected diff --git a/tests/base/test_sim_backend_smoke.py b/tests/base/test_sim_backend_smoke.py index a6227ab32..55bf69036 100644 --- a/tests/base/test_sim_backend_smoke.py +++ b/tests/base/test_sim_backend_smoke.py @@ -29,7 +29,6 @@ def _xml(robot: str, scene: str = "scene_flat.xml") -> str: BASIC_ROBOTS = [ pytest.param(dict(model_file=_xml("g1"), base_name="pelvis"), id="g1"), - pytest.param(dict(model_file=_xml("go1"), base_name="trunk"), id="go1"), pytest.param(dict(model_file=_xml("go2"), base_name="base"), id="go2"), ] @@ -502,18 +501,17 @@ def test_backend_batch_sensor_data_matches_individual_sensors(backend_type): pytest.importorskip("motrixsim") from unilab.base.backend_factory import create_backend - from unilab.tasks.locomotion.go2w.base import JOINT_SENSOR_PREFIXES bkd = create_backend( backend_type, - SceneCfg(model_file=_xml("go2w", "scene_flat.xml")), + SceneCfg(model_file=_xml("go2", "scene_flat.xml")), NUM_ENVS, SIM_DT, - base_name="base_link", + base_name="base", ) bkd.materialize() - names = tuple(f"{prefix}_pos" for prefix in JOINT_SENSOR_PREFIXES[:4]) + names = ("FR_pos", "FL_pos", "gyro", "upvector") expected = np.concatenate( [np.asarray(bkd.get_sensor_data(name)).reshape(NUM_ENVS, -1) for name in names], axis=1, diff --git a/tests/benchmark/test_env_step_config_contract.py b/tests/benchmark/test_env_step_config_contract.py index f7bbe7c64..7fd96e9b3 100644 --- a/tests/benchmark/test_env_step_config_contract.py +++ b/tests/benchmark/test_env_step_config_contract.py @@ -5,7 +5,6 @@ from scripts.benchmark.env import benchmark_env_step as bench from unilab.envs import ManagerBasedRlEnvCfg, make_manager_based_rl_env -from unilab.tasks.locomotion.common.rough_manager_terms import QuadrupedRoughTerrainCfg # Importing benchmark_env_step installs a process-wide create_backend patch for # the benchmark script. These tests only build configs, so undo the patch to @@ -13,45 +12,32 @@ bench._uninstall_mjwarp_patch() -def test_go2w_flat_benchmark_uses_production_manager_owner() -> None: - cfg = bench.TASK_CONFIGS["go2w"].build_cfg("mujoco") +def test_go2_flat_benchmark_uses_production_manager_owner() -> None: + cfg = bench.TASK_CONFIGS["go2"].build_cfg("mujoco") assert isinstance(cfg, ManagerBasedRlEnvCfg) - assert list(cfg.actions) == ["motor"] + assert list(cfg.actions) == ["joint_pos"] assert cfg.critic_observation_group == "critic" - assert bench.TASK_CONFIGS["go2w"].env_cls_factory() is make_manager_based_rl_env + assert bench.TASK_CONFIGS["go2"].env_cls_factory() is make_manager_based_rl_env assert bench.DEFAULT_NUM_ENVS == 4096 -def test_go2w_rough_cfg_matches_ppo_owner_yaml() -> None: - cfg = bench.TASK_CONFIGS["go2w_rough"].build_cfg("mujoco") - - assert isinstance(cfg, ManagerBasedRlEnvCfg) - assert cfg.scene is not None - assert cfg.scene.terrain is not None - assert isinstance(cfg.scene.terrain.generator, QuadrupedRoughTerrainCfg) - assert cfg.scene.model_file.endswith("go2w_mujoco.xml") - assert cfg.actions["motor"].wheel_action_scale == pytest.approx(5.0) - assert cfg.rewards["tracking_lin_vel"].weight == pytest.approx(3.0) - assert bench.TASK_CONFIGS["go2w_rough"].env_cls_factory() is make_manager_based_rl_env - - def test_env_and_reward_overrides_use_hydra_composition() -> None: - cfg = bench.TASK_CONFIGS["go2w_rough"].build_cfg( + cfg = bench.TASK_CONFIGS["go2"].build_cfg( "mujoco", [ - "env.actions.motor.leg_action_scale=0.125", + "env.sim_dt=0.004", "reward.tracking_lin_vel.weight=2.25", ], ) - assert cfg.actions["motor"].leg_action_scale == pytest.approx(0.125) + assert cfg.sim_dt == pytest.approx(0.004) assert cfg.rewards["tracking_lin_vel"].weight == pytest.approx(2.25) def test_unknown_env_override_fails_in_hydra() -> None: with pytest.raises(ConfigCompositionException, match="env.not_a_real_field"): - bench.TASK_CONFIGS["go2w_rough"].build_cfg( + bench.TASK_CONFIGS["go2"].build_cfg( "mujoco", ["env.not_a_real_field=1"], ) @@ -63,13 +49,13 @@ def test_unknown_env_override_fails_in_hydra() -> None: ) def test_training_sim_backend_override_is_rejected(override: str) -> None: with pytest.raises(ValueError, match=r"task=/"): - bench._resolve_task_and_backend(["task=go2w_joystick_rough/mujoco", override]) + bench._resolve_task_and_backend(["task=go2_joystick_flat/mujoco", override]) def test_only_owner_config_overrides_are_forwarded() -> None: overrides = [ - "task=go2w_joystick_rough/mujoco", - "env.actions.motor.leg_action_scale=0.125", + "task=go2_joystick_flat/mujoco", + "env.scene.sim_dt=0.004", "reward.tracking_lin_vel.weight=2.25", ] diff --git a/tests/config/test_config_system.py b/tests/config/test_config_system.py index 5be759f93..81b0c919c 100644 --- a/tests/config/test_config_system.py +++ b/tests/config/test_config_system.py @@ -53,7 +53,7 @@ def _normalize_overrides(algo_dir: str, overrides: list[str] | None) -> list[str if algo_dir in ("sac", "td3", "flashsac"): normalized.append("task=g1_walk_flat/mujoco") else: - normalized.append("task=go1_joystick_flat/mujoco") + normalized.append("task=go2_joystick_flat/mujoco") return normalized @@ -193,20 +193,6 @@ def test_offpolicy_td3_go2_joystick_flat_motrix_composes(): assert cfg.reward.base_height.params.target_height == pytest.approx(0.3) -def test_offpolicy_td3_go1_joystick_flat_motrix_composes(): - cfg = _compose( - "td3", - overrides=["task=go1_joystick_flat/motrix"], - ) - - assert cfg.training.task_name == "Go1JoystickFlat" - assert cfg.training.sim_backend == "motrix" - assert cfg.algo.algo == "td3" - assert cfg.reward.tracking_lin_vel.weight == pytest.approx(1.0) - assert cfg.reward.contact is None - assert cfg.env.events.push_robot is None - - def test_offpolicy_g1_walk_flat_mjwarp_owner_preserves_sac_contract(): mujoco_cfg = _compose("sac", overrides=["task=g1_walk_flat/mujoco"]) mjwarp_cfg = _compose("sac", overrides=["task=g1_walk_flat/mjwarp"]) @@ -279,21 +265,6 @@ def test_appo_adaptive_lr_factors_are_overridden_only_by_dex_hand_owners(): assert allegro_motrix_cfg.algo.algorithm.adaptive_lr_factor == pytest.approx(1.5) -def test_ppo_go1_motrix_preserves_reward_and_algo_values(): - cfg = _compose("ppo", overrides=["task=go1_joystick_flat/motrix"]) - - assert cfg.algo.max_iterations == 151 - assert cfg.algo.empirical_normalization is True - assert cfg.algo.policy.init_noise_std == pytest.approx(0.5) - assert cfg.algo.algorithm.learning_rate == pytest.approx(3.0e-4) - assert cfg.reward.tracking_lin_vel.weight == pytest.approx(1.0) - assert cfg.reward.contact is None - assert cfg.env.commands.twist.ranges.lin_vel_x == [0.5, 0.5] - assert cfg.env.commands.twist.ranges.lin_vel_y == [0.0, 0.0] - assert cfg.env.commands.twist.ranges.ang_vel_z == [0.0, 0.0] - assert cfg.env.events.push_robot is None - - def test_ppo_go2_motrix_preserves_backend_env_overrides(): cfg = _compose("ppo", overrides=["task=go2_joystick_flat/motrix"]) @@ -305,64 +276,6 @@ def test_ppo_go2_motrix_preserves_backend_env_overrides(): assert cfg.env.commands.twist.ranges.ang_vel_z == [0.0, 0.0] -def test_ppo_go2w_mujoco_uses_motor_owner_dr_path(): - cfg = _compose("ppo", overrides=["task=go2w_joystick_flat/mujoco"]) - - assert cfg.training.task_name == "Go2WJoystickFlat" - assert cfg.training.sim_backend == "mujoco" - command = cfg.env.commands.twist - assert command.ranges.lin_vel_x == [0.0, 1.0] - assert command.ranges.lin_vel_y == [0.0, 0.0] - assert command.ranges.ang_vel_z == [-1.0, 1.0] - action = cfg.env.actions.motor - assert action.leg_action_scale == pytest.approx(0.5) - assert action.leg_kp == pytest.approx(50.0) - assert action.leg_kd == pytest.approx(1.5) - assert action.wheel_action_scale == pytest.approx(10.0) - assert action.wheel_kd == pytest.approx(0.5) - gains = cfg.env.events.motor_gains.params - assert gains.kp_multiplier_range == [1.0, 1.0] - assert gains.kd_multiplier_range == [1.0, 1.0] - assert cfg.reward.tracking_ang_vel.weight == pytest.approx(0.75) - assert cfg.reward.orientation.weight == pytest.approx(-2.0) - assert cfg.reward.upward.weight == pytest.approx(1.0) - assert cfg.reward.base_height.params.target_height == pytest.approx(0.4) - assert cfg.reward.torques.weight < 0.0 - - -def test_ppo_go2w_motrix_uses_motor_owner_dr_path(): - cfg = _compose("ppo", overrides=["task=go2w_joystick_flat/motrix"]) - - assert cfg.training.task_name == "Go2WJoystickFlat" - assert cfg.training.sim_backend == "motrix" - assert cfg.env.render_offset_mode == "zero" - command = cfg.env.commands.twist - assert command.ranges.lin_vel_x == [0.0, 1.0] - assert command.ranges.lin_vel_y == [0.0, 0.0] - assert command.ranges.ang_vel_z == [-1.0, 1.0] - action = cfg.env.actions.motor - assert action.leg_action_scale == pytest.approx(0.5) - assert action.leg_kp == pytest.approx(50.0) - assert action.leg_kd == pytest.approx(1.5) - assert action.wheel_action_scale == pytest.approx(10.0) - assert action.wheel_kd == pytest.approx(0.5) - assert cfg.reward.tracking_ang_vel.weight == pytest.approx(0.75) - assert cfg.reward.orientation.weight == pytest.approx(-2.0) - assert cfg.reward.upward.weight == pytest.approx(1.0) - assert cfg.reward.torques.weight < 0.0 - - -def test_ppo_go2w_motrix_uses_motor_owner_scene_path(): - cfg = _compose("ppo", overrides=["task=go2w_joystick_flat/motrix"]) - - assert cfg.training.task_name == "Go2WJoystickFlat" - assert cfg.training.sim_backend == "motrix" - assert str(cfg.env.scene.model_file).endswith("src/unilab/assets/robots/go2w/scene_flat.xml") - assert cfg.env.scene.default_keyframe_name == "home" - assert cfg.env.actions.motor.wheel_action_scale == pytest.approx(10.0) - assert cfg.reward.torques.weight < 0.0 - - def test_offpolicy_g1_walk_flat_motrix_preserves_backend_env_overrides(): cfg = _compose("sac", overrides=["task=g1_walk_flat/motrix"]) diff --git a/tests/config/test_locomotion_params.py b/tests/config/test_locomotion_params.py index f3ed8a3c9..ecb564858 100644 --- a/tests/config/test_locomotion_params.py +++ b/tests/config/test_locomotion_params.py @@ -2,7 +2,6 @@ from __future__ import annotations -import re from pathlib import Path import pytest @@ -43,7 +42,6 @@ 0.07450087032950714, 0.07450087032950714, ] -G1_23DOF_BEYONDMIMIC_ACTION_SCALE = G1_BEYONDMIMIC_ACTION_SCALE[:13] + [0.43857731392336724] * 10 X2_ACTION_SCALE = [0.25] * 29 @@ -290,13 +288,13 @@ def test_appo_g1_task_overrides(): # --------------------------------------------------------------------------- -def test_ppo_go1_max_iterations(): +def test_ppo_go2_max_iterations(): from hydra import compose, initialize_config_dir from hydra.core.global_hydra import GlobalHydra GlobalHydra.instance().clear() with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - cfg = compose("config", overrides=["task=go1_joystick_flat/mujoco"]) + cfg = compose("config", overrides=["task=go2_joystick_flat/mujoco"]) assert cfg.algo.max_iterations == 151 assert "actor" in cfg.algo.obs_groups assert cfg.algo.algorithm.enable_compile is False @@ -326,37 +324,6 @@ def test_ppo_go2_num_envs(): assert cfg.algo.max_iterations == 151 -def test_ppo_go2_footstand_uses_hydra_owned_manager_task(): - from hydra import compose, initialize_config_dir - from hydra.core.global_hydra import GlobalHydra - - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - cfg = compose("config", overrides=["task=go2_footstand/mujoco"]) - - assert cfg.training.task_name == "Go2FootStand" - assert cfg.training.sim_backend == "mujoco" - assert cfg.algo.num_envs == 4096 - assert cfg.env.sim_dt == pytest.approx(0.004) - assert cfg.env.ctrl_dt == pytest.approx(0.02) - assert cfg.env.max_episode_seconds == pytest.approx(10.0) - assert cfg.env.observations.policy.terms.frame.history_length == 15 - assert cfg.env.observations.critic.terms.frame.history_length == 15 - assert cfg.env.actions.joint_pos.action_scale == pytest.approx(0.3) - assert cfg.env.actions.joint_pos.clip_actions == pytest.approx(1.0) - assert cfg.env.terminations.footstand.params.energy_threshold == pytest.approx(200.0) - assert cfg.reward.footstand.params.scales.energy == pytest.approx(-0.003) - assert cfg.reward.footstand.params.scales.dof_acc == pytest.approx(-2.5e-7) - assert cfg.reward.footstand.params.scales.rear_leg_symmetry == pytest.approx(-0.2) - assert cfg.reward.footstand.params.scales.knee_clearance == pytest.approx(-0.5) - assert cfg.reward.footstand.params.knee_height_target == pytest.approx(0.08) - assert cfg.env.events.floor_friction is not None - assert cfg.env.events.link_mass is not None - assert cfg.env.events.torso_com is not None - assert cfg.env.events.joint_armature is not None - assert cfg.env.events.reset_joints is not None - - def test_ppo_g1_motion_tracking(): from hydra import compose, initialize_config_dir from hydra.core.global_hydra import GlobalHydra @@ -369,55 +336,6 @@ def test_ppo_g1_motion_tracking(): assert cfg.algo.algorithm.entropy_coef == pytest.approx(0.005) -def test_ppo_g1_motion_tracking_deploy(): - from hydra import compose, initialize_config_dir - from hydra.core.global_hydra import GlobalHydra - - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - cfg = compose("config", overrides=["task=g1_motion_tracking_deploy/mujoco"]) - assert cfg.training.task_name == "G1MotionTrackingDeploy" - assert cfg.algo.max_iterations == 15000 - assert cfg.algo.algorithm.entropy_coef == pytest.approx(0.005) - assert cfg.env.sim_dt == pytest.approx(0.005) - assert cfg.env.observations.actor.terms.base_ang_vel.params.sensor_name == "pelvis_gyro" - assert cfg.env.actions.joint_pos.scale[".*_(hip_pitch|hip_yaw)_joint"] == pytest.approx( - G1_BEYONDMIMIC_ACTION_SCALE[0] - ) - assert cfg.env.actions.joint_pos.scale[".*_wrist_(pitch|yaw)_joint"] == pytest.approx( - G1_BEYONDMIMIC_ACTION_SCALE[20] - ) - - -@pytest.mark.parametrize( - ("task", "expected"), - [ - ("g1_motion_tracking_deploy", G1_BEYONDMIMIC_ACTION_SCALE), - ("g1_23dof_motion_tracking_deploy", G1_23DOF_BEYONDMIMIC_ACTION_SCALE), - ], -) -def test_ppo_g1_motion_tracking_deploy_action_scale_expands_in_joint_order( - task: str, - expected: list[float], -) -> None: - from hydra import compose, initialize_config_dir - from hydra.core.global_hydra import GlobalHydra - - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - cfg = compose("config", overrides=[f"task={task}/mujoco"]) - - scales = cfg.env.actions.joint_pos.scale - resolved: list[float] = [] - for joint_name in cfg.env.scene.entities.robot.joint_names: - matches = [ - float(value) for pattern, value in scales.items() if re.fullmatch(pattern, joint_name) - ] - assert len(matches) == 1, f"{joint_name} matched {len(matches)} action-scale patterns" - resolved.append(matches[0]) - assert resolved == pytest.approx(expected) - - def test_ppo_g1_box_tracking(): from hydra import compose, initialize_config_dir from hydra.core.global_hydra import GlobalHydra @@ -466,36 +384,6 @@ def test_ppo_g1_flip_tracking(): assert cfg.reward.undesired_contacts.weight == pytest.approx(-0.1) -def test_ppo_g1_wall_flip_tracking(): - from hydra import compose, initialize_config_dir - from hydra.core.global_hydra import GlobalHydra - - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - cfg = compose("config", overrides=["task=g1_wall_flip_tracking/mujoco"]) - assert cfg.training.task_name == "G1WallFlipTracking" - assert cfg.algo.num_envs == 1024 - assert cfg.algo.max_iterations == 20000 - assert cfg.algo.empirical_normalization is True - assert cfg.algo.obs_groups.critic == ["critic"] - assert cfg.algo.algorithm.entropy_coef == pytest.approx(0.005) - assert cfg.algo.algorithm.desired_kl == pytest.approx(0.01) - assert cfg.env.commands.motion.params.sampling_mode == "start" - assert cfg.env.commands.motion.params.truncate_on_clip_end is False - assert cfg.env.sim_dt == pytest.approx(0.005) - assert cfg.env.actions.joint_pos.scale[".*_(hip_pitch|hip_yaw)_joint"] == pytest.approx( - G1_BEYONDMIMIC_ACTION_SCALE[0] - ) - assert cfg.env.scene.model_file.endswith("scene_flat_with_wall.xml") - assert cfg.reward.motion_joint_pos.weight == pytest.approx(0.5) - assert cfg.reward.motion_joint_vel.weight == pytest.approx(0.25) - assert cfg.reward.motion_body_pos.weight == pytest.approx(2.0) - assert cfg.reward.motion_body_ori.weight == pytest.approx(1.5) - assert cfg.reward.motion_ee_body_pos_z.weight == pytest.approx(2.0) - assert cfg.reward.action_rate_l2.weight == pytest.approx(-0.005) - assert cfg.reward.undesired_contacts.weight == pytest.approx(-0.1) - - def test_ppo_x2_wall_flip_tracking(): from hydra import compose, initialize_config_dir from hydra.core.global_hydra import GlobalHydra diff --git a/tests/envs/locomotion/a2/__init__.py b/tests/envs/locomotion/a2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/envs/locomotion/a2/test_a2_joystick_contract.py b/tests/envs/locomotion/a2/test_a2_joystick_contract.py deleted file mode 100644 index 77e4d940a..000000000 --- a/tests/envs/locomotion/a2/test_a2_joystick_contract.py +++ /dev/null @@ -1,331 +0,0 @@ -"""Hydra-owned Manager-Based production contract for A2JoystickFlat.""" - -from __future__ import annotations - -from collections.abc import Mapping, Sequence -from dataclasses import fields, is_dataclass -from pathlib import Path -from typing import Any - -import numpy as np -import pytest -from hydra import compose, initialize_config_dir -from hydra.core.global_hydra import GlobalHydra -from omegaconf import DictConfig, OmegaConf - -from unilab.assets import ASSETS_ROOT_PATH -from unilab.base import registry -from unilab.base.config_adapter import BackendAdapter -from unilab.base.config_materialization import apply_cfg_overrides -from unilab.envs import ManagerBasedRlEnv, ManagerBasedRlEnvCfg, mdp -from unilab.tasks.locomotion.common import manager_terms - -ROOT_DIR = Path(__file__).parents[4] -CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" - -_JOINT_NAMES = ( - "FL_hip_joint", - "FL_thigh_joint", - "FL_calf_joint", - "FR_hip_joint", - "FR_thigh_joint", - "FR_calf_joint", - "RL_hip_joint", - "RL_thigh_joint", - "RL_calf_joint", - "RR_hip_joint", - "RR_thigh_joint", - "RR_calf_joint", -) -_ACTUATOR_NAMES = ( - "FL_hip", - "FL_thigh", - "FL_calf", - "FR_hip", - "FR_thigh", - "FR_calf", - "RL_hip", - "RL_thigh", - "RL_calf", - "RR_hip", - "RR_thigh", - "RR_calf", -) -_HOME_JOINT_POS = np.array( - [-0.1, 0.9, -1.8, 0.1, 0.9, -1.8, -0.1, 0.9, -1.8, 0.1, 0.9, -1.8], - dtype=np.float32, -) -_KP = np.array([100.0, 100.0, 150.0] * 4) -_KD = np.array([4.0, 4.0, 6.0] * 4) - - -def _compose() -> DictConfig: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - return compose("config", overrides=["task=a2_joystick_flat/mujoco"]) - - -def _materialize() -> tuple[DictConfig, ManagerBasedRlEnvCfg, dict[str, Any]]: - hydra_cfg = _compose() - env_override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config("A2JoystickFlat") - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - apply_cfg_overrides(env_cfg, env_override) - env_cfg.validate() - return hydra_cfg, env_cfg, env_override - - -def _assert_no_omegaconf(value: Any) -> None: - assert not OmegaConf.is_config(value) - if is_dataclass(value) and not isinstance(value, type): - for item in fields(value): - _assert_no_omegaconf(getattr(value, item.name)) - elif isinstance(value, Mapping): - for key, item in value.items(): - _assert_no_omegaconf(key) - _assert_no_omegaconf(item) - elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)): - for item in value: - _assert_no_omegaconf(item) - - -def test_a2_asset_declares_home_pose_and_per_joint_pd_defaults() -> None: - mujoco = pytest.importorskip("mujoco") - model = mujoco.MjModel.from_xml_path(str(ASSETS_ROOT_PATH / "robots" / "a2" / "scene_flat.xml")) - - actuator_names = tuple( - mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_ACTUATOR, index) for index in range(model.nu) - ) - assert actuator_names == _ACTUATOR_NAMES - affine = int(mujoco.mjtBias.mjBIAS_AFFINE) - assert all(int(value) == affine for value in model.actuator_biastype) - np.testing.assert_allclose(model.actuator_gainprm[:, 0], _KP) - np.testing.assert_allclose(model.actuator_biasprm[:, 1], -_KP) - np.testing.assert_allclose(model.actuator_biasprm[:, 2], -_KD) - - key_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_KEY, "home") - assert key_id >= 0 - assert model.nq == 19 - assert model.key_qpos[key_id, 2] == pytest.approx(0.4) - np.testing.assert_allclose(model.key_qpos[key_id, 7:19], _HOME_JOINT_POS) - np.testing.assert_allclose(model.key_ctrl[key_id], _HOME_JOINT_POS) - - -def test_a2_asset_exposes_manager_sensor_and_floor_friction_contract() -> None: - mujoco = pytest.importorskip("mujoco") - model = mujoco.MjModel.from_xml_path(str(ASSETS_ROOT_PATH / "robots" / "a2" / "scene_flat.xml")) - sensors = { - mujoco.mj_id2name(model, mujoco.mjtObj.mjOBJ_SENSOR, index) - for index in range(model.nsensor) - } - assert { - "gyro", - "local_linvel", - "upvector", - "FL_pos", - "FR_pos", - "RL_pos", - "RR_pos", - "FL_foot_contact", - "FR_foot_contact", - "RL_foot_contact", - "RR_foot_contact", - } <= sensors - - floor = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_GEOM, "floor") - foot = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_GEOM, "FL") - assert floor >= 0 and foot >= 0 - assert int(model.geom_priority[floor]) > int(model.geom_priority[foot]) - assert int(model.geom_condim[floor]) == 6 - - -def test_a2_owner_materializes_complete_plain_manager_config() -> None: - registry.ensure_registries() - hydra_cfg, env_cfg, _ = _materialize() - - assert hydra_cfg.training.task_name == "A2JoystickFlat" - assert hydra_cfg.training.sim_backend == "mujoco" - assert hydra_cfg.algo.max_iterations == 500 - assert list(hydra_cfg.algo.obs_groups.actor) == ["actor"] - assert list(hydra_cfg.algo.obs_groups.critic) == ["critic"] - assert env_cfg.sim_dt == pytest.approx(0.01) - assert env_cfg.ctrl_dt == pytest.approx(0.02) - assert env_cfg.max_episode_seconds == pytest.approx(20.0) - assert env_cfg.policy_observation_group == "policy" - assert env_cfg.critic_observation_group == "critic" - - assert env_cfg.scene is not None - assert env_cfg.scene.model_file.endswith("robots/a2/scene_flat.xml") - assert env_cfg.scene.default_keyframe_name == "home" - robot = env_cfg.scene.entities["robot"] - assert robot.root_body_name == "base_link" - assert tuple(robot.joint_names or ()) == _JOINT_NAMES - assert tuple(robot.actuator_names or ()) == _ACTUATOR_NAMES - assert robot.body_names == ["base_link"] - assert robot.geom_names == ["floor"] - - policy_terms = [ - "base_ang_vel", - "projected_gravity", - "joint_pos", - "joint_vel", - "actions", - "command", - "gait_phase", - ] - assert list(env_cfg.observations) == ["policy", "critic"] - assert list(env_cfg.observations["policy"].terms) == policy_terms - assert list(env_cfg.observations["critic"].terms) == [*policy_terms, "base_lin_vel"] - assert env_cfg.observations["policy"].terms["gait_phase"].params == { - "frequency": 2.0, - "command_name": "twist", - "command_threshold": 0.1, - } - assert list(env_cfg.actions) == ["joint_pos"] - assert env_cfg.actions["joint_pos"].scale == pytest.approx(0.25) - command = env_cfg.commands["twist"] - assert command.resampling_time_range == [5.0, 5.0] - assert command.rel_standing_envs == pytest.approx(0.1) - assert tuple(command.ranges.lin_vel_x) == (-0.6, 1.0) - - expected_weights = { - "tracking_lin_vel": 1.0, - "tracking_ang_vel": 0.4, - "lin_vel_z": -5.0, - "ang_vel_xy": -0.1, - "base_height": -100.0, - "action_rate": -0.02, - "similar_to_default": -0.25, - "contact": 0.5, - "swing_feet_z": 4.0, - "stand_still": -4.0, - "hip_deviation": -1.0, - "stand_feet_air": -1.0, - } - assert {name: term.weight for name, term in env_cfg.rewards.items()} == expected_weights - assert env_cfg.rewards["stand_still"].func is manager_terms.stand_still_l1 - assert env_cfg.rewards["stand_feet_air"].func is manager_terms.feet_air_while_standing - assert env_cfg.rewards["hip_deviation"].params["asset_cfg"].joint_names == ".*_hip_joint" - for name in ("contact", "swing_feet_z"): - assert env_cfg.rewards[name].params["command_name"] == "twist" - assert env_cfg.rewards[name].params["command_threshold"] == pytest.approx(0.1) - - for manager_name in ("observations", "events", "rewards", "terminations"): - for term in getattr(env_cfg, manager_name).values(): - if term is None: - continue - terms = term.terms.values() if manager_name == "observations" else (term,) - for nested in terms: - if nested is None: - continue - module = nested.func.__module__ - assert ".backend." not in module - assert not any(name in module for name in (".mujoco", ".motrix", ".drake")) - - _assert_no_omegaconf(env_cfg) - - -def test_a2_owner_declares_all_randomization_as_manager_events() -> None: - _, env_cfg, _ = _materialize() - assert list(env_cfg.events) == [ - "reset_scene_to_default", - "reset_root_state_uniform", - "base_mass", - "base_com", - "foot_friction", - "joint_armature", - "pd_gains", - "push_robot", - ] - - mass = env_cfg.events["base_mass"] - assert mass.func is mdp.randomize_rigid_body_mass - assert mass.params["mass_distribution_params"] == [0.0, 8.0] - assert mass.params["recompute_inertia"] is False - com = env_cfg.events["base_com"] - assert com.func is mdp.randomize_rigid_body_com - assert com.params["com_range"] == { - "x": [-0.08, 0.08], - "y": [-0.08, 0.08], - "z": [-0.08, 0.08], - } - friction = env_cfg.events["foot_friction"] - assert friction.func is mdp.geom_friction - assert friction.params["ranges"] == [0.3, 1.6] - assert friction.params["operation"] == "scale" - assert friction.params["shared_random"] is True - armature = env_cfg.events["joint_armature"] - assert armature.func is mdp.joint_armature - assert armature.params["ranges"] == [0.9, 1.1] - gains = env_cfg.events["pd_gains"] - assert gains.func is mdp.pd_gains - assert gains.params["kp_range"] == [0.9, 1.1] - assert gains.params["kd_range"] == [0.9, 1.1] - push = env_cfg.events["push_robot"] - assert push.func is mdp.push_by_setting_velocity - assert push.mode == "interval" - assert push.interval_range_s == [8.0, 8.0] - assert push.is_global_time is True - - -def test_a2_registry_is_manager_only() -> None: - registry.ensure_registries() - assert registry.list_registered_envs()["A2JoystickFlat"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco"], - } - - -def test_a2_registry_executes_real_manager_runtime() -> None: - pytest.importorskip("mujoco") - pytest.importorskip("mjbatch", reason="mjbatch not installed") - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - - hydra_cfg, _, env_override = _materialize() - env = registry.make( - str(hydra_cfg.training.task_name), - sim_backend="mujoco", - env_cfg_override=env_override, - num_envs=2, - ) - try: - assert isinstance(env, ManagerBasedRlEnv) - assert env.obs_groups_spec == {"obs": 49, "critic": 52} - assert env.action_space.shape == (12,) - action = env.action_manager.get_term("joint_pos") - assert action.target_names == list(_JOINT_NAMES) - np.testing.assert_allclose(action.offset, np.broadcast_to(_HOME_JOINT_POS, (2, 12))) - assert env.event_manager.active_terms == { - "reset": [ - "reset_scene_to_default", - "reset_root_state_uniform", - "base_mass", - "base_com", - "foot_friction", - "joint_armature", - "pd_gains", - ], - "interval": ["push_robot"], - } - - obs, info = env.reset(seed=7) - assert {name: value.shape for name, value in obs.items()} == { - "obs": (2, 49), - "critic": (2, 52), - } - assert isinstance(info, dict) - np.testing.assert_allclose( - env.scene["robot"].data.default_joint_pos, - np.broadcast_to(_HOME_JOINT_POS, (2, 12)), - ) - for _ in range(10): - state = env.step(np.zeros((2, 12), dtype=np.float32)) - assert state.reward.shape == (2,) - for value in (*state.obs.values(), state.reward): - assert isinstance(value, np.ndarray) - assert np.isfinite(value).all() - finally: - env.close() diff --git a/tests/envs/locomotion/g1/test_g1_owner_contract.py b/tests/envs/locomotion/g1/test_g1_owner_contract.py index 86c3bb6f3..23899196b 100644 --- a/tests/envs/locomotion/g1/test_g1_owner_contract.py +++ b/tests/envs/locomotion/g1/test_g1_owner_contract.py @@ -86,7 +86,6 @@ ) _POSE_WEIGHTS_29 = [0.01, 1.0, 5.0, 0.01, 5.0, 5.0] * 2 + [50.0] * 17 -_POSE_WEIGHTS_23 = [0.01, 1.0, 5.0, 0.01, 5.0, 5.0] * 2 + [50.0] * 11 _OWNER_CASES = ( pytest.param( @@ -182,45 +181,6 @@ False, id="ppo-isaacsim", ), - pytest.param( - "ppo", - ("task=g1_23dof_walk_flat/mujoco",), - "G1Walk23DofFlat", - "mujoco", - 23, - 0.25, - "scene_flat_23dof.xml", - _PPO_WALK_FLAT_REWARDS, - (*_RESET_EVENTS, "pd_gains"), - False, - id="ppo-23dof-mujoco", - ), - pytest.param( - "ppo", - ("task=g1_23dof_walk_flat/motrix",), - "G1Walk23DofFlat", - "motrix", - 23, - 0.5, - "scene_flat_23dof.xml", - (*_PPO_WALK_FLAT_REWARDS, *_MOTRIX_EXTRA_REWARDS), - _RESET_EVENTS, - False, - id="ppo-23dof-motrix", - ), - pytest.param( - "ppo", - ("task=g1_23dof_walk_rough/mujoco",), - "G1Walk23DofRough", - "mujoco", - 23, - 0.25, - "scene_rough_23dof.xml", - _PPO_REWARDS, - (*_RESET_EVENTS, "pd_gains"), - True, - id="ppo-23dof-rough-mujoco", - ), pytest.param( "appo", ("task=g1_walk_flat/mujoco",), @@ -234,19 +194,6 @@ False, id="appo-mujoco", ), - pytest.param( - "appo", - ("task=g1_23dof_walk_flat/mujoco",), - "G1Walk23DofFlat", - "mujoco", - 23, - 0.25, - "scene_flat_23dof.xml", - _PPO_REWARDS, - (*_RESET_EVENTS, "pd_gains"), - False, - id="appo-23dof-mujoco", - ), pytest.param( "sac", ("task=g1_walk_flat/mujoco",), @@ -354,32 +301,6 @@ True, id="sac-rough-motrix", ), - pytest.param( - "sac", - ("task=g1_23dof_walk_flat/mujoco",), - "G1Walk23DofFlat", - "mujoco", - 23, - 1.0, - "scene_flat_23dof.xml", - _OFFPOLICY_REWARDS, - (*_RESET_EVENTS, "pd_gains"), - True, - id="sac-23dof-mujoco", - ), - pytest.param( - "sac", - ("task=g1_23dof_walk_rough/motrix",), - "G1Walk23DofRough", - "motrix", - 23, - 1.0, - "scene_rough_23dof.xml", - _OFFPOLICY_REWARDS, - _RESET_EVENTS, - True, - id="sac-23dof-rough-motrix", - ), pytest.param( "td3", ("task=g1_walk_flat/mujoco",), @@ -417,8 +338,6 @@ "sac-isaacsim", "sac-rough-mujoco", "sac-rough-motrix", - "sac-23dof-mujoco", - "sac-23dof-rough-motrix", "td3-mujoco", "flashsac-mujoco", } @@ -623,7 +542,7 @@ def test_g1_owner_materializes_complete_plain_manager_cfg( assert hydra_cfg.play_profile.enabled is False pose = env_cfg.rewards["pose"] - expected_weights = _POSE_WEIGHTS_29 if num_dof == 29 else _POSE_WEIGHTS_23 + expected_weights = _POSE_WEIGHTS_29 if case_id == "flashsac-mujoco": expected_weights = [2.0 if i in (1, 7) else w for i, w in enumerate(expected_weights)] assert list(pose.params["pose_weights"]) == pytest.approx(expected_weights) @@ -673,14 +592,6 @@ def test_g1_walk_registries_are_manager_only() -> None: "config_factory": "ManagerBasedRlEnvCfg", "available_backends": ["mujoco", "motrix"], } - assert metadata["G1Walk23DofFlat"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix"], - } - assert metadata["G1Walk23DofRough"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix"], - } @pytest.mark.parametrize( @@ -716,26 +627,6 @@ def test_g1_walk_registries_are_manager_only() -> None: 101, id="sac-mujoco", ), - pytest.param( - "ppo", - ("task=g1_23dof_walk_flat/mujoco",), - "G1Walk23DofFlat", - "mujoco", - 23, - 80, - 83, - id="ppo-23dof-mujoco", - ), - pytest.param( - "ppo", - ("task=g1_23dof_walk_rough/mujoco",), - "G1Walk23DofRough", - "mujoco", - 23, - 80, - 83, - id="ppo-23dof-rough-mujoco", - ), ), ) def test_g1_registry_executes_real_manager_runtime( @@ -914,18 +805,6 @@ def test_g1_penalty_curriculum_scales_negative_weights_from_start() -> None: "G1WalkRough", id="sac-walk-rough", ), - pytest.param( - "sac", - ("task=g1_23dof_walk_flat/mujoco",), - "G1Walk23DofFlat", - id="sac-23dof-walk-flat", - ), - pytest.param( - "sac", - ("task=g1_23dof_walk_rough/mujoco",), - "G1Walk23DofRough", - id="sac-23dof-walk-rough", - ), pytest.param( "td3", ("task=g1_walk_flat/mujoco",), @@ -961,16 +840,6 @@ def test_offpolicy_penalty_curriculum_matches_legacy_effective_schedule( assert params["degree"] == pytest.approx(0.001) -def test_ppo_penalty_curriculum_matches_legacy_effective_schedule() -> None: - # The on-policy runner builds a single env per training run, so the legacy - # effective schedule equals the declared 0.5 -> 1.0 range. - _, env_cfg, _ = _materialize("ppo", ("task=g1_23dof_walk_rough/mujoco",), "G1Walk23DofRough") - params = env_cfg.curriculum["penalty_scaling"].params - assert params["initial_scale"] == pytest.approx(0.5) - assert params["min_scale"] == pytest.approx(0.5) - assert params["max_scale"] == pytest.approx(1.0) - - def _genesis_runtime_available() -> bool: from unisim.backend.genesis.dependencies import genesis_dependencies_available diff --git a/tests/envs/locomotion/go1/test_manager_based_flat_cfg.py b/tests/envs/locomotion/go1/test_manager_based_flat_cfg.py deleted file mode 100644 index fb99a41e0..000000000 --- a/tests/envs/locomotion/go1/test_manager_based_flat_cfg.py +++ /dev/null @@ -1,348 +0,0 @@ -"""Hydra-owned production contract for the Go1 flat Manager-Based task.""" - -from __future__ import annotations - -from collections.abc import Mapping, Sequence -from copy import deepcopy -from dataclasses import fields, is_dataclass -from pathlib import Path -from typing import Any - -import numpy as np -import pytest -from hydra import compose, initialize_config_dir -from hydra.core.global_hydra import GlobalHydra -from omegaconf import DictConfig, OmegaConf - -from unilab.base import registry -from unilab.base.config_adapter import BackendAdapter -from unilab.base.config_materialization import apply_cfg_overrides -from unilab.envs import ( - ManagerBasedRlEnv, - ManagerBasedRlEnvCfg, - make_manager_based_rl_env, - mdp, -) -from unilab.tasks.locomotion.common import manager_terms - -ROOT_DIR = Path(__file__).parents[4] -CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" - -_JOINT_NAMES = ( - "FR_hip_joint", - "FR_thigh_joint", - "FR_calf_joint", - "FL_hip_joint", - "FL_thigh_joint", - "FL_calf_joint", - "RR_hip_joint", - "RR_thigh_joint", - "RR_calf_joint", - "RL_hip_joint", - "RL_thigh_joint", - "RL_calf_joint", -) -_ACTUATOR_NAMES = tuple(name.removesuffix("_joint") for name in _JOINT_NAMES) -_HOME_JOINT_POS = np.array( - [0.0, 0.9, -1.8, 0.0, 0.9, -1.8, 0.0, 1.0, -1.8, 0.0, 1.0, -1.8], - dtype=np.float32, -) -_RESET_EVENTS = ("reset_scene_to_default", "reset_root_state_uniform") -_DR_EVENTS = ("base_mass", "base_com", "pd_gains") -_BASE_REWARDS = ( - "tracking_lin_vel", - "tracking_ang_vel", - "lin_vel_z", - "ang_vel_xy", - "base_height", - "action_rate", - "similar_to_default", -) - -_OWNER_CASES = ( - pytest.param( - "ppo", - ("task=go1_joystick_flat/mujoco",), - "mujoco", - (*_RESET_EVENTS, *_DR_EVENTS, "push_robot"), - (*_BASE_REWARDS, "contact", "swing_feet_z"), - False, - id="ppo-mujoco", - ), - pytest.param( - "ppo", - ("task=go1_joystick_flat/motrix",), - "motrix", - (*_RESET_EVENTS, *_DR_EVENTS), - (*_BASE_REWARDS, "swing_feet_z"), - True, - id="ppo-motrix", - ), - pytest.param( - "ppo", - ("task=go1_joystick_flat/drake",), - "drake", - _RESET_EVENTS, - (*_BASE_REWARDS, "swing_feet_z"), - False, - id="ppo-drake", - ), - pytest.param( - "appo", - ("task=go1_joystick_flat/mujoco",), - "mujoco", - (*_RESET_EVENTS, *_DR_EVENTS, "push_robot"), - (*_BASE_REWARDS, "contact"), - False, - id="appo-mujoco", - ), - pytest.param( - "appo", - ("task=go1_joystick_flat/motrix",), - "motrix", - (*_RESET_EVENTS, *_DR_EVENTS), - (*_BASE_REWARDS, "swing_feet_z", "action_smooth"), - True, - id="appo-motrix", - ), - pytest.param( - "td3", - ("task=go1_joystick_flat/motrix",), - "motrix", - (*_RESET_EVENTS, *_DR_EVENTS), - (*_BASE_REWARDS, "swing_feet_z"), - True, - id="td3-motrix", - ), -) - - -def _compose(config_group: str, overrides: Sequence[str]) -> DictConfig: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / config_group), version_base="1.3"): - return compose("config", overrides=list(overrides)) - - -def _materialize( - config_group: str, overrides: Sequence[str] -) -> tuple[DictConfig, ManagerBasedRlEnvCfg, dict[str, Any]]: - hydra_cfg = _compose(config_group, overrides) - env_override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config("Go1JoystickFlat") - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - apply_cfg_overrides(env_cfg, env_override) - env_cfg.validate() - return hydra_cfg, env_cfg, env_override - - -def _assert_no_omegaconf(value: Any) -> None: - assert not OmegaConf.is_config(value) - if is_dataclass(value) and not isinstance(value, type): - for item in fields(value): - _assert_no_omegaconf(getattr(value, item.name)) - elif isinstance(value, Mapping): - for key, item in value.items(): - _assert_no_omegaconf(key) - _assert_no_omegaconf(item) - elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)): - for item in value: - _assert_no_omegaconf(item) - - -@pytest.mark.parametrize( - "config_group,overrides,backend,expected_events,expected_rewards,fixed_command", - _OWNER_CASES, -) -def test_go1_flat_owner_materializes_complete_plain_manager_cfg( - config_group: str, - overrides: tuple[str, ...], - backend: str, - expected_events: tuple[str, ...], - expected_rewards: tuple[str, ...], - fixed_command: bool, -) -> None: - registry.ensure_registries() - hydra_cfg, env_cfg, _ = _materialize(config_group, overrides) - - assert hydra_cfg.training.task_name == "Go1JoystickFlat" - assert hydra_cfg.training.sim_backend == backend - assert env_cfg.sim_dt == pytest.approx(0.01) - assert env_cfg.ctrl_dt == pytest.approx(0.02) - assert env_cfg.max_episode_seconds == pytest.approx(20.0) - assert env_cfg.policy_observation_group == "policy" - assert env_cfg.critic_observation_group == "critic" - assert env_cfg.scale_rewards_by_dt is True - - assert env_cfg.scene is not None - assert env_cfg.scene.model_file.endswith("robots/go1/scene_flat.xml") - assert env_cfg.scene.default_keyframe_name == "home" - robot = env_cfg.scene.entities["robot"] - assert robot.root_body_name == "trunk" - assert tuple(robot.joint_names or ()) == _JOINT_NAMES - assert tuple(robot.actuator_names or ()) == _ACTUATOR_NAMES - assert robot.body_names == ["trunk"] - - observation_terms = [ - "base_ang_vel", - "projected_gravity", - "joint_pos", - "joint_vel", - "actions", - "command", - "gait_phase", - ] - assert list(env_cfg.observations) == ["policy", "critic"] - assert list(env_cfg.observations["policy"].terms) == observation_terms - assert list(env_cfg.observations["critic"].terms) == [*observation_terms, "base_lin_vel"] - assert list(env_cfg.actions) == ["joint_pos"] - assert env_cfg.actions["joint_pos"].scale == pytest.approx(0.25) - assert list(env_cfg.terminations) == ["time_out", "bad_orientation"] - assert ( - tuple(name for name, term in env_cfg.events.items() if term is not None) == expected_events - ) - assert tuple(name for name, term in env_cfg.rewards.items() if term is not None) == ( - expected_rewards - ) - - command = env_cfg.commands["twist"] - assert command.resampling_time_range == [20.0, 20.0] - ranges = command.ranges - if fixed_command: - assert tuple(ranges.lin_vel_x) == (0.5, 0.5) - assert tuple(ranges.lin_vel_y) == (0.0, 0.0) - assert tuple(ranges.ang_vel_z) == (0.0, 0.0) - else: - assert tuple(ranges.lin_vel_x) == (-0.6, 1.0) - - if env_cfg.events["base_mass"] is not None: - mass = env_cfg.events["base_mass"] - assert mass.func is mdp.randomize_rigid_body_mass - assert mass.params["mass_distribution_params"] == [-1.5, 1.5] - assert mass.params["recompute_inertia"] is False - com = env_cfg.events["base_com"] - assert com.func is mdp.randomize_rigid_body_com - assert com.params["com_range"] == { - "x": [-0.05, 0.05], - "y": [0.0, 0.0], - "z": [0.0, 0.0], - } - gains = env_cfg.events["pd_gains"] - assert gains.func is mdp.pd_gains - assert gains.params["kp_range"] == [35.0, 35.0] - assert gains.params["kd_range"] == [0.5, 0.5] - assert gains.params["operation"] == "abs" - - push = env_cfg.events["push_robot"] - if push is not None: - assert push.func is mdp.push_by_setting_velocity - assert push.interval_range_s == [15.0, 15.0] - assert push.is_global_time is True - - contact = env_cfg.rewards["contact"] - if contact is not None: - assert contact.func is manager_terms.feet_phase_contact - # Legacy Go1 returned a four-foot sum; the community term returns a mean. - assert contact.weight == pytest.approx(4.0 * 0.24) - action_smooth = env_cfg.rewards.get("action_smooth") - if action_smooth is not None: - assert action_smooth.func is mdp.action_acc_l2 - assert action_smooth.weight == pytest.approx(-0.01) - - for manager_name in ("observations", "events", "rewards", "terminations"): - for term in getattr(env_cfg, manager_name).values(): - if term is None: - continue - nested_terms = term.terms.values() if manager_name == "observations" else (term,) - for nested in nested_terms: - if nested is None: - continue - module = nested.func.__module__ - assert ".backend." not in module - assert not any(name in module for name in (".mujoco", ".motrix", ".drake")) - - _assert_no_omegaconf(env_cfg) - - -def test_go1_flat_and_rough_registries_are_manager_only() -> None: - registry.ensure_registries() - - assert registry.list_registered_envs()["Go1JoystickFlat"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix", "drake"], - } - assert registry.list_registered_envs()["Go1JoystickRough"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix"], - } - - -@pytest.mark.parametrize( - ("backend", "owner", "expected_events"), - ( - ( - "mujoco", - "task=go1_joystick_flat/mujoco", - {"reset": [*_RESET_EVENTS, *_DR_EVENTS], "interval": ["push_robot"]}, - ), - ( - "motrix", - "task=go1_joystick_flat/motrix", - {"reset": [*_RESET_EVENTS, *_DR_EVENTS]}, - ), - ), -) -def test_go1_flat_registry_executes_real_manager_runtime( - backend: str, - owner: str, - expected_events: dict[str, list[str]], -) -> None: - registry.ensure_registries() - hydra_cfg, _, env_override = _materialize("ppo", (owner,)) - try: - env = registry.make( - str(hydra_cfg.training.task_name), - sim_backend=backend, - env_cfg_override=env_override, - num_envs=2, - ) - except ImportError as exc: - pytest.skip(f"{backend} runtime unavailable: {exc}") - - try: - assert isinstance(env, ManagerBasedRlEnv) - assert env.obs_groups_spec == {"obs": 49, "critic": 52} - assert env.action_space.shape == (12,) - action = env.action_manager.get_term("joint_pos") - assert action.target_names == list(_JOINT_NAMES) - np.testing.assert_allclose(action.offset, np.broadcast_to(_HOME_JOINT_POS, (2, 12))) - assert env.event_manager.active_terms == expected_events - - obs, info = env.reset(seed=7) - assert {name: value.shape for name, value in obs.items()} == { - "obs": (2, 49), - "critic": (2, 52), - } - assert isinstance(info, dict) - np.testing.assert_allclose( - env.scene["robot"].data.default_joint_pos, - np.broadcast_to(_HOME_JOINT_POS, (2, 12)), - ) - for _ in range(5): - state = env.step(np.zeros((2, 12), dtype=np.float32)) - for value in (*state.obs.values(), state.reward): - assert isinstance(value, np.ndarray) - assert np.isfinite(value).all() - finally: - env.close() - - -def test_go1_motrix_velocity_push_request_fails_closed() -> None: - _, motrix_cfg, _ = _materialize("ppo", ("task=go1_joystick_flat/motrix",)) - _, mujoco_cfg, _ = _materialize("ppo", ("task=go1_joystick_flat/mujoco",)) - motrix_cfg.events["push_robot"] = deepcopy(mujoco_cfg.events["push_robot"]) - - try: - with pytest.raises(NotImplementedError, match="interval root velocity delta.*motrix"): - make_manager_based_rl_env(motrix_cfg, num_envs=1, backend_type="motrix") - except ImportError as exc: - pytest.skip(f"motrix runtime unavailable: {exc}") diff --git a/tests/envs/locomotion/go2w/test_go2w_manager_based_flat_cfg.py b/tests/envs/locomotion/go2w/test_go2w_manager_based_flat_cfg.py deleted file mode 100644 index 9f3289253..000000000 --- a/tests/envs/locomotion/go2w/test_go2w_manager_based_flat_cfg.py +++ /dev/null @@ -1,304 +0,0 @@ -"""Hydra-owned production contract for the Go2W flat Manager-Based task.""" - -from __future__ import annotations - -import inspect -from collections.abc import Mapping, Sequence -from dataclasses import fields, is_dataclass -from pathlib import Path -from typing import Any - -import numpy as np -import pytest -from hydra import compose, initialize_config_dir -from hydra.core.global_hydra import GlobalHydra -from omegaconf import DictConfig, OmegaConf - -from unilab.base import registry -from unilab.base.config_adapter import BackendAdapter -from unilab.base.config_materialization import apply_cfg_overrides -from unilab.envs import ManagerBasedRlEnv, ManagerBasedRlEnvCfg, make_manager_based_rl_env -from unilab.tasks.locomotion.go2w import manager_terms -from unilab.tasks.locomotion.go2w.manager_terms import ( - Go2WMixedAction, - Go2WMixedActionCfg, - Go2WVelocityCommandCfg, -) - -ROOT_DIR = Path(__file__).parents[4] -CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" - -_LEG_JOINT_NAMES = tuple( - f"{leg}_{joint}_joint" for leg in ("FR", "FL", "RR", "RL") for joint in ("hip", "thigh", "calf") -) -_WHEEL_JOINT_NAMES = tuple(f"{leg}_wheel_joint" for leg in ("FR", "FL", "RR", "RL")) -_JOINT_NAMES = (*_LEG_JOINT_NAMES, *_WHEEL_JOINT_NAMES) -_ACTUATOR_NAMES = tuple(name.removesuffix("_joint") for name in _JOINT_NAMES) -_HOME_JOINT_POS = np.asarray([0.0, 0.8, -1.5] * 4 + [0.0] * 4, dtype=np.float32) - - -def test_go2w_mixed_action_declares_substep_state_feedback() -> None: - assert Go2WMixedAction.requires_substep_state_feedback is True - - -def _compose(backend: str) -> DictConfig: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "ppo"), version_base="1.3"): - return compose("config", overrides=[f"task=go2w_joystick_flat/{backend}"]) - - -def _materialize( - backend: str, -) -> tuple[DictConfig, ManagerBasedRlEnvCfg, dict[str, Any]]: - hydra_cfg = _compose(backend) - env_override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config("Go2WJoystickFlat") - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - apply_cfg_overrides(env_cfg, env_override) - env_cfg.validate() - return hydra_cfg, env_cfg, env_override - - -def _assert_no_omegaconf(value: Any) -> None: - assert not OmegaConf.is_config(value) - if is_dataclass(value) and not isinstance(value, type): - for item in fields(value): - _assert_no_omegaconf(getattr(value, item.name)) - elif isinstance(value, Mapping): - for key, item in value.items(): - _assert_no_omegaconf(key) - _assert_no_omegaconf(item) - elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)): - for item in value: - _assert_no_omegaconf(item) - - -@pytest.mark.parametrize("backend", ["mujoco", "motrix", "drake"]) -def test_go2w_flat_owner_materializes_complete_plain_manager_cfg(backend: str) -> None: - registry.ensure_registries() - hydra_cfg, env_cfg, _ = _materialize(backend) - - assert hydra_cfg.training.task_name == "Go2WJoystickFlat" - assert hydra_cfg.training.sim_backend == backend - assert list(hydra_cfg.algo.obs_groups.actor) == ["actor"] - assert list(hydra_cfg.algo.obs_groups.critic) == ["critic"] - assert env_cfg.sim_dt == pytest.approx(0.005) - assert env_cfg.ctrl_dt == pytest.approx(0.02) - assert env_cfg.max_episode_seconds == pytest.approx(20.0) - assert env_cfg.policy_observation_group == "policy" - assert env_cfg.critic_observation_group == "critic" - - assert env_cfg.scene is not None - assert env_cfg.scene.model_file.endswith("robots/go2w/scene_flat.xml") - assert env_cfg.scene.default_keyframe_name == "home" - robot = env_cfg.scene.entities["robot"] - assert robot.root_body_name == "base_link" - assert tuple(robot.joint_names or ()) == _JOINT_NAMES - assert tuple(robot.actuator_names or ()) == _ACTUATOR_NAMES - assert robot.body_names == ["base_link"] - - policy_terms = [ - "base_ang_vel", - "projected_gravity", - "leg_joint_pos", - "leg_joint_vel", - "wheel_joint_vel", - "actions", - "command", - ] - assert list(env_cfg.observations) == ["policy", "critic"] - assert list(env_cfg.observations["policy"].terms) == policy_terms - assert list(env_cfg.observations["critic"].terms) == [ - *policy_terms, - "base_lin_vel", - "motor_torque", - ] - - assert list(env_cfg.actions) == ["motor"] - action = env_cfg.actions["motor"] - assert isinstance(action, Go2WMixedActionCfg) - assert action.leg_action_scale == pytest.approx(0.5) - assert action.wheel_action_scale == pytest.approx(10.0) - assert action.leg_kp == pytest.approx(50.0) - assert action.leg_kd == pytest.approx(1.5) - assert action.wheel_kd == pytest.approx(0.5) - - command = env_cfg.commands["twist"] - assert isinstance(command, Go2WVelocityCommandCfg) - assert command.resampling_time_range == [20.0, 20.0] - assert command.planar_dead_zone == pytest.approx(0.2) - assert tuple(command.ranges.lin_vel_x) == (0.0, 1.0) - assert tuple(command.ranges.lin_vel_y) == (0.0, 0.0) - assert tuple(command.ranges.ang_vel_z) == (-1.0, 1.0) - - assert list(env_cfg.events) == [ - "reset_scene_to_default", - "reset_root_state_uniform", - "motor_gains", - ] - gains = env_cfg.events["motor_gains"] - assert gains.func is manager_terms.randomize_motor_gains - assert gains.params["kp_multiplier_range"] == [1.0, 1.0] - assert gains.params["kd_multiplier_range"] == [1.0, 1.0] - assert list(env_cfg.terminations) == ["time_out", "bad_orientation"] - assert {name: term.weight for name, term in env_cfg.rewards.items()} == { - "tracking_lin_vel": 1.0, - "tracking_ang_vel": 0.75, - "lin_vel_z": -5.0, - "ang_vel_xy": -0.1, - "base_height": -100.0, - "orientation": -2.0, - "action_rate": -0.005, - "similar_to_default": -0.5, - "torques": -0.0002, - "wheel_vel": 0.0, - "alive": 0.5, - "upward": 1.0, - } - - for manager_name in ("observations", "events", "rewards", "terminations"): - for term in getattr(env_cfg, manager_name).values(): - if term is None: - continue - terms = term.terms.values() if manager_name == "observations" else (term,) - for nested in terms: - if nested is None: - continue - module = nested.func.__module__ - assert ".backend." not in module - assert not any(name in module for name in (".mujoco", ".motrix", ".drake")) - - _assert_no_omegaconf(env_cfg) - - -def test_go2w_sac_drake_owner_uses_the_same_manager_contract() -> None: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / "sac"), version_base="1.3"): - hydra_cfg = compose( - "config", - overrides=["task=go2w_joystick_flat/drake"], - ) - env_override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config("Go2WJoystickFlat") - apply_cfg_overrides(env_cfg, env_override) - - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - assert hydra_cfg.training.task_name == "Go2WJoystickFlat" - assert hydra_cfg.training.sim_backend == "drake" - assert list(env_cfg.actions) == ["motor"] - assert env_cfg.scene is not None - assert env_cfg.scene.default_keyframe_name == "home" - env_cfg.validate() - - -def test_go2w_flat_and_rough_registries_are_manager_only() -> None: - registry.ensure_registries() - - assert registry.list_registered_envs()["Go2WJoystickFlat"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix", "drake"], - } - assert registry.list_registered_envs()["Go2WJoystickRough"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix"], - } - - -@pytest.mark.parametrize("backend", ["mujoco", "motrix"]) -def test_go2w_flat_registry_executes_real_manager_runtime(backend: str) -> None: - registry.ensure_registries() - _, _, env_override = _materialize(backend) - try: - env = registry.make( - "Go2WJoystickFlat", - sim_backend=backend, - env_cfg_override=env_override, - num_envs=2, - ) - except ImportError as exc: - pytest.skip(f"{backend} runtime unavailable: {exc}") - - try: - assert isinstance(env, ManagerBasedRlEnv) - assert env.obs_groups_spec == {"obs": 53, "critic": 72} - assert env.action_space.shape == (16,) - action = env.action_manager.get_term("motor") - assert isinstance(action, Go2WMixedAction) - np.testing.assert_allclose(action.leg_kp, 50.0) - np.testing.assert_allclose(action.leg_kd, 1.5) - - obs, info = env.reset(seed=7) - assert {name: value.shape for name, value in obs.items()} == { - "obs": (2, 53), - "critic": (2, 72), - } - assert isinstance(info, dict) - np.testing.assert_allclose( - env.scene["robot"].data.default_joint_pos, - np.broadcast_to(_HOME_JOINT_POS, (2, 16)), - ) - - state = env.step(np.full((2, 16), 2.0, dtype=np.float32)) - np.testing.assert_allclose(action.raw_action, 1.0) - np.testing.assert_allclose(action.previous_raw_action, 0.0) - np.testing.assert_allclose( - action.processed_action[:, :12], - np.broadcast_to(_HOME_JOINT_POS[:12] + 0.5, (2, 12)), - ) - np.testing.assert_allclose(action.processed_action[:, 12:], 10.0) - np.testing.assert_allclose(state.obs["critic"][:, -16:], action.motor_torque) - for value in (*state.obs.values(), state.reward, action.motor_torque): - assert np.isfinite(value).all() - - env.reset(np.asarray([0], dtype=np.int32)) - np.testing.assert_allclose(action.raw_action[0], 0.0) - np.testing.assert_allclose(action.raw_action[1], 1.0) - np.testing.assert_allclose(action.motor_torque[0], 0.0) - finally: - env.close() - - -def test_go2w_flat_dead_zone_and_motor_gain_overrides_are_manager_owned() -> None: - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - _, env_cfg, _ = _materialize("mujoco") - command = env_cfg.commands["twist"] - command.ranges.lin_vel_x = (0.1, 0.1) - command.ranges.lin_vel_y = (0.0, 0.0) - command.ranges.ang_vel_z = (0.0, 0.0) - gains = env_cfg.events["motor_gains"].params - gains["kp_multiplier_range"] = (0.5, 0.5) - gains["kd_multiplier_range"] = (2.0, 2.0) - - env = make_manager_based_rl_env(env_cfg, num_envs=2, backend_type="mujoco") - try: - env.reset(seed=11) - np.testing.assert_allclose(env.command_manager.get_command("twist"), 0.0) - action = env.action_manager.get_term("motor") - assert isinstance(action, Go2WMixedAction) - np.testing.assert_allclose(action.leg_kp, 25.0) - np.testing.assert_allclose(action.leg_kd, 3.0) - finally: - env.close() - - -def test_go2w_flat_incomplete_motor_selection_fails_closed() -> None: - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - _, env_cfg, _ = _materialize("mujoco") - action = env_cfg.actions["motor"] - assert isinstance(action, Go2WMixedActionCfg) - action.actuator_names = ["FR_.*"] - - with pytest.raises(ValueError, match="requires exactly 16 actuators and target joints"): - make_manager_based_rl_env(env_cfg, num_envs=1, backend_type="mujoco") - - -def test_go2w_manager_terms_do_not_leak_backend_or_physical_layout() -> None: - source = inspect.getsource(manager_terms) - for forbidden in ("._backend", "getattr(", "hasattr(", "qpos", "qvel", "ASSETS_ROOT_PATH"): - assert forbidden not in source diff --git a/tests/envs/locomotion/test_go2_footstand.py b/tests/envs/locomotion/test_go2_footstand.py deleted file mode 100644 index 7586eca15..000000000 --- a/tests/envs/locomotion/test_go2_footstand.py +++ /dev/null @@ -1,459 +0,0 @@ -"""Hydra-owned Manager-Based contract for Go2 footstand.""" - -from __future__ import annotations - -import importlib.util -from collections.abc import Mapping, Sequence -from dataclasses import fields, is_dataclass -from pathlib import Path -from typing import Any - -import numpy as np -import pytest -from hydra import compose, initialize_config_dir -from hydra.core.global_hydra import GlobalHydra -from omegaconf import DictConfig, OmegaConf -from unisim.backend.base import SimBackend - -from unilab.base import registry -from unilab.base.config_adapter import BackendAdapter -from unilab.base.config_materialization import apply_cfg_overrides -from unilab.envs import ManagerBasedRlEnv, ManagerBasedRlEnvCfg, make_manager_based_rl_env -from unilab.managers._noise import UniformNoiseCfg -from unilab.tasks.locomotion.go2.footstand import ( - FRAME_OBS_DIM, - NUM_ACTIONS, - PRIVILEGED_OBS_DIM, - FootstandIncrementalAction, - FootstandIncrementalActionCfg, - FootstandMassRandomization, - FootstandReward, - FootstandTermination, -) - -ROOT_DIR = Path(__file__).parents[3] -CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" - -_JOINT_NAMES = ( - "FL_hip_joint", - "FL_thigh_joint", - "FL_calf_joint", - "FR_hip_joint", - "FR_thigh_joint", - "FR_calf_joint", - "RL_hip_joint", - "RL_thigh_joint", - "RL_calf_joint", - "RR_hip_joint", - "RR_thigh_joint", - "RR_calf_joint", -) -_ACTION_JOINT_NAMES = ( - "FR_hip_joint", - "FR_thigh_joint", - "FR_calf_joint", - "FL_hip_joint", - "FL_thigh_joint", - "FL_calf_joint", - "RR_hip_joint", - "RR_thigh_joint", - "RR_calf_joint", - "RL_hip_joint", - "RL_thigh_joint", - "RL_calf_joint", -) -_ACTUATOR_NAMES = tuple(name.removesuffix("_joint") for name in _ACTION_JOINT_NAMES) -_BODY_NAMES = ( - "base", - "FL_hip", - "FL_thigh", - "FL_calf", - "FR_hip", - "FR_thigh", - "FR_calf", - "RL_hip", - "RL_thigh", - "RL_calf", - "RR_hip", - "RR_thigh", - "RR_calf", -) -_OWNER_CASES = ( - pytest.param( - "ppo", - ("task=go2_footstand/mujoco",), - "mujoco", - frozenset(("pd_gains", "floor_friction", "link_mass", "torso_com", "joint_armature")), - 0.05, - 2.0, - id="ppo-mujoco", - ), - pytest.param( - "ppo", - ("task=go2_footstand/motrix",), - "motrix", - frozenset(("pd_gains",)), - 0.02, - 3.0, - id="ppo-motrix", - ), - pytest.param( - "ppo", - ("task=go2_footstand/drake",), - "drake", - frozenset(), - 0.05, - 2.0, - id="ppo-drake", - ), - pytest.param( - "sac", - ("task=go2_footstand/drake",), - "drake", - frozenset(), - 0.05, - 2.0, - id="sac-drake", - ), -) - - -def _compose(config_group: str, overrides: Sequence[str]) -> DictConfig: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR / config_group), version_base="1.3"): - return compose("config", overrides=list(overrides)) - - -def _materialize( - config_group: str, - overrides: Sequence[str], -) -> tuple[DictConfig, ManagerBasedRlEnvCfg, dict[str, Any]]: - hydra_cfg = _compose(config_group, overrides) - env_override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config("Go2FootStand") - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - apply_cfg_overrides(env_cfg, env_override) - env_cfg.validate() - return hydra_cfg, env_cfg, env_override - - -def _make_env(backend: str, *, num_envs: int = 2) -> ManagerBasedRlEnv: - hydra_cfg, _, env_override = _materialize( - "ppo", - (f"task=go2_footstand/{backend}", f"algo.num_envs={num_envs}"), - ) - env = registry.make( - str(hydra_cfg.training.task_name), - sim_backend=backend, - env_cfg_override=env_override, - num_envs=num_envs, - ) - assert isinstance(env, ManagerBasedRlEnv) - return env - - -def _assert_plain(value: Any) -> None: - assert not OmegaConf.is_config(value) - if is_dataclass(value) and not isinstance(value, type): - for item in fields(value): - _assert_plain(getattr(value, item.name)) - elif isinstance(value, Mapping): - for key, item in value.items(): - _assert_plain(key) - _assert_plain(item) - elif isinstance(value, Sequence) and not isinstance(value, (str, bytes)): - for item in value: - _assert_plain(item) - - -def _action(env: ManagerBasedRlEnv) -> FootstandIncrementalAction: - term = env.action_manager.get_term("joint_pos") - assert isinstance(term, FootstandIncrementalAction) - return term - - -def _termination(env: ManagerBasedRlEnv) -> FootstandTermination: - term = env.termination_manager.get_term_cfg("footstand").func - assert isinstance(term, FootstandTermination) - return term - - -def _reward(env: ManagerBasedRlEnv) -> FootstandReward: - term = env.reward_manager.get_term_cfg("footstand").func - assert isinstance(term, FootstandReward) - return term - - -@pytest.mark.parametrize( - "config_group,overrides,backend,backend_events,joint_reset_radius,orientation_scale", - _OWNER_CASES, -) -def test_footstand_owner_materializes_complete_plain_manager_cfg( - config_group: str, - overrides: tuple[str, ...], - backend: str, - backend_events: frozenset[str], - joint_reset_radius: float, - orientation_scale: float, -) -> None: - registry.ensure_registries() - hydra_cfg, env_cfg, _ = _materialize(config_group, overrides) - - assert hydra_cfg.training.task_name == "Go2FootStand" - assert hydra_cfg.training.sim_backend == backend - assert hydra_cfg.algo.num_envs == 4096 - assert env_cfg.sim_dt == pytest.approx(0.004) - assert env_cfg.ctrl_dt == pytest.approx(0.02) - assert env_cfg.max_episode_seconds == pytest.approx(10.0) - assert env_cfg.policy_observation_group == "policy" - assert env_cfg.critic_observation_group == "critic" - - assert env_cfg.scene is not None - assert env_cfg.scene.default_keyframe_name == "home" - robot = env_cfg.scene.entities["robot"] - assert robot.root_body_name == "base" - assert tuple(robot.joint_names or ()) == _JOINT_NAMES - assert tuple(robot.body_names or ()) == _BODY_NAMES - assert tuple(robot.geom_names or ()) == ("floor",) - assert tuple(robot.actuator_names or ()) == _ACTUATOR_NAMES - - policy = env_cfg.observations["policy"] - critic = env_cfg.observations["critic"] - assert policy is not None and critic is not None - assert list(policy.terms) == ["frame"] - assert list(critic.terms) == ["frame", "privileged"] - assert policy.enable_corruption is True - assert policy.terms["frame"] is not None - assert critic.terms["frame"] is not None - assert critic.terms["privileged"] is not None - assert policy.terms["frame"].history_length == 15 - assert critic.terms["frame"].history_length == 15 - assert critic.terms["privileged"].history_length == 0 - noise = policy.terms["frame"].noise - assert isinstance(noise, UniformNoiseCfg) - assert np.asarray(noise.n_min).shape == (FRAME_OBS_DIM,) - assert np.asarray(noise.n_max).shape == (FRAME_OBS_DIM,) - - action = env_cfg.actions["joint_pos"] - assert isinstance(action, FootstandIncrementalActionCfg) - assert tuple(action.actuator_names) == _ACTUATOR_NAMES - assert tuple(action.joint_names) == _ACTION_JOINT_NAMES - assert action.action_scale == pytest.approx(0.3) - assert action.clip_actions == pytest.approx(1.0) - assert action.kp == pytest.approx(35.0) - assert action.kd == pytest.approx(0.5) - - always_enabled = { - "reset_scene_to_default", - "reset_root_state_uniform", - "reset_joints", - } - active_events = {name for name, term in env_cfg.events.items() if term is not None} - assert active_events == always_enabled | backend_events - reset_joints = env_cfg.events["reset_joints"] - assert reset_joints is not None - assert tuple(reset_joints.params["position_offset_range"]) == pytest.approx( - (-joint_reset_radius, joint_reset_radius) - ) - if "link_mass" in backend_events: - link_mass = env_cfg.events["link_mass"] - assert link_mass is not None - assert link_mass.func is FootstandMassRandomization - - termination = env_cfg.terminations["footstand"] - assert termination is not None - assert termination.params["grace_steps"] == 100 - assert termination.params["energy_threshold"] == pytest.approx(200.0) - reward = env_cfg.rewards["footstand"] - assert reward is not None - assert reward.func is FootstandReward - assert reward.params["scales"]["orientation"] == pytest.approx(orientation_scale) - - assert FRAME_OBS_DIM * 15 == 675 - assert FRAME_OBS_DIM * 15 + PRIVILEGED_OBS_DIM == 724 - _assert_plain(env_cfg) - - -def test_footstand_registry_has_no_legacy_config_or_factory() -> None: - registry.ensure_registries() - bare_cfg = registry.materialize_env_config("Go2FootStand") - - assert isinstance(bare_cfg, ManagerBasedRlEnvCfg) - assert bare_cfg.actions == {} - assert bare_cfg.observations == {} - assert registry.list_registered_envs()["Go2FootStand"] == { - "config_factory": "ManagerBasedRlEnvCfg", - "available_backends": ["mujoco", "motrix", "drake"], - } - meta = registry._envs["Go2FootStand"] - assert all(factory is make_manager_based_rl_env for factory in meta.env_factory_dict.values()) - - -@pytest.mark.parametrize("backend", ("mujoco", "motrix")) -def test_footstand_real_runtime_preserves_history_action_and_partial_reset( - backend: str, -) -> None: - if backend == "mujoco": - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - registry.ensure_registries() - env = _make_env(backend) - try: - obs, info = env.reset(seed=7) - assert set(info) == {"log"} - assert env.obs_groups_spec == {"obs": 675, "critic": 724} - assert env.action_space.shape == (NUM_ACTIONS,) - assert obs["obs"].shape == (2, 675) - assert obs["critic"].shape == (2, 724) - assert np.isfinite(obs["obs"]).all() - assert np.isfinite(obs["critic"]).all() - - reset_frames = obs["obs"].reshape(2, 15, FRAME_OBS_DIM) - np.testing.assert_allclose(reset_frames, np.repeat(reset_frames[:, :1], 15, axis=1)) - clean_history = obs["critic"][:, :675].reshape(2, 15, FRAME_OBS_DIM) - np.testing.assert_allclose(clean_history, np.repeat(clean_history[:, :1], 15, axis=1)) - - action = _action(env) - initial_target = action.target.copy() - first_policy_action = np.full((2, NUM_ACTIONS), 2.0, dtype=np.float32) - action.process_actions(first_policy_action) - expected_target = np.clip( - initial_target + 0.3, - action.joint_lower[action.joint_ids], - action.joint_upper[action.joint_ids], - ) - np.testing.assert_allclose(action.target, expected_target, atol=1e-6) - - obs, _ = env.reset(seed=7) - first_policy_action = np.full((2, NUM_ACTIONS), 0.05, dtype=np.float32) - first_state = env.step(first_policy_action) - assert not first_state.terminated.any() - first_frames = first_state.obs["obs"].reshape(2, 15, FRAME_OBS_DIM) - np.testing.assert_allclose(first_frames[:, -1, -NUM_ACTIONS:], 0.0) - - second_policy_action = np.full((2, NUM_ACTIONS), 0.025, dtype=np.float32) - second_state = env.step(second_policy_action) - assert not second_state.terminated.any() - second_frames = second_state.obs["obs"].reshape(2, 15, FRAME_OBS_DIM) - np.testing.assert_allclose(second_frames[:, -1, -NUM_ACTIONS:], 0.05) - assert np.isfinite(second_state.reward).all() - assert np.all(second_state.reward >= 0.0) - - untouched_target = action.target[1].copy() - untouched_torque = action.state.torques[1].copy() - assert env.state is not None - untouched_obs = {name: value[1].copy() for name, value in env.state.obs.items()} - reset_obs, _ = env.reset(env_ids=np.asarray([0], dtype=np.int32)) - assert reset_obs["obs"].shape == (1, 675) - partial_frames = reset_obs["obs"].reshape(1, 15, FRAME_OBS_DIM) - np.testing.assert_allclose(partial_frames, np.repeat(partial_frames[:, :1], 15, axis=1)) - np.testing.assert_allclose(action.target[1], untouched_target) - np.testing.assert_allclose(action.state.torques[1], untouched_torque) - assert env.state is not None - for name, expected in untouched_obs.items(): - np.testing.assert_allclose(env.state.obs[name][1], expected) - finally: - env.close() - - -def test_footstand_termination_uses_grace_boundary() -> None: - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - registry.ensure_registries() - env = _make_env("mujoco") - try: - env.reset(seed=11) - term = _termination(env) - state = term.state - state.height[:] = 0.0 - state.orientation[:] = 0.0 - state.upvector[:] = (0.0, 0.0, 1.0) - state.termination_contact[:] = False - state.torques[:] = 0.0 - state.joint_vel[:] = 0.0 - - env.episode_length_buf[:] = 100 - assert not term(env).any() - env.episode_length_buf[:] = 101 - assert term(env).all() - finally: - env.close() - - -def test_footstand_reward_clips_aggregate_before_dt_scaling() -> None: - pytest.importorskip( - "unisim.backend.mujoco.backend", - reason="unisim-core MuJoCo adapter (mjbatch build) not available", - ) - registry.ensure_registries() - env = _make_env("mujoco") - try: - env.reset(seed=13) - term = _termination(env) - reward = _reward(env) - state = term.state - term.terminated[:] = False - state.height[:] = 0.53 - state.foot_contact[:] = False - state.foot_contact[0, 0] = True - reward._scales = {"height": 2.0, "contact": -100.0} - - np.testing.assert_allclose(reward(env), np.asarray([0.0, 2.0], dtype=np.float32)) - np.testing.assert_allclose( - env.reward_manager.compute(dt=env.step_dt), - np.asarray([0.0, 0.04], dtype=np.float32), - ) - finally: - env.close() - - -def _drake_batch_extension_available() -> bool: - try: - return importlib.util.find_spec("drake_uni.compiled._drake_env_pool") is not None - except ModuleNotFoundError: - return False - - -def _drake_geom_capability_available() -> bool: - """Footstand's contact terms require geom-name metadata from the backend.""" - try: - from unisim.backend.drake.backend import DrakeBackend - except ImportError: - return False - return DrakeBackend.get_geom_names is not SimBackend.get_geom_names - - -@pytest.mark.skipif( - not (_drake_batch_extension_available() and _drake_geom_capability_available()), - reason="Drake batch extension or geom metadata capability is unavailable", -) -def test_footstand_drake_real_runtime_when_available() -> None: - registry.ensure_registries() - env = _make_env("drake") - try: - obs, _ = env.reset(seed=17) - assert {name: value.shape for name, value in obs.items()} == { - "obs": (2, 675), - "critic": (2, 724), - } - state = env.step(np.zeros((2, NUM_ACTIONS), dtype=np.float32)) - assert np.isfinite(state.reward).all() - finally: - env.close() - - -def test_footstand_production_terms_do_not_leak_backend_or_layout() -> None: - source = (ROOT_DIR / "src/unilab/tasks/locomotion/go2/footstand.py").read_text(encoding="utf-8") - for forbidden in ( - "._backend", - "getattr(", - "hasattr(", - "ASSETS_ROOT_PATH", - " qpos", - " qvel", - ): - assert forbidden not in source diff --git a/tests/envs/locomotion/test_go2_terrain_spawn.py b/tests/envs/locomotion/test_go2_terrain_spawn.py deleted file mode 100644 index 298d191cb..000000000 --- a/tests/envs/locomotion/test_go2_terrain_spawn.py +++ /dev/null @@ -1,227 +0,0 @@ -"""Production contracts for the Manager-Based quadruped rough family.""" - -from __future__ import annotations - -import inspect -from pathlib import Path -from types import SimpleNamespace -from typing import Any, cast - -import numpy as np -import pytest -from hydra import compose, initialize_config_dir -from hydra.core.global_hydra import GlobalHydra -from omegaconf import DictConfig - -from unilab.base import registry -from unilab.base.config_adapter import BackendAdapter -from unilab.base.config_materialization import apply_cfg_overrides -from unilab.envs import ManagerBasedRlEnv, ManagerBasedRlEnvCfg -from unilab.tasks.locomotion.common.rough_manager_terms import ( - QuadrupedRoughTerrainCfg, - RoughHeightScan, - RoughJointPositionAction, - RoughTerrainCurriculum, - RoughTerrainOutOfBounds, - RoughTerrainReset, -) -from unilab.tasks.locomotion.go2w.manager_terms import Go2WMixedAction -from unilab.utils.sim2sim import extract_contract_snapshot - -# CPU-bound on the single-core CI runner; kept in the slow lane (make test-slow). -pytestmark = pytest.mark.slow - -ROOT_DIR = Path(__file__).parents[3] -CONF_DIR = ROOT_DIR / "src" / "unilab" / "conf" / "ppo" - -_OWNER_CASES = tuple( - pytest.param(task_id, task_name, backend, *dims, id=f"{task_id.split('_')[0]}-{backend}") - for task_id, task_name, dims in ( - ("go1_joystick_rough", "Go1JoystickRough", (45, 235, 12)), - ("go2_joystick_rough", "Go2JoystickRough", (45, 235, 12)), - ("go2w_joystick_rough", "Go2WJoystickRough", (53, 243, 16)), - ) - for backend in ("mujoco", "motrix") -) - - -def _compose(task_id: str, backend: str, extra: tuple[str, ...] = ()) -> DictConfig: - GlobalHydra.instance().clear() - with initialize_config_dir(config_dir=str(CONF_DIR), version_base="1.3"): - return compose("config", overrides=[f"task={task_id}/{backend}", *extra]) - - -def _materialize( - task_id: str, - task_name: str, - backend: str, - extra: tuple[str, ...] = (), -) -> tuple[DictConfig, ManagerBasedRlEnvCfg, dict[str, Any]]: - hydra_cfg = _compose(task_id, backend, extra) - override = BackendAdapter(hydra_cfg, root_dir=ROOT_DIR).build_task_env_cfg_override() - env_cfg = registry.materialize_env_config(task_name) - assert isinstance(env_cfg, ManagerBasedRlEnvCfg) - apply_cfg_overrides(env_cfg, override) - env_cfg.validate() - return hydra_cfg, env_cfg, override - - -@pytest.mark.parametrize("task_id,task_name,backend,policy_dim,critic_dim,action_dim", _OWNER_CASES) -def test_rough_registry_executes_real_backend_contract( - task_id: str, - task_name: str, - backend: str, - policy_dim: int, - critic_dim: int, - action_dim: int, -) -> None: - if backend == "motrix": - pytest.importorskip("motrixsim") - registry.ensure_registries() - hydra_cfg, env_cfg, override = _materialize(task_id, task_name, backend) - assert (hydra_cfg.training.task_name, hydra_cfg.training.sim_backend) == (task_name, backend) - assert hydra_cfg.env.commands.twist.planar_dead_zone == pytest.approx(0.08) - override["commands"]["twist"]["ranges"]["lin_vel_x"] = [0.04, 0.04] - override["commands"]["twist"]["ranges"]["lin_vel_y"] = [0.0, 0.0] - assert env_cfg.scene is not None and env_cfg.scene.terrain is not None - terrain = env_cfg.scene.terrain.generator - assert isinstance(terrain, QuadrupedRoughTerrainCfg) - assert (terrain.num_rows, terrain.num_cols, len(terrain.sub_terrains)) == (6, 6, 7) - assert terrain.horizontal_scale == pytest.approx(0.1 if "go2w" in task_id else 0.2) - assert registry.list_registered_envs()[task_name]["config_factory"] == "ManagerBasedRlEnvCfg" - env = cast( - ManagerBasedRlEnv, - registry.make( - task_name, - sim_backend=backend, - env_cfg_override=override, - num_envs=2, - ), - ) - try: - obs, _ = env.reset(seed=7) - np.testing.assert_allclose(env.command_manager.get_command("twist")[:, :2], 0.0) - assert obs["obs"].shape == (2, policy_dim) - assert obs["critic"].shape == (2, critic_dim) - assert env.obs_groups_spec == {"obs": policy_dim, "critic": critic_dim} - assert env.action_space.shape == (action_dim,) - np.testing.assert_array_equal(env.scene.env_origins, np.zeros((2, 3))) - - terrain_data = env._backend.get_terrain_spawn_data() - assert terrain_data is not None - assert terrain_data.sample_height is not None - assert terrain_data.terrain_origins.shape == (6, 6, 3) - reset_term = env.event_manager.get_term_cfg("terrain_root_state").func - assert isinstance(reset_term, RoughTerrainReset) - spawn = reset_term.spawn_manager - ids = np.arange(2, dtype=np.int32) - base_pos = env.scene["robot"].data.root_link_pos_w - assigned_origins = spawn.origins_for(ids) - assert np.all(np.abs(base_pos[:, :2] - assigned_origins[:, :2]) <= 0.5) - surface_height = terrain_data.sample_height(base_pos[:, :2]) - assert np.all(base_pos[:, 2] - surface_height > 0.25) - - action = env.action_manager.get_term("motor" if "go2w" in task_id else "joint_pos") - saturated = np.full((2, action_dim), 200.0, dtype=np.float32) - action.process_actions(saturated) - np.testing.assert_allclose(action.raw_action, 100.0) - if isinstance(action, RoughJointPositionAction): - scale = np.asarray(action.scale)[0] - for name, value in zip(action.target_names, scale, strict=True): - expected = 0.125 if "_hip_joint" in name else 0.25 - assert value == pytest.approx(expected) - assert action.cfg.clip_actions == pytest.approx(100.0) - else: - assert isinstance(action, Go2WMixedAction) - assert action.cfg.leg_action_scale == pytest.approx(0.25) - assert action.cfg.hip_action_scale == pytest.approx(0.125) - assert action.cfg.wheel_action_scale == pytest.approx(5.0) - assert action.cfg.clip_actions == pytest.approx(100.0) - - state = env.step(np.zeros((2, action_dim), dtype=np.float32)) - assert state.obs["obs"].shape == (2, policy_dim) - assert state.obs["critic"].shape == (2, critic_dim) - for value in (*state.obs.values(), state.reward): - assert np.isfinite(value).all() - finally: - env.close() - - -@pytest.mark.parametrize( - ("task_id", "task_name"), - ( - ("go1_joystick_rough", "Go1JoystickRough"), - ("go2_joystick_rough", "Go2JoystickRough"), - ("go2w_joystick_rough", "Go2WJoystickRough"), - ), -) -def test_rough_sim2sim_snapshot_matches_across_backends(task_id: str, task_name: str) -> None: - registry.ensure_registries() - mujoco_cfg, _, _ = _materialize(task_id, task_name, "mujoco") - motrix_cfg, _, _ = _materialize(task_id, task_name, "motrix") - assert extract_contract_snapshot(mujoco_cfg) == extract_contract_snapshot(motrix_cfg) - - -def test_curriculum_updates_before_next_spawn_and_oob_fails_closed() -> None: - registry.ensure_registries() - extra = ( - "env.scene.terrain.generator.curriculum=true", - "env.scene.terrain.generator.num_rows=3", - ) - _, _, override = _materialize("go2_joystick_rough", "Go2JoystickRough", "mujoco", extra) - env = cast( - ManagerBasedRlEnv, - registry.make( - "Go2JoystickRough", - sim_backend="mujoco", - env_cfg_override=override, - num_envs=2, - ), - ) - try: - env.reset(seed=7) - reset_term = env.event_manager.get_term_cfg("terrain_root_state").func - assert isinstance(reset_term, RoughTerrainReset) - spawn = reset_term.spawn_manager - np.testing.assert_array_equal(spawn.levels, np.zeros(2, dtype=np.int32)) - - current = env.scene["robot"].data.root_link_pos_w.copy() - spawn._episode_start_xyz[0, :2] = current[0, :2] - np.asarray([5.0, 0.0]) - env.reset_buf[0] = True - _, info = env.reset(env_ids=np.asarray([0], dtype=np.int32)) - - assert spawn.levels[0] == 1 - assert info["log"]["Curriculum/terrain_levels/num_promoted"] == 1 - next_pos = env.scene["robot"].data.root_link_pos_w[0] - next_origin = spawn.origins_for(np.asarray([0], dtype=np.int32))[0] - assert np.all(np.abs(next_pos[:2] - next_origin[:2]) <= 0.5) - np.testing.assert_allclose(spawn._episode_start_xyz[0], next_pos) - - oob = env.termination_manager.get_term_cfg("terrain_out_of_bounds").func - assert isinstance(oob, RoughTerrainOutOfBounds) - oob._asset = SimpleNamespace( - data=SimpleNamespace( - root_link_pos_w=np.asarray([[0.0, 0.0, 0.5], [oob._half_width + 1.0, 0.0, 0.5]]) - ) - ) - np.testing.assert_array_equal(oob(env), np.asarray([False, True])) - finally: - env.close() - - -def test_rough_hot_paths_use_only_cached_runtime_objects() -> None: - for term in ( - RoughTerrainReset, - RoughTerrainCurriculum, - RoughTerrainOutOfBounds, - RoughHeightScan, - ): - source = inspect.getsource(term.__call__) - for forbidden in ( - "ASSETS_ROOT_PATH", - "model_file", - "getattr(", - "hasattr(", - "._backend", - ): - assert forbidden not in source diff --git a/tests/envs/test_env_configs.py b/tests/envs/test_env_configs.py index aa63acdd1..ce2fed8f9 100644 --- a/tests/envs/test_env_configs.py +++ b/tests/envs/test_env_configs.py @@ -129,7 +129,6 @@ def blocked_import(name, globals=None, locals=None, fromlist=(), level=0): ensure_registries() assert callable(create_backend) assert registry.contains("G1MotionTracking") - assert registry.contains("G1MotionTrackingDeploy") assert registry.contains("X2WallFlipTracking") assert registry.contains("AllegroInhandRotation") metadata = registry.list_registered_envs() @@ -713,27 +712,7 @@ def test_allegro_grasp_manager_runtime_uses_zero_increment_action(sim_backend: s _MOTION_CORE_RUNTIME_CASES = ( pytest.param("ppo", "g1_motion_tracking", "G1MotionTracking", 160, 286, 29, False), - pytest.param( - "ppo", - "g1_motion_tracking_deploy", - "G1MotionTrackingDeploy", - 154, - 286, - 29, - False, - ), - pytest.param("ppo", "g1_23dof_motion_tracking", "G1MotionTracking23Dof", 130, 256, 23, False), - pytest.param( - "ppo", - "g1_23dof_motion_tracking_deploy", - "G1MotionTracking23DofDeploy", - 124, - 256, - 23, - False, - ), pytest.param("appo", "g1_motion_tracking", "G1MotionTracking", 160, 286, 29, False), - pytest.param("appo", "g1_23dof_motion_tracking", "G1MotionTracking23Dof", 130, 256, 23, False), pytest.param( "sac", "g1_motion_tracking", @@ -743,15 +722,6 @@ def test_allegro_grasp_manager_runtime_uses_zero_increment_action(sim_backend: s 29, True, ), - pytest.param( - "sac", - "g1_23dof_motion_tracking", - "G1MotionTrackingSAC23Dof", - 130, - 259, - 23, - True, - ), ) @@ -760,13 +730,7 @@ def test_g1_motion_core_registrations_are_manager_only() -> None: ensure_registries() metadata = registry.list_registered_envs() - for task_name in ( - "G1MotionTracking", - "G1MotionTrackingDeploy", - "G1MotionTracking23Dof", - "G1MotionTracking23DofDeploy", - "G1MotionTrackingSAC23Dof", - ): + for task_name in ("G1MotionTracking",): assert metadata[task_name] == { "config_factory": "ManagerBasedRlEnvCfg", "available_backends": ["mujoco", "motrix"], diff --git a/tests/envs/test_motion_profiles.py b/tests/envs/test_motion_profiles.py index 35a9892dd..c24a7dfd3 100644 --- a/tests/envs/test_motion_profiles.py +++ b/tests/envs/test_motion_profiles.py @@ -22,19 +22,9 @@ _PROFILE_IDENTITIES = ( "G1BoxTracking", - "G1BoxTracking23Dof", - "G1ClimbTracking", - "G1ClimbTracking23Dof", "G1FlipTracking", - "G1FlipTracking23Dof", "G1FlipTrackingSAC", - "G1FlipTrackingSAC23Dof", - "G1WallFlipTracking", - "G1WallFlipTracking23Dof", - "G1WallFlipTrackingSAC", - "G1WallFlipTrackingSAC23Dof", "G1WBTObs", - "G1WBTObs23Dof", "X2WallFlipTracking", ) @@ -45,43 +35,7 @@ "scene_flat_with_largebox.xml", "sub3_largebox_003_boxconverted.npz", ), - ( - "g1_23dof_box_tracking", - "G1BoxTracking23Dof", - "scene_flat_23dof_with_largebox.xml", - "sub3_largebox_003_boxconverted_23dof.npz", - ), - ( - "g1_climb_tracking", - "G1ClimbTracking", - "scene_climb_20_z_scale_1.xml", - "climb_20_z_scale_1.0.npz", - ), - ( - "g1_23dof_climb_tracking", - "G1ClimbTracking23Dof", - "scene_climb_20_z_scale_1_23dof.xml", - "climb_20_z_scale_1.0_23dof.npz", - ), ("g1_flip_tracking", "G1FlipTracking", "scene_flat.xml", "flip_360_001__A304.npz"), - ( - "g1_23dof_flip_tracking", - "G1FlipTracking23Dof", - "scene_flat_23dof.xml", - "flip_360_001__A304_23dof.npz", - ), - ( - "g1_wall_flip_tracking", - "G1WallFlipTracking", - "scene_flat_with_wall.xml", - "flip_from_wall_104__A304.npz", - ), - ( - "g1_23dof_wall_flip_tracking", - "G1WallFlipTracking23Dof", - "scene_flat_23dof_with_wall.xml", - "flip_from_wall_104__A304_23dof.npz", - ), ( "x2_wall_flip_tracking", "X2WallFlipTracking", @@ -98,31 +52,7 @@ _SAC_PROFILES = ( ("g1_flip_tracking", "G1FlipTrackingSAC", "scene_flat.xml", "flip_360_001__A304.npz"), - ( - "g1_23dof_flip_tracking", - "G1FlipTrackingSAC23Dof", - "scene_flat_23dof.xml", - "flip_360_001__A304_23dof.npz", - ), - ( - "g1_wall_flip_tracking", - "G1WallFlipTrackingSAC", - "scene_flat_with_wall.xml", - "flip_from_wall_104__A304.npz", - ), - ( - "g1_23dof_wall_flip_tracking", - "G1WallFlipTrackingSAC23Dof", - "scene_flat_23dof_with_wall.xml", - "flip_from_wall_104__A304_23dof.npz", - ), ("g1_wbt_obs", "G1WBTObs", "scene_flat.xml", "dance1_subject2_part.npz"), - ( - "g1_23dof_wbt_obs", - "G1WBTObs23Dof", - "scene_flat_23dof.xml", - "dance1_subject2_part_23dof.npz", - ), ) _OWNER_CASES = ( @@ -154,9 +84,6 @@ _LEGACY_SCALAR_ACTION_SCALE = { ("ppo", "g1_flip_tracking", "motrix"): 0.25, - ("ppo", "g1_23dof_flip_tracking", "motrix"): 0.25, - ("appo", "g1_wall_flip_tracking", "motrix"): 0.25, - ("appo", "g1_23dof_wall_flip_tracking", "motrix"): 0.25, } @@ -290,15 +217,8 @@ def test_motion_profile_action_scale_matches_legacy_runtime( "replay_queue_size", ), ( - ("g1_climb_tracking", "mujoco", 1.2, 1.1, False, 24, None), - ("g1_climb_tracking", "motrix", 1.2, 1.1, False, 24, None), - ("g1_23dof_climb_tracking", "mujoco", 1.2, 1.1, False, 24, None), - ("g1_23dof_climb_tracking", "motrix", 1.2, 1.1, False, 24, None), - ("g1_23dof_flip_tracking", "mujoco", 1.2, 1.1, False, 24, None), - ("g1_23dof_flip_tracking", "motrix", 2.0, 1.5, True, 24, None), - ("g1_wall_flip_tracking", "motrix", 2.0, 1.5, True, 24, None), - ("g1_23dof_wall_flip_tracking", "mujoco", 2.0, 1.5, True, 20, 5), - ("g1_23dof_wall_flip_tracking", "motrix", 2.0, 1.5, True, 24, None), + ("g1_flip_tracking", "mujoco", 2.0, 1.5, True, 24, None), + ("g1_flip_tracking", "motrix", 2.0, 1.5, True, 24, None), ), ) def test_appo_profiles_preserve_training_owner_contract( @@ -319,7 +239,7 @@ def test_appo_profiles_preserve_training_owner_contract( assert owner.training.replay_queue_size == replay_queue_size -@pytest.mark.parametrize("task", ("g1_flip_tracking", "g1_23dof_flip_tracking")) +@pytest.mark.parametrize("task", ("g1_flip_tracking",)) def test_ppo_motrix_flip_profiles_keep_actor_normalization_disabled(task: str) -> None: owner = _compose_owner("ppo", task, "motrix") @@ -330,13 +250,7 @@ def test_ppo_motrix_flip_profiles_keep_actor_normalization_disabled(task: str) - @pytest.mark.parametrize( "task", - ( - "g1_23dof_box_tracking", - "g1_23dof_climb_tracking", - "g1_23dof_flip_tracking", - "g1_23dof_wall_flip_tracking", - "x2_wall_flip_tracking", - ), + ("x2_wall_flip_tracking",), ) def test_ppo_profiles_without_legacy_play_overrides_stay_disabled(task: str) -> None: owner = _compose_owner("ppo", task, "mujoco") @@ -345,7 +259,7 @@ def test_ppo_profiles_without_legacy_play_overrides_stay_disabled(task: str) -> assert owner.play_profile.env is None -@pytest.mark.parametrize("task", ("g1_box_tracking", "g1_23dof_box_tracking")) +@pytest.mark.parametrize("task", ("g1_box_tracking",)) def test_box_motrix_drops_unconsumed_algorithm_noise_config(task: str) -> None: owner = _compose_owner("ppo", task, "motrix") @@ -363,17 +277,11 @@ def test_all_motion_profiles_have_one_manager_factory_and_both_backends() -> Non } -def test_box_wall_wbt_and_x2_profiles_keep_only_owner_differences() -> None: +def test_box_flip_wbt_and_x2_profiles_keep_only_owner_differences() -> None: from unilab.tasks.motion_tracking.g1.manager_terms import BoxMotionCommandCfg _, box, _ = _materialize_profile("ppo", "g1_box_tracking", "mujoco", "G1BoxTracking") _, flip, _ = _materialize_profile("sac", "g1_flip_tracking", "mujoco", "G1FlipTrackingSAC") - _, wall, _ = _materialize_profile( - "sac", - "g1_wall_flip_tracking", - "mujoco", - "G1WallFlipTrackingSAC", - ) _, wbt, _ = _materialize_profile("sac", "g1_wbt_obs", "mujoco", "G1WBTObs") _, x2, _ = _materialize_profile("ppo", "x2_wall_flip_tracking", "mujoco", "X2WallFlipTracking") @@ -386,9 +294,6 @@ def test_box_wall_wbt_and_x2_profiles_keep_only_owner_differences() -> None: assert flip.commands["motion"].params.sampling_mode == "mixed" assert flip.commands["motion"].params.sampling_start_ratio == pytest.approx(0.1) - assert wall.commands["motion"].params.sampling_mode == "uniform" - assert wall.terminations["undesired_contacts"] is None - assert wall.terminations["anchor_pos"].params["threshold"] == pytest.approx(1.0e9) actor_terms = wbt.observations["actor"].terms critic_terms = wbt.observations["critic"].terms @@ -494,7 +399,6 @@ def test_joint_acc_reset_updates_selected_rows_without_pairwise_indexing() -> No ("ppo", "x2_wall_flip_tracking", "X2WallFlipTracking", "mujoco", 154, 430, 29), ("ppo", "x2_wall_flip_tracking", "X2WallFlipTracking", "motrix", 154, 430, 29), ("sac", "g1_wbt_obs", "G1WBTObs", "mujoco", 514, 289, 29), - ("sac", "g1_23dof_wbt_obs", "G1WBTObs23Dof", "mujoco", 412, 259, 23), ), ) def test_representative_motion_profiles_reset_and_step( diff --git a/tests/scripts/test_check_docs.py b/tests/scripts/test_check_docs.py index f0de99bca..177072290 100644 --- a/tests/scripts/test_check_docs.py +++ b/tests/scripts/test_check_docs.py @@ -17,8 +17,8 @@ def test_check_training_entrypoint_semantics_flags_issue_204_patterns(): root = Path(__file__).resolve().parents[2] doc_path = root / "README.md" content = """ -uv run scripts/train_rsl_rl.py task=go1_joystick_flat -uv run scripts/train_rsl_rl.py task=go1_joystick_flat/mujoco training.load_run=2026-01-01 +uv run scripts/train_rsl_rl.py task=go2_joystick_flat +uv run scripts/train_rsl_rl.py task=go2_joystick_flat/mujoco training.load_run=2026-01-01 Training logs are saved to logs/rsl_rl_train/MyTask/. """ @@ -26,14 +26,14 @@ def test_check_training_entrypoint_semantics_flags_issue_204_patterns(): assert any("training.load_run" in error for error in errors) assert any("logs/rsl_rl_train/" in error for error in errors) - assert any("task=go1_joystick_flat" in error for error in errors) + assert any("task=go2_joystick_flat" in error for error in errors) def test_check_training_entrypoint_semantics_accepts_current_patterns(): root = Path(__file__).resolve().parents[2] doc_path = root / "README.md" content = """ -uv run scripts/train_rsl_rl.py task=go1_joystick_flat/mujoco algo.load_run=2026-01-01 +uv run scripts/train_rsl_rl.py task=go2_joystick_flat/mujoco algo.load_run=2026-01-01 uv run scripts/train_sac.py task=g1_walk_flat/mujoco Logs live under logs///. """ @@ -56,7 +56,7 @@ def test_check_hydra_keys_ignores_non_command_fenced_blocks(): ``` ```bash -uv run scripts/train_rsl_rl.py missing_key=true task=go1_joystick_flat/mujoco +uv run scripts/train_rsl_rl.py missing_key=true task=go2_joystick_flat/mujoco ``` """ @@ -96,7 +96,7 @@ def test_collect_doc_errors_scans_issue_templates_for_script_paths(tmp_path): issue_template = tmp_path / ".github" / "ISSUE_TEMPLATE" / "bug_report.yml" issue_template.parent.mkdir(parents=True) issue_template.write_text( - "placeholder: |\n uv run scripts/missing_entrypoint.py task=go1_joystick_flat/mujoco\n", + "placeholder: |\n uv run scripts/missing_entrypoint.py task=go2_joystick_flat/mujoco\n", encoding="utf-8", ) @@ -108,7 +108,7 @@ def test_collect_doc_errors_scans_issue_templates_for_script_paths(tmp_path): def test_collect_doc_errors_flags_unclosed_markdown_fence(tmp_path): readme = tmp_path / "README.md" readme.write_text( - "```bash\nuv run scripts/train_rsl_rl.py task=go1_joystick_flat/mujoco\n", encoding="utf-8" + "```bash\nuv run scripts/train_rsl_rl.py task=go2_joystick_flat/mujoco\n", encoding="utf-8" ) errors = doc_checks.collect_doc_errors(tmp_path) @@ -119,7 +119,7 @@ def test_collect_doc_errors_flags_unclosed_markdown_fence(tmp_path): def test_collect_doc_errors_flags_python_script_invocation(tmp_path): readme = tmp_path / "README.md" readme.write_text( - "```bash\nuv run python scripts/train_rsl_rl.py task=go1_joystick_flat/mujoco\n```\n", + "```bash\nuv run python scripts/train_rsl_rl.py task=go2_joystick_flat/mujoco\n```\n", encoding="utf-8", ) script_path = tmp_path / "scripts" / "train_rsl_rl.py" diff --git a/tests/scripts/test_drake_training_smoke.py b/tests/scripts/test_drake_training_smoke.py index 1308efca4..93a8cac26 100644 --- a/tests/scripts/test_drake_training_smoke.py +++ b/tests/scripts/test_drake_training_smoke.py @@ -26,7 +26,7 @@ def _drake_batch_available() -> bool: not _drake_batch_available(), reason="optional DrakeUni batch extension has not been built", ) -@pytest.mark.parametrize("task", ["go1_joystick_flat/drake", "go2_joystick_flat/drake"]) +@pytest.mark.parametrize("task", ["go2_joystick_flat/drake", "go2_joystick_flat/drake"]) def test_drake_ppo_one_iteration_training_smoke(task: str, tmp_path: Path) -> None: """Drake task configs can run the real RSL-RL training entry point.""" result = subprocess.run( diff --git a/tests/scripts/test_support_matrix.py b/tests/scripts/test_support_matrix.py index 882a72ad7..07326b2ba 100644 --- a/tests/scripts/test_support_matrix.py +++ b/tests/scripts/test_support_matrix.py @@ -164,13 +164,6 @@ def test_support_matrix_does_not_promote_unvalidated_mjwarp_entries(): assert appo_row.cells["mjwarp"].level == EvidenceLevel.REGISTERED -def test_support_matrix_marks_appo_go1_backends_as_tested(): - row = _row("APPO (torch)", "go1_joystick_flat") - - assert row.cells["mujoco"].level == EvidenceLevel.TESTED - assert row.cells["motrix"].level == EvidenceLevel.TESTED - - def test_support_matrix_marks_allegro_appo_backends_as_tested(): allegro_appo_row = _row("APPO (torch)", "allegro_inhand") diff --git a/tests/scripts/test_train_script_configs.py b/tests/scripts/test_train_script_configs.py index 85a8a7618..76bc53903 100644 --- a/tests/scripts/test_train_script_configs.py +++ b/tests/scripts/test_train_script_configs.py @@ -23,18 +23,17 @@ ROOT_DIR = Path(__file__).resolve().parents[2] APPO_MUJOCO_SMOKE_TASKS = [ - "go1_joystick_flat/mujoco", + "go2_joystick_flat/mujoco", "go2_joystick_flat/mujoco", "g1_walk_flat/mujoco", "g1_motion_tracking/mujoco", "g1_flip_tracking/mujoco", - "g1_wall_flip_tracking/mujoco", ] APPO_MOTION_SMOKE_TASKS = { "g1_motion_tracking/mujoco", "g1_flip_tracking/mujoco", - "g1_wall_flip_tracking/mujoco", + "g1_box_tracking/mujoco", } diff --git a/tests/scripts/test_train_scripts.py b/tests/scripts/test_train_scripts.py index b5c34430c..5d6300c90 100644 --- a/tests/scripts/test_train_scripts.py +++ b/tests/scripts/test_train_scripts.py @@ -44,7 +44,7 @@ def _normalize_overrides(overrides: list[str] | None, *, offpolicy: bool = False if offpolicy: normalized.append("task=g1_walk_flat/mujoco") else: - normalized.append("task=go1_joystick_flat/mujoco") + normalized.append("task=go2_joystick_flat/mujoco") return normalized @@ -301,12 +301,12 @@ def test_offpolicy_hydra_algo_td3(): assert cfg.algo.algo == "td3" -def test_offpolicy_go1_motrix_task_is_not_configured(): - """SAC has no Go1 Motrix owner config; use PPO for Go1 joystick tasks.""" +def test_offpolicy_go2_motrix_task_is_not_configured(): + """SAC has no Go2 Motrix owner config; use PPO for Go2 joystick tasks.""" from hydra.errors import MissingConfigException - with pytest.raises(MissingConfigException, match="task/go1_joystick_flat/motrix"): - _offpolicy_cfg(["task=go1_joystick_flat/motrix"]) + with pytest.raises(MissingConfigException, match="task/go2_joystick_flat/motrix"): + _offpolicy_cfg(["task=go2_joystick_flat/motrix"]) def test_offpolicy_g1_walk_flat_motrix_resolved_algo_matches_task_owner(): @@ -407,9 +407,9 @@ def test_offpolicy_isaacsim_training_and_eval_use_separate_render_overrides(): assert play_override["isaacsim_render_mode"] == "record" -def test_ppo_go1_resolved_algo_matches_old_motrix_behavior(): - """Equivalence: PPO Go1 algo hyperparams match pre-refactor motrix values.""" - cfg = _ppo_cfg(["task=go1_joystick_flat/motrix"]) +def test_ppo_go2_resolved_algo_matches_old_motrix_behavior(): + """Equivalence: PPO Go2 algo hyperparams match pre-refactor motrix values.""" + cfg = _ppo_cfg(["task=go2_joystick_flat/motrix"]) assert cfg.algo.max_iterations == 151 assert cfg.algo.empirical_normalization is True @@ -471,18 +471,6 @@ def test_ppo_task_go2_aligns_mujoco_with_motrix_defaults(): assert cfg.algo.algorithm.entropy_coef == pytest.approx(1.0e-3) -def test_ppo_go1_drake_batch_config_matches_current_contact_support(): - cfg = _ppo_cfg(["task=go1_joystick_flat/drake"]) - - assert cfg.env.drake_backend_mode == "batch" - assert cfg.env.drake_nthread == 0 - assert cfg.reward.contact is None - assert cfg.env.events.base_mass is None - assert cfg.env.events.base_com is None - assert cfg.env.events.pd_gains is None - assert cfg.env.events.push_robot is None - - def test_ppo_go2_drake_batch_config_matches_go2_training_defaults(): cfg = _ppo_cfg(["task=go2_joystick_flat/drake"]) @@ -503,22 +491,22 @@ def test_ppo_go2_drake_batch_config_matches_go2_training_defaults(): assert cfg.reward.contact is None -def test_build_ppo_env_cfg_override_go1_motrix( +def test_build_ppo_env_cfg_override_go2_motrix( monkeypatch: pytest.MonkeyPatch, ): mod = _train_rsl_rl(monkeypatch) - cfg = _ppo_cfg(["task=go1_joystick_flat/motrix"]) + cfg = _ppo_cfg(["task=go2_joystick_flat/motrix"]) env_cfg_override = mod.build_ppo_env_cfg_override(cfg) assert env_cfg_override["rewards"]["tracking_lin_vel"]["weight"] == pytest.approx(1.0) - assert env_cfg_override["rewards"]["contact"] is None + assert env_cfg_override["rewards"]["contact"]["func"].endswith("feet_phase_contact") assert env_cfg_override["commands"]["twist"]["ranges"] == { "lin_vel_x": [0.5, 0.5], "lin_vel_y": [0.0, 0.0], "ang_vel_z": [0.0, 0.0], } - assert env_cfg_override["events"]["push_robot"] is None + assert env_cfg_override["events"]["pd_gains"] is None def test_build_ppo_env_cfg_override_g1_motrix( @@ -2255,7 +2243,7 @@ def test_train_rsl_rl_play_missing_checkpoint_skips_env_creation_and_prints_cont ): monkeypatch.delenv("UNILAB_TEST_LOG_ROOT", raising=False) mod = _train_rsl_rl(monkeypatch) - cfg = _ppo_cfg(["task=go1_joystick_flat/mujoco", "training.play_only=true"]) + cfg = _ppo_cfg(["task=go2_joystick_flat/mujoco", "training.play_only=true"]) cfg.algo.algo_log_name = "custom_ppo" monkeypatch.chdir(tmp_path) @@ -2284,7 +2272,7 @@ def test_train_rsl_rl_play_reports_missing_requested_checkpoint_in_resolved_run( ): monkeypatch.delenv("UNILAB_TEST_LOG_ROOT", raising=False) mod = _train_rsl_rl(monkeypatch) - cfg = _ppo_cfg(["task=go1_joystick_flat/mujoco", "training.play_only=true"]) + cfg = _ppo_cfg(["task=go2_joystick_flat/mujoco", "training.play_only=true"]) cfg.algo.algo_log_name = "custom_ppo" cfg.algo.checkpoint = 12 @@ -2319,7 +2307,7 @@ def test_train_rsl_rl_motrix_auto_play_is_interactive( mod = _train_rsl_rl(monkeypatch) cfg = _ppo_cfg( [ - "task=go2_joystick_rough/motrix", + "task=go2_joystick_flat/motrix", "training.play_only=true", "training.play_steps=37", "training.render_spacing=2.5", @@ -2413,7 +2401,7 @@ def test_train_rsl_rl_record_play_uses_backend_plan( mod = _train_rsl_rl(monkeypatch) cfg = _ppo_cfg( [ - "task=go2_joystick_rough/motrix", + "task=go2_joystick_flat/motrix", "training.play_only=true", "training.play_render_mode=record", "training.play_steps=37", @@ -2548,13 +2536,13 @@ def test_play_interactive_parses_explicit_cli(): mod = _play_interactive() parsed = mod._parse_interactive_cli( - ["--algo", "ppo", "--task", "go1_joystick_flat", "--sim", "mujoco"] + ["--algo", "ppo", "--task", "go2_joystick_flat", "--sim", "mujoco"] ) assert parsed.algo == "ppo" - assert parsed.task == "go1_joystick_flat" + assert parsed.task == "go2_joystick_flat" assert parsed.sim == "mujoco" - assert parsed.overrides == ["task=go1_joystick_flat/mujoco"] + assert parsed.overrides == ["task=go2_joystick_flat/mujoco"] @pytest.mark.parametrize("algo", ["appo", "sac", "td3"]) @@ -2573,18 +2561,18 @@ def test_play_interactive_cli_respects_owner_action_mode_and_user_override(): mod = _play_interactive() default_parsed = mod._parse_interactive_cli( - ["--algo", "ppo", "--task", "go2_joystick_rough", "--sim", "mujoco"] + ["--algo", "ppo", "--task", "go2_joystick_flat", "--sim", "mujoco"] ) default_cfg = mod._compose_interactive_config(default_parsed.algo, default_parsed.overrides) - assert default_cfg.interactive.action_mode == "policy" + assert default_cfg.interactive.action_mode == "zero" parsed = mod._parse_interactive_cli( [ "--algo", "ppo", "--task", - "go2_joystick_rough", + "go2_joystick_flat", "--sim", "mujoco", "interactive.action_mode=random", @@ -2593,7 +2581,7 @@ def test_play_interactive_cli_respects_owner_action_mode_and_user_override(): cfg = mod._compose_interactive_config(parsed.algo, parsed.overrides) assert parsed.overrides == [ - "task=go2_joystick_rough/mujoco", + "task=go2_joystick_flat/mujoco", "interactive.action_mode=random", ] assert cfg.interactive.action_mode == "random" @@ -2604,14 +2592,14 @@ def test_play_interactive_rejects_unknown_algo_flag(): with pytest.raises(SystemExit): mod._parse_interactive_cli( - ["--algo=unknown", "--task", "go1_joystick_flat", "--sim", "mujoco"] + ["--algo=unknown", "--task", "go2_joystick_flat", "--sim", "mujoco"] ) def test_play_interactive_dynamic_compose_supports_algo_roots(): mod = _play_interactive() - ppo_cfg = mod._compose_interactive_config("ppo", ["task=go1_joystick_flat/mujoco"]) + ppo_cfg = mod._compose_interactive_config("ppo", ["task=go2_joystick_flat/mujoco"]) appo_cfg = mod._compose_interactive_config("appo", ["task=allegro_inhand/mujoco"]) sac_cfg = mod._compose_interactive_config("sac", ["task=g1_walk_flat/mujoco"]) td3_cfg = mod._compose_interactive_config("td3", ["task=g1_walk_flat/mujoco"]) @@ -2788,7 +2776,7 @@ def test_train_rsl_rl_play_uses_shared_playback_session_factory( mod = _train_rsl_rl(monkeypatch) cfg = _ppo_cfg( [ - "task=go1_joystick_flat/mujoco", + "task=go2_joystick_flat/mujoco", "training.play_only=true", "training.play_render_mode=record", "training.play_steps=5", diff --git a/tests/scripts/test_visualization_entrypoints.py b/tests/scripts/test_visualization_entrypoints.py index 0785b23f8..cde91af80 100644 --- a/tests/scripts/test_visualization_entrypoints.py +++ b/tests/scripts/test_visualization_entrypoints.py @@ -45,7 +45,7 @@ def test_visualize_task_env_parses_explicit_args(): args = mod._parse_args( [ "--task", - "Go2JoystickRough", + "G1WalkFlat", "--backend", "motrix", "--num_envs", @@ -53,7 +53,7 @@ def test_visualize_task_env_parses_explicit_args(): ] ) - assert args.task == "Go2JoystickRough" + assert args.task == "G1WalkFlat" assert args.backend == "motrix" assert args.num_envs == 8 diff --git a/tests/tasks/test_package_boundary.py b/tests/tasks/test_package_boundary.py index 0398f7ddc..c220526fd 100644 --- a/tests/tasks/test_package_boundary.py +++ b/tests/tasks/test_package_boundary.py @@ -13,11 +13,8 @@ _CONCRETE_TASK_PACKAGES = ("locomotion", "manipulation", "motion_tracking") _TASK_REGISTRY_MODULES = ( - "unilab.tasks.locomotion.go1", "unilab.tasks.locomotion.go2", - "unilab.tasks.locomotion.go2w", "unilab.tasks.locomotion.g1", - "unilab.tasks.locomotion.a2", "unilab.tasks.manipulation.allegro_inhand", "unilab.tasks.manipulation.stewart", "unilab.tasks.manipulation.fr3", diff --git a/tests/tasks/test_production_registry_closeout.py b/tests/tasks/test_production_registry_closeout.py index 1758b156c..eea74ae94 100644 --- a/tests/tasks/test_production_registry_closeout.py +++ b/tests/tasks/test_production_registry_closeout.py @@ -14,10 +14,10 @@ Scope note: the registry has no unregister API and no provenance tracking, and the pytest session pollutes it with fixture-only envs (``DummyFlatTest`` via ``UNILAB_EXTRA_REGISTRY_PACKAGES``, the cartpole fixtures reusing -``ManagerBasedRlEnvCfg``/``make_manager_based_rl_env``). The registry snapshot -is therefore taken in a fresh subprocess with that env var scrubbed -(``tests/base/test_backend_imports.py`` idiom), so only the production -``unilab.tasks`` bootstrap contributes registrations. +``ManagerBasedRlEnvCfg``/``make_manager_based_rl_env``). Installed ecosystem +packages may also deliberately contribute third-party task entry points. The +registry snapshot is therefore taken in a fresh subprocess that imports only +the core ``unilab.tasks`` bootstrap modules, not the global entry-point set. """ from __future__ import annotations @@ -43,10 +43,13 @@ _SNAPSHOT_CODE = textwrap.dedent( """ import json + import importlib from unilab.base import registry + from unilab.tasks import __unilab_registry_modules__ - registry.ensure_registries() + for module_name in __unilab_registry_modules__: + importlib.import_module(module_name) snapshot = { name: { backend: [ @@ -65,11 +68,12 @@ def _production_factories() -> dict[str, dict[str, tuple[str, str]]]: - """Snapshot the production registry in a clean interpreter. + """Snapshot the core production registry in a clean interpreter. Returns ``{task: {backend: (factory_module, factory_qualname)}}``. The - subprocess scrubs ``UNILAB_EXTRA_REGISTRY_PACKAGES`` so fixture-only test - envs injected by ``tests/conftest.py`` cannot leak into the snapshot. + The subprocess deliberately bypasses ``ensure_registries()`` so installed + ecosystem entry points and fixture-only test envs cannot leak into the + core production snapshot. """ global _snapshot_cache if _snapshot_cache is None: diff --git a/tests/test_cli.py b/tests/test_cli.py index 2a3b936b9..26c22baba 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -105,10 +105,17 @@ def test_macos_motrix_finds_uv_venv_mxpython_when_not_on_path( assert command[0] == str(fake_mxpython) -def test_train_profile_routes_to_owner_variant(tmp_path: Path) -> None: +def test_train_profile_routes_to_owner_variant( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + monkeypatch.setattr( + cli, + "find_spec", + lambda name: object() if name in {"mujoco", "mjbatch"} else None, + ) (tmp_path / "scripts").mkdir(parents=True) (tmp_path / "scripts" / "train_rsl_rl.py").write_text("", encoding="utf-8") - owner_dir = tmp_path / "conf" / "ppo" / "task" / "go1_joystick_flat" + owner_dir = tmp_path / "conf" / "ppo" / "task" / "go2_joystick_flat" owner_dir.mkdir(parents=True) (owner_dir / "mujoco_nodr.yaml").write_text( "training:\n sim_backend: mujoco\n", @@ -118,7 +125,7 @@ def test_train_profile_routes_to_owner_variant(tmp_path: Path) -> None: command = cli.build_command( mode="train", algo="ppo", - task="go1_joystick_flat", + task="go2_joystick_flat", sim="mujoco", profile="nodr", overrides=[], @@ -127,7 +134,7 @@ def test_train_profile_routes_to_owner_variant(tmp_path: Path) -> None: assert command[1:] == [ str(tmp_path / "scripts" / "train_rsl_rl.py"), - "task=go1_joystick_flat/mujoco_nodr", + "task=go2_joystick_flat/mujoco_nodr", ] @@ -493,7 +500,7 @@ def test_eval_fallback_prefers_same_profile_owner( ) -> None: (tmp_path / "scripts").mkdir(parents=True) (tmp_path / "scripts" / "train_rsl_rl.py").write_text("", encoding="utf-8") - owner_dir = tmp_path / "conf" / "ppo" / "task" / "go1_joystick_flat" + owner_dir = tmp_path / "conf" / "ppo" / "task" / "go2_joystick_flat" owner_dir.mkdir(parents=True) (owner_dir / "mujoco_nodr.yaml").write_text( "training:\n sim_backend: mujoco\n", encoding="utf-8" @@ -505,7 +512,7 @@ def test_eval_fallback_prefers_same_profile_owner( command = cli.build_command( mode="eval", algo="ppo", - task="go1_joystick_flat", + task="go2_joystick_flat", sim="motrix", profile="nodr", overrides=[], @@ -513,7 +520,7 @@ def test_eval_fallback_prefers_same_profile_owner( root=tmp_path, ) - assert "task=go1_joystick_flat/mujoco_nodr" in command + assert "task=go2_joystick_flat/mujoco_nodr" in command assert "training.sim_backend=motrix" in command @@ -522,7 +529,7 @@ def test_eval_fallback_without_same_profile_sibling_fails( ) -> None: (tmp_path / "scripts").mkdir(parents=True) (tmp_path / "scripts" / "train_rsl_rl.py").write_text("", encoding="utf-8") - owner_dir = tmp_path / "conf" / "ppo" / "task" / "go1_joystick_flat" + owner_dir = tmp_path / "conf" / "ppo" / "task" / "go2_joystick_flat" owner_dir.mkdir(parents=True) (owner_dir / "mujoco.yaml").write_text("training:\n sim_backend: mujoco\n", encoding="utf-8") _pretend_motrix_is_installed(monkeypatch) @@ -532,7 +539,7 @@ def test_eval_fallback_without_same_profile_sibling_fails( cli.build_command( mode="eval", algo="ppo", - task="go1_joystick_flat", + task="go2_joystick_flat", sim="motrix", profile="nodr", overrides=[], @@ -748,12 +755,11 @@ def _register_play_interactive_demo(monkeypatch: pytest.MonkeyPatch) -> str: def test_demo_registry_contains_expected_entries() -> None: assert set(demo.DEMO_REGISTRY) == { "dance", - "wallflip", "boxtracking", "teaser", } assert demo.DEMO_REGISTRY["teaser"].entry == "teaser" - for name in ("dance", "wallflip", "boxtracking"): + for name in ("dance", "boxtracking"): spec = demo.DEMO_REGISTRY[name] assert spec.entry == "eval" assert spec.sim == "motrix" diff --git a/tests/test_completion.py b/tests/test_completion.py index a42a1bfdb..330cf52e7 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -308,7 +308,6 @@ def test_demo_positional_completes_all_demo_names(tmp_path: Path) -> None: "boxtracking", "dance", "teaser", - "wallflip", ] diff --git a/tests/training/test_seed_contract.py b/tests/training/test_seed_contract.py index 6d9fc5f19..437acb012 100644 --- a/tests/training/test_seed_contract.py +++ b/tests/training/test_seed_contract.py @@ -62,9 +62,9 @@ def test_derive_worker_seed_is_deterministic_and_distinct_from_base_seed(): @pytest.mark.parametrize( ("config_dir", "overrides"), [ - ("ppo", ["task=go1_joystick_flat/mujoco"]), - ("ppo", ["task=go1_joystick_flat/mujoco", "algo.seed=41"]), - ("appo", ["task=go1_joystick_flat/mujoco"]), + ("ppo", ["task=go2_joystick_flat/mujoco"]), + ("ppo", ["task=go2_joystick_flat/mujoco", "algo.seed=41"]), + ("appo", ["task=go2_joystick_flat/mujoco"]), ("sac", ["task=g1_walk_flat/mujoco"]), ("td3", ["task=g1_walk_flat/mujoco"]), ], diff --git a/tests/training/test_training_helpers.py b/tests/training/test_training_helpers.py index 47bf735a3..a0f670cc2 100644 --- a/tests/training/test_training_helpers.py +++ b/tests/training/test_training_helpers.py @@ -68,7 +68,7 @@ def _normalize_overrides(overrides: list[str] | None, *, offpolicy: bool = False if offpolicy: normalized.append("task=g1_walk_flat/mujoco") else: - normalized.append("task=go1_joystick_flat/mujoco") + normalized.append("task=go2_joystick_flat/mujoco") return normalized diff --git a/tests/utils/test_experiment_tracking.py b/tests/utils/test_experiment_tracking.py index 9defe11eb..c4433d2ba 100644 --- a/tests/utils/test_experiment_tracking.py +++ b/tests/utils/test_experiment_tracking.py @@ -317,17 +317,17 @@ def test_build_wandb_settings_defaults_for_shared_workspace(): settings = build_wandb_settings( {"wandb_project": "unilab"}, algo_name="ppo", - task_name="Go1JoystickFlat", + task_name="Go2JoystickFlat", sim_backend="mujoco", - log_dir="logs/rsl_rl_train/Go1JoystickFlat/2026-04-02_00-00-00_mujoco", + log_dir="logs/rsl_rl_train/Go2JoystickFlat/2026-04-02_00-00-00_mujoco", ) assert settings["project"] == "unilab" - assert settings["group"] == "Go1JoystickFlat" + assert settings["group"] == "Go2JoystickFlat" assert settings["job_type"] == "ppo" - assert settings["name"].startswith("ppo__Go1JoystickFlat__") + assert settings["name"].startswith("ppo__Go2JoystickFlat__") assert "ppo" in settings["tags"] - assert "Go1JoystickFlat" in settings["tags"] + assert "Go2JoystickFlat" in settings["tags"] assert "mujoco" in settings["tags"] @@ -391,7 +391,7 @@ def test_onpolicy_logger_reuses_existing_wandb_run(monkeypatch): logger = OnPolicyLogger( algo_name="PPO", - env_name="Go1JoystickFlat", + env_name="Go2JoystickFlat", log_backend="wandb", ) @@ -426,14 +426,14 @@ def test_onpolicy_logger_creates_and_finishes_owned_wandb_run(monkeypatch): logger = OnPolicyLogger( algo_name="PPO", - env_name="Go1JoystickFlat", + env_name="Go2JoystickFlat", log_backend="wandb", wandb_project="unilab", wandb_entity="team", - wandb_name="ppo-go1", - wandb_group="go1", + wandb_name="ppo-go2", + wandb_group="go2", wandb_job_type="train", - wandb_tags=["ppo", "go1"], + wandb_tags=["ppo", "go2"], wandb_notes="notes", ) @@ -442,13 +442,13 @@ def test_onpolicy_logger_creates_and_finishes_owned_wandb_run(monkeypatch): init_call = fake_wandb.init_calls[0] assert init_call["project"] == "unilab" assert init_call["entity"] == "team" - assert init_call["name"] == "ppo-go1" - assert init_call["group"] == "go1" + assert init_call["name"] == "ppo-go2" + assert init_call["group"] == "go2" assert init_call["job_type"] == "train" - assert init_call["tags"] == ["ppo", "go1"] + assert init_call["tags"] == ["ppo", "go2"] assert init_call["notes"] == "notes" assert init_call["config"]["algo"] == "PPO" - assert init_call["config"]["env"] == "Go1JoystickFlat" + assert init_call["config"]["env"] == "Go2JoystickFlat" assert init_call["config"]["num_envs"] == 4096 logger.finish() diff --git a/tests/utils/test_xml_utils.py b/tests/utils/test_xml_utils.py index e1a4354a3..1b54b8552 100644 --- a/tests/utils/test_xml_utils.py +++ b/tests/utils/test_xml_utils.py @@ -31,34 +31,10 @@ def _go2_mujoco_robot() -> str: return str(ASSETS_ROOT_PATH / "robots" / "go2" / "go2_mujoco.xml") -def _go1_robot() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go1" / "go1.xml") - - -def _go1_mujoco_robot() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go1" / "go1_mujoco.xml") - - -def _go2w_robot() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go2w" / "go2w.xml") - - -def _go2w_mujoco_robot() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go2w" / "go2w_mujoco.xml") - - def _go2_locomotion_task() -> str: return str(ASSETS_ROOT_PATH / "robots" / "go2" / "locomotion_task.xml") -def _go1_locomotion_task() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go1" / "locomotion_task.xml") - - -def _go2w_locomotion_task() -> str: - return str(ASSETS_ROOT_PATH / "robots" / "go2w" / "locomotion_task.xml") - - def _geom_id(model, mujoco, name: str) -> int: geom_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_GEOM, name) assert geom_id >= 0 @@ -234,85 +210,6 @@ def test_materialize_mujoco_hfield_attached_scene_composes_robot_and_task_fragme assert mujoco.mj_name2id(reloaded_model, mujoco.mjtObj.mjOBJ_GEOM, "floor") >= 0 -def test_materialize_mujoco_hfield_attached_scene_preserves_go1_collision_xml( - tmp_path, -) -> None: - mujoco = pytest.importorskip("mujoco") - - from unilab.terrains import TerrainGeneratorCfg, flat - - cfg = TerrainGeneratorCfg( - size=(4.0, 4.0), - horizontal_scale=0.2, - border_width=0.0, - num_rows=1, - num_cols=1, - sub_terrains={"flat": flat()}, - ) - - model, terrain_origins = materialize_mujoco_hfield_attached_scene( - model_file=_go1_mujoco_robot(), - terrain_cfg=cfg, - output_dir=tmp_path, - fragment_files=[_go1_locomotion_task()], - ) - - assert terrain_origins.shape == (1, 1, 3) - assert model.opt.ccd_iterations == 500 - _assert_geom_contact_params( - model, - mujoco, - name="FL", - condim=6, - margin=0.005, - friction=(0.8, 0.02, 0.01), - ) - _assert_geom_contact_params( - model, - mujoco, - name="FL_thigh_geom", - condim=1, - margin=0.001, - friction=(0.0, 0.0, 0.0), - ) - assert mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_SENSOR, "FL_foot_contact") >= 0 - - -def test_materialize_mujoco_hfield_attached_scene_preserves_go2w_collision_xml( - tmp_path, -) -> None: - mujoco = pytest.importorskip("mujoco") - - from unilab.terrains import TerrainGeneratorCfg, flat - - cfg = TerrainGeneratorCfg( - size=(4.0, 4.0), - horizontal_scale=0.2, - border_width=0.0, - num_rows=1, - num_cols=1, - sub_terrains={"flat": flat()}, - ) - - model, terrain_origins = materialize_mujoco_hfield_attached_scene( - model_file=_go2w_mujoco_robot(), - terrain_cfg=cfg, - output_dir=tmp_path, - fragment_files=[_go2w_locomotion_task()], - ) - - assert terrain_origins.shape == (1, 1, 3) - assert model.opt.ccd_iterations == 500 - _assert_geom_contact_params( - model, - mujoco, - name="FL_wheel_collision", - condim=6, - margin=0.005, - friction=(0.8, 0.02, 0.01), - ) - - def test_materialize_mujoco_hfield_attached_scene_accepts_repo_relative_fragments( tmp_path, ) -> None: