Source code for genesis.engine.materials.rigid

from typing import TYPE_CHECKING

import genesis as gs

from .kinematic import Kinematic

if TYPE_CHECKING:
    from genesis.engine.entities.rigid_entity import RigidEntity


[docs]class Rigid(Kinematic["RigidEntity"]): """ The Rigid class represents a material used in rigid body simulation. Note ---- This class is intended for use with the rigid solver and provides parameters relevant to physical interactions such as friction, density, and signed distance fields (SDFs). Parameters ---------- rho : float, optional The density of the material used to compute mass. Default is 200.0. friction : float, optional Friction coefficient within the rigid solver. If None, a default of 1.0 may be used or parsed from file. needs_coup : bool, optional Whether the material participates in coupling with other solvers. Default is True. coup_friction : float, optional Friction used during coupling. Must be non-negative. Default is 0.1. coup_softness : float, optional Softness of coupling interaction. Must be non-negative. Default is 0.002. coup_restitution : float, optional Restitution coefficient in collision coupling. Should be between 0 and 1. Default is 0.0. sdf_cell_size : float, optional Cell size in SDF grid in meters. Defines grid resolution. Default is 0.005. sdf_min_res : int, optional Minimum resolution of the SDF grid. Must be at least 16. Default is 32. sdf_max_res : int, optional Maximum resolution of the SDF grid. Must be >= sdf_min_res. Default is 128. gravity_compensation : float, optional Compensation factor for gravity. 1.0 cancels gravity. Default is 0. coup_type : str or None, optional Coupling mode for this entity. Only used by the IPC coupler. Requires ``needs_coup=True``. If None, auto-selected based on entity type: ``'external_articulation'`` for fixed-base articulated robots, ``'two_way_soft_constraint'`` for floating-base robots, and ``'ipc_only'`` for non-articulated objects. Valid values: - 'two_way_soft_constraint': Two-way soft coupling. - 'external_articulation': Joint-level coupling for articulated bodies. Joint positions will be coupled at the DOF level. - 'ipc_only': IPC controls entity, transforms copied to Genesis (one-way). Only supported by rigid non-articulated objects. Default is None. coup_links : tuple of str or None, optional Tuple of link names to include in coupling. When set, only the named links participate in coupling; other links are excluded. Only supported with needs_coup=True and ``two_way_soft_constraint`` type in IPC. Default is None. enable_coup_collision : bool, optional Whether coupler collision is enabled for this entity's links. Only used by the IPC coupler. Unlike ``needs_coup=False`` (which removes the entity from the coupler entirely), setting this to False keeps the entity in the coupler for coupling forces but disables contact response. Default is True. coup_collision_links : tuple of str or None, optional Tuple of link names whose geoms participate in coupler collision. Only used by the IPC coupler. Only effective when ``enable_coup_collision=True``. If None, all coupled links have collision. When set, only the named links get coupler collision; other links are marked no-collision. Default is None. contact_resistance : float or None, optional IPC coupling contact resistance/stiffness override for this entity. ``None`` means use ``IPCCouplerOptions.contact_resistance``. Default is None. """ def __init__( self, rho=200.0, friction=None, needs_coup=True, coup_friction=0.1, coup_softness=0.002, coup_restitution=0.0, sdf_cell_size=0.005, sdf_min_res=32, sdf_max_res=128, gravity_compensation=0.0, coup_type=None, coup_links=None, enable_coup_collision=True, coup_collision_links=None, contact_resistance=None, ): super().__init__() if coup_type is not None: if not needs_coup: gs.raise_exception( "`coup_type` is only supported with needs_coup=True. " f"Got needs_coup={needs_coup}, coup_type='{coup_type}'." ) if coup_type not in ("two_way_soft_constraint", "external_articulation", "ipc_only"): gs.raise_exception( f"`coup_type` must be one of None, 'two_way_soft_constraint', " f"'external_articulation', or 'ipc_only', got '{coup_type}'." ) if coup_links is not None and (not needs_coup or coup_type not in (None, "two_way_soft_constraint")): gs.raise_exception( "`coup_links` is only supported with needs_coup=True and 'two_way_soft_constraint' type in IPC. " f"Got needs_coup={needs_coup}, coup_type='{coup_type}'." ) if coup_collision_links is not None and not enable_coup_collision: gs.raise_exception( "`coup_collision_links` is only effective when `enable_coup_collision=True`. " "Set `enable_coup_collision=False` to disable collision for all links." ) if friction is not None: if friction < 1e-2 or friction > 5.0: gs.raise_exception("`friction` must be in the range [1e-2, 5.0] for simulation stability.") if coup_friction < 0: gs.raise_exception("`coup_friction` must be non-negative.") if coup_softness < 0: gs.raise_exception("`coup_softness` must be non-negative.") if contact_resistance is not None and contact_resistance <= 0: gs.raise_exception("`contact_resistance` must be strictly positive.") if coup_restitution < 0 or coup_restitution > 1: gs.raise_exception("`coup_restitution` must be in the range [0, 1].") if coup_restitution != 0: gs.logger.warning("Non-zero `coup_restitution` could lead to instability. Use with caution.") if sdf_min_res < 16: gs.raise_exception("`sdf_min_res` must be at least 16.") if sdf_min_res > sdf_max_res: gs.raise_exception("`sdf_min_res` must be smaller than or equal to `sdf_max_res`.") # ipc_only entities have their dynamics fully controlled by IPC (gravity + collision). # Genesis gravity must be disabled to avoid double-counting. if coup_type == "ipc_only": if abs(gravity_compensation) > gs.EPS: gs.raise_exception("User-specified `gravity_compensation` not supported with coup_type='ipc_only'.") self._friction = float(friction) if friction is not None else None self._needs_coup = bool(needs_coup) self._coup_friction = float(coup_friction) self._coup_softness = float(coup_softness) self._coup_restitution = float(coup_restitution) self._sdf_cell_size = float(sdf_cell_size) self._sdf_min_res = int(sdf_min_res) self._sdf_max_res = int(sdf_max_res) self._rho = float(rho) self._gravity_compensation = float(gravity_compensation) self._coup_type = coup_type self._coup_links = tuple(coup_links) if coup_links is not None else None self._enable_coup_collision = bool(enable_coup_collision) self._coup_collision_links = tuple(coup_collision_links) if coup_collision_links is not None else None self._contact_resistance = float(contact_resistance) if contact_resistance is not None else None @property def gravity_compensation(self) -> float: """Gravity compensation factor. 1.0 cancels gravity.""" return self._gravity_compensation @property def friction(self) -> float | None: """Friction coefficient used within the rigid solver.""" return self._friction @property def needs_coup(self) -> bool: """Whether this material requires solver coupling.""" return self._needs_coup @property def coup_friction(self) -> float: """Friction coefficient used in coupling interactions.""" return self._coup_friction @property def coup_softness(self) -> float: """Softness parameter controlling the influence range of coupling.""" return self._coup_softness @property def coup_restitution(self) -> float: """Restitution coefficient used during contact in coupling.""" return self._coup_restitution @property def contact_resistance(self) -> float | None: """IPC coupling contact resistance/stiffness override, or None for coupler default.""" return self._contact_resistance @property def sdf_cell_size(self) -> float: """Size of each SDF grid cell in meters.""" return self._sdf_cell_size @property def sdf_min_res(self) -> int: """Minimum allowed resolution for the SDF grid.""" return self._sdf_min_res @property def sdf_max_res(self) -> int: """Maximum allowed resolution for the SDF grid.""" return self._sdf_max_res @property def rho(self) -> float: """Density of the rigid material.""" return self._rho @property def coup_type(self) -> str | None: """IPC coupling mode for this entity.""" return self._coup_type @property def coup_links(self) -> tuple[str, ...] | None: """Tuple of link names to include in coupling.""" return self._coup_links @property def enable_coup_collision(self) -> bool: """Whether IPC collision is enabled for this entity's links.""" return self._enable_coup_collision @property def coup_collision_links(self) -> tuple[str, ...] | None: """Tuple of link names whose geoms participate in IPC collision. None = all coupled links.""" return self._coup_collision_links