Grasp Sampling¶
Grasp samplers propose 6-DoF grasps of an object in a built env, from a camera's point cloud or the object's own
cloud, for a given end effector. A sampler is a GraspSamplerBase
subclass registered in GRASP_SAMPLER_REGISTRY and returns a GraspResult. Two backends ship: GraspGen (one model
per gripper) and GraspGenX (one cross-embodiment model, the gripper selected by name). The
grasp sampling guide covers installation and use.
from eden.extensions.grasp_sampling.base import GRASP_SAMPLER_REGISTRY, GraspResult, GraspSamplerBase
from eden.options.extensions.grasp_sampling import GraspSamplerOptions
Base class, result and registry¶
Base class and result type for grasp samplers.
A grasp sampler turns one entity's point cloud into 6-DoF grasp poses. :class:GraspSamplerBase
owns everything that is the same for every backend — reading the target's points off the camera or
its surface, the obstacle cloud for collision filtering, ranking, the frame the poses place, and
packing the result into Eden's pos / wxyz quat tensors — so a backend only implements
:meth:~GraspSamplerBase._infer (the model call), declares its pose frame, and, if its grippers
carry collision geometry, implements :meth:~GraspSamplerBase._collision_free.
Frames. Every backend's model returns grasp frames: z is the approach direction and x the
direction the fingers close along, whatever the gripper. A grasp frame is generally no link of the
real gripper. Each backend therefore names the frame its poses place instead (GraspGenX: its gripper
description's base link), and with end_effector= an Eden robot's link, from the pairings it has
verified (:attr:GraspSamplerBase.END_EFFECTORS).
One call samples for one env (sample_grasps(..., env_idx=)), or for several with one render and
one batched model call (:meth:GraspSamplerBase.sample_grasps_batch). In a batched env the camera
must render each env on its own (EnvOptions(env_separate_rigid=True) or the batch renderer): a
shared view holds every env's copy of the target under one segmentation id.
Attributes¶
GRASP_SAMPLER_REGISTRY
module-attribute
¶
GRASP_SAMPLER_REGISTRY = Registry('GRASP_SAMPLER', populated_by=('eden.extensions.grasp_sampling.graspgen.sampler', 'eden.extensions.grasp_sampling.graspgenx.sampler'))
Classes¶
EndEffectorPairing
dataclass
¶
EndEffectorPairing(gripper: str, link_name: str, link_in_frame: tuple[tuple[float, float, float], tuple[float, float, float, float]] = IDENTITY_POSE)
How one of a backend's grippers maps onto an Eden robot's link.
| ATTRIBUTE | DESCRIPTION |
|---|---|
gripper |
The backend's gripper: the value of its gripper option (GraspGenX's
TYPE:
|
link_name |
The Eden robot's link each pose then places.
TYPE:
|
link_in_frame |
That link's pose,
TYPE:
|
GraspResult
dataclass
¶
World-frame grasp poses, best first.
Each pose places the sampler's :attr:~GraspSamplerBase.pose_link_name.
| ATTRIBUTE | DESCRIPTION |
|---|---|
pos |
Grasp positions, shape
TYPE:
|
quat |
Grasp orientations as wxyz quaternions, shape
TYPE:
|
confidences |
Discriminator confidences in
TYPE:
|
Attributes¶
Methods:¶
from_transforms
classmethod
¶
from_transforms(transforms: ndarray, confidences: ndarray, device: device, max_grasps: int | None = None) -> GraspResult
Rank (n, 4, 4) world-frame transforms by confidence and convert them to pos/quat.
Source code in eden/extensions/grasp_sampling/base.py
GraspSamplerBase
¶
GraspSamplerBase(env: EnvBase, options: GraspSamplerOptions)
Bases: ConfigurableMixin[GraspSamplerOptions], ABC
Abstract base class for grasp samplers.
The shared options (camera_name, object_cloud, grasp_threshold, max_grasps,
filter_collisions, end_effector, …) are documented on
:class:~eden.options.extensions.grasp_sampling.GraspSamplerOptions.
A backend's __init__ calls :meth:_set_pose_frame once it knows its gripper, naming the
frame its poses place without a pairing.
| PARAMETER | DESCRIPTION |
|---|---|
env
|
The built environment the grasps are sampled in. With
TYPE:
|
options
|
From the backend's
TYPE:
|
Source code in eden/extensions/grasp_sampling/base.py
Attributes¶
object_cloud
class-attribute
instance-attribute
¶
object_cloud: Literal['camera', 'surface'] = 'camera'
collision_ignore_entities
class-attribute
instance-attribute
¶
camera
instance-attribute
¶
camera: Camera | None = self._resolve_camera() if reads_camera else None
pose_link_name
property
¶
pose_link_name: str | None
The link each returned pose places: end_effector's link when set, else the backend's own.
None when the poses are the backend's grasp frame itself, which is no link of the gripper
(GraspGen without end_effector).
approach_axis
property
¶
The approach direction, a unit vector of shape (3,) in the posed link's frame, on the env's device.
A grasp moves the gripper along this axis onto the object, so a pregrasp backs off along it:
pos - transform_by_quat(approach_axis[None], quat) * distance.
closing_axis
property
¶
The direction the fingers close along, a unit vector of shape (3,) in the posed link's frame.
With :attr:approach_axis and :attr:tcp_offset it is what a scripted demonstrator's top-down
move_to(pos, yaw) needs from a grasp: the heading of
transform_by_quat(closing_axis[None], quat) is the one its fingers must close along.
tcp_offset
property
¶
The TCP in the posed link's frame, shape (3,), on the env's device.
The TCP is the point the grasp puts on the object (for a parallel jaw, the fingertip center),
so pos + transform_by_quat(tcp_offset[None], quat) is where a grasp puts it.
Methods:¶
sample_grasps
¶
sample_grasps(entity_name: str, env_idx: int = 0) -> GraspResult
Sample grasps of entity entity_name in its current pose, in env env_idx.
| PARAMETER | DESCRIPTION |
|---|---|
entity_name
|
The entity to grasp.
TYPE:
|
env_idx
|
The env to sample in. The returned poses are world-frame poses of that env's copy.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
GraspResult
|
World-frame grasps, best first. Empty ( |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
When there are no points of the entity to sample from: the camera sees none of it
( |
Source code in eden/extensions/grasp_sampling/base.py
sample_grasps_batch
¶
sample_grasps_batch(entity_name: str, envs_idx: Sequence[int] | None = None) -> list[GraspResult]
Sample grasps of entity entity_name in several envs at once.
The camera renders once for all of them and the model runs once on all their clouds, where
:meth:sample_grasps per env would render the whole batch and run the model for each. A
scripted demonstrator that runs one routine per env samples every env here first and hands
each routine its result.
| PARAMETER | DESCRIPTION |
|---|---|
entity_name
|
The entity to grasp.
TYPE:
|
envs_idx
|
The envs to sample in; |
| RETURNS | DESCRIPTION |
|---|---|
list[GraspResult]
|
One result per entry of |
Source code in eden/extensions/grasp_sampling/base.py
Functions:¶
Options¶
Configuration options for grasp-sampling extensions.
:class:GraspSamplerOptions mirrors
:class:~eden.extensions.grasp_sampling.base.GraspSamplerBase's attributes, so the fields every
backend shares are type-checked at configure() time. Backend-specific knobs stay as class
attributes on the backend and arrive as extras — e.g. GraspGen's gripper_config or GraspGenX's
gripper_name / planner.
:class:GraspMoEOptions groups GraspGenX's GraspMoE planner knobs so they validate as a unit
(extra="forbid" plus Literal choices) instead of reaching the planner unchecked.
Classes¶
GraspSamplerOptions
¶
Bases: DynamicConfigurableOptions
Options shared by every grasp-sampling backend.
| PARAMETER | DESCRIPTION |
|---|---|
camera_name
|
Camera whose point cloud the sampler reads: the target's visible points when
TYPE:
|
object_cloud
|
Where the target's points come from.
TYPE:
|
surface_points
|
Points sampled over the entity's surface when
TYPE:
|
grasp_threshold
|
Discriminator confidence, in
TYPE:
|
num_grasps
|
Grasps the generator proposes per inference pass, before thresholding.
TYPE:
|
max_grasps
|
Keep at most this many of the highest-confidence grasps.
TYPE:
|
filter_collisions
|
Drop grasps whose gripper collision mesh comes within
TYPE:
|
collision_threshold
|
Distance in meters under which a gripper surface point counts as colliding.
TYPE:
|
collision_ignore_entities
|
Entities left out of the obstacle cloud; names are checked whether or not the filter is on.
|
max_scene_points
|
Randomly downsample the obstacle cloud to at most this many points before the check.
TYPE:
|
seed
|
Seed of the obstacle cloud's downsampling. It does not make grasps reproducible: neither the surface sampling nor the model's own sampling reads it.
TYPE:
|
end_effector
|
The Eden robot that executes the grasps, by its robot options class name (e.g.
TYPE:
|
Source code in eden/options/options.py
Attributes¶
object_cloud
class-attribute
instance-attribute
¶
object_cloud: Literal['camera', 'surface'] = 'camera'
grasp_threshold
class-attribute
instance-attribute
¶
grasp_threshold: float = Field(default=0.8, ge=0.0, le=1.0)
collision_threshold
class-attribute
instance-attribute
¶
collision_threshold: float = Field(default=0.02, gt=0.0)
collision_ignore_entities
class-attribute
instance-attribute
¶
GraspMoEOptions
¶
Bases: ConfigurableOptions
GraspGenX's GraspMoE planner knobs (GraspGenXSampler.planner="graspmoe").
GraspMoE scores the union of the diffusion model's grasps and a set of grasps swept over the
object's oriented bounding box (OBB). These fields tune only the OBB branch. The defaults are
those of GraspGenX's own scripts/demo_object_pc.py.
| PARAMETER | DESCRIPTION |
|---|---|
num_yaws
|
World-Z yaw samples of the OBB sweep.
TYPE:
|
z_offsets_cm
|
Offsets in cm, relative to the OBB top, at which candidates are placed. |
outlier_threshold
|
Distance threshold in meters of the outlier removal run on the object cloud.
TYPE:
|
outlier_k
|
Neighbour count of that outlier removal.
TYPE:
|
obb_mode
|
How the OBB is fitted.
TYPE:
|
skip_obb_rule
|
TYPE:
|
obb_density
|
How densely candidates are placed over the OBB:
TYPE:
|
obb_position_spacing_cm
|
Spacing in cm of candidate positions along the OBB's long axis; read by the
TYPE:
|
Source code in eden/options/options.py
GraspGenX¶
Eden wrapper around GraspGenX: cross-embodiment 6-DoF grasp generation.
GraspGenX (NVlabs/GraspGenX <https://github.com/NVlabs/GraspGenX>) conditions one diffusion
model, and its discriminator, on a gripper description: the gripper's swept volume, its open and
closed point clouds, and its URDF. A gripper is therefore picked by name, with no per-gripper model.
Eden consumes the inference-only fork Kashu7100/GraspGenX <https://github.com/Kashu7100/GraspGenX>,
published as eden-graspgenx (import name graspgenx) and installed by the graspgenx
extra. The checkpoints and the gripper descriptions download from Hugging Face on first use. See
docs/guides/grasp-sampling.md.
Frames. GraspGenX poses a grasp at the world link of the description's URDF: its z axis is
the approach direction and its x axis the closing direction, whatever the gripper. That frame is no
link of the real gripper; the description welds the gripper's base link to it through a fixed
world_joint (rotated 90° about z for the Franka hand and the Robotiq 2F-85, offset by several
centimeters for the dexterous hands). The sampler applies that joint, so each pose it returns is
the pose of the description's base link (pose_link_name) — or, with end_effector=, of the
Eden robot's link it pairs that base link with (:attr:GraspGenXSampler.END_EFFECTORS).
Attributes¶
GraspGenXGripper
module-attribute
¶
GraspGenXGripper = Literal['abb_yumi', 'arx_x5', 'fetch_robot', 'franka_panda', 'franka_umi', 'galaxea_g1', 'piper_hand', 'robotiq_hande', 'bd_spot', 'dh_ag95', 'ezgripper', 'onrobot_RG2', 'onrobot_RG6', 'robotiq_2f_140', 'robotiq_2f_85', 'sawyer_hand', 'schunk_wsg50', 'tesollo_delto2f', 'xarm_hand', 'barrett_hand', 'inspire_hand', 'robotiq_3f', 'sharpa_wave', 'surge_hand', 'unitree_g1', 'wuji_hand']
GraspGenXEndEffector
module-attribute
¶
GraspGenXEndEffector = Literal['FrankaEmikaPanda', 'FrankaHand', 'InspireRH56_R', 'Robotiq2f85', 'SharpaWave_R', 'WujiHand1_R']
Classes¶
GraspGenXSampler
¶
GraspGenXSampler(env: EnvBase, options: GraspSamplerOptions)
Bases: GraspSamplerBase
Sample grasps with GraspGenX for any gripper it has a description of.
The shared options (camera_name, object_cloud, grasp_threshold, max_grasps, …)
are documented on :class:~eden.options.extensions.grasp_sampling.GraspSamplerOptions; the
fields below are GraspGenX's own and reach the options as extras. grasp_threshold defaults
to 0.7 here, GraspGenX's own default: its confidences run lower than GraspGen's.
Each returned pose places the description's base link, or with end_effector that Eden
robot's link (:attr:pose_link_name either way); see the module docstring. The model runs on
CUDA only, and is loaded at construction.
filter_collisions is refused: no GraspGenX description ships a collision mesh
(coll_mesh.obj), and GraspGenX substitutes a 1 cm box that every grasp clears. Check a
grasp against the scene in simulation instead, by posing the gripper there and calling
detect_collision (as examples/recipes/planning/grasp_sampling_graspgenx.py does).
| PARAMETER | DESCRIPTION |
|---|---|
gripper_name
|
The GraspGenX gripper description to sample for, one of :data:
TYPE:
|
checkpoint_dir
|
Directory holding GraspGenX's
TYPE:
|
end_effector
|
The Eden robot that executes the grasps (see
:class:
TYPE:
|
planner
|
TYPE:
|
graspmoe
|
The GraspMoE planner's knobs. Read only when
TYPE:
|
Source code in eden/extensions/grasp_sampling/graspgenx/sampler.py
Attributes¶
END_EFFECTORS
class-attribute
¶
END_EFFECTORS: dict[str, EndEffectorPairing] = {'FrankaEmikaPanda': EndEffectorPairing('franka_panda', 'hand'), 'FrankaHand': EndEffectorPairing('franka_panda', 'hand'), 'InspireRH56_R': EndEffectorPairing('inspire_hand', 'base', ((0.0, 0.0, 0.0), _HALF_TURN_Y_MINUS_Z)), 'Robotiq2f85': EndEffectorPairing('robotiq_2f_85', 'world'), 'SharpaWave_R': EndEffectorPairing('sharpa_wave', 'right_hand_C_MC'), 'WujiHand1_R': EndEffectorPairing('wuji_hand', 'right_palm_link')}
graspmoe
class-attribute
instance-attribute
¶
graspmoe: GraspMoEOptions = GraspMoEOptions.model_validate(self.graspmoe)
open_dofs_pos
property
¶
The description's open configuration, by joint name: the one GraspGenX's grasps assume.
Joint names follow the description's URDF. Eden's dexterous hands share them (sharpa_wave
with SharpaWave_R, inspire_hand with InspireRH56_R); its parallel jaws carry their own
open/close targets (ManipulatorOptions.gripper_open).
close_dofs_pos
property
¶
The description's closed configuration, by joint name (see :attr:open_dofs_pos).
Methods:¶
Functions:¶
GraspGen¶
Eden wrapper around GraspGen: diffusion-based 6-DoF grasp generation, one model per gripper.
GraspGen (NVlabs/GraspGen <https://github.com/NVlabs/GraspGen>_) is consumed through the packaged
eden-grasp-gen (import name grasp_gen), installed by the graspgen extra;
grasp_gen download fetches its per-gripper models
into $GRASPGEN_CHECKPOINT_DIR. For a gripper GraspGen has no model of, use
:class:~eden.extensions.grasp_sampling.graspgenx.GraspGenXSampler, whose single model takes the
gripper by name.
Frames. A GraspGen pose is its grasp frame (z approach, x closing), with its origin at the
gripper's base. That is no link of an Eden robot: the Franka's hand link closes its fingers
along y, so it is the grasp frame turned 90° about z, and a hand driven onto the bare grasp frame
closes across the wrong axis. Configure end_effector= (:attr:GraspGenSampler.END_EFFECTORS) for
poses of the Eden link instead.
Attributes¶
GraspGenEndEffector
module-attribute
¶
GraspGenEndEffector = Literal['FrankaEmikaPanda', 'FrankaHand']
Classes¶
GraspGenSampler
¶
GraspGenSampler(env: EnvBase, options: GraspSamplerOptions)
Bases: GraspSamplerBase
Sample grasps with GraspGen, for a gripper it ships a model of.
The shared options are documented on
:class:~eden.options.extensions.grasp_sampling.GraspSamplerOptions. grasp_gen download
ships models of franka_panda, robotiq_2f_140 and suction_cup_30mm. Each pose is that
model's grasp frame, or with end_effector the Eden robot's link (:attr:pose_link_name); see
the module docstring. Unlike GraspGenX's, GraspGen's grippers carry collision meshes, so
filter_collisions works.
| PARAMETER | DESCRIPTION |
|---|---|
gripper_config
|
The model's gripper config, e.g.
TYPE:
|
end_effector
|
The Eden robot that executes the grasps (see
:class:
TYPE:
|
Source code in eden/extensions/grasp_sampling/graspgen/sampler.py
Attributes¶
END_EFFECTORS
class-attribute
¶
END_EFFECTORS: dict[str, EndEffectorPairing] = {'FrankaEmikaPanda': EndEffectorPairing('graspgen_franka_panda.yml', 'hand', _FRANKA_HAND_IN_GRASP), 'FrankaHand': EndEffectorPairing('graspgen_franka_panda.yml', 'hand', _FRANKA_HAND_IN_GRASP)}