I'm able to make a sphere geometry hydroelastic using the following code:
# Add sphere geometry
pusher_geometry = Sphere(dimensions)
pusher_shape = AddShape(
plant,
pusher_geometry,
"pusher_geometry",
color=[0.9, 0.5, 0.5, 1.0],
)
_ = plant.AddRigidBody(
"false_body1", pusher_shape, SpatialInertia(0, [0, 0, 0], UnitInertia(0, 0, 0))
)
pusher_geometry_x = plant.AddJoint(
PrismaticJoint(
"pusher_geometry_x",
plant.world_frame(),
plant.GetFrameByName("false_body1"),
[1, 0, 0],
-10.0,
10.0,
)
)
pusher_geometry_x.set_default_translation(position[0])
plant.AddJointActuator("pusher_geometry_x", pusher_geometry_x)
_ = plant.AddRigidBody(
"false_body2", pusher_shape, SpatialInertia(0, [0, 0, 0], UnitInertia(0, 0, 0))
)
pusher_geometry_y = plant.AddJoint(
PrismaticJoint(
"pusher_geometry_y",
plant.GetFrameByName("false_body1"),
plant.GetFrameByName("false_body2"),
[0, 1, 0],
-10.0,
10.0,
)
)
pusher_geometry_y.set_default_translation(position[1])
plant.AddJointActuator("pusher_geometry_y", pusher_geometry_y)
pusher_geometry_z = plant.AddJoint(
PrismaticJoint(
"pusher_geometry_z",
plant.GetFrameByName("false_body2"),
plant.GetFrameByName("pusher_geometry"),
[0, 0, 1],
-10.0,
10.0,
)
)
pusher_geometry_z.set_default_translation(position[2])
plant.AddJointActuator("pusher_geometry_z", pusher_geometry_z)
# Make pusher_geometry complient hydroelastic
pusher_geometry = plant.GetBodyByName("pusher_geometry")
geometry_ids = plant.GetCollisionGeometriesForBody(pusher_geometry)
inspector = scene_graph.model_inspector()
for geometry_id in geometry_ids:
new_proximity_properties = ProximityProperties()
AddCompliantHydroelasticProperties(
resolution_hint=0.1,
hydroelastic_modulus=1e8,
properties=new_proximity_properties,
)
const_proximity_properties = inspector.GetProximityProperties(geometry_id)
copy_object_proximity_properties(
const_proximity_properties, new_proximity_properties
)
scene_graph.AssignRole(
plant.get_source_id(),
geometry_id,
new_proximity_properties,
RoleAssign.kReplace,
)
However, this no longer works when I replace pusher_geometry = Sphere(dimensions)
with pusher_geometry = Box(dimensions[0], dimensions[1], dimensions[2])
. For the sphere, geometry_ids
contains a single ID, while for the box, it contains multiple IDs. The system breaks with "RuntimeError: Bad tetrahedron. Cannot compute gradient.", the second time that scene_graph.AssignRole
is called. It works when I apply the property to the first geometry ID rather than to all of them but doesn't work if I assign it to a random one. I don't know how to differentiate the geometries associated with the different geometry IDs. They all seem to have the same properties.
Why are there multiple geometry IDs for a box, and what do these different IDs refer to? How do I know which of these geometry IDs to assign the hydroelastic properties to?
The AddShape()
function when invoked with a Box geometry adds tiny spheres (radius 1e-7 meter) to the corners of the box. That explains
Instead of calling AddShape()
, I'd recommend directly add the box collision geometry via plant.RegisterCollisionGeometry(...)
and the box visual geometry via plant.RegisterVisualGeometry(...)
.
If you prefer checking the volume, you can use SceneGraphInspector::GetShape
which takes a GeometryId to get the shape and find the volume of the shape with CalcVolume(shape)
. However, doing that leaves the tiny spheres in your simulation, which participates in contact using point contact and defeats the purpose of hydroelastics.