Search code examples
drake

Enable hydroelastic for box geometry


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?


Solution

  • The AddShape() function when invoked with a Box geometry adds tiny spheres (radius 1e-7 meter) to the corners of the box. That explains

    1. more than one collision geometry when you use boxes, and
    2. the runtime error which is caused by trying to tetrahedralize the tiny spheres.

    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.