MoveIt Task Constructor:Connect与MoveRelative碰撞设置冲突致规划失败
我正在用MoveIt Task Constructor(MTC)实现装配任务的取放流水线,卡在放置阶段——部件即将接触主装配体的时候。我需要给两个连续阶段设置不同的碰撞规则:
Connect阶段:不允许碰撞MoveRelative(接近)阶段:允许碰撞(预期会产生接触)
我用ModifyPlanningScene修改碰撞矩阵,但规划完整轨迹时IK求解器找不到解。我猜测问题出在Connect会双向传播约束,导致它和MoveRelative阶段的碰撞约束冲突,进而引发规划失败。
日志信息如下:
[mtc_node-1] - 0 → 0 → - 0 / lift object [mtc_node-1] - 0 → 0 ← 0 - / move to predeliver [mtc_node-1] 0 - ← 0 ← 0 - / allow collision PRS - piece [mtc_node-1] 0 - ← 0 ← 0 - / approach dest [mtc_node-1] 0 - ← 0 → - 0 / dest pose IK [mtc_node-1] 0 - ← 0 → - 0 / generate place pose [mtc_node-1] Failing stage(s): [mtc_node-1] grasp pose IK (0/1): no IK found
以下是定义Connect、ModifyPlanningScene、MoveRelative和IK阶段的代码片段,有没有其他组件排列方式能让IK求解成功?
// ---- * Move to Predeliver * ---- auto stage_move_to_predeliver = std::make_unique<mtc::stages::Connect>( "move to predeliver", mtc::stages::Connect::GroupPlannerVector{{arm_group_name, sampling_planner}, {hand_group_name, interpolation_planner}}); stage_move_to_predeliver->setTimeout(15.0); stage_move_to_predeliver->properties().configureInitFrom(mtc::Stage::PARENT); task.add(std::move(stage_move_to_predeliver)); // ---- * Allow Collision Stage (PRS - Piece) * ---- auto stage_allow_piece_PRS = std::make_unique<mtc::stages::ModifyPlanningScene>("allow collision PRS - piece"); stage_allow_piece_PRS->properties().configureInitFrom(mtc::Stage::INTERFACE); stage_allow_piece_PRS->allowCollisions(object, "PRS001", true); stage_place_ptr = stage_allow_piece_PRS.get(); task.add(std::move(stage_allow_piece_PRS)); // ---- * Approach Destination Stage * ---- auto stage_approach_dest = std::make_unique<mtc::stages::MoveRelative>("approach dest", cartesian_planner); // clang-format on stage_approach_dest->properties().set("marker_ns", "approach_dest"); stage_approach_dest->properties().set("link", ee_frame); stage_approach_dest->properties().configureInitFrom(mtc::Stage::PARENT, {"group"}); if (use_only_arm){ stage_approach_dest->properties().set("group", only_arm_group); } stage_approach_dest->setMinMaxDistance(0.1, 0.4); stage_approach_dest->setDirection(vec_approach_dest); task.add(std::move(stage_approach_dest)); geometry_msgs::msg::PoseStamped dest_pose_msg; dest_pose_msg = getFramePose( dest_frame, // target frame (world) dest_frame, // TF frame name rclcpp::Duration::from_seconds(1.0)); // Sample place pose auto stage_ik_dest = std::make_unique<mtc::stages::GeneratePose>("generate place pose"); stage_ik_dest->properties().configureInitFrom(mtc::Stage::PARENT); stage_ik_dest->properties().set("marker_ns", "place_pose"); // stage_ik_dest->setObject(object); stage_ik_dest->setPose(dest_pose_msg); stage_ik_dest->setMonitoredStage(stage_place_ptr); auto ik_dest = std::make_unique<mtc::stages::ComputeIK>("dest pose IK", std::move(stage_ik_dest)); ik_dest->setMaxIKSolutions(8); ik_dest->setMinSolutionDistance(0.24); ik_dest->setIKFrame(ee_frame); // "tool0" // Pipe required properties ik_dest->properties().configureInitFrom(mtc::Stage::PARENT, { "eef", "group", "ik_frame" }); ik_dest->properties().configureInitFrom(mtc::Stage::INTERFACE, { "target_pose" }); // ik_dest->setIgnoreCollisions(true); task.add(std::move(ik_dest));
1. 用子任务隔离碰撞约束
Connect的双向约束传播会把后续的碰撞规则反向传递到前面阶段,导致冲突。可以把MoveRelative和IK阶段包装成子任务容器,在子容器开头添加允许碰撞的ModifyPlanningScene,让碰撞规则仅在子容器内部生效,不影响外部的Connect阶段:
// 创建子任务容器 auto place_subtask = std::make_unique<mtc::Task>("place_subtask"); // 子任务内添加允许碰撞阶段 auto stage_allow_piece_PRS = std::make_unique<mtc::stages::ModifyPlanningScene>("allow collision PRS - piece"); stage_allow_piece_PRS->properties().configureInitFrom(mtc::Stage::PARENT); stage_allow_piece_PRS->allowCollisions(object, "PRS001", true); place_subtask->add(std::move(stage_allow_piece_PRS)); // 子任务内添加MoveRelative阶段 auto stage_approach_dest = std::make_unique<mtc::stages::MoveRelative>("approach dest", cartesian_planner); // ... 保留原有的stage_approach_dest配置代码 ... place_subtask->add(std::move(stage_approach_dest)); // 子任务内添加IK相关阶段 auto stage_ik_dest = std::make_unique<mtc::stages::GeneratePose>("generate place pose"); // ... 保留原有的stage_ik_dest配置代码 ... auto ik_dest = std::make_unique<mtc::stages::ComputeIK>("dest pose IK", std::move(stage_ik_dest)); // ... 保留原有的ik_dest配置代码 ... place_subtask->add(std::move(ik_dest)); // 将子任务添加到主任务 task.add(std::move(place_subtask));
2. 单独给IK阶段开启碰撞忽略
取消注释ik_dest->setIgnoreCollisions(true);,让IK求解器直接忽略碰撞——毕竟放置阶段的目标姿态本身就是需要接触的,无需碰撞检查。同时保留ModifyPlanningScene给MoveRelative阶段允许碰撞,避免笛卡尔规划失败。
3. 限制Connect阶段的约束传播方向
强制Connect仅向前连接,禁止反向传播约束:
stage_move_to_predeliver->setDirection(mtc::stages::Connect::FORWARD);
这样后续的碰撞规则不会反向影响Connect阶段的无碰撞要求。
4. 验证目标姿态的合理性
日志显示失败的是grasp pose IK,和当前放置阶段的代码不符,可能是日志关联错误。可以单独测试IK阶段的目标姿态,确认在允许碰撞的情况下是否有解,再逐步整合到流水线中。
内容的提问来源于stack exchange,提问作者Walter Ronaldo Cachi Delgado




