为Box几何体启用Hydroelastic时的多Geometry ID问题咨询
Drake中Box几何体Hydroelastic属性赋值问题解答
问题描述
原本通过以下代码可为Sphere几何体实现Hydroelastic效果:
# 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, )
但将pusher_geometry = Sphere(dimensions)替换为pusher_geometry = Box(dimensions[0], dimensions[1], dimensions[2])后代码失效:
- Sphere对应的
geometry_ids仅含单个ID,Box对应多个ID - 第二次调用
scene_graph.AssignRole时抛出RuntimeError: Bad tetrahedron. Cannot compute gradient.错误 - 仅为第一个ID赋予属性时可正常运行,但随机选择其他ID则不行,且无法区分这些ID对应的几何体
疑问:
- 为何Box会有多个Geometry ID?
- 这些ID分别指代什么?
- 应选择哪个ID来赋予Hydroelastic属性?
解答
1. Box出现多个Geometry ID的原因
Drake默认会将Box这类多面体几何体拆分为单个的面(共6个),每个面对应一个独立的Geometry ID。这是碰撞检测模块的优化策略,平面拆分后能提升特定场景下的碰撞检测效率。而Sphere是连续曲面,无需拆分,因此只有一个Geometry ID。
2. 多个Geometry ID的指代
每个ID对应Box的一个矩形表面(前/后、左/右、上/下),但Drake返回的ID列表没有固定的顺序映射关系,无法直接通过索引判断具体对应哪个面。
3. 正确的Hydroelastic属性赋值方式
Hydroelastic是针对刚体体积的柔体模拟,需要基于完整的几何体体积生成四面体网格。而拆分出的单个面属于"surface"类型几何体,没有体积,无法生成合法的四面体网格(这就是报错Bad tetrahedron的核心原因)。
正确做法是在创建Box时,强制生成单个体积型几何体,避免拆分为多个面:
# 创建Box前先配置 proximity 属性,指定使用体积碰撞 proximity_props = ProximityProperties() AddRigidHydroelasticProperties(resolution_hint=0.1, properties=proximity_props) # 创建Box并关联上述属性 pusher_geometry = Box(dimensions[0], dimensions[1], dimensions[2]) pusher_shape = AddShape( plant, pusher_geometry, "pusher_geometry", color=[0.9, 0.5, 0.5, 1.0], proximity_properties=proximity_props # 关键:传入预配置的属性 )
修改后,plant.GetCollisionGeometriesForBody(pusher_geometry)只会返回单个Geometry ID,后续的Hydroelastic属性赋值逻辑就和Sphere的情况完全一致,不会再报错。
内容的提问来源于stack exchange,提问作者Nicholas Pfaff
相关产品推荐
相关产品推荐

