simulo.SurfaceGripperActuator
Surface gripper actuator.
A surface gripper uses physics constraints to attach to nearby objects. The gripper has three states: OPEN, CLOSING, CLOSED.
Command Interface:
command < -0.3: Open the gripper-0.3 ≤ command ≤ 0.3: Idle (hold state)command > 0.3: Close the gripper
Pass a GripperCommand for scripted intent or a raw float
for a policy’s continuous action — see that enum for which to use when.
This band is the engine’s and is not configurable here. Unlike
ParallelGripperActuator, whose dead band this SDK evaluates
itself, a surface gripper’s command is buffered and classified inside
the engine, against ±0.3 written into the engine’s own source. This
class therefore takes no open_threshold / close_threshold: it
used to accept both, assign both, and read neither, which made the
knob a promise nothing kept. Passing either now raises TypeError
rather than being silently ignored.
State Interface:
- OPEN (-1): Gripper is open, not grasping
- CLOSING (0): Gripper is attempting to grasp
- CLOSED (1): Gripper has grasped an object
Example:
import simulo
# Create grippergripper = simulo.SurfaceGripperActuator( max_grip_distance=0.1, shear_force_limit=500.0)
# Add to scene (path is set here, consistent with robots)scene.add(gripper, at="/World/Robot/ee_link/Gripper")
# Control gripper (commands are automatically flushed before world.step())gripper.set_command(simulo.GripperCommand.CLOSE)# No write_to_sim() needed - automatically flushed before physics stepworld.step()gripper.update(dt)states = gripper.get_state()Backend Mapping:
IsaacLab: Maps to isaaclab.assets.SurfaceGripper. Commands are
forwarded verbatim to set_grippers_command, which documents the
fixed band quoted above and hands the raw value on to Isaac Sim’s
gripper view — which is why this class does not rescale or re-band a
command on the way through.
Note:
Path patterns (e.g., /World/Robot.*/gripper) are a special optimization for
batch operations and RL training scenarios. For typical applications with
independent control per robot, create separate actuator instances:
# Typical pattern: one actuator per robotgripper_1 = simulo.SurfaceGripperActuator(...)scene.add(gripper_1, at="/World/Robot1/gripper")
gripper_2 = simulo.SurfaceGripperActuator(...)scene.add(gripper_2, at="/World/Robot2/gripper")Attributes:
path— Scene path where gripper is attached. Supports wildcard patterns (e.g.,.*) for multi-instance batch operations, but typically use one actuator per robot.max_grip_distance— Maximum distance to grasp objects (meters)shear_force_limit— Force limit perpendicular to gripper axis (N)coaxial_force_limit— Force limit along gripper axis (N)retry_interval— Time gripper stays in grasping state (seconds)
simulo.SurfaceGripperActuator( path: Optional[str] = None, max_grip_distance: float = 0.1, shear_force_limit: float = 500.0, coaxial_force_limit: float = 500.0, retry_interval: float = 0.1, enabled: bool = True,)set_command()
Section titled “set_command()”SurfaceGripperActuator.set_command(command: Union[GripperCommand, float]) -> NoneSet gripper command for single instance.
Command behavior (the engine’s fixed band — see the class docstring):
- command < -0.3: Open gripper
- -0.3 ≤ command ≤ 0.3: Idle (maintain state)
- command > 0.3: Close gripper
Args:
command— AGripperCommand(OPEN/IDLE/CLOSE) for scripted intent, or a raw command value in range [-1, 1] — typically a policy’s continuous action, which is why the dead band above exists.GripperCommandis anIntEnum, so it travels the same float path with no conversion.
Raises:
TypeError— If given aGripperState. Both enums areIntEnum, so a state passed where a command belongs would otherwise be accepted and silently mean something else.
set_commands()
Section titled “set_commands()”SurfaceGripperActuator.set_commands(commands: Sequence[Union[GripperCommand, float]]) -> NoneSet commands for multiple gripper instances.
Args:
commands— One command value per instance — each aGripperCommandor a raw float (the two may be mixed).
Raises:
ValueError— If the count does not match the instance count. The check is unconditional: it used to be skipped whenever the count was one, which is also what “not attached yet” reports, so an over-long batch reached the engine and failed there as a tensor-shape error naming a mask instead of the input.TypeError— If any element is aGripperState.
get_state()
Section titled “get_state()”SurfaceGripperActuator.get_state() -> List[GripperState]Get current gripper state for all instances.
Returns:
List of GripperState values, one per instance: - OPEN (-1): Not grasping - CLOSING (0): Attempting to grasp - CLOSED (1): Grasping object Before the first update() the list is the pre-attach placeholder — one OPEN per instance the actuator knows about, which is a single entry until the engine attaches it. Read it after update(dt), not before, if you need one entry per environment.
is_open()
Section titled “is_open()”SurfaceGripperActuator.is_open(instance: int = 0) -> boolCheck if gripper instance is open.
Args:
instance— Gripper instance index
Returns:
True if gripper is open
is_closed()
Section titled “is_closed()”SurfaceGripperActuator.is_closed(instance: int = 0) -> boolCheck if gripper instance is closed (grasping).
Args:
instance— Gripper instance index
Returns:
True if gripper is closed/grasping
update()
Section titled “update()”SurfaceGripperActuator.update(dt: float) -> NoneUpdate gripper state from simulation.
Args:
dt— Time step in seconds
reset()
Section titled “reset()”SurfaceGripperActuator.reset(env_ids: Optional[Any] = None) -> NoneReset gripper instances to the open state.
Args:
env_ids— Instance indices to reset — a tensor, a sequence of ints, orNonefor all of them. Pass the ids. RL environments reset per-environment (Task.reset_idx(env_ids)), and this actuator is not registered with the scene, so nothing resets it on your behalf; an all-instances reset triggered by one environment terminating physically opens every other gripper mid-grasp. The engine’s ownSurfaceGripper.reset(indices=...)has taken indices all along — this signature is what makes them reachable.