ROS2系列教程:Moveit2环境与机械臂建模准备
本文摘要
本文是 ROS2 系列教程的第 35 篇:MoveIt2 环境与机械臂建模准备。第 31~34 篇我们完成了移动底盘机器人的完整实战(建图、导航、任务、安全)。。第 35…
本文是 ROS2 系列教程的第 35 篇
本文是 ROS2 系列教程的第 35 篇:MoveIt2 环境与机械臂建模准备。第 31~34 篇我们完成了移动底盘机器人的完整实战(建图、导航、任务、安全)。从本篇开始,系列进入最后一个大阶段:MoveIt2 机械臂篇。第 35 篇先解决“地基”:MoveIt2 是什么、环境怎么装、机械臂怎么用 URDF/Xacro 描述、怎么用工具自动生成 MoveIt2 配置包,最后用 RViz 可视化验证模型。移动机器人关心“轮子转多少”,机械臂关心“关节动多少”——坐标系与运动学思维将从这里焕然一新。
一、MoveIt2 到底是什么
1.1 一句话理解
MoveIt2 是 ROS2 的机械臂运动规划框架:你给它一个机械臂的 URDF 模型和一个目标位姿(比如“把手伸到桌上那个杯子”),它负责规划出一条无碰撞的关节轨迹,并交给控制器执行。
它不是一个单体程序,而是一组模块的集合:
MoveIt2 核心模块├── Move Group 节点 # 中枢:接收目标,调度规划├── Robot Model / URDF # 机械臂几何与运动学描述├── Planning Scene # 场景:障碍物、自碰撞、允许碰撞矩阵├── Motion Planner # 规划器:OMPL(默认)/ Pilz / STOMP├── Kinematics # 运动学:正向 FK / 逆解 IK(KDL / IKFast / TRAC-IK)├── Collision Checking # 碰撞检测:FCL 库├── MoveIt 控制接口 # 与 ros2_control 对接(第 28 篇基础)└── RViz 插件(MotionPlanning) # 可视化与手动拖拽目标1.2 MoveIt2 vs MoveIt1
| 对比 | MoveIt1(ROS1) | MoveIt2(ROS2) |
|---|---|---|
| 驱动接口 | 自定义 ControllerManager | ros2_control 统一管理 |
| 参数 | YAML + rosparam | YAML + rclcpp 参数节点 |
| 规划器 | OMPL | OMPL(C++ 重构版) |
| 行为树 | SMACH | Behavior Trees(可选) |
| 维护状态 | 维护模式 | 活跃开发 |
学习建议:直接学 MoveIt2。教程环境是 Humble 版 MoveIt2,与 ROS2 Humble 一一对应。
二、环境安装(一步到位)
2.1 二进制安装(推荐)
MoveIt2 官方提供二进制包,比源码编译快得多:
# 1. 确认 ROS2 Humble 已安装source /opt/ros/humble/setup.bashecho $ROS_DISTRO # 期望输出 humble
# 2. 安装 MoveIt2 全部二进制包sudo apt install ros-humble-moveit
# 3. 安装机械臂模型(示例用 Panda 或 UR5)sudo apt install ros-humble-panda-moveit-config
# 4. 验证安装ros2 pkg list | grep moveit# 期望看到:moveit_core moveit_ros_planning moveit_ros_planning_interface 等安装完成后用一个小测试确认能跑:
ros2 launch moveit2_tutorials demo.launch.py# 或直接用 Panda 演示ros2 launch panda_moveit_config demo.launch.py如果能看到 RViz 里出现一个 Panda 机械臂模型(7 个关节的红色/灰色手臂),环境就绪。
2.2 源码编译(可选,进阶)
二进制满足不了需求(想改 MoveIt2 源码)时再走源码:
mkdir -p ~/moveit2_ws/src && cd ~/moveit2_wswget https://raw.githubusercontent.com/moveit/moveit2/humble/moveit2.reposvcs import src < moveit2.reposrosdep install -r --from-paths src --ignore-src --rosdistro humble -ycolcon build --cmake-args -DCMAKE_BUILD_TYPE=Release源码编译约需 20~40 分钟(视机器性能),编译失败常见原因是依赖缺失,跑 rosdep install 即可。
2.3 安装验证清单
# 快速自查 5 项ros2 pkg prefix moveit_core # 1. 核心包存在ros2 pkg prefix moveit_ros_planning_interface # 2. 接口包存在ls /opt/ros/humble/share/moveit_ros_visualization # 3. RViz 插件存在which ros2 # 4. ROS2 可用echo $ROS_DISTRO # 5. 版本正确三、机械臂的 URDF 描述(与移动机器人的差异)
3.1 机械臂 URDF 的独特之处
第 16 篇我们写过移动底盘的 URDF。机械臂 URDF 有三点明显不同:
- 关节类型是 revolute(旋转):移动底盘的轮子是 continuous(连续旋转),机械臂关节是有限角度旋转,用
<limit>限制关节范围。 - 每个关节一个电机:不是“两轮差速”一个控制器,而是每个关节一个 joint 控制器。
- 末端执行器(end effector):最末端的 link 是夹爪/吸盘/工具,MoveIt2 要单独知道它。
一个简化版两连杆机械臂 URDF(理解结构用):
<!-- two_link_arm.urdf:两连杆机械臂(简化教学版) --><robot name="two_link_arm"> <!-- 基座:固定在地面 --> <link name="base_link"> <visual> <geometry><box size="0.2 0.2 0.1"/></geometry> </visual> <collision> <geometry><box size="0.2 0.2 0.1"/></geometry> </collision> </link>
<!-- 肩关节:绕 z 轴旋转,-90°~90° --> <joint name="shoulder_joint" type="revolute"> <parent link="base_link"/> <child link="shoulder_link"/> <origin xyz="0 0 0.1" rpy="0 0 0"/> <axis xyz="0 0 1"/> <limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/> </joint> <link name="shoulder_link"> <visual> <geometry><box size="0.05 0.05 0.4"/></geometry> <origin xyz="0 0 0.2"/> </visual> </link>
<!-- 肘关节:绕 y 轴旋转(另一个方向) --> <joint name="elbow_joint" type="revolute"> <parent link="shoulder_link"/> <child link="elbow_link"/> <origin xyz="0 0 0.4" rpy="0 0 0"/> <axis xyz="0 1 0"/> <limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/> </joint> <link name="elbow_link"> <visual> <geometry><box size="0.05 0.05 0.35"/></geometry> <origin xyz="0 0 0.175"/> </visual> </link>
<!-- 末端执行器 --> <link name="tool0"/> <joint name="tool_joint" type="fixed"> <parent link="elbow_link"/> <child link="tool0"/> <origin xyz="0 0 0.35"/> </joint></robot>三个关键点:
<limit lower upper>:必填,MoveIt2 规划不能越过关节限位。<axis>:旋转轴方向(肩绕 z,肘绕 y),写错轴模型会“乱扭”。- 末端固定关节:工具坐标系
tool0用固定关节挂在末杆上。
3.2 用 Xacro 参数化(正式项目必用)
真实机械臂(如 Panda、UR5)连杆多、参数繁,全部写死在一个 URDF 里维护困难。用 Xacro 宏定义“连杆 + 关节”模板:
<!-- arm.xacro:参数化机械臂 --><robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="arm"> <!-- 定义一个连杆宏:名字 + 长度 + 半径 --> <xacro:macro name="arm_link" params="prefix length radius"> <link name="${prefix}_link"> <visual> <geometry><cylinder radius="${radius}" length="${length}"/></geometry> <origin xyz="0 0 ${length/2}"/> <material name="gray"><color rgba="0.5 0.5 0.5 1"/></material> </visual> <collision> <geometry><cylinder radius="${radius}" length="${length}"/></geometry> <origin xyz="0 0 ${length/2}"/> </collision> </link> <joint name="${prefix}_joint" type="revolute"> <parent link="${prefix}_base"/> <child link="${prefix}_link"/> <axis xyz="0 0 1"/> <limit lower="-3.14" upper="3.14" effort="20" velocity="1.5"/> </joint> </xacro:macro>
<!-- 调用 3 次生成三连杆 --> <xacro:arm_link prefix="link1" length="0.3" radius="0.04"/> <xacro:arm_link prefix="link2" length="0.3" radius="0.04"/> <xacro:arm_link prefix="link3" length="0.2" radius="0.03"/></robot>好处:改长度只改一处参数;加一节手臂只加一行调用。真实机械臂的 xacro 都这么组织(link 定义 + joint 定义分离 + 宏复用)。
3.3 检查模型的必备工具
模型写完先自查,再进 MoveIt2:
# 1. 语法与几何检查check_urdf arm.urdf # 输出 link/joint 树,报错会指出问题
# 2. Xacro 展开为纯 URDF(MoveIt2 用的是展开后的)xacro arm.xacro > arm_generated.urdf
# 3. RViz 可视化ros2 launch urdf_tutorial display.launch.py model:=arm_generated.urdf# 或手动:robot_state_publisher + RViz 加载
# 4. TF 树确认ros2 run tf2_ros tf2_echo base_link tool0check_urdf 输出应显示完整父子链:base_link → shoulder → elbow → tool0。有断链说明 joint 的 parent/child 写错了。
四、示例 1:用工具生成 MoveIt2 配置包
手工写 MoveIt2 配置(SRDF、规划组、控制器 YAML、launch)繁琐且易错。官方工具 moveit_setup_assistant 一条龙生成。
4.1 启动 Setup Assistant
ros2 run moveit_setup_assistant moveit_setup_assistant界面操作流程(英文界面,按顺序):
- Create New MoveIt Configuration Package → 选择你的 URDF/Xacro 文件(如
arm_generated.urdf)。 - Self-Collisions:点 “Generate Collision Matrix” 自动计算自碰撞矩阵(哪些 link 对永远不会碰,直接排除,省规划时间)。
- Virtual Joints:机械臂装在移动底盘上时,加一个虚拟关节
virtual_joint(固定类型,parent 为 world/odom)。纯固定机械臂可跳过。 - Planning Groups:点 “Add Group”,勾选所有关节组成一个运动组(如
arm_group,Kinematic Solver 选kdl_kinematics_plugin/KDLKinematicsPlugin)。 - Robot Poses(可选):预设几个常用姿态(home、vertical 等),便于测试。
- End Effectors:把
tool0标记为末端执行器,命名eef_group,parent link 填tool0。 - Passive Joints / Controllers:默认即可,控制器 YAML 由助理生成。
- Author Information:填包名
arm_moveit_config。 - 点 Generate Package 选择输出目录,生成完毕。
4.2 生成的包结构
arm_moveit_config/├── config/│ ├── arm.srdf # 语义描述:规划组/虚拟关节/末端│ ├── joint_limits.yaml # 关节限位(从 URDF 提取,可覆盖)│ ├── kinematics.yaml # 逆解求解器配置(KDL)│ ├── ompl_planning.yaml # OMPL 规划器配置│ ├── moveit_controllers.yaml # 与 ros2_control 的映射│ └── move_group.yaml # move_group 节点参数├── launch/│ ├── demo.launch.py # 一键演示:RViz + move_group + 仿真控制器│ ├── move_group.launch.py│ └── setup_assistant.launch.py├── package.xml└── CMakeLists.txt4.3 一键测试生成的包
ros2 launch arm_moveit_config demo.launch.py成功标准:RViz 出现机械臂模型 + MoveIt MotionPlanning 面板。此时已经可以用“拖拽末端目标”或“规划执行”按钮让虚拟机械臂动起来——第 36 篇将详细讲运动规划,这里先确认链路通了。
五、示例 2:手动编写 SRDF(理解原理)
Setup Assistant 自动生成 SRDF,但理解它才能改它。SRDF(Semantic Robot Description Format)告诉 MoveIt2 “哪些 link 组成了一个可规划的组”。核心三块:
<!-- arm.srdf 核心片段(手动版) --><robot name="arm"> <!-- 1. 规划组:arm_group 包含全部 3 个关节 --> <group name="arm_group"> <joint name="shoulder_joint"/> <joint name="elbow_joint"/> <joint name="wrist_joint"/> </group>
<!-- 2. 末端执行器组 --> <group name="eef_group"> <link name="tool0"/> </group> <end_effector name="eef" parent_link="elbow_link" group="eef_group"/>
<!-- 3. 默认姿态:规划前回到 home 位 --> <group_state name="home" group="arm_group"> <joint name="shoulder_joint" value="0.0"/> <joint name="elbow_joint" value="0.0"/> <joint name="wrist_joint" value="0.0"/> </group_state>
<!-- 4. 禁用碰撞对:肩-肘永远不会碰,告诉规划器不用查 --> <disable_collisions link1="base_link" link2="shoulder_link" reason="Adjacent"/> <disable_collisions link1="shoulder_link" link2="elbow_link" reason="Adjacent"/></robot>- group:规划的最小单位,MoveIt2 对整个组做运动学计算。
- group_state:预设姿态,测试时一键回到某姿态。
- disable_collisions:相邻连杆必选(它们本来就固定相连),不相邻的靠 Setup Assistant 自动算。
六、示例 3:kinematics.yaml 与逆解求解器
6.1 逆解(IK)是什么
- 正解 FK:给定关节角度 → 求末端位置(唯一,好算)。
- 逆解 IK:给定末端目标位姿 → 求关节角度(可能无解/多解,难)。
MoveIt2 用运动学插件做 IK。kinematics.yaml 声明用哪个插件:
# kinematics.yaml:声明 IK 求解器arm_group: kinematics_solver: kdl_kinematics_plugin/KDLKinematicsPlugin kinematics_solver_search_resolution: 0.005 kinematics_solver_timeout: 0.005 kinematics_solver_attempts: 3常用求解器对比:
| 求解器 | 特点 | 适用 |
|---|---|---|
| KDL(默认) | 通用数值解,够用 | 大多数机械臂 |
| TRAC-IK | KDL 加强版,成功率更高 | 复杂构型 / 奇异位形 |
| IKFast | 解析解,快且准 | 6 自由度且运动学结构简单 |
6.2 手写测试 IK
# 用 moveit 的 IK 命令行工具测试(需先启动 demo)ros2 launch arm_moveit_config demo.launch.py
# 在另一个终端调用 IK 服务(服务名随配置可能不同)ros2 service list | grep compute_ik规划失败先怀疑 IK:把末端目标挪到工作空间内(离基座 0.3~0.5m、不越过肩关节正上方),再试。
七、MoveIt2 与 ros2_control 的对接(真机准备)
第 28 篇讲过 ros2_control。MoveIt2 规划出的轨迹要执行,必须通过 ros2_control 发给关节控制器。对接的“合同”就是 moveit_controllers.yaml:
# moveit_controllers.yaml:MoveIt2 到 ros2_control 的映射moveit_simple_controller_manager: controller_names: - arm_controller
arm_controller: type: FollowJointTrajectory action_ns: follow_joint_trajectory default: true joints: - shoulder_joint - elbow_joint - wrist_joint配合 ros2_control 端的控制器配置(第 28 篇的 joint_trajectory_controller):
# arm_controllers.yaml(ros2_control 侧)controller_manager: ros__parameters: update_rate: 100 arm_controller: type: joint_trajectory_controller/JointTrajectoryController
arm_controller: ros__parameters: joints: - shoulder_joint - elbow_joint - wrist_joint command_interfaces: [position] state_interfaces: [position]职责划分:MoveIt2 负责“想清楚怎么动”(规划),ros2_control 负责“真去动”(发指令给电机)。两者通过 Action 通信:MoveIt2 发 FollowJointTrajectory 目标,控制器执行后回报结果。真机篇(第 40 篇)会完整展开。
八、常见问题与排障
| 现象 | 原因 | 解决 |
|---|---|---|
| 安装后 ros2 pkg list 查不到 moveit | 没 source /opt/ros/humble/setup.bash | source 后再查 |
| demo.launch.py 报包找不到 | 没 build / 没 source 工作空间 | colcon build + source install/setup.bash |
| RViz 无机械臂模型 | robot_description 没发布 | 检查 robot_state_publisher 是否启动 |
| 关节乱扭 | URDF 的 axis 写错 | 逐个核对 joint 的 axis 与物理轴一致 |
| 逆解无解 | 目标超出工作空间 | 目标移到工作空间内(半径 = 臂长总和) |
| 规划失败但没报错 | 目标与自碰撞冲突 | 查看 Planning Scene,检查初始姿态 |
| Setup Assistant 打不开 | 缺 GUI 库 / 显示问题 | 确认有桌面环境;检查 DISPLAY 变量 |
| 生成的包 demo 报控制器错 | 控制器 YAML 未生成/未 source | 检查 moveit_controllers.yaml 是否被加载 |
九、小结与下一篇预告
本篇核心:
- MoveIt2 是“规划框架”不是单个程序:Move Group 中枢 + OMPL 规划 + KDL 逆解 + FCL 碰撞检测 + RViz 可视化。
- 机械臂 URDF 与移动底盘不同:revolute 关节 + 限位 + 末端执行器,用 Xacro 宏参数化。
- Setup Assistant 一键生成配置包(SRDF / kinematics / controllers),理解 SRDF 才能手改。
- MoveIt2 规划、ros2_control 执行,两者靠 Action 对接——真机控制的地基。
至此,MoveIt2 的“地基”已打好:环境装好、模型建好、配置包生成、可视化验证通过。
下一篇(第 36 篇)「MoveIt2 仿真与运动规划(基础)」:深入 demo 启动流程,用 MoveIt2 的 Python/C++ 接口写第一个运动规划程序,理解 move_group 的 API(设置目标、规划、执行、轨迹可视化),并动手控制仿真机械臂做点到点运动与笛卡尔路径运动。
ROS2系列教程:Moveit2环境与机械臂建模准备
作者:Wang Shijie
本文链接:https://wsj-blog.pages.dev/posts/ros2-xi-lie-jiao-cheng-moveit2-huan-jing-yu-ji-xie-bi-jian/
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
留言评论
评论资源加载失败,请重试。