Engine#

Core simulation engine components for GenesisLab.

Overview#

The engine module provides the core simulation infrastructure:

  • LabScene: Central simulation orchestrator

  • Scene Patterns: Builder, Controller, Querier patterns

  • MDP Interface: Reset and step functions

  • Genesis Integration: Interface to Genesis physics engine

LabScene#

LabScene is the central component that manages the entire simulation.

Class Definition#

class LabScene:
    """
    Central simulation manager that orchestrates all components.
    
    Attributes:
        cfg: Scene configuration
        num_envs: Number of parallel environments
        device: PyTorch device (CPU/GPU)
        scene: Genesis scene instance
        observation_manager: Observation computation
        action_manager: Action processing
        reward_manager: Reward calculation
        termination_manager: Termination checking
        command_manager: Command generation
        event_manager: Domain randomization
        curriculum_manager: Training curriculum
    """
    
    def __init__(self, cfg: LabSceneCfg, num_envs: int = 4096):
        """
        Initialize the scene.
        
        Args:
            cfg: Scene configuration
            num_envs: Number of parallel environments
        """
        pass

Configuration#

@configclass
class LabSceneCfg:
    # Simulation settings
    num_envs: int = 4096
    env_spacing: float = 4.0
    sim_dt: float = 0.005  # 5ms
    control_dt: float = 0.02  # 20ms (control frequency)
    
    # Physics settings
    gravity: tuple[float, float, float] = (0.0, 0.0, -9.81)
    
    # Rendering settings
    headless: bool = True
    viewer_camera_cfg: ViewerCameraCfg = ViewerCameraCfg()

MDP Interface#

reset()#

def reset(
    self,
    env_ids: torch.Tensor | None = None
) -> tuple[dict[str, torch.Tensor], dict]:
    """
    Reset the environment.
    
    Args:
        env_ids: Environment indices to reset. If None, reset all.
        
    Returns:
        Tuple of:
        - observations: Dictionary with 'obs' and optionally 'obs_critic'
        - info: Dictionary with reset information
        
    Example:
        >>> obs, info = scene.reset()
        >>> print(obs['obs'].shape)
        torch.Size([4096, 48])
    """
    pass

What happens during reset:

  1. Event manager applies reset events

  2. Scene controller resets robot states

  3. Command manager samples new commands

  4. Managers are reset

  5. Initial observations computed

step()#

def step(
    self,
    actions: torch.Tensor
) -> tuple[dict[str, torch.Tensor], torch.Tensor, torch.Tensor, torch.Tensor, dict]:
    """
    Step the environment.
    
    Args:
        actions: Action tensor [num_envs, action_dim]
        
    Returns:
        Tuple of:
        - observations: Dictionary with 'obs' and optionally 'obs_critic'
        - rewards: Reward tensor [num_envs]
        - terminated: Boolean tensor [num_envs]
        - truncated: Boolean tensor [num_envs]
        - info: Dictionary with step information
        
    Example:
        >>> action = torch.randn(4096, 12)
        >>> obs, rew, term, trunc, info = scene.step(action)
    """
    pass

What happens during step:

  1. Action manager processes actions

  2. Scene controller applies motor commands

  3. Genesis physics simulation steps

  4. Event manager applies interval events

  5. Observations computed

  6. Rewards computed

  7. Terminations checked

  8. Environments auto-reset if needed

Properties#

@property
def num_envs(self) -> int:
    """Number of parallel environments."""
    pass

@property
def device(self) -> torch.device:
    """PyTorch device."""
    pass

@property
def dt(self) -> float:
    """Simulation timestep in seconds."""
    pass

@property
def episode_length(self) -> torch.Tensor:
    """Current episode length for each environment."""
    pass

Scene Patterns#

SceneBuilder#

Constructs the initial scene during setup.

class SceneBuilder:
    """
    Builds the Genesis scene with terrain, robots, sensors, etc.
    """
    
    def build(self, scene: gs.Scene, cfg: LabSceneCfg) -> dict:
        """
        Build the complete scene.
        
        Args:
            scene: Genesis scene instance
            cfg: Scene configuration
            
        Returns:
            Dictionary of created entities
        """
        entities = {}
        
        # Build terrain
        entities['terrain'] = self.build_terrain(scene, cfg.terrain)
        
        # Build robots
        entities['robot'] = self.build_robot(scene, cfg.robot)
        
        # Build sensors
        entities['sensors'] = self.build_sensors(scene, cfg.sensors)
        
        # Build objects
        entities['objects'] = self.build_objects(scene, cfg.objects)
        
        return entities
    
    def build_terrain(
        self,
        scene: gs.Scene,
        cfg: TerrainCfg
    ) -> gs.Entity:
        """Build terrain."""
        pass
    
    def build_robot(
        self,
        scene: gs.Scene,
        cfg: RobotCfg
    ) -> gs.Entity:
        """Build robot."""
        pass

SceneController#

Modifies scene state during simulation.

class SceneController:
    """
    Controls and modifies the scene during simulation.
    """
    
    def apply_actions(
        self,
        scene: gs.Scene,
        actions: torch.Tensor,
        env_ids: torch.Tensor | None = None
    ):
        """
        Apply actions to robots.
        
        Args:
            scene: Genesis scene
            actions: Action tensor
            env_ids: Environment indices (None = all)
        """
        pass
    
    def reset_robots(
        self,
        scene: gs.Scene,
        env_ids: torch.Tensor,
        cfg: ResetCfg
    ):
        """
        Reset robot states.
        
        Args:
            scene: Genesis scene
            env_ids: Environments to reset
            cfg: Reset configuration
        """
        pass

SceneQuerier#

Reads data from the scene without modifying it.

class SceneQuerier:
    """
    Queries scene state for observations and rewards.
    """
    
    def get_robot_state(
        self,
        scene: gs.Scene,
        env_ids: torch.Tensor | None = None
    ) -> dict[str, torch.Tensor]:
        """
        Get robot state.
        
        Returns:
            Dictionary with robot state tensors:
            - 'joint_pos': Joint positions
            - 'joint_vel': Joint velocities
            - 'base_pos': Base position
            - 'base_quat': Base orientation
            - 'base_lin_vel': Base linear velocity
            - 'base_ang_vel': Base angular velocity
        """
        pass
    
    def get_sensor_data(
        self,
        scene: gs.Scene,
        sensor_name: str
    ) -> torch.Tensor:
        """Get sensor measurements."""
        pass
    
    def get_contact_forces(
        self,
        scene: gs.Scene,
        body_names: list[str]
    ) -> torch.Tensor:
        """Get contact forces on specified bodies."""
        pass

Genesis Integration#

Scene Creation#

import genesis as gs

# Initialize Genesis
gs.init(backend=gs.gpu)

# Create scene
scene = gs.Scene(
    show_viewer=not headless,
    sim_options=gs.options.SimOptions(
        dt=sim_dt,
        gravity=gravity
    ),
    vis_options=gs.options.VisOptions(
        show_world_frame=True
    )
)

# Build scene
scene.build()

Entity Access#

# Access robot
robot = scene.entities['robot']

# Get DOF positions
dof_pos = robot.get_dofs_position()  # [num_envs, num_dof]

# Set DOF targets
robot.set_dofs_position_target(targets)

# Get link states
link_pos = robot.get_links_pos()  # [num_envs, num_links, 3]

Usage Examples#

Basic Scene Setup#

# Create configuration
cfg = LabSceneCfg(
    num_envs=4096,
    env_spacing=4.0,
    sim_dt=0.005
)

# Create scene
scene = LabScene(cfg)

# Reset
obs, info = scene.reset()

# Run simulation
for _ in range(1000):
    action = policy(obs['obs'])
    obs, rew, term, trunc, info = scene.step(action)

Custom Scene Builder#

class MySceneBuilder(SceneBuilder):
    def build_robot(self, scene: gs.Scene, cfg: RobotCfg):
        # Load URDF
        robot = scene.add_entity(
            gs.morphs.URDF(
                file=cfg.urdf_path,
                pos=(0, 0, 0.5)
            )
        )
        return robot

Next Steps#