🦾 MoveIt2 进阶:运动规划与抓取管线

从「让机械臂动起来」到「让机械臂真正干活」—— 深入 OMPL 规划器、约束规划、避障感知、MoveIt Task Constructor 抓取管线,并打通 MoveIt2 与 ros2_control 真机部署的最后一公里。前置是本站 04-10 的 URDF 与 MoveIt2 入门。
OMPL C-space 笛卡尔路径 碰撞矩阵 Octomap Task Constructor ros2_control 双臂协同
🎯 本页学习目标
1. 能说清构型空间(C-space)是什么,以及正/逆运动学在运动规划中各自扮演的角色,能区分采样规划解析规划
2. 能讲出 RRT / RRTConnect / RRTstar / PRM / BiTRRT / EST / LazyPRM 的直觉与适用场景,会看 ompl_planning.yaml 里的 planner_id 并调规划时间/尝试次数
3. 能解释路径约束computeCartesianPath 的区别,知道 fraction(完成比例)小于 1 意味着什么
4. 能说清碰撞矩阵(ACM)、自碰撞/环境碰撞、Octomap 感知避障的机制,以及动态障碍下如何规划重试
5. 能用 MoveIt Task Constructor 描述一个「接近 → 抓取 → 抬升 → 放置」的抓取流程,理解各 Stage 的作用
6. 能讲清 MoveIt2 与 ros2_control 集成的部署链路(joint_trajectory_controller),并列出真机规划失败的常见排查点
建议用时:90-120 分钟(含动手)。前置:建议先读本站 04-10 ROS2 实战进阶:URDF 与 MoveIt2(已讲 URDF、Setup Assistant、MoveGroup 入门),本页默认你已会拖动 RViz 规划、读懂 moveit_config 包结构。

1 运动规划问题定义

上一页我们只「用了」规划器,这一页要回答一个更根本的问题:规划器到底在解什么?运动规划的形式化定义是:给定机器人当前状态、目标状态、障碍物集合,找一条从起点到终点、全程无碰撞、满足运动学约束的轨迹(按时间排列的位形序列)。

1.1 构型空间 C-space:规划的「主战场」

机器人一条手臂若有 n 个关节,它的完整状态可以用一个 n 维向量 q = (q₁, q₂, …, qₙ) 表示。所有可能 q 组成的空间叫构型空间(Configuration Space,简称 C-space)。规划器不在三维物理空间里搜索,而是在 C-space 里搜索:

概念含义在本页语境中的角色
C-space(构型空间)所有关节角度向量的集合,维数 = 自由度(DoF)规划的搜索空间;一条 7-DoF 手臂的 C-space 是 7 维
C-obstacle(障碍空间)C-space 中会导致碰撞的 q 的集合规划要绕开的「禁区」
C-free(自由空间)C-space 减去障碍空间后的可行区域合法轨迹必须始终落在 C-free 内
位形(q)一个具体的关节角组合轨迹 = 一串按时间排布的 q
💡 为什么绕开 C-space 直接算?物理空间里「手臂能否通过」的约束,在 C-space 里会变成形状复杂的「禁区」。但把问题搬到 C-space 后,机器人就退化成一个「点」,障碍物变成「块」,搜索问题统一了——这正是所有采样规划器的共同前提。

1.2 正/逆运动学在规划中的角色

1.3 采样规划 vs 解析规划

维度采样规划(Sampling-based)解析/优化规划
代表OMPL 全家(RRT/RRTConnect/PRM…)、MoveIt2 默认路径CHOMP、STOMP、TrajOpt、Time-Optimal 等
思想在 C-space 里随机撒点 + 连线,构造一张「路网」再搜索把轨迹参数化,用梯度/优化器最小化代价(平滑、避障)
完备性概率完备:时间越长越可能找到解(若解存在)通常只保证局部最优,依赖好初值
优点高维、复杂障碍下鲁棒;不依赖初值轨迹平滑、可显式加约束与代价
缺点轨迹「乱」、不平滑,需后处理(简化/平滑/时间参数化)易陷局部最优,高维时慢

MoveIt2 默认是采样规划(OMPL),并在规划后追加「轨迹简化 + 时间参数化」步骤,把采样出的锯齿轨迹变平滑、再配上速度时间戳——这就是 request_adapters 干的活(见第 2 节 yaml)。

2 OMPL 规划器详解

OMPL(Open Motion Planning Library)是 MoveIt2 默认的规划后端,一个与机器人无关的采样规划算法库。MoveIt2 通过 ompl_interface 插件把 OMPL 挂进来,自带 RRT / RRTConnect / RRTstar / PRM / PRMstar / BiTRRT / EST / KPIECE / LazyPRM / STRIDE / SPARS 等 20 余种算法(不同版本略有增减)。

2.1 常用算法:直觉与适用场景

算法直觉特点与适用场景
RRT从起点长一棵随机「树」,朝随机方向探索单树探索;简单直观但慢,轨迹质量一般
RRTConnect起点、终点两棵树同时长,快速「对接」收敛快、鲁棒,是 MoveIt2 默认;日常首选
RRTstarRRT + 不断「重连」优化路径长度渐近最优,路径更短更平滑;但更慢,需更长规划时间
PRM先铺满一张「路网」(roadmap),再多次查询适合同一环境多次规划;建图开销大,动态障碍下要重建
BiTRRT双向 RRT + 控制与障碍的距离(clearance)擅长狭窄通道,尽量贴着「中间」走,避免擦边
EST在「能扩展」的区域附近集中采样老牌算法;某些约束场景下比 RRT 稳,速度中等
LazyPRM先连线、后「偷懒」延迟碰撞检查边检查很贵时快;但可能频繁碰壁重试
💡 选型心法:没有「万能规划器」。默认 RRTConnect 打底;追求路径短/平滑换 RRTstar;狭窄缝隙用 BiTRRT;同一环境反复抓取用 PRM。真机建议「多个规划器排队 + 失败切换」:先 RRTConnect 快试,不行再上 BiTRRT/RRTstar。

2.2 planner_id 配置:ompl_planning.yaml

MoveIt2 的规划器在 ompl_planning.yaml 里声明。关键结构:planner_configs 定义「算法库」,每个规划组的 planner_configs 列出「本组可用哪些」,default_planner_config 指定默认项。

planning_plugin: ompl_interface/OMPLPlanner

request_adapters: >-
    default_planner_request_adapters/AddTimeParameterization
    default_planner_request_adapters/FixWorkspaceBounds
    default_planner_request_adapters/FixStartStateBounds
    default_planner_request_adapters/FixStartStateCollision
    default_planner_request_adapters/FixStartStatePathConstraints

start_state_max_bounds_error: 0.1

planner_configs:
  RRTConnectkConfigDefault:
    type: geometric::RRTConnect   # 算法类型,决定用哪个 OMPL 规划器
    range: 0.0                    # 单步扩展上限;0=按状态空间自动取默认
  RRTstarkConfigDefault:
    type: geometric::RRTstar
    range: 0.0
  BiTRRTkConfigDefault:
    type: geometric::BiTRRT
    range: 0.0
  PRMkConfigDefault:
    type: geometric::PRM
    max_nearest_neighbors: 10

arm:
  default_planner_config: RRTConnectkConfigDefault
  planner_configs:
    - RRTConnectkConfigDefault
    - RRTstarkConfigDefault
    - BiTRRTkConfigDefault
    - PRMkConfigDefault
  planning_time: 5.0        # 单次规划时间上限(秒)
  planning_attempts: 10     # 最多尝试几次
  max_solutions: 10         # 最多保留几条候选解再选优

运行时可临时改规划器(不重启):RViz MotionPlanning 面板里直接选,或代码里 move_group.setPlannerId("RRTstarkConfigDefault")

2.3 规划参数:时间、次数与质量

参数含义典型默认调参建议
planning_time单次规划的时间预算5.0 s复杂环境/高维臂可加到 10 s;实时性要求高则降到 1~2 s
planning_attempts尝试次数(每次内各自跑 planning_time)10失败率高时增大;但真机别让它无限重试
max_solutions保留候选解数量,从中选「最短/最平滑」10调大更容易拿到平滑路径,代价是更慢
range树单步扩展的最大步长0(自动)越大探索越「粗」,越小越「细」;一般保持自动
goal_position_tolerance末端位置容差(米)0.0001抓取前可适当放宽到毫米级,提高成功率
goal_orientation_tolerance末端姿态容差(弧度)0.001拧螺丝等姿态敏感任务要收紧

2.4 规划结果质量评估

「规划成功」≠「轨迹好用」。评估一条轨迹至少要盯三件事:

⚠️ 别被「绿了」骗了:RViz 里轨迹变绿只代表通过了碰撞检测与约束,不代表它平滑、不撞到「没建进场景的物体」、也不代表真机执行时不会因关节速度/力矩超限而失败。真机执行前务必看轨迹回放与速度曲线。

3 约束规划与笛卡尔路径

很多任务要求末端全程保持某种姿态或轨迹形状——端一杯水不能倾斜、插销要沿直线插入、焊接要贴面滑行。这就要用到 MoveIt2 的路径约束(Path Constraints)

3.1 三类路径约束

约束类型含义人形机器人典型用途
方向约束(OrientationConstraint)末端坐标系的某一轴要指向某方向(或与参考方向夹角 ≤ 容差)端水平托盘、保持掌心向上
位置约束(PositionConstraint)末端(或其上某点)要落在某区域内(球/盒)沿直线插入、贴面焊接
关节约束(JointConstraint)某关节角度需落在给定区间限制肘部方向、避免反关节

注意区分两个层级:目标约束(goal constraints)只约束「终点」,路径约束(path constraints)约束「全程每一点」。方向约束既可做目标也可做路径,含义完全不同——这是新手常踩的坑。

3.2 笛卡尔路径 computeCartesianPath

当你需要末端沿一条直线(或给定路径点序列)运动时,关节空间规划会「乱绕」,要用笛卡尔路径规划:在笛卡尔空间按步长插值出密集途经点,对每个点解 IK,再串成轨迹。核心接口(C++ MoveGroupInterface):

// waypoints: 一串末端位姿(几何直线就取起点与终点间等距插值)
std::vector<geometry_msgs::msg::Pose> waypoints;
// ... 填充 waypoints ...

moveit_msgs::msg::RobotTrajectory trajectory;
// eef_step:末端每步移动距离(m);jump_threshold:允许关节最大跳变(0=禁用)
double fraction = move_group.computeCartesianPath(
    waypoints, eef_step, jump_threshold, trajectory);

// fraction ∈ [0,1]:= 1 表示走完全程;小于 1 表示中途卡住(奇异/碰撞/不可达)
if (fraction >= 0.999) {
    move_group.execute(trajectory);
} else {
    RCLCPP_WARN(node->get_logger(),
                "笛卡尔路径仅完成 %.1f%%,剩余段未解出", fraction * 100);
}

Python 侧(MoveIt2 官方绑定为 MoveItPy,前身是 ROS1 的 moveit_commander)做「规划 + 执行」的最小示例:

import rclpy
from rclpy.node import Node
from moveit_py import MoveItPy

rclpy.init()
node = Node("moveit_py_demo")

# 初始化 MoveItPy(会加载 moveit_config 包)
moveit_py = MoveItPy(node_name="moveit_py")
arm = moveit_py.get_planning_component("arm")

# 起点=当前状态,目标=命名位姿 "home"
arm.set_start_state_to_current_state()
arm.set_goal_state(configuration_name="home")

# 规划
plan_result = arm.plan()
if plan_result:
    # plan_result.trajectory 是 RobotTrajectory,可交给控制器执行
    moveit_py.execute(plan_result.trajectory, controllers=[])
else:
    node.get_logger().warn("规划失败,请检查目标/约束/碰撞")
⚠️ fraction 与奇异位形:笛卡尔路径每一步都在解 IK,遇到奇异位形(如手臂完全伸直、腕关节轴线重合)或目标在工作空间外,IK 会无解,fraction 停在小于 1 的位置。常见对策:缩短 eef_step、换初始位形、或改用关节空间目标绕开奇异点。

3.3 人形机器人手臂常用约束

4 避障与碰撞检测

规划器「避障」靠的是碰撞检测,而 MoveIt2 的碰撞检测分两层:自碰撞(机器人自己打自己)与环境碰撞(机器人与周围物体)。

4.1 碰撞矩阵 ACM:允许碰撞矩阵

机器人的某些连杆天生就是贴着的(如相邻连杆、夹爪的两指),如果处处检测会误报大量「碰撞」。ACM(Allowed Collision Matrix,允许碰撞矩阵)声明「哪些连杆对之间不检查碰撞」,从而避免误报、加速检测。它由 Setup Assistant 采样生成,存于 SRDF 的 <disable_collisions> 段,并以 default 表示「默认允许、其它情况才查」。

<!-- SRDF 片段:声明 link1 与 link2 之间永不检查碰撞 -->
<disable_collisions link1="link1" link2="link2" reason="Adjacent"/>
<!-- 或:默认允许,只有列出的「危险对」才检查 -->
<disable_collisions link1="base_link" link2="gripper_link" reason="Default"/>
💡 语义要分清:ACM 里的「默认允许」意思是这一对默认不查碰撞(被「豁免」),不是「允许真的撞上」。给两个根本不会碰到的连杆设置豁免,是省算力;给相邻关节设豁免,是避免「贴脸即报错」。而真正会互撞的组合(如手与胸)必须保留检查。

4.2 自碰撞 vs 环境碰撞

4.3 Octomap:点云 → 八叉树 → 规划场景

真实场景里障碍物是动态、未知的,靠深度相机/激光雷达的点云来「看」。MoveIt2 的感知避障链路:

1采集
深度相机发布点云(sensor_msgs/PointCloud2)
2转八叉树
Occupancy Map Monitor 把点云插入 Octomap(八叉树占用栅格)
3入场景
Octomap 作为 PlanningScene 的碰撞来源
4规划
规划器绕开八叉树里的占用体素

Octomap 的优势是内存友好 + 多分辨率:空旷区用粗大格子,障碍边缘用细密格子,适合大范围场景。配置要点是 sensors_3d.yaml(声明点云话题、更新频率、过滤范围)与 octomap 参数(体素分辨率,典型 0.05 m)。

4.4 动态障碍与规划重试

⚠️ 规划与执行是「两个时间点」:规划时点云 A,执行时障碍可能已移动到 B。真机常见「规划通过、执行撞上」,根因就是规划场景与实际不同步。对策:提高点云更新率;执行前重新校验一次当前状态是否碰撞;发现碰撞立即中止并重新规划;PlanningSceneMonitor 持续订阅最新场景,而不是用一份「快照」。

5 抓取管线:MoveIt Task Constructor

「抓起一个东西」不是一个规划动作,而是一连串有依赖关系的子任务:先规划到抓取点、再闭夹、再抬升、再搬运、再放置。若把整件事塞进一次 MoveGroup 规划,成功率极低且难调试。MoveIt Task Constructor(MTC) 就是为此设计的:把复杂操作拆成有向图上的多个 Stage(阶段),每个 Stage 可独立求解、可回溯,前一个 Stage 的成功结果作为后一个的起点。

5.1 MTC 核心概念

5.2 抓取流程的典型 Stage

阶段常用 Stage做什么
① 接近MoveTo(预抓位姿)把手臂移到物体上方的「预抓取点」
② 生成抓取GenerateGraspPose围绕物体生成多个候选抓取姿态(角度/位置采样)
③ 求解 IKComputeIK对每个抓取姿态解出关节解
④ 伸手MoveRelative沿接近方向小步移动,把夹爪送到物体处
⑤ 抓取ModifyPlanningScene夹爪闭合 + 把物体 attach 到末端(附着)
⑥ 抬升MoveRelative沿垂直方向抬起物体
⑦ 放置Place / MoveTo + AllowCollision移到放置点、松爪、解除附着

MTC 官方仓库自带 demo/scripts/pickplace.py 与 C++ 版 Pick and Place 示例,可作为起点改写。配置好后的启动方式:

# 官方 Pick and Place 示例(以 panda 为例,不同版本包名略有差异)
ros2 launch moveit_task_constructor_demo pick_place_demo.launch.py
# 或跑 Python 脚本版
python3 pickplace.py

5.3 感知集成与夹爪配合

💡 何时用 MTC:简单的「单段点到点」用 MoveGroup 即可;一旦涉及抓取-抬升-放置、多末端、条件分支(失败重试),就用 MTC。它把「一堆 if-else + 多次 plan」收敛成一张可复用、可调试的图。

6 MoveIt2 与真实机器人

仿真里 MoveIt2 规划的轨迹「凭空」执行;真机上轨迹必须经 ros2_control 下发给关节模组,并由硬件接口读回编码器反馈。

6.1 集成链路:controller manager + joint_trajectory_controller

MoveIt2 规划轨迹(MoveGroup / MoveItPy)
        │  发布 moveit_msgs/msg/JointTrajectory
        ▼
joint_trajectory_controller(ros2_control)
        │  每个控制周期(如 100 Hz)插值下发位置/速度
        ▼
hardware_interface(真机驱动:CAN/EtherCAT 或仿真插件)
        │  写入电机命令 / 读回编码器
        ▼
关节模组(伺服电机 + 减速器)

真机配置示例(ros2_controllers.yaml):

controller_manager:
  ros__parameters:
    update_rate: 100   # 控制循环 Hz

arm_controller:
  ros__parameters:
    type: joint_trajectory_controller/JointTrajectoryController
    joints:
      - shoulder_pan_joint
      - shoulder_lift_joint
      - elbow_joint
      - wrist_1_joint
    command_interfaces:
      - position           # 位置控制接口(也可加 velocity/effort)
    state_interfaces:
      - position
      - velocity
    state_publish_rate: 50.0
    action_monitor_rate: 20.0
    allow_partial_joints_goal: false
    constraints:
      stopped_velocity_tolerance: 0.01
      goal_time: 0.0

6.2 真实机械臂部署流程

1准备 moveit_config 包
Setup Assistant 生成,SRDF/ompl_planning.yaml/kinematics.yaml 齐全
2接入硬件接口
实现 SystemInterface,把关节命令映射到电机驱动器
3起控制器
spawner 启动 joint_state_broadcaster + joint_trajectory_controller 并激活
4启动 MoveIt
demo.launch.py 连上真机控制器
5减速试跑
先 setMaxVelocityScalingFactor(0.1~0.2) 空载走一遍
🔴 真机安全铁律:关节名在 URDF、控制器配置、MoveIt 配置三处必须逐字一致;首次执行务必低速缩放 + 手按急停;先空载后带载。

6.3 伺服 servoing:绕过「规划」的实时控制

规划适合「点到点」;而遥操作、力引导、人机协作需要机器人实时跟随外部输入(手柄、手部追踪、力矩)。moveit_servo 提供高频率(约百 Hz 级)的末端速度伺服:输入「末端期望速度/增量」,直接解出关节速度下发,不做完整规划。它常与视觉遥操作、临场感控制配合,是实现「人手带着机械臂走」的关键模块。

6.4 常见失败与调试

⚠️ motion planning failure 排查清单:
1. 目标不可达:末端位姿超出工作空间,或方向约束与姿态互相矛盾 → 换目标/放宽容差;
2. 奇异位形:IK 无解或关节速度爆炸 → 换初始位形、绕开奇异点;
3. 规划场景不同步:场景里没加障碍(导致「穿模」)或加了幽灵障碍(导致「处处撞」)→ 刷新 PlanningScene;
4. 规划时间/次数不足:复杂场景 RRT 没搜完 → 调大 planning_time / 换 RRTConnect / BiTRRT;
5. 控制器没激活或关节名不匹配:规划成功但执行不动 → 查 ros2 control list_controllers 与三处关节名;
6. 碰撞几何过细:用高精度 mesh 做 collision,检测慢到超时 → 换凸体简化几何。

7 人形机器人场景

人形机器人的手臂规划与桌面机械臂最大的不同:双臂、双足浮动基座、全身平衡。这里只谈手臂层面的落地现状,整机平衡与步态见本站其它章节。

7.1 双臂协同规划(dual-arm)

双臂协同通常有两种做法:

实际工程里常用「主子臂」模式:主臂走笛卡尔/关节规划,从臂用相对约束跟随,兼顾成功率与同步性。

7.2 宇树 H1:整机 URDF 与双臂规划

宇树 H1 是双臂人形机器人,官方 unitree_ros 仓库提供了 h1_description(URDF 与 MJCF 两种描述),以及 H1-2 型号描述;同时社区有基于 H1 的 ROS2 SDK 与 MoveIt 配置实践。在 H1 上跑 MoveIt2 的典型路径是:用官方 URDF 经 Setup Assistant 生成 moveit_config,建 left_arm / right_arm 规划组,再接入宇树的关节控制接口。注意:H1 双臂的 MoveIt 配置多由社区维护,官方公开资料以描述文件与 SDK 为主,具体型号的规划组命名与控制器需以对应仓库为准(约)。

7.3 智元(稚晖君团队)开源实践

智元机器人(AgiBot)在 2024 年 10 月开源了 灵犀 X1 的软硬件资料(官方称「0 元购」软硬件全套图纸与代码),含推理代码仓库 AgibotTech/agibot_x1_infer 等,以及自研开源通信中间件 AimRT。这套资料为「整机 + 双臂操作」的学习与二次开发提供了从模型到算法的完整参考。手臂层面的规划仍可复用 MoveIt2 生态(约,具体以各仓库 README 为准)。

📌 人形机器人规划的现实:当前人形机器人手臂大多沿用「固定基座假设」做规划(把躯干当基座),再由整机控制器协调平衡;「规划时把双足/质心也纳入约束」的全身规划(whole-body)仍在快速演进,难度更高,不在本页展开。

8 性能与进阶资源

继续深入的方向与官方入口(均为核实过的官方文档,详见文末「参考来源」):

🚀 性能小抄:想「快」就 RRTConnect + 缩短 planning_time;想「短而顺」就 RRTstar/PRM + 调大 max_solutions 再选优;想「安全贴中走」就 BiTRRT;想「边走边感知」就把点云更新与 PlanningSceneMonitor 配到位,并在执行前重校验。

9 本节自测

1. 采样规划器(RRT 类)主要在哪个空间里搜索?正运动学(FK)在其中起什么作用?
💡 采样规划器把机器人看成 C-space 里的一个「点」,在关节角空间采样;每采样一个 q 都要用 FK 算出连杆位姿,才能判断是否与环境/自碰撞。
2. 关于 OMPL 规划器的默认与选型,下列说法正确的是?
💡 RRTConnect 是双向搜索、收敛快,是 MoveIt2 默认;RRTstar 渐近最优但更慢;BiTRRT 通过控制 clearance 擅长狭窄通道;LazyPRM 只在「边检查昂贵」时占优。
3. computeCartesianPath 返回的 fraction = 0.6 意味着什么?
💡 fraction 是「成功解出的路径比例」,∈[0,1];小于 1 表示中途 IK 无解(常见奇异位形或目标超工作空间),需缩短步长或换初始位形。
4. 关于碰撞矩阵 ACM(允许碰撞矩阵),正确的是?
💡 ACM 是「豁免检测」清单,由 Setup Assistant 采样生成、存于 SRDF 的 disable_collisions 段;它是为了防误报与提速,而不是允许真碰撞;环境障碍走 PlanningScene 而非 ACM。
5. Octomap 在 MoveIt2 感知避障链路中的角色是?
💡 深度相机点云经 Occupancy Map Monitor 插入 Octomap(八叉树),再作为规划场景的障碍来源,让规划器绕开实时感知到的物体。
6. 关于 MoveIt Task Constructor(MTC),错误的是?
💡 MTC 既有 C++ 也有 Python 接口(官方示例含 demo/scripts/pickplace.py);它用 Generator/Propagator/Connector 三类 Stage 把抓取流程拆成图。
7. MoveIt2 真机上「规划成功但机械臂不动」,最不可能的原因是?
💡 规划成功=算法层通过;执行不动通常是控制器未激活、关节名不匹配或硬件接口没接好;RViz 卡顿只影响显示,不影响轨迹下发。
8. 关于「目标约束(goal constraints)」与「路径约束(path constraints)」的区别,下列说法正确的是?
💡 这是第 3.1 节提到的「新手常踩的坑」:目标约束只管终点,路径约束管全程每一点;同一个方向约束,做目标与做路径含义完全不同(端水平托盘要全程保持掌心朝上,就必须用路径约束而非只给终点目标)。
9. 关于采样规划(OMPL)与解析/优化规划(CHOMP、STOMP 等),下列说法错误的是?
💡 见第 1.3 节对照表:采样规划概率完备、不依赖初值但轨迹不平滑;解析/优化规划轨迹平滑可显式加代价,但通常只保证局部最优且依赖好初值——「保证全局最优且不依赖初值」恰恰说反了。
10. 关于 moveit_servo 伺服,下列说法正确的是?
💡 见第 6.3 节:moveit_servo 输入「末端期望速度/增量」,以约百 Hz 级直接解出关节速度下发,绕过完整规划,因此适合实时跟随类任务(手柄、手部追踪、力矩),而不是替代 OMPL 做点到点规划。
📌 本节要点速查:① 规划在构型空间(C-space)里避开 C-obstacle 找 C-free 路径,采样规划靠 FK 做碰撞检测、IK 只用于把位姿目标转成关节角;② MoveIt2 默认 OMPL 采样规划,RRTConnect 打底,短而顺换 RRTstar、狭窄通道用 BiTRRT、同环境多次规划用 PRM,靠 planning_time/planning_attempts 调参;③ 目标约束只管终点、路径约束管全程,fraction<1 表示笛卡尔路径中途 IK 无解(奇异/不可达);④ 避障靠 ACM(豁免检测)+ 自/环境碰撞 + Octomap 感知;⑤ 复杂抓取用 MoveIt Task Constructor 拆 Stage 图,真机经 ros2_control(joint_trajectory_controller)下发,实时跟随用 moveit_servo
📌 本节小结:运动规划本质是在C-space里避开 C-obstacle 找一条 C-free 路径;MoveIt2 默认用 OMPL 采样规划,以 RRTConnect 打底,靠 ompl_planning.yaml 里的 planner_id / planning_time / planning_attempts 调参。约束规划与 computeCartesianPath 解决「直线/定姿态」类任务,避障靠 ACM + 自/环境碰撞 + Octomap 感知。复杂抓取用 MoveIt Task Constructor 拆成 Stage 图;真机落地靠 ros2_control(joint_trajectory_controller)+ moveit_servo 伺服;人形机器人则叠加双臂协同与整机平衡,宇树 H1 与智元灵犀 X1 的开源资料是重要实践参考。
🤔 思考题: 1. 若一条 7-DoF 手臂用 RRTConnect 在密集货架里规划反复失败,你会依次尝试哪三个调整?为什么?
2. 端一杯水走直线,为什么 computeCartesianPath 比关节空间规划更合适?fraction 停在 0.4 时最可能是哪里出了问题?
3. 抓取时把物体 attach 到末端与不 attach,对后续「抬升搬运」的碰撞检测结果有什么本质区别?
4. 自己动手:用官方 MTC 的 pickplace.py 在仿真里跑通一次「接近→抓取→抬升→放置」,并尝试把 GenerateGraspPose 的采样角度从 90° 改成 180°,观察成功率与候选解数量的变化。

10 参考来源

资料整理更新至 2026-08;版本与参数以各官方文档当前版本为准,本文中未能逐一核实之处均标注「约」。