You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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对应的几何体

疑问:

  1. 为何Box会有多个Geometry ID?
  2. 这些ID分别指代什么?
  3. 应选择哪个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:10:35