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

Drake::IK::AddMinimumDistanceLowerBoundConstraint未按预期工作问题排查

Drake基于优化的逆运动学(IK)最小距离约束异常问题

背景

我基于Drake开发UR5机械臂(搭配3D打印铲头和探针)的优化式逆运动学,核心需求:

  • 过滤相邻连杆间的碰撞对
  • 施加最小距离下界约束,确保机器人连杆间保持安全间距

碰撞过滤实现代码

def __exclude_collision_pairs(scene_graph: SceneGraph) -> None:
    # add collision filter to the scene graph.
    collision_filter_manager = scene_graph.collision_filter_manager()
    scene_graph_inspector = scene_graph.model_inspector()

    frame_name_to_id = dict()
    for frame_id in scene_graph_inspector.GetAllFrameIds():
        frame_name_to_id[scene_graph_inspector.GetName(frame_id)] = frame_id

    ground_geo_set = GeometrySet(frame_name_to_id['UR5::ground'])
    base_link_geo_set = GeometrySet(frame_name_to_id['UR5::base_link'])
    shoulder_link_geo_set = GeometrySet(frame_name_to_id['UR5::shoulder_link'])
    upperarm_link_geo_set = GeometrySet(frame_name_to_id['UR5::upperarm_link'])
    forearm_link_geo_set = GeometrySet(frame_name_to_id['UR5::forearm_link'])
    wrist1_link_geo_set = GeometrySet(frame_name_to_id['UR5::wrist1_link'])
    wrist2_link_geo_set = GeometrySet(frame_name_to_id['UR5::wrist2_link'])
    EE_link_geo_set = GeometrySet(frame_name_to_id['UR5::EE_link'])
    scoop_link_geo_set = GeometrySet(frame_name_to_id['UR5::scoop_link'])
    probe_link_geo_set = GeometrySet(frame_name_to_id['UR5::probe_link'])

    collision_filter_declaration = CollisionFilterDeclaration()
    collision_filter_declaration.ExcludeWithin(ground_geo_set)
    collision_filter_declaration.ExcludeWithin(base_link_geo_set)
    collision_filter_declaration.ExcludeWithin(shoulder_link_geo_set)
    collision_filter_declaration.ExcludeWithin(upperarm_link_geo_set)
    collision_filter_declaration.ExcludeWithin(forearm_link_geo_set)
    collision_filter_declaration.ExcludeWithin(wrist1_link_geo_set)
    collision_filter_declaration.ExcludeWithin(wrist2_link_geo_set)
    collision_filter_declaration.ExcludeWithin(EE_link_geo_set)
    collision_filter_declaration.ExcludeWithin(scoop_link_geo_set)
    collision_filter_declaration.ExcludeWithin(probe_link_geo_set)
    collision_filter_declaration.ExcludeBetween(ground_geo_set, base_link_geo_set)
    collision_filter_declaration.ExcludeBetween(base_link_geo_set, shoulder_link_geo_set)
    collision_filter_declaration.ExcludeBetween(shoulder_link_geo_set, upperarm_link_geo_set)
    collision_filter_declaration.ExcludeBetween(upperarm_link_geo_set, forearm_link_geo_set)
    collision_filter_declaration.ExcludeBetween(forearm_link_geo_set, wrist1_link_geo_set)
    collision_filter_declaration.ExcludeBetween(wrist1_link_geo_set, wrist2_link_geo_set)
    collision_filter_declaration.ExcludeBetween(wrist2_link_geo_set, EE_link_geo_set)
    collision_filter_declaration.ExcludeBetween(wrist2_link_geo_set, scoop_link_geo_set)
    collision_filter_declaration.ExcludeBetween(EE_link_geo_set, scoop_link_geo_set)
    collision_filter_declaration.ExcludeBetween(probe_link_geo_set, scoop_link_geo_set)
    collision_filter_manager.Apply(collision_filter_declaration)

IK实现代码

builder = DiagramBuilder()
plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=0)
parser = Parser(plant)
robot = parser.AddModels(self._bot_urdf_path)
__exclude_collision_pairs(scene_graph)  
plant.Finalize()
diagram = builder.Build()
ik_context = diagram.CreateDefaultContext()
ik_plant_context = plant.GetMyMutableContextFromRoot(ik_context)
ee_frame = plant.GetFrameByName(self._bot_params['ee_link_name'])
ik = InverseKinematics(plant, ik_plant_context)
# ik.AddMinimumDistanceLowerBoundConstraint(bound=0.0001, influence_distance_offset=0.0005) # hard-coded
ik.prog().AddBoundingBoxConstraint(plant.GetPositionLowerLimits(),  # [-2pi, 2pi]
    plant.GetPositionUpperLimits(), ik.q()) 
if init_guess is None:
    init_guess = self.GetConfiguration()
ik.prog().SetInitialGuess(ik.q(), init_guess)
ik.prog().AddQuadraticCost(
    (ik.q() - init_guess).dot(np.diag(weights)).dot(ik.q() - init_guess))
ik.AddPositionConstraint(ee_frame, [0, 0, 0], plant.world_frame(), 
    translation - 1e-5 * np.ones(3), translation + 1e-5 * np.ones(3))
ik.AddOrientationConstraint(ee_frame, RotationMatrix(), plant.world_frame(), 
                            RotationMatrix(orientation), 1e-5)
result = Solve(ik.prog())
if kVerbose and result.get_solver_id().name() != 'SNOPT':
    print("ScoopingBot::__inverse_kinematics -- SNOPT is not available")
if kVerbose and not result.is_success():
    print("ScoopingBot::__inverse_kinematics -- IK failed")
    print(result.GetInfeasibleConstraintNames(ik.prog()))
    return False, None
return True, result.GetSolution(ik.q())

问题现象

已确认碰撞过滤逻辑生效,但启用AddMinimumDistanceLowerBoundConstraint后(即使将bound设为0),出现以下异常:

  • 情况1:最小距离约束被违反
  • 情况2:约束未被违反,但末端位姿约束必须放宽至1e-2(1cm误差,无法接受)

移除该约束后,IK运行完全正常,位姿约束仅需1e-3~1e-5的放宽;若将bound设为-100,约束可正常生效且无碰撞问题。

内容的提问来源于stack exchange,提问作者Chaoqi LIU

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:44:58