You can perform collision detection in Python using the coal bindings. The typical workflow involves creating shapes (like Ellipsoid or loaded meshes), defining their spatial placement using Transform3s, and then using coal.collide with a CollisionRequest and CollisionResult object.
Key steps:
- Load Meshes: Use
coal.MeshLoader() to load geometry files. - Define Shapes: Instantiate shape objects like
coal.Ellipsoid or use the convex hull from a loaded mesh. - Set Placements: Use
coal.Transform3s to define translation and rotation. These can be populated using numpy arrays or pinocchio SE3 modules. - Execute Collision: Call
coal.collide(shape1, T1, shape2, T2, col_req, col_res). - Retrieve Results: Check
col_res.isCollision() and use col_res.getContact(index) to access contact details like penetration_depth, normal, and witness points. - Cleanup: Always call
col_res.clear() before reusing a CollisionResult object for a new collision call to avoid stale data.
import numpy as np
import coal
import pinocchio as pin
def loadConvexMesh(file_name: str):
loader = coal.MeshLoader()
bvh: coal.BVHModelBase = loader.load(file_name)
bvh.buildConvexHull(True, "Qt")
return bvh.convex
if __name__ == "__main__":
# Create coal shapes
shape1 = coal.Ellipsoid(0.7, 1.0, 0.8)
shape2 = loadConvexMesh("../path/to/mesh/file.obj")
# Define the shapes' placement in 3D space
T1 = coal.Transform3s()
T1.setTranslation(pin.SE3.Random().translation)
T1.setRotation(pin.SE3.Random().rotation)
T2 = coal.Transform3s()
T1.setTranslation(np.random.rand(3))
T2.setRotation(pin.SE3.Random().rotation)
# Define collision requests and results
col_req = coal.CollisionRequest()
col_res = coal.CollisionResult()
# Collision call
coal.collide(shape1, T1, shape2, T2, col_req, col_res)
# Accessing the collision result once it has been populated
print("Is collision? ", {col_res.isCollision()})
if col_res.isCollision():
contact: coal.Contact = col_res.getContact(0)
print("Penetration depth: ", contact.penetration_depth)
print("Distance between the shapes including the security margin: ", contact.penetration_depth + col_req.security_margin)
print("Witness point shape1: ", contact.getNearestPoint1())
print("Witness point shape2: ", contact.getNearestPoint2())
print("Normal: ", contact.normal)
# Before running another collision call, it is important to clear the old one
col_res.clear()