简介:本资源是面向ROS2开发者与机器人算法工程师的ABB YuMi双臂协作机器人MoveIt2完整集成方案,聚焦双臂运动规划、碰撞避障与Gazebo仿真验证等核心需求。压缩包共64个文件,含12个xacro宏定义文件(构建模块化URDF模型)、6个YAML配置文件(涵盖运动学参数、规划器设置与传感器参数)、9个Python脚本(含双臂协同抓取、路径规划与RViz可视化控制示例)、22个STL网格模型(支撑高保真Gazebo物理仿真),以及URDF主模型、SRDF语义描述、RViz配置与多份说明文档,总大小11.42MB。已有70人学习下载,资源结构清晰,以yumi_moveit_config和yumi_description两大功能包为核心,配套launch启动脚本、CMakeLists编译配置及LICENSE合规声明,开箱即用于ROS2 Humble环境。读者可直接复用URDF模型、调用现成MoveIt2配置、运行Gazebo双臂仿真,并基于示例代码快速开发自定义双臂协同任务。 前段时间一直在做双臂协作场景的仿真预研,把一台 ABBYuMi 搬进了 ROS2 Humble 环境里,整套东西从 URDF 模型到 MoveIt2 配置包,再到 Gazebo 仿真和运动规划示例,全都跑通之后,我决定把整个搭建过程整理成一篇可以照着复现的文章。
这个项目解决的问题其实很现实:真实 ABBYuMi 硬件价格高、调试周期长,而且双臂机器人涉及的运动规划、碰撞避免、双手协同等问题,直接在真机上试错成本太高。所以用 URDF 建模 + MoveIt2 配置 + Gazebo 仿真,把整条链路在软件里先跑通,是性价比最高的方案。适合正在学习 ROS2 运动规划的学生、准备上手双臂机器人的工程师,以及想在 Gazebo 里做双臂算法验证的研究者参考。
下面我会按实际搭建顺序,从项目拆解、URDF 建模、MoveIt2 配置、Gazebo 集成,到最后的踩坑记录,完整过一遍。
1. 项目整体拆解:为什么是 ABBYuMi + MoveIt2 + Gazebo
很多做机械臂开发的人第一次接触双臂机器人时,第一反应是“这不就是两个单臂一起控制吗”。实际动手以后才发现,双臂系统的复杂性远不是简单叠加。它会涉及两个机械臂之间的碰撞避免、共享基座的动力学耦合、协同任务的轨迹约束等问题。这个项目选 ABBYuMi 作为载体,恰恰是因为它在这些方面很有代表性。
1.1 项目核心需求解析
把标题拆开看,这个项目其实包含五个模块:
- URDF 模型:机器人本体描述文件,包含运动学链路、几何外观、惯性参数、碰撞属性,是后续所有工作的基础。
- MoveIt2 配置包:基于 URDF 自动生成的配置集,定义规划组、IK 求解器、规划器参数、预定义位姿等。
- 运动规划示例:通过代码或 RViz 手动画目标点,让机械臂完成路径规划。
- Gazebo 仿真环境:在 Gazebo 中加载 URDF 模型,让机器人具备物理属性,可以响应控制器指令运动。
- ROS2 Humble 集成:以上所有模块在 ROS2 Humble 这个发行版下面协同工作。
这五个模块不是孤立的,它们之间的关系可以这样理解:URDF 是机器人的“身体描述”,MoveIt2 配置包是“大脑和运动神经系统”,Gazebo 是“虚拟训练场”,而 ROS2 Humble 是连接所有部分的“通信基站”。整个项目中,最难的不是某一个模块,而是让它们顺畅地协同工作。
1.2 为什么选 ABBYuMi 作为仿真对象
ABBYuMi 是典型的双臂协作机器人,14 个自由度,单臂 7 轴。它的工业场景非常明确:小件装配、插拔线束、精密操作。这些场景天然需要双臂配合,单个机械臂很难完成。
在仿真中做 ABBYuMi 还有一个好处:它的 URDF 描述相对规范,公开资料里能找到接近真实参数的模型。相比自己从零画一个双臂模型,直接基于 YuMi 的模型做配置,能把精力集中在 MoveIt2 和 Gazebo 集成这些更核心的问题上。
我用这个词直接搜的是“ABBYuMi”,虽然是 ABB 的简化叫法,但社区资料里都能对上,不会混淆。也有一些人用“YuMi”称呼,项目里统一写 ABBYuMi 就行。
1.3 技术选型:为什么是 MoveIt2 + Gazebo,而不是其他方案
双臂运动规划有很多技术栈组合,最常用的是下面这几种对比:
| 技术组合 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| MoveIt2 + Gazebo Classic | ROS2 原生支持好,教程多,生态成熟 | 仿真物理精度一般 | 绝大多数 ROS2 机器人项目 |
| MoveIt2 + MuJoCo | 物理仿真速度快,接触稳定 | ROS2 集成需要额外适配层 | 强化学习、高速仿真 |
| MoveIt1 + Gazebo (ROS1) | 老项目资料最多 | ROS1 已停止维护 | 维护旧工程 |
| CoppeliaSim + MoveIt 桥接 | 自带丰富模型和传感仿真 | 授权与社区资源受限 | 教学、轻量验证 |
这个项目选 MoveIt2 + Gazebo,核心原因是 ROS2 Humble 是当前长期支持版本,生态最成熟,遇到问题搜资料最容易。而且 ros2_control 已经深度集成到 Gazebo Classic 中,可以直接用 gazebo_ros2_control 插件把控制器管线跑通。MuJoCo 虽然物理仿真更稳,但为了完整覆盖 MoveIt2 的规划链路和 RViz 可视化,Gazebo 是更稳妥的选择。
2. 环境准备与 URDF 模型解析:打好双臂仿真的地基
在碰 MoveIt2 之前,先把环境搭好。一个干净的 ROS2 Humble 环境能省掉后面大部分烦恼。
2.1 ROS2 Humble + Gazebo 环境搭建
我用的是 Ubuntu 22.04 + ROS2 Humble。安装 ROS2 Humble 桌面版:
sudo apt update sudo apt install ros-humble-desktop python3-rosdep sudo rosdep init rosdep update echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrcGazebo 相关的包单独装:
sudo apt install ros-humble-gazebo-ros-pkgs ros-humble-gazebo-ros2-control这里有个容易踩的坑:ROS2 Humble 对应的是 Gazebo Classic 11,不是 Gazebo Fortress(gz sim)。虽然 Fortress 功能更新,但 MoveIt2 集成教程和 ros2_control 插件适配目前还是以 Gazebo Classic 为主。装完确认一下:
gazebo --version如果看到 Gazebo multi-robot simulator, version 11.x,说明环境没问题。
还需要安装 MoveIt2:
sudo apt install ros-humble-moveit安装完成后,建议建一个工作空间,把所有自定义包放进去:
mkdir -p ~/yumi_ws/src cd ~/yumi_ws colcon build2.2 YuMi 双臂机器人的 URDF 结构拆解
ABBYuMi 的 URDF 结构比较规整,整棵坐标树大致是:
base_link:机器人基座,固定在世界坐标系base:基座上的固定连杆link_1~link_7(左臂)link_1~link_7(右臂)gripper相关连杆(左右各一个)
左右臂的关节命名一般带_left和_right后缀,比如yumi_joint_1_l、yumi_joint_1_r。实际模型里可能名称会略微不同,但命名规则基本是这样。在配置 MoveIt2 规划组之前,必须先确认关节名称,因为后面所有配置都依赖这些字符串。
URDF 文件通常用 xacro 宏来写,因为左右臂高度对称,用一个宏批量生成两个臂的连杆和关节,能避免重复代码。一个典型的 xacro 定义大概长这样:
<xacro:macro name="yumi_arm" params="prefix"> <link name="${prefix}link_1"> <visual> <geometry> <mesh filename="package://yumi_description/meshes/${prefix}link_1.stl"/> </geometry> </visual> <collision> <geometry> <mesh filename="package://yumi_description/meshes/${prefix}link_1.stl"/> </geometry> </collision> </link> <joint name="${prefix}joint_1" type="revolute"> <parent link="base"/> <child link="${prefix}link_1"/> <origin xyz="... " rpy="..."/> <axis xyz="0 0 1"/> <limit lower="-2.96" upper="2.96" effort="20" velocity="1.5"/> </joint> </xacro:macro>调用时直接:
<xacro:yumi_arm prefix="yumi_"/>这样左侧就是yumi_joint_1、yumi_link_1,右侧同理加后缀。用宏封装的好处是:如果想要更换手臂尺寸或关节限位,只需改一处。
2.3 URDF 改造成符合 MoveIt2 和 Gazebo 要求的格式
很多人从网上下载一个 URDF 直接跑 MoveIt2,结果各种报错。原因是 MoveIt2 和 Gazebo 对 URDF 的要求比普通可视化展示严格得多。
第一,每个连杆必须有<collision>和<inertial>标签。没有惯性参数,Gazebo 里机器人会直接坍缩或者飘起来;没有碰撞参数,MoveIt2 无法做碰撞检测。如果找不到准确的惯性数据,最简单的方法是用 mesh 体积等量估算:
<inertial> <mass value="1.2"/> <inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/> </inertial>第二,必须在 URDF 里加入ros2_control标签,否则 Gazebo 无法通过 ros2_control 接口控制关节:
<ros2_control name="GazeboSystem" type="system"> <hardware> <plugin>gazebo_ros2_control/GazeboSystem</plugin> </hardware> <joint name="yumi_joint_1_l"> <command_interface name="position"> <param name="min">-2.96</param> <param name="max">2.96</param> </command_interface> <state_interface name="position"/> <state_interface name="velocity"/> </joint> <!-- 其他关节依此类推,左右臂全部写全 --> </ros2_control>第三,坐标系的命名要统一。MoveIt2 默认需要world坐标系或者base_link作为规划参考系。如果 URDF 里没有 world 链接,可以在 launch 文件里加一个虚拟 joint 把 base_link 固定到 world 上。
写完之后做自检:
cd ~/yumi_ws/src/yumi_description/urdf xacro yumi.urdf.xacro > yumi.urdf check_urdf yumi.urdfcheck_urdf会输出整棵运动学树,仔细检查左右臂是否对称、parent/child 关系是否正确。这一步发现问题修复成本最低,等进了 MoveIt2 再发现问题,排查难度会翻倍。
3. MoveIt2 配置包生成与运动规划:把“大脑”装给机器人
URDF 只是描述机器人的“身体”,MoveIt2 配置包则是让这台机器人“会动”的关键。手动写 MoveIt2 配置包会让人怀疑人生,幸好有 moveit_setup_assistant 这个交互工具。
3.1 用 moveit_setup_assistant 一键生成配置包
在刚才建好的工作空间里,先创建一个目录存放模型文件,然后启动配置助手:
mkdir -p ~/yumi_ws/src/yumi_description/urdf cp yumi.urdf ~/yumi_ws/src/yumi_description/urdf/ cd ~/yumi_ws colcon build source install/setup.bash ros2 launch moveit_setup_assistant setup_assistant.launch.py打开界面后,选择“Create New MoveIt Configuration Package”,加载写好的 yumi.urdf 文件。接下来是重点,几个关键步骤:
Self-Collision 矩阵:点击生成碰撞矩阵,MoveIt2 会自动计算哪些连杆对不可能碰撞,生成 SRDF 里的 disabled collision 矩阵。双臂机器人这一步特别重要,因为左右臂之间的很多碰撞关系是固定的,生成后不需要每次规划都检测,能大幅提升规划速度。
规划组设置:这是双臂机器人配置中最重要的部分。我设置了四个规划组:
| 规划组名 | 包含关节 | 用途 |
|---|---|---|
| left_arm | yumi_joint_1_l ~ yumi_joint_7_l | 左臂独立控制 |
| right_arm | yumi_joint_1_r ~ yumi_joint_7_r | 右臂独立控制 |
| both_arms | 左右臂全部 14 个关节 | 双臂协同规划 |
| left_gripper / right_gripper | 夹爪关节 | 夹爪控制 |
规划组的设置有讲究。如果只设置一个 both_arms 组,控制左臂时会把右臂也卷进来,规划效率低;如果只设置单个臂,双臂协同规划就没法做。这里全部设置,后续按场景选择。
预定义位姿:设置 home、zero、ready 等常用位姿。双臂机器人建议至少设置 home(两侧手臂自然下垂)和 ready(两侧手臂前伸准备操作)两个,调试时能省大量时间。
ROS2 Control:在配置助手里可以选择启用 ros2_control,它会自动生成 controllers.yaml 模板,后续在 Gazebo 里会用得上。
全部配置完成后,点击 Generate Package,选择输出目录,一般生成到 src 下。包名字可以叫yumi_moveit_config。
生成后编译验证:
cd ~/yumi_ws colcon build source install/setup.bash ros2 launch yumi_moveit_config demo.launch.py能顺利打开 RViz 并看到 YuMi 模型,说明配置包基本可用。
3.2 规划组与 IK 求解器配置:影响双臂稳定性的关键
MoveIt2 配置包生成后,有几处需要手动微调。
kinematics.yaml文件里默认的 IK 求解器是 KDL。KDL 对单臂效果不错,但双臂 14 自由度场景下,IK 求解速度会明显变慢,有时候还会出现奇异位形问题。我的建议是安装 TRAC-IK 替代:
sudo apt install ros-humble-trac-ik然后在 kinematics.yaml 中修改:
left_arm: kinematics_solver: trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin kinematics_solver_search_resolution: 0.005 kinematics_solver_timeout: 0.05 kinematics_solver_attempts: 3 right_arm: kinematics_solver: trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin kinematics_solver_search_resolution: 0.005 kinematics_solver_timeout: 0.05 kinematics_solver_attempts: 3 both_arms: kinematics_solver: trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin kinematics_solver_search_resolution: 0.005 kinematics_solver_timeout: 0.05 kinematics_solver_attempts: 3TRAC-IK 在双臂场景下的求解成功率明显高于 KDL,尤其是靠近工作空间边界的位置。
ompl_planning.yaml里可以调整各规划器的参数。默认用的 RRTConnect 对 14 自由度来说效率尚可,但如果觉得规划抖动大,可以改用 LBKPIECE 或设定更长的规划时间。我调试时降低了规划器的最大迭代次数,用允许略长一点的时间换更平滑的路径。
3.3 运动规划示例:用 MoveGroupInterface 写一个双臂规划程序
配置包只是基础,真正干活的是运动规划节点。我用 MoveGroupInterface 写了一个简单示例,实现左右臂同时运动到目标姿态:
#include <moveit/move_group_interface/move_group_interface.h> #include <rclcpp/rclcpp.hpp> int main(int argc, char* argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<rclcpp::Node>("yumi_dual_arm_plan"); moveit::planning_interface::MoveGroupInterface move_group_left(node, "left_arm"); moveit::planning_interface::MoveGroupInterface move_group_right(node, "right_arm"); move_group_left.setPlannerId("RRTConnect"); move_group_right.setPlannerId("RRTConnect"); move_group_left.setPlanningTime(5.0); move_group_right.setPlanningTime(5.0); // 设置目标位姿 geometry_msgs::msg::Pose target_pose_left; target_pose_left.position.x = 0.3; target_pose_left.position.y = 0.2; target_pose_left.position.z = 0.4; target_pose_left.orientation.w = 1.0; move_group_left.setPoseTarget(target_pose_left); geometry_msgs::msg::Pose target_pose_right; target_pose_right.position.x = 0.3; target_pose_right.position.y = -0.2; target_pose_right.position.z = 0.4; target_pose_right.orientation.w = 1.0; move_group_right.setPoseTarget(target_pose_right); // 分别规划 moveit::planning_interface::MoveGroupInterface::Plan plan_left; moveit::planning_interface::MoveGroupInterface::Plan plan_right; bool ok_left = (move_group_left.plan(plan_left) == moveit::core::MoveItErrorCode::SUCCESS); bool ok_right = (move_group_right.plan(plan_right) == moveit::core::MoveItErrorCode::SUCCESS); if (ok_left && ok_right) { move_group_left.execute(plan_left); move_group_right.execute(plan_right); } rclcpp::shutdown(); return 0; }编译方式和普通 ROS2 包一样,在 CMakeLists 里链接相应库。这个示例的关键点是两个 MoveGroupInterface 实例在同一个节点里分别控制两个规划组,这样能保证两条轨迹在时间上尽量同步,双臂协同效果更好。
如果要做真正的双臂协同(比如双手搬一块板),规划组要选both_arms,然后把目标位姿设到某个物体坐标系上,让 MoveIt2 同时规划 14 个关节。这种方式规划时间更长,但轨迹天然满足双臂之间的约束。
4. Gazebo 仿真环境集成:让机器人真正“动起来”
MoveIt2 在 RViz 里的规划只是“理论轨迹”,要让机器人真正按轨迹运动,必须接入 Gazebo 物理仿真。这也是很多人卡住的环节,MoveIt2 规划好了但 Gazebo 里机器人就是不动,或者动得完全不对。
4.1 MoveIt2 和 Gazebo 是如何“结合”的
先理解整个数据流。MoveIt2 运动规划完成后,把轨迹发送给执行器。在 Gazebo 场景里,执行器不是硬件,而是 ros2_control 的控制器。整条链路如下:
- MoveIt2 规划出一条轨迹
- MoveIt2 把轨迹发送到 FollowJointTrajectory 控制器(话题通常是
/controller_manager/node_names或者具体的/yumi_arm_controller/follow_joint_trajectory) - ros2_control 的 JointTrajectoryController 拆解轨迹,按控制周期下发关节位置
- gazebo_ros2_control 插件把位置指令转换成物理仿真里的关节驱动力矩
- 仿真模型通过
/joint_states发布实际关节状态 - MoveIt2 订阅关节状态,更新机器人当前位姿
用一句话概括:MoveIt2 负责“想”,Gazebo 负责“做”,ros2_control 是负责传递动作的“神经”。
这个通信链条里最常出问题的是控制器名字不匹配。MoveIt2 默认发送到/follow_joint_trajectory,但实际控制器可能叫/yumi_arm_controller/follow_joint_trajectory,不匹配就导致 MoveIt2 规划完轨迹却没人执行。
4.2 ros2_control 控制器配置
在生成 MoveIt2 配置包时,如果勾选了 ROS2 Control 选项,会有一个 controllers.yaml 模板。实际使用时要根据 URDF 里的关节名称做修改:
controller_manager: ros__parameters: update_rate: 100 use_sim_time: true yumi_arm_controller: type: joint_trajectory_controller/JointTrajectoryController joint_state_broadcaster: type: joint_state_broadcaster/JointStateBroadcaster yumi_arm_controller: ros__parameters: joints: - yumi_joint_1_l - yumi_joint_2_l - yumi_joint_3_l - yumi_joint_4_l - yumi_joint_5_l - yumi_joint_6_l - yumi_joint_7_l - yumi_joint_1_r - yumi_joint_2_r - yumi_joint_3_r - yumi_joint_4_r - yumi_joint_5_r - yumi_joint_6_r - yumi_joint_7_r注意双臂机器人这里要一次把所有关节都写上,不能只写一条手臂。否则另一条手臂会失去控制。
在 Gazebo 的 world 文件或者 launch 文件里,需要加载 ros2_control 插件。一般情况下 launch 文件会处理这些。一个标准的 Gazebo + MoveIt2 联合启动顺序是:
- 启动 Gazebo 服务端并加载模型
- 启动 controller_manager 并加载 controllers
- 启动 MoveIt2 move_group
- 启动 RViz 可视化
4.3 启动文件整合
我习惯把启动逻辑写在一个 launch 文件里,按顺序串起来:
import launch import launch_ros.actions from launch.actions import ExecuteProcess from launch_ros.actions import Node def generate_launch_description(): return launch.LaunchDescription([ # 1. 启动 Gazebo ExecuteProcess( cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_init.so', '-s', 'libgazebo_ros_factory.so'], output='screen' ), # 2. 加载机器人模型到 Gazebo Node( package='gazebo_ros', executable='spawn_entity.py', arguments=['-entity', 'yumi', '-file', 'yumi.urdf'], output='screen' ), # 3. 启动 controller_manager Node( package='controller_manager', executable='ros2_control_node', parameters=['config/controllers.yaml'], output='screen' ), # 4. 激活控制器 ExecuteProcess( cmd=['ros2', 'control', 'load_controller', '--set-state', 'active', 'joint_state_broadcaster'], output='screen' ), ExecuteProcess( cmd=['ros2', 'control', 'load_controller', '--set-state', 'active', 'yumi_arm_controller'], output='screen' ), # 5. 启动 MoveIt2 move_group Node( package='yumi_moveit_config', executable='move_group', output='screen' ), # 6. 启动 RViz Node( package='rviz2', executable='rviz2', arguments=['-d', 'config/moveit.rviz'], output='screen' ), ])实际调试时,我不会直接一次性全启动,而是先启动前四步,确认 Gazebo 里机器人正常加载、控制器 active,再启动 move_group 和 RViz。这样出了问题能快速定位是控制链路的问题还是规划链路的问题。
4.4 在 Gazebo 中验证双臂轨迹执行
全部启动后,用命令行发一条轨迹测试:
ros2 topic pub -1 /yumi_arm_controller/joint_trajectory trajectory_msgs/msg/JointTrajectory \ "{joint_names: [yumi_joint_1_l, yumi_joint_2_l, yumi_joint_3_l, yumi_joint_4_l, yumi_joint_5_l, yumi_joint_6_l, yumi_joint_7_l, yumi_joint_1_r, yumi_joint_2_r, yumi_joint_3_r, yumi_joint_4_r, yumi_joint_5_r, yumi_joint_6_r, yumi_joint_7_r], points: [{positions: [0.1, 0.2, 0.3, 0.0, 0.5, 0.0, 0.1, -0.1, -0.2, -0.3, 0.0, 0.5, 0.0, -0.1], time_from_start: {sec: 3}}]}"如果机器人在 Gazebo 里按预期轨迹运动,说明整条控制链路是通的。这时候再回到 MoveIt2 的 RViz 界面,拖动手柄设置目标,点 Plan & Execute,不出意外就能看到双臂在 Gazebo 里执行规划好的动作。
这里有一个细节需要留意:Gazebo 里的关节响应默认是纯位置控制,如果 PID 参数调得不好,动作会比较“肉”,跟手速度跟不上 MoveIt2 的轨迹点下发速度。出现这种情况时,调节gazebo_ros2_control插件中的 PID 参数,通常先把比例增益调大,再微调微分项。实测下来,双臂仿真对 PID 比单臂更敏感,因为两条手臂同时运动时,基座会有轻微反作用力,PID 不当会导致末端轨迹出现肉眼可见的偏差。
5. 常见问题与排查技巧实录
做这个项目时踩了不少坑,我把典型问题整理出来,按现象、原因、解决方案的方式列在下面,基本都是可以直接照做的。
5.1 MoveIt2 规划失败,提示 “No Solution Found”
现象:RViz 里点 Plan,状态栏提示规划失败。
排查思路:
- 先看目标是否在可达空间内。双臂机器人的工作空间不是简单的两个球体相加,左右臂协同时会互相挤压活动范围,特别是靠近身体中线的位置。
- 检查 allowed_planning_time,默认 5 秒对双臂场景略短,建议调大到 10 秒。
- 检查碰撞矩阵。如果两条手臂默认位姿就在碰撞状态,MoveIt2 会认为初始状态不合法,任何规划都失败。
解决方案:先手动把机器人拖到一个无碰撞的初始位姿,重新 Set Start State,再规划;或者修改ompl_planning.yaml,增大max_goal_samples和max_planning_time。
5.2 Gazebo 里机器人“散架”或关节不受控
现象:模型加载后,手臂乱甩、下垂、抖动,或者完全不动。
原因:绝大多数是惯性参数缺失或 PID 参数不合理。URDF 里如果没有<inertial>,Gazebo 内部的物理引擎会用默认值,这个默认值对双臂这种长悬臂结构非常不友好,重力作用下关节直接发飘。
解决方案:
- 给每个连杆补全
<inertial>参数,质量设置要尽量接近真实值,xacro 宏最好把惯性参数也参数化。 - 调高控制器 PID 的比例增益,在
gazebo_ros2_control插件参数里找到gains配置:
gazebo_ros2_control: ros__parameters: gains: yumi_joint_1_l: {p: 100.0, i: 0.5, d: 1.0} yumi_joint_2_l: {p: 100.0, i: 0.5, d: 1.0} # 其他关节按需调整可以先每个关节统一设置一个较大 P 值,观察稳定性,再逐个调试。
5.3 Gazebo 和 MoveIt2 的通信不上,执行轨迹没反应
现象:MoveIt2 RViz 里看着规划成功,也提示执行了,但 Gazebo 里机器人纹丝不动。
原因:这是 MoveIt2 + Gazebo 集成最常见的坑,90% 的情况是控制器话题名不匹配。
排查方法:
ros2 topic list | grep trajectory我看一下实际话题名。如果看到/yumi_arm_controller/follow_joint_trajectory,说明控制器名字是 yumi_arm_controller,此时需要让 MoveIt2 知道用这个控制器执行轨迹。检查 MoveIt2 配置包中的 move_group 节点参数,一般会有一个trajectory_execution的配置文件,确保里面的controller_names列表和实际控制器名字一致。
还有一种情况是 use_sim_time 没有设置为 true。Gazebo 发布的是仿真时钟,如果不启用 use_sim_time,MoveIt2 和 ros2_control 会各自使用系统时钟,导致时间不同步,轨迹执行状态永远对不上。所有节点都要设置:
ros__parameters: use_sim_time: true5.4 双臂规划时一条手臂动,另一条手臂不动
现象:用 both_arms 规划组做双臂规划,执行时只有一条手臂在动。
原因:controllers.yaml 里关节列表只写了部分关节,或者 joint_state_broadcaster 没有发布全部关节状态。
解决方案:确认 controllers.yaml 中joints列表包含全部 14 个关节,同时检查 Gazebo 启动时关节状态话题,确认左右臂关节都在更新。还有一种可能是 SRDF 中定义的规划组遗漏了某个关节,回到 moveit_setup_assistant 检查规划组包含的关节列表。
5.5 常见问题速查表
为了方便快速定位,我把问题整理成速查表:
| 现象 | 大概率原因 | 首要排查步骤 |
|---|---|---|
| RViz 里模型显示为空白 | URDF 加载失败或 mesh 路径错误 | 检查 xacro 生成的 URDF,确认 mesh 路径是 package 绝对引用 |
| Gazebo 里模型下沉或反弹 | 惯性参数为 0 或接触参数错误 | 逐个连杆补 inertials,调整 contact 参数 |
| 规划很慢 | 碰撞矩阵没有生成 | 在 moveit_setup_assistant 重新生成 Self-Collision 矩阵 |
| 控制器一直 inactive | controller_manager 没加载资源 | 检查 URDF 的 ros2_control 标签和 controllers.yaml 是否匹配 |
| move_group 启动报错 | SRDF 与 URDF 不匹配 | 重新用 moveit_setup_assistant 生成配置包 |
| Gazebo 仿真速度很慢 | 物理步长太小或模型面数太多 | 调大 max_step_size,简化 mesh 面数 |
做双臂仿真的体验和单臂差别很大。单臂出现问题,直接看运动学就能定位;双臂则要考虑两条手臂之间的相互影响,很多时候左臂规划失败,原因出在右臂的位姿上。我在实际调试中体会到,仿真环境下这种问题还算好处理,如果是在真机上,排查成本会高得多。
最后分享一个我自己的小小经验:每次调整 URDF 或者控制参数后,不要急着跑完整链路,先单独验证两步。第一步用check_urdf确认模型结构正确,第二步直接给关节发位置指令验证控制器能响应。这两步都通了,再把 MoveIt2 加进来做规划执行。分段验证看起来繁琐,但能帮你把问题隔绝在最小范围内。
本文还有配套的精品资源,点击获取