import numpy as np from numpy.random import choice from scipy import interpolate from isaacgym import terrain_utils from legged_gym.envs.base.legged_robot_config import LeggedRobotCfg class Terrain: def __init__(self, cfg: LeggedRobotCfg.terrain, num_robots) -> None: self.cfg = cfg self.num_robots = num_robots self.type = cfg.mesh_type if self.type in ["none", 'plane']: return self.env_length = cfg.terrain_length self.env_width = cfg.terrain_width self.proportions = [np.sum(cfg.terrain_proportions[:i+1]) for i in range(len(cfg.terrain_proportions))] self.cfg.num_sub_terrains = cfg.num_rows * cfg.num_cols self.env_origins = np.zeros((cfg.num_rows, cfg.num_cols, 3)) self.width_per_env_pixels = int(self.env_width / cfg.horizontal_scale) self.length_per_env_pixels = int(self.env_length / cfg.horizontal_scale) self.border = int(cfg.border_size/self.cfg.horizontal_scale) self.tot_cols = int(cfg.num_cols * self.width_per_env_pixels) + 2 * self.border self.tot_rows = int(cfg.num_rows * self.length_per_env_pixels) + 2 * self.border self.height_field_raw = np.zeros((self.tot_rows , self.tot_cols), dtype=np.int16) if cfg.curriculum: self.curiculum() elif cfg.selected: self.selected_terrain() else: self.randomized_terrain() self.heightsamples = self.height_field_raw if self.type=="trimesh": self.vertices, self.triangles = terrain_utils.convert_heightfield_to_trimesh( self.height_field_raw, self.cfg.horizontal_scale, self.cfg.vertical_scale, self.cfg.slope_treshold) def randomized_terrain(self): for k in range(self.cfg.num_sub_terrains): # Env coordinates in the world (i, j) = np.unravel_index(k, (self.cfg.num_rows, self.cfg.num_cols)) choice = np.random.uniform(0, 1) difficulty = np.random.choice([0.5, 0.75, 0.9]) terrain = self.make_terrain(choice, difficulty) self.add_terrain_to_map(terrain, i, j) def curiculum(self): for j in range(self.cfg.num_cols): for i in range(self.cfg.num_rows): difficulty = i / self.cfg.num_rows choice = j / self.cfg.num_cols + 0.001 terrain = self.make_terrain(choice, difficulty) self.add_terrain_to_map(terrain, i, j) def selected_terrain(self): terrain_type = self.cfg.terrain_kwargs.pop('type') for k in range(self.cfg.num_sub_terrains): # Env coordinates in the world (i, j) = np.unravel_index(k, (self.cfg.num_rows, self.cfg.num_cols)) terrain = terrain_utils.SubTerrain("terrain", width=self.width_per_env_pixels, length=self.width_per_env_pixels, vertical_scale=self.vertical_scale, horizontal_scale=self.horizontal_scale) eval(terrain_type)(terrain, **self.cfg.terrain_kwargs.terrain_kwargs) self.add_terrain_to_map(terrain, i, j) def make_terrain(self, choice, difficulty): terrain = terrain_utils.SubTerrain( "terrain", width=self.width_per_env_pixels, length=self.width_per_env_pixels, vertical_scale=self.cfg.vertical_scale, horizontal_scale=self.cfg.horizontal_scale) slope = difficulty * 0.4 step_height = 0.05 + 0.18 * difficulty discrete_obstacles_height = 0.05 + difficulty * 0.2 stepping_stones_size = 1.5 * (1.05 - difficulty) stone_distance = 0.05 if difficulty==0 else 0.1 gap_size = 1. * difficulty pit_depth = 1. * difficulty if choice < self.proportions[0]: if choice < self.proportions[0]/ 2: slope *= -1 terrain_utils.pyramid_sloped_terrain(terrain, slope=slope, platform_size=3.) elif choice < self.proportions[1]: terrain_utils.pyramid_sloped_terrain(terrain, slope=slope, platform_size=3.) terrain_utils.random_uniform_terrain(terrain, min_height=-0.05, max_height=0.05, step=0.005, downsampled_scale=0.2) elif choice < self.proportions[3]: if choice