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

Drake中SceneGraphCollisionChecker碰撞过滤异常问题咨询

问题:Drake SceneGraphCollisionChecker 忽略预期环境碰撞时触发内部错误

我在使用Drake检测包含桌子、机械臂和桌面零件的场景碰撞时,调用SceneGraphCollisionChecker.CalcContextRobotClearance方法检测到桌子(ingress_table_link)与零件(part1_link)存在负距离(即碰撞)——但这是预期接触,需要忽略该碰撞。尝试为两者添加碰撞过滤器时,触发Drake内部错误:

RuntimeError: Drake internal error at planning/scene_graph_collision_checker.cc:217 in DoCalcContextRobotClearance(): Collision between bodies [ingress_table::ingress_table_link] and [part1::part1_link] should already be filtered

相关代码如下(通过set_collision_filter参数控制是否设置碰撞过滤器):

from pathlib import Path
from time import time

from pydrake.all import (
    CollisionCheckerContext,
    Meshcat,
    RigidTransform,
    RobotDiagramBuilder,
    RollPitchYaw,
    SceneGraphCollisionChecker,
)
from pydrake.systems.analysis import Simulator
from pydrake.visualization import AddDefaultVisualization

ROOT_PATH = Path(__file__).parent.parent.parent.as_posix()
ROBOT_URDF_PATH = ROOT_PATH + "/component_configs/abb/urdf/irb1200_7_70.urdf"
PART1_URDF_PATH = ROOT_PATH + "/resources/test_objects/part1.urdf"
TABLE_URDF_PATH = ROOT_PATH + "/component_configs/ingress_table/urdf/ingress_table.urdf"


def launch_abb_simulator(
    time_step: float,
    realtime_rate: float,
    set_collision_filter: bool = False,
) -> None:
    robot_diagram_builder = RobotDiagramBuilder(time_step=0)
    builder = robot_diagram_builder.builder()
    plant = robot_diagram_builder.plant()
    parser = robot_diagram_builder.parser()

    # Add robot
    robot_model = parser.AddModels(ROBOT_URDF_PATH)
    plant.WeldFrames(plant.world_frame(), plant.GetFrameByName("base_link"))

    # Add table
    table_model = parser.AddModels(TABLE_URDF_PATH)
    translation = [0, 0.5, 0.325]
    rotation = RollPitchYaw(0, 0, 0).ToQuaternion()
    table_transform = RigidTransform(rotation, translation)
    plant.WeldFrames(plant.world_frame(), plant.GetFrameByName("ingress_table_link"), table_transform)

    # Add the part object
    part_model = parser.AddModels(PART1_URDF_PATH)

    # Finalize the scene and add visualization
    plant.Finalize()
    meshcat = Meshcat()
    AddDefaultVisualization(builder, meshcat)
    diagram = robot_diagram_builder.Build()
    simulator = Simulator(diagram)

    # Set context
    collision_context = CollisionCheckerContext(diagram)
    # plant_context = collision_context.plant_context()
    simulator_context = simulator.get_mutable_context()
    plant_sim_context = plant.GetMyContextFromRoot(simulator_context)

    # Set the initial positions, with the part on the table
    robot_joint_positions = [0, 0, 0, 0, 0, 0]
    part_quaternion = [1, 0, 0, 0]
    part_translation = [0, 0.5, 0.4]
    positions = robot_joint_positions + part_quaternion + part_translation

    plant.SetPositions(plant_sim_context, positions)

    # Make a collision checker
    collision_checker = SceneGraphCollisionChecker(
        model=diagram,
        robot_model_instances=robot_model + table_model + part_model,
        edge_step_size=0.01,
        env_collision_padding=0.0,
        self_collision_padding=0.0,
    )

    if set_collision_filter:
        collision_checker.SetCollisionFilteredBetween(
            plant.GetBodyByName("ingress_table_link"),
            plant.GetBodyByName("part1_link"),
            filter_collision=True,
        )

    simulator.Initialize()
    simulator.set_publish_every_time_step(False)
    simulator.set_target_realtime_rate(realtime_rate)

    while True:
        meshcat.PublishRecording()
        simulator.AdvanceTo(simulator_context.get_time() + time_step)

        clearance = collision_checker.CalcContextRobotClearance(
            collision_context,
            plant.GetPositions(plant_sim_context),
            100,
        )
        for i, dist in enumerate(clearance.distances()):
            if dist < 0:
                robot = clearance.robot_indices()[i]
                other = clearance.other_indices()[i]
                print(f"{time()}: {plant.get_body(robot)} is in collision with {plant.get_body(other)}")


if __name__ == "__main__":
    launch_abb_simulator(
        time_step=3e-3,
        realtime_rate=1.0,
        set_collision_filter=False,
    )

问题根源

SceneGraphCollisionChecker通过robot_model_instances参数区分机器人部件和环境部件:只有被指定为机器人的部件才会被主动检查碰撞,环境部件之间的碰撞Drake要求必须在plant.Finalize()之前完成过滤,而不是在运行时通过SetCollisionFilteredBetween设置。

你之前把桌子、零件都加入了robot_model_instances,导致Drake将它们视为机器人部件,但桌子是焊接到世界的固定部件,两者的碰撞逻辑不符合机器人部件的检查规则,从而触发内部错误。

解决方案

1. 区分机器人与环境部件

仅将机械臂设为robot_model_instances,桌子和零件归为环境部件。

2. 在Plant构建阶段提前设置碰撞过滤

在plant.Finalize()之前,调用CollisionFilterDeclaration过滤桌子和零件的碰撞。

修改后的核心代码片段

# ... 原有添加模型的代码 ...

# Add the part object
part_model = parser.AddModels(PART1_URDF_PATH)

# 在Finalize之前添加碰撞过滤:忽略桌子和零件的碰撞
table_body = plant.GetBodyByName("ingress_table_link")
part_body = plant.GetBodyByName("part1_link")
plant.CollisionFilterDeclaration().ExcludeBetween(
    table_body.collision_geometry_ids(),
    part_body.collision_geometry_ids()
)

# Finalize the scene and add visualization
plant.Finalize()

# ... 后续上下文设置代码 ...

# 初始化碰撞检查器:仅将机械臂设为机器人部件
collision_checker = SceneGraphCollisionChecker(
    model=diagram,
    robot_model_instances=robot_model,  # 仅包含机械臂模型实例
    edge_step_size=0.01,
    env_collision_padding=0.0,
    self_collision_padding=0.0,
)

# 移除原有的SetCollisionFilteredBetween调用,因为已在Plant阶段完成过滤

效果说明

修改后,桌子和零件的碰撞会被提前过滤,CalcContextRobotClearance只会检查机械臂与环境(桌子、零件)的碰撞以及机械臂自碰撞,既不会触发内部错误,也不会报告桌子和零件的预期碰撞。

内容的提问来源于stack exchange,提问作者Jasmine Cheng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:54:53