Collision · repose-collision

Attached objects & exclusions

When the robot picks something up, that object moves with the robot and must not hit anything else. But it also touches the gripper by design. Attached shapes and exclusions model exactly that.

Attached shapes

An attached shape is geometry expressed in a robot frame (Some(i)) or the base (None). It moves with that frame and is checked against obstacles, other attached shapes and the robot's own links.

rust
// A tool changer permanently on the flange (joint frame 5):
let changer = scene.add_attached(Some(5), changer_shape, None)?;

// Change frame or geometry later:
scene.update_attached(changer, CuAttachedUpdate::new().with_shape(bigger_shape))?;

CuAttachedShape::with_transform(&frame_from_shape) re-expresses a shape through a frame-relative transform, handy when you know where the object sits relative to the tool rather than the joint frame.

Grasp and release

Picking turns an obstacle into an attached shape, and placing turns it back. The CuObjectId stays the same throughout:

rust
// Grasp: the part (obstacle) now rides on the flange, in flange coordinates.
scene.attach(part, Some(5), part_in_flange_frame)?;

// … move …

// Release: the part becomes a world obstacle again, where it was put down.
scene.detach(part, part_in_world_frame)?;

You provide the geometry in the new frame because only you know where the object sits relative to the gripper or the world after the move.

Exclusions: intended contacts

A grasped part overlaps the gripper fingers. Without help, every check would report that as a collision. An exclusion says "don't check this attached shape against that partner":

rust
let mut excl = CuSceneExclusions::<16>::new();
excl.add(CuSceneExclusion::robot(part, 5))?;              // part × robot shape 5 (the gripper)
excl.add(CuSceneExclusion::attached(part, changer))?;     // part × another attached shape
excl.add(CuSceneExclusion::obstacle(part, fixture))?;     // part × an obstacle, e.g. while in the fixture

let env = scene.collision_env().with_exclusions(&excl);

The subject is always an attached shape. The partner is a robot shape (by index into link_shapes()), another attached shape, or an obstacle (both by ID). Attached-vs-attached exclusions apply in both directions.

Why stable IDs

Exclusions refer to objects by CuObjectId, not by slot index, so they stay correct when other objects are removed and storage is compacted. CuSceneExclusions is its own payload, published next to the scene. Every check validates it against the scene it is used with: an exclusion that names an ID not in the scene, references itself, or names a robot shape index that doesn't exist is an error, not a silent no-op. excl.validate(&scene, model.shape_count()) lets you reject a bad set up front.

Keep them consistent

  • Publish scene and exclusions together. An exclusion for a part that was already detached will make the next check fail.
  • Exclude as little as possible: the part against the fingers it touches, not against the whole arm.
  • Plans record the exclusions they used (CuJointPlanPath::exclusions), so you can tell which contacts a path was allowed to have.

API reference