mjlab.terrains#
Terrain generation and importing.
- class mjlab.terrains.HfDiscreteObstaclesTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, obstacle_height_mode: Literal['choice', 'fixed'] = 'choice', obstacle_width_range: tuple[float, float], obstacle_height_range: tuple[float, float], num_obstacles: int, platform_width: float = 1.0, horizontal_scale: float = 0.1, vertical_scale: float = 0.005, base_thickness_ratio: float = 1.0, border_width: float = 0.0, square_obstacles: bool = False, origin_z_offset: float = 0.0) None#
- base_thickness_ratio: float = 1.0#
Ratio of the heightfield base thickness to its maximum surface height.
- border_width: float = 0.0#
Width of the flat border around the terrain edges, in meters. Must be >= horizontal_scale if non-zero.
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- obstacle_height_mode: Literal['choice', 'fixed'] = 'choice'#
How obstacle heights are chosen. “choice” randomly picks from [-h, -h/2, h/2, h] (mix of pits and bumps); “fixed” uses h for all obstacles.
- origin_z_offset: float = 0.0#
Vertical offset added to spawn origin height (meters).
Useful to prevent robot feet from clipping through terrain when spawning at the origin.
- platform_width: float = 1.0#
Side length of the obstacle-free flat square at the terrain center, in meters.
- square_obstacles: bool = False#
If True, obstacles have equal width and length. If False, each dimension is sampled independently.
- vertical_scale: float = 0.005#
Heightfield height resolution, in meters per integer unit of the noise array.
- class mjlab.terrains.HfPerlinNoiseTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, height_range: tuple[float, float], octaves: int = 4, persistence: float = 0.5, lacunarity: float = 2.0, scale: float = 10.0, horizontal_scale: float = 0.1, resolution: float = 0.05, base_thickness_ratio: float = 1.0, border_width: float = 0.0) None#
- class mjlab.terrains.HfPyramidSlopedTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, slope_range: tuple[float, float], platform_width: float = 1.0, inverted: bool = False, border_width: float = 0.0, horizontal_scale: float = 0.1, vertical_scale: float = 0.005, base_thickness_ratio: float = 1.0) None#
- base_thickness_ratio: float = 1.0#
Ratio of the heightfield base thickness to its maximum surface height.
- border_width: float = 0.0#
Width of the flat border around the terrain edges, in meters. Must be >= horizontal_scale if non-zero.
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- platform_width: float = 1.0#
Side length of the flat square platform at the terrain center, in meters.
- class mjlab.terrains.HfRandomUniformTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, noise_range: tuple[float, float], noise_step: float = 0.005, downsampled_scale: float | None = None, horizontal_scale: float = 0.1, vertical_scale: float = 0.005, base_thickness_ratio: float = 1.0, border_width: float = 0.0) None#
- base_thickness_ratio: float = 1.0#
Ratio of the heightfield base thickness to its maximum surface height.
- border_width: float = 0.0#
Width of the flat border around the terrain edges, in meters. Must be >= horizontal_scale if non-zero.
- downsampled_scale: float | None = None#
Spacing between randomly sampled height points before interpolation, in meters. If None, uses horizontal_scale. Must be >= horizontal_scale.
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- noise_step: float = 0.005#
Height quantization step, in meters. Sampled heights are multiples of this value within noise_range.
- class mjlab.terrains.HfWaveTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, amplitude_range: tuple[float, float], num_waves: int = 1, horizontal_scale: float = 0.1, vertical_scale: float = 0.005, base_thickness_ratio: float = 0.25, border_width: float = 0.0) None#
- base_thickness_ratio: float = 0.25#
Ratio of the heightfield base thickness to its maximum surface height.
- border_width: float = 0.0#
Width of the flat border around the terrain edges, in meters. Must be >= horizontal_scale if non-zero.
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- class mjlab.terrains.BoxFlatTerrainCfg[source]#
Bases:
SubTerrainCfg
- class mjlab.terrains.BoxInvertedPyramidStairsTerrainCfg[source]#
Bases:
BoxPyramidStairsTerrainCfg
- class mjlab.terrains.BoxNarrowBeamsTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, num_beams: int = 16, beam_width_range: tuple[float, float] = (0.2, 0.4), beam_height: float = 0.2, spacing: float = 0.8, platform_width: float = 1.0, border_width: float = 0.25, floor_depth: float = 2.0) None#
- class mjlab.terrains.BoxNestedRingsTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, num_rings: int = 5, ring_width_range: tuple[float, float] = (0.3, 0.6), gap_range: tuple[float, float] = (0.0, 0.2), height_range: tuple[float, float] = (0.1, 0.4), platform_width: float = 1.0, border_width: float = 0.25, floor_depth: float = 2.0) None#
- class mjlab.terrains.BoxOpenStairsTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, step_height_range: tuple[float, float] = (0.1, 0.2), step_width_range: tuple[float, float] = (0.4, 0.8), platform_width: float = 1.0, border_width: float = 0.25, step_thickness: float = 0.05, inverted: bool = True) None#
- class mjlab.terrains.BoxPyramidStairsTerrainCfg[source]#
Bases:
SubTerrainCfgConfiguration for a pyramid stairs terrain.
- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, border_width: float = 0.0, step_height_range: tuple[float, float], step_width: float, platform_width: float = 1.0, holes: bool = False) None#
- border_width: float = 0.0#
Width of the flat border frame around the staircase, in meters. Ignored when holes is True.
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- platform_width: float = 1.0#
Side length of the flat square platform at the top of the staircase, in meters.
- class mjlab.terrains.BoxRandomGridTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, grid_width: float, grid_height_range: tuple[float, float], platform_width: float = 1.0, holes: bool = False, merge_similar_heights: bool = False, height_merge_threshold: float = 0.05, max_merge_distance: int = 3, border_width: float = 0.25) None#
- function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- height_merge_threshold: float = 0.05#
Maximum height difference between cells that can be merged, in meters.
- holes: bool = False#
If True, only the cross-shaped region around the center platform has grid cells.
- class mjlab.terrains.BoxRandomSpreadTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, num_boxes: int = 60, box_width_range: tuple[float, float] = (0.3, 1.0), box_length_range: tuple[float, float] = (0.3, 1.0), box_height_range: tuple[float, float] = (0.05, 1.0), box_yaw_range: tuple[float, float] = (0, 360), add_floor: bool = True, platform_width: float = 1.0, border_width: float = 0.25) None#
- class mjlab.terrains.BoxRandomStairsTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, step_width: float = 0.8, step_height_range: tuple[float, float] = (0.1, 0.3), platform_width: float = 1.0, border_width: float = 0.25) None#
- class mjlab.terrains.BoxSteppingStonesTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, stone_size_range: tuple[float, float] = (0.4, 0.8), stone_distance_range: tuple[float, float] = (0.2, 0.5), stone_height: float = 0.2, stone_height_variation: float = 0.1, stone_size_variation: float = 0.1, floor_depth: float = 2.0, displacement_range: float = 0.1, platform_width: float = 1.0, border_width: float = 0.25) None#
- class mjlab.terrains.BoxTiltedGridTerrainCfg[source]#
Bases:
SubTerrainCfg- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None, *, grid_width: float = 1.0, tilt_range_deg: float = 15.0, height_range: float = 0.1, platform_width: float = 1.0, border_width: float = 0.25, floor_depth: float = 2.0) None#
- class mjlab.terrains.FlatPatchSamplingCfg[source]#
Bases:
objectConfiguration for sampling flat patches on a heightfield surface.
- __init__(num_patches: int = 10, patch_radius: float = 0.5, max_height_diff: float = 0.05, x_range: tuple[float, float] = (-1000000.0, 1000000.0), y_range: tuple[float, float] = (-1000000.0, 1000000.0), z_range: tuple[float, float] = (-1000000.0, 1000000.0), grid_resolution: float | None = None) None#
- grid_resolution: float | None = None#
Resolution of the grid used for flat-patch detection, in meters. When
None(default), the terrain’s ownhorizontal_scaleis used. Set to a smaller value (e.g. 0.025) for finer boundary precision at the cost of a larger intermediate grid.
- max_height_diff: float = 0.05#
Maximum allowed height variation within the patch footprint, in meters.
- x_range: tuple[float, float] = (-1000000.0, 1000000.0)#
Allowed range of x coordinates for sampled patches, in meters.
- class mjlab.terrains.SubTerrainCfg[source]#
Bases:
ABC- __init__(proportion: float = 1.0, size: tuple[float, float] = (10.0, 10.0), flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None) None#
- flat_patch_sampling: dict[str, FlatPatchSamplingCfg] | None = None#
Named flat-patch sampling configurations, or None to disable.
- abstractmethod function(difficulty: float, spec: MjSpec, rng: Generator) TerrainOutput[source]#
Generate terrain geometry.
- Returns:
TerrainOutput containing spawn origin and list of geometries.
- proportion: float = 1.0#
Terrain type allocation weight (behavior depends on curriculum mode):
curriculum=True: Controls column allocation. Normalized proportions determine how many columns each terrain type occupies via cumulative distribution. Example: proportions [0.5, 0.5] with num_cols=2 gives one terrain per column.
curriculum=False: Sampling probability for each patch. Each patch independently samples a terrain type weighted by normalized proportions.
- class mjlab.terrains.TerrainGenerator[source]#
Bases:
objectGenerates procedural terrain grids with configurable difficulty.
Creates a grid of terrain patches where each patch can be a different terrain type. Supports two modes:
Random mode (curriculum=False): Every patch independently samples a terrain type weighted by proportions. Results in random variety across all patches.
Curriculum mode (curriculum=True): Columns are deterministically assigned to terrain types based on proportions. All patches in a column share the same terrain type, with difficulty increasing along rows. Use this to ensure each terrain type occupies specific column(s).
Terrain types are weighted by proportion and their geometry is generated based on a difficulty value in the configured range. The grid is centered at the world origin. A border can be added around the entire grid along with optional overhead lighting.
- __init__(cfg: TerrainGeneratorCfg, device: str = 'cpu') None[source]#
- class mjlab.terrains.TerrainGeneratorCfg[source]#
Bases:
object- __init__(*, seed: int | None = None, curriculum: bool = False, size: tuple[float, float], border_width: float = 0.0, border_height: float = 1.0, num_rows: int = 1, num_cols: int = 1, color_scheme: ~typing.Literal['height', 'random', 'none'] = 'height', sub_terrains: dict[str, ~mjlab.terrains.terrain_generator.SubTerrainCfg] = <factory>, difficulty_range: tuple[float, float] = (0.0, 1.0), add_lights: bool = False) None#
- color_scheme: Literal['height', 'random', 'none'] = 'height'#
Coloring strategy for terrain geometry. “height” colors by elevation, “random” assigns random colors, “none” uses uniform gray.
- curriculum: bool = False#
Controls terrain allocation mode:
curriculum=True: Each column gets ONE terrain type (deterministic allocation). Difficulty increases along rows. Use this to ensure each terrain type occupies its own column(s).
curriculum=False: Every patch is randomly sampled from all terrain types. Proportions control sampling probability. Use this for random variety.
Example: With 2 terrain types and num_cols=2, curriculum=True gives one terrain per column. curriculum=False gives a random mix of both types in all patches.
- difficulty_range: tuple[float, float] = (0.0, 1.0)#
Min and max difficulty values used when generating sub-terrains.
- num_cols: int = 1#
Number of sub-terrain columns in the grid. Represents terrain type variants. Note: Environments are evenly distributed across columns (not random).
- num_rows: int = 1#
Number of sub-terrain rows in the grid. Represents difficulty levels in curriculum mode. Note: Environments are randomly assigned to rows, so multiple envs can share the same patch.
- sub_terrains: dict[str, SubTerrainCfg]#
Named sub-terrain configurations to populate the grid.
- class mjlab.terrains.TerrainImporter[source]#
Bases:
objectBuilds a MuJoCo spec with terrain geometry and maps environments to spawn origins.
The terrain is a grid of sub-terrain patches (num_rows x num_cols), each with a spawn origin. When num_envs exceeds the number of patches, environment origins are sampled from the sub-terrain origins.
Note
Environment allocation for procedural terrain: Columns (terrain types) are evenly distributed across environments, but rows (difficulty levels) are randomly sampled. This means multiple environments can spawn on the same (row, col) patch, leaving others unoccupied, even when num_envs > num_patches.
See FAQ: “How does env_origins determine robot layout?”
- __init__(cfg: TerrainImporterCfg, device: str) None[source]#
- configure_env_origins(origins: ndarray | Tensor | None = None)[source]#
Configure the origins of the environments based on the added terrain.
- randomize_env_origins(env_ids: Tensor) None[source]#
Randomize the environment origins to random sub-terrains.
This randomizes both the terrain level (row) and terrain type (column), useful for play/evaluation mode where you want to test on varied terrains.
- property spec: MjSpec#
- class mjlab.terrains.TerrainImporterCfg[source]#
Bases:
objectConfiguration for terrain import and environment placement.
- __init__(terrain_type: Literal['generator', 'plane'] = 'plane', terrain_generator: TerrainGeneratorCfg | None = None, env_spacing: float | None = 2.0, max_init_terrain_level: int | None = None, num_envs: int = 1) None#
- env_spacing: float | None = 2.0#
Distance between environment origins when using grid layout. Required for “plane” terrain or when no sub-terrain origins exist.
- max_init_terrain_level: int | None = None#
Maximum initial difficulty level (row index) for environment placement in curriculum mode. None uses all available rows.
- num_envs: int = 1#
Number of parallel environments to create. This will get overridden by the scene configuration if specified there.
- terrain_generator: TerrainGeneratorCfg | None = None#
Configuration for procedural terrain generation. Required when terrain_type is “generator”.