Skip to content

Commit 40bcd3a

Browse files
authored
Merge pull request #34 from KraHsu/dev
Promote dev to main: M2-M4 + showcase + foundation docs
2 parents 0168cf6 + 239e865 commit 40bcd3a

147 files changed

Lines changed: 11327 additions & 685 deletions

File tree

Some content is hidden

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

‎CHANGELOG.md‎

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Changelog
2+
3+
All notable changes to GeneLab are recorded here. The format follows
4+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the project is still on a 0.x
5+
trajectory so breaking changes can land in any minor release until the 1.0 stabilisation.
6+
7+
## [Unreleased]
8+
9+
### Added
10+
11+
- `docs/concepts/rl-runner.{en,zh}.md`: bilingual concept page for `genelab.rl`
12+
(`train_task` / `play_task` signatures, `RslRlOnPolicyRunnerCfg` field
13+
layout, `AgentKind` Literal, `RslRlVecEnvWrapper` adapter, torchrun-based
14+
`--gpus N` distributed-training relaunch, `maybe_profile` flag/env-var
15+
matrix, failure modes).
16+
- `docs/concepts/mdp.{en,zh}.md`: bilingual reference for the reusable MDP term
17+
library (`genelab.mdp.{actions,commands,observations,rewards,terminations,
18+
events,curriculums,noise}`). Every re-exported function / class is tabulated
19+
with its required params, output shape, and a minimal wiring example, plus
20+
warnings on the `joint_acc_l2` / `feet_air_time` placeholder rewards.
21+
- `docs/concepts/managers.{en,zh}.md`, `docs/cli/list-info.{en,zh}.md`: bilingual
22+
manager-system concept page (seven managers + `ManagerTermBaseCfg` + term
23+
lifecycle + `EventMode` semantics + per-manager wiring examples) and CLI
24+
discovery page (`list KIND` enumeration, `info NAME` panel anatomy, override
25+
path lookup workflow, simulation flag shortcuts).
26+
- `examples/genelab_showcase/`: six play-only TaskCfgs that exercise every M1–M4
27+
building block (sensors / ray-cast patterns / contact + air-time / 5 sub-terrains /
28+
`terrain_levels_vel` curriculum / `IdealPDActuator` arm). Each task dumps
29+
per-feature evidence (PNG frames, distance histograms, tracking error, terrain
30+
level histograms) into `logs/showcase/<slug>/` so the visual + numerical behaviour
31+
of every building block can be eyeballed without launching an RL training run.
32+
- `InteractiveScene.viewer_closed` / `ManagerBasedRlEnv.viewer_closed`: viewer-closed
33+
handling moved into the kernel. `InteractiveScene.step` catches Genesis's
34+
`GenesisException("Viewer closed.")`, flips the flag, and becomes a no-op on
35+
subsequent calls. Consumers (RL runner, showcase runner, custom rollouts) only
36+
need to poll `env.viewer_closed` and break; the previous per-consumer
37+
`try/except gs.GenesisException` boilerplate is no longer required.
38+
- `InteractiveSceneCfg.batch_render: bool`: when set, `InteractiveScene._build`
39+
passes `gs.renderers.BatchRenderer(use_rasterizer=False)` to `gs.Scene`. Required
40+
for `CameraSensor` to produce per-env RGB-D tensors. Defaults to `False` for
41+
backwards compatibility.
42+
- `Sensor.pre_build_genesis(gs_scene, entities)`: new no-op hook on the sensor base
43+
class. `InteractiveScene._build` calls it on every sensor cfg right after entity
44+
spawn and before `gs_scene.build`, giving sensors a chance to register Genesis
45+
resources that the renderer snapshots at build time. `CameraSensor` overrides it
46+
to allocate its camera early — required for BatchRender to register the camera in
47+
its build-time snapshot. `InteractiveScene.sensors` now exposes the resulting
48+
instances, and `ManagerBasedRlEnv` binds those instances instead of re-building.
49+
- `docs/concepts/scene.{en,zh}.md`: bilingual concept page covering the M1 stack —
50+
`InteractiveScene` lifecycle, `SimulationCfg`, `InteractiveSceneCfg`, `Articulation`,
51+
`RigidObject`, and the four documented failure modes.
52+
- `docs/examples/showcase.{en,zh}.md`, `docs/examples/unitree-g1.{en,zh}.md`:
53+
bilingual examples pages — the showcase index plus a distilled Unitree G1
54+
walk-through (velocity tracking, motion imitation, long-run profiling).
55+
- `CameraSensor` (with `CameraSensorCfg` and `CameraData`): rigid-mount RGB-D probe
56+
wrapping Genesis's `BatchRenderer` camera. Per-env tensors with shape
57+
`(num_envs, H, W, 3)` for RGB (uint8) and `(num_envs, H, W)` for depth (float meters);
58+
both channels independently toggleable via `render_rgb` / `render_depth`. `bind()`
59+
resolves the named link, builds the 4×4 mounting offset from `offset_pos` /
60+
`offset_quat`, and calls `cam.attach`; `_compute_data()` runs `cam.move_to_attach()`
61+
then `cam.render(...)`. Linux x86-64 + CUDA only — Genesis's `BatchRenderer` is the
62+
only parallel-env camera backend.
63+
- `genelab.asset_zoo` now ships five built-in robots: `CartpoleCfg`, `FrankaPandaCfg`,
64+
`UnitreeG1Cfg` (29-DoF humanoid, 6 DCMotor groups mirroring
65+
`examples/unitree/.../g1/constants.py`), `UnitreeGo1Cfg` (12-DoF quadruped, 3
66+
ImplicitPD groups aligned to Isaac Lab Go1 defaults), and `AnymalCCfg` (12-DoF
67+
quadruped, single ImplicitPD group aligned to Isaac Lab Anymal C defaults). All four
68+
Menagerie-sourced robots (Franka, G1, Go1, Anymal C) ship as `.tar.gz` bundles in
69+
`KraHsu/genelab-assets`, preserving the upstream LICENSE and README.
70+
- `AssetSpec.archive_member`: optional field that switches `fetch_asset` from
71+
single-file to archive mode. The URL is treated as a `.tar.gz`, the blob's md5 is
72+
verified end-to-end, and `tarfile`'s `data` filter extracts the contents into
73+
`<md5>/extracted/` (rejects symlinks, absolute paths, and parent-directory escapes).
74+
The returned path is `<md5>/extracted/<archive_member>` — Menagerie mesh references
75+
resolve automatically because the full folder structure is preserved.
76+
- `genelab.asset_zoo` namespace with the first two built-in robot configurations,
77+
`CartpoleCfg` and `FrankaPandaCfg`. Both are registered into `ROBOTS` as an import
78+
side-effect of `load_builtin_registries()`; factories stay lazy so `genelab list
79+
robots` never touches the network. Cartpole gain values mirror
80+
`examples/inverted_pendulum` (`stiffness=80`, passive pole); Franka follows Isaac
81+
Lab's high-PD configuration (`panda_arm` k=400, `panda_hand` k=1e4) with the
82+
Menagerie home pose.
83+
84+
### Changed
85+
86+
- **Breaking** (asset zoo only — no released API): `FrankaPandaCfg` now sources the full
87+
MuJoCo Menagerie `franka_emika_panda` model (Apache-2.0) instead of the minimal stub
88+
shipped during initial M4. Joint regexes drop the `panda_` prefix (`joint[1-7]`,
89+
`finger_joint.*`) to match the upstream MJCF, and `default_joint_pos` follows the
90+
Menagerie `home` keyframe (`joint4=-1.57079`, `joint6=1.57079`, `joint7=-0.7853`).
91+
- `genelab.utils.download.fetch_asset` + `AssetSpec` + `AssetDownloadError`: md5-verified
92+
download helper for asset zoo entries. Files cache under
93+
`<project_root>/.cache/assets/<name>/<md5>/<filename>` via atomic stage-and-rename;
94+
md5 mismatches and `URLError` failures raise `AssetDownloadError` with both expected
95+
and actual digests in the message.
96+
- `docs/concepts/asset_zoo.{en,zh}.md`: bilingual concept page covering the asset
97+
lifecycle, cache layout, md5 verification, and the template for adding new robot
98+
configurations.
99+
- `FrameTransformerSensor` (with `FrameTransformerSensorCfg`, `TargetFrameCfg`, and
100+
`FrameTransformerData`): stateless forward-kinematics probe that outputs the world-frame
101+
pose AND source-frame pose for one or more target frames relative to a single source
102+
frame. Both source and target support rigid local-frame offsets (position + quaternion).
103+
`target_frames` is order-preserving so observation terms can slice by position; the
104+
matching `target_names: tuple[str, ...]` attribute exposes column identities. `bind`
105+
rejects unknown link names and empty `target_frames` (mirrors the contact-sensor
106+
unresolved-link error path).
107+
- `IMUSensor` (with `IMUSensorCfg` and `IMUData`) sits alongside `BodyVelocitySensor` and
108+
outputs orientation, body-frame projected unit gravity, and body-frame linear / angular
109+
acceleration at a site rigidly attached to a link. Accelerations are computed by finite
110+
difference of the world-frame velocity buffers; the first control step after each
111+
`reset` returns zero acceleration (deliberate — avoids a spurious spike from a stale
112+
prev buffer). `gravity_bias=True` (default) follows the real-IMU specific-force
113+
convention. Per-env `bias_range_lin_acc` / `bias_range_ang_acc` resample on every reset.
114+
- `RingPattern` and `HemispherePattern` ray-cast patterns alongside the existing
115+
`GridPattern`. `RingPattern` covers multi-line LIDAR sweeps (`num_horizontal × num_vertical`
116+
rays, automatic wrap-around handling on a 360° span); `HemispherePattern` distributes rays
117+
on a spherical cap via a Fibonacci lattice with configurable pole axis and half-angle.
118+
`RayCastSensorCfg.pattern` is now typed `GridPattern | RingPattern | HemispherePattern`.
119+
- `genelab.terrains` namespace with `SubTerrainCfg` (abstract) and five concrete
120+
sub-terrains: `FlatPatchCfg`, `PyramidStairsCfg`, `RandomRoughCfg`, `SlopeCfg`,
121+
`WaveCfg`. `TerrainGeneratorCfg` composes them into a 2D grid (random by proportion
122+
or explicit `layout`); `TerrainGenerator` emits Genesis kwargs and per-cell
123+
`env_origins`; `TerrainImporter` spawns `gs.morphs.Terrain` and exposes the
124+
post-build `heightfield` for sensors.
125+
- `InteractiveSceneCfg.terrain` now accepts a `TerrainGeneratorCfg`; `InteractiveScene`
126+
routes through `TerrainImporter` when set, falling back to the default flat plane
127+
otherwise. `InteractiveScene.terrain` exposes the active importer to consumers.
128+
- `RayCastSensor` now samples `scene.terrain.heightfield_tensor` bilinearly when a
129+
terrain is attached; flat-plane behaviour is preserved when `scene.terrain is None`
130+
or when the sensor runs against a fake env without a `scene` attribute (unit-test
131+
surface). `TerrainHeightSensor` inherits the new path through its inner ray-cast.
132+
- `TerrainImporter` gains `heightfield_tensor(device, dtype)` (device-keyed cache),
133+
`horizontal_scale`, `vertical_scale`, and `terrain_origin` accessors used by the
134+
ray-cast sampler.
135+
- `TerrainImporter` tracks per-env curriculum state via `terrain_levels` /
136+
`terrain_cols` / `spawn_pos`; `init_per_env_state(num_envs, device)` is called once
137+
by `InteractiveScene.build()` post-Genesis-build. `update_env_origins(env_ids)`
138+
recomputes spawn origins after a level change.
139+
- `genelab.mdp.curriculums.terrain_levels_vel`: curriculum term that promotes /
140+
demotes each env's terrain level by how far it walked from spawn (XY distance vs
141+
configurable `distance_threshold` and `demote_ratio`), then writes the new spawn
142+
pose into the sim via `Articulation.write_root_state`.
143+
- `docs/concepts/terrains.{en,zh}.md`: bilingual concept page covering the generator,
144+
importer, sensor integration, curriculum, and known failure modes.
145+
- `genelab.actuator` namespace with `ActuatorBase` and three concrete electromechanical
146+
models: `ImplicitPDActuator` (Genesis-internal PD), `IdealPDActuator` (Python-side PD
147+
via `control_dofs_force`), `DCMotorActuator` (`IdealPD` plus driving-direction torque
148+
saturation).
149+
- `ArticulationCfg.actuators: dict[str, ActuatorBaseCfg]` groups joints by regex and
150+
carries `stiffness` / `damping` / `effort_limit` / `velocity_limit` / `armature` /
151+
`friction` / `action_scale` per group.
152+
- `Articulation.write_joint_targets_partial` routes per-step joint targets to each
153+
actuator group's declared channel (position-target or force).
154+
- `Articulation.action_scale_tensor` aggregates per-group action scales for inheritance
155+
by `JointPositionAction` when its `scale` is left `None` (the new default).
156+
- `docs/concepts/actuators.{en,zh}.md` covers the actuator design and failure modes.
157+
158+
### Changed
159+
160+
- **Breaking**: `ArticulationCfg.joint_kp` / `joint_kv` / `action_scale=dict` are removed;
161+
configure equivalent groups via `actuators`. The bundled inverted-pendulum and Unitree
162+
G1 examples migrate accordingly — G1 now ships six `DCMotorActuatorCfg` groups
163+
(5020 / 7520_14 / 7520_22 / 4010 / waist / ankle).
164+
- **Breaking**: `Articulation.joint_kp` / `joint_kv` / `action_scale` properties and the
165+
matching `ManagerBasedRlEnv` delegates are removed. Read actuator parameters through
166+
`articulation.actuators[name]` instead.
167+
- **Breaking**: `Articulation.bind` rejects an empty `actuators` dict and any actuator
168+
configuration that leaves an actuated joint uncovered or covered by more than one
169+
group. Passive joints need an explicit zero-gain `ImplicitPDActuatorCfg`.
170+
- `JointPositionActionCfg.scale` defaults to `None`, in which case per-joint scale is
171+
inherited from `Articulation.action_scale_tensor`. Passing a `float` or `dict` still
172+
overrides.
173+
174+
### Removed
175+
176+
- `examples/unitree/.../g1/constants.py` no longer exports `ActuatorGroup`, `_fan_out`,
177+
`G1_JOINT_KP`, `G1_JOINT_KV`, or `G1_ACTION_SCALE` — superseded by `G1_ACTUATORS_CFG`.
178+
179+
## [0.1.0] — 2026-05-14
180+
181+
- M1 milestone: `InteractiveScene` + `Articulation` / `RigidObject` entities extracted
182+
from `ManagerBasedRlEnv`; `SimulationCfg` / `InteractiveSceneCfg` split.
183+
- Sensor abstraction (`Sensor[T]`) with contact, body velocity, ray-cast, and terrain
184+
height sensors.
185+
- Mouse-interaction viewer plugin.
186+
- rsl_rl-based PPO training/replay for the inverted-pendulum and Unitree G1 examples.

‎CONTRIBUTING.md‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,19 @@ All four must pass — CI enforces the same set as required status checks on eve
5050

5151
## Branch and PR workflow
5252

53-
`main` is protected: direct pushes are rejected and the required CI checks (`lint`, `typecheck`, `test`) must be green before a PR can merge.
53+
GeneLab uses a two-layer flow: feature branches integrate into `dev` first, then `dev` is promoted to `main` via PR. `main` is protected — direct pushes are rejected and the required CI checks (`lint`, `typecheck`, `test`) must be green before a PR can merge.
5454

55-
1. Branch off `main` with a descriptive prefix: `fix/...`, `feat/...`, `ci/...`, `chore/...`, `docs/...`.
55+
```
56+
feat/* ──┐
57+
fix/* ──┼──> dev ──PR──> main
58+
docs/* ──┘
59+
```
60+
61+
1. Branch off `dev` with a descriptive prefix: `fix/...`, `feat/...`, `ci/...`, `chore/...`, `docs/...`.
5662
2. Run the checks above locally.
57-
3. Push and open a PR — CI runs automatically on every push.
58-
4. If `main` advances during review, merge it into your branch (or rebase) so the PR stays current.
63+
3. Push and either open a PR targeting `dev`, or merge into `dev` locally and push `dev` directly — pick whichever fits the size of the change.
64+
4. To promote `dev` to `main`, open a PR `dev` → `main`. CI runs on every push and must be green before merge.
65+
5. If `dev` advances during review of a feature branch, merge `dev` into your branch (or rebase) so the PR stays current.
5966

6067
## Commit messages
6168

‎docs/cli/list-info.en.md‎

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Discovery: list and info
2+
3+
The `list` and `info` subcommands are the discovery surface — together they
4+
turn an installed extension into a printable map of available tasks, envs,
5+
robots, and the dotted-path keys that `play` / `train` can override.
6+
7+
## Listing the registry
8+
9+
`list KIND` enumerates one of the three global registries (`robots`, `envs`,
10+
`tasks`). The command imports every discovered extension first, so the listing
11+
reflects the current install set.
12+
13+
```bash
14+
uv run genelab list robots
15+
uv run genelab list envs
16+
uv run genelab list tasks
17+
```
18+
19+
Each row prints the registered name, description, and a per-entry detail line
20+
(for tasks: `env=..., robot=..., trainable=...`; for envs / robots: the first
21+
few scalar cfg fields). Tasks that registered `examples=[...]` strings via
22+
`register_task(..., examples=[...])` show an `(N example(s))` suffix.
23+
24+
## Inspecting a task
25+
26+
`info NAME` resolves a single registered name and prints a detail panel. The
27+
lookup falls through tasks → envs → robots in that order and exits with the
28+
combined available-name listing when nothing matches.
29+
30+
```bash
31+
uv run genelab info GeneLab-Sensors-Showcase-v0
32+
```
33+
34+
The task panel contains three sections:
35+
36+
1. **Description and meta** — the one-line description plus the `env=...,
37+
robot=..., trainable=...` strip pulled from the task cfg.
38+
2. **Overridable cfg paths** — a three-column table (`Path`, `Type`,
39+
`Default`) generated by walking the cfg dataclass tree depth-first. Field
40+
names beginning with `_` are skipped. Sub-dataclasses are expanded inline
41+
under their parent's dotted path.
42+
3. **Examples** — the verbatim `examples=[...]` lines the extension supplied at
43+
registration time. They are display-only — `info` does not run them.
44+
45+
The same panel renders for envs and robots, but without the `env / robot /
46+
trainable` meta strip.
47+
48+
## Override paths
49+
50+
Every row in the "Overridable cfg paths" table is the exact dotted path that
51+
`play` and `train` accept on the command line. The CLI forwards each
52+
`--<a.b.c> VALUE` flag into `genelab.configs.apply_overrides`, which coerces
53+
the value against the target field's type hint at config build time.
54+
55+
| `info` row | Equivalent override flag |
56+
|---|---|
57+
| `env.simulation.vis` (bool, false) | `--vis` (shortcut) or `--env.simulation.vis true` |
58+
| `env.simulation.gpu` (bool, false) | `--gpu` (shortcut) or `--env.simulation.gpu true` |
59+
| `env.simulation.steps` (int, 240) | `--steps 500` (shortcut) or `--env.simulation.steps 500` |
60+
| `env.simulation.dt` (float, 0.01) | `--dt 0.005` (shortcut) or `--env.simulation.dt 0.005` |
61+
| `env.rewards_cfg.track_lin_vel.weight` (float, 1.0) | `--env.rewards_cfg.track_lin_vel.weight 2.0` |
62+
| `env.rewards_cfg.track_lin_vel.params.std` (float, 0.25) | `--env.rewards_cfg.track_lin_vel.params.std 0.5` |
63+
| `env.scene.env_spacing` (tuple, `(2.0, 2.0)`) | `--env.scene.env_spacing 3.0,3.0` |
64+
| `env.scene.batch_render` (bool, false) | `--env.scene.batch_render true` |
65+
66+
The four simulation shortcuts (`--vis`, `--gpu`, `--steps`, `--dt`) rewrite to
67+
the `env.simulation.{vis,gpu,steps,dt}` paths before forwarding, so they show
68+
up in profiler-trace argv exactly like an explicit override would.
69+
70+
## Examples
71+
72+
A short discovery loop for the inverted-pendulum task:
73+
74+
```bash
75+
# Confirm the extension is installed and pick a task id.
76+
uv run genelab list tasks | grep Pendulum
77+
78+
# Drill into one task — copy a dotted path from the "Overridable cfg paths" table.
79+
uv run genelab info GeneLab-Inverted-Pendulum-v0
80+
81+
# Run the task with overrides applied.
82+
uv run genelab play GeneLab-Inverted-Pendulum-v0 --vis --steps 240 \
83+
--env.rewards_cfg.pole_upright.weight 5.0
84+
```
85+
86+
The same flow works against envs and robots: `genelab info FrankaPandaCfg` (a
87+
robot) reveals every `ArticulationCfg` field including the per-group
88+
`actuators.*.stiffness` and `default_joint_pos.*` keys.
89+
90+
## See also
91+
92+
- [Play and Train](play-train.md)
93+
- [Configs](../concepts/configs.md)
94+
- [Managers and MDP terms](../concepts/managers.md)

0 commit comments

Comments
 (0)