ROS2 Humble + Gazebo 11 保姆级教程:从零搭建一个能跑能停的差分AGV模型
ROS2 Humble Gazebo 11 实战指南从零构建可自主导航的差分AGV在机器人开发领域仿真环境的重要性不言而喻。它不仅能大幅降低硬件成本还能加速算法验证和系统调试的迭代周期。ROS2与Gazebo的组合正成为现代机器人开发者不可或缺的工具链。本文将带你从零开始构建一个完整的差分驱动AGV自动导引车仿真系统涵盖模型创建、物理仿真、运动控制等关键环节。1. 开发环境准备与基础配置1.1 系统与软件要求在开始之前请确保你的系统满足以下最低要求操作系统Ubuntu 22.04 LTS推荐或20.04 LTSROS2版本Humble Hawksbill长期支持版Gazebo版本Gazebo Fortress或Classic 11本文基于11版本安装基础环境sudo apt update sudo apt install -y ros-humble-desktop ros-humble-gazebo-ros-pkgs验证安装source /opt/ros/humble/setup.bash ros2 run gazebo_ros gazebo --version1.2 创建工作空间与功能包创建一个独立的工作空间有助于项目管理mkdir -p ~/agv_ws/src cd ~/agv_ws/src ros2 pkg create --build-type ament_cmake agv_simulation \ --dependencies rclcpp gazebo_ros_pkgs geometry_msgs目录结构建议如下agv_simulation/ ├── config/ # 配置文件 ├── launch/ # 启动文件 ├── meshes/ # 3D模型文件 ├── models/ # Gazebo模型 ├── scripts/ # Python脚本 ├── urdf/ # URDF/Xacro文件 ├── CMakeLists.txt └── package.xml提示在package.xml中添加以下依赖项确保功能完整dependrobot_state_publisher/depend dependjoint_state_publisher/depend dependxacro/depend2. AGV机械模型构建2.1 Xacro模型定义基础XacroXML宏是ROS中用于简化URDF编写的工具。我们首先定义差分AGV的基本结构!-- agv_simulation/urdf/agv.xacro -- robot namediff_agv xmlns:xacrohttp://www.ros.org/wiki/xacro !-- 材料定义 -- material nameblue color rgba0 0 0.8 1/ /material material nameblack color rgba0.1 0.1 0.1 1/ /material !-- 基础链接 -- link namebase_link visual geometry box size0.4 0.2 0.1/ /geometry material nameblue/ /visual collision geometry box size0.4 0.2 0.1/ /geometry /collision inertial mass value5.0/ inertia ixx0.1 ixy0 ixz0 iyy0.1 iyz0 izz0.1/ /inertial /link /robot2.2 完整差分驱动结构扩展模型包含驱动轮和万向轮!-- 左驱动轮 -- link nameleft_wheel visual geometry cylinder radius0.05 length0.03/ /geometry material nameblack/ /visual collision geometry cylinder radius0.05 length0.03/ /geometry /collision inertial mass value0.5/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.002/ /inertial /link joint nameleft_wheel_joint typecontinuous parent linkbase_link/ child linkleft_wheel/ origin xyz0 0.15 -0.05 rpy1.5708 0 0/ axis xyz0 1 0/ /joint !-- 右驱动轮与左轮对称 -- link nameright_wheel !-- 类似左轮的定义 -- /link joint nameright_wheel_joint typecontinuous !-- 类似左轮关节 -- /joint !-- 万向轮 -- link namecaster_wheel visual geometry sphere radius0.03/ /geometry material nameblack/ /visual collision geometry sphere radius0.03/ /geometry /collision inertial mass value0.2/ inertia ixx0.0001 ixy0 ixz0 iyy0.0001 iyz0 izz0.0001/ /inertial /link joint namecaster_joint typefixed parent linkbase_link/ child linkcaster_wheel/ origin xyz-0.15 0 -0.05/ /joint2.3 模型验证与调试使用RViz进行可视化验证ros2 launch agv_simulation display.launch.py常见问题排查模型不显示检查URDF转换是否正确xacro agv.xacro agv.urdf关节异常验证joint_state_publisher是否正常运行颜色丢失确保material定义正确且RViz配置中RobotModel的Alpha值不为03. Gazebo仿真集成3.1 Gazebo插件配置要让模型在Gazebo中具有物理特性需要添加Gazebo标签!-- 在xacro文件中添加 -- gazebo referencebase_link materialGazebo/Blue/material /gazebo gazebo referenceleft_wheel mu1 value1.0/ mu2 value1.0/ materialGazebo/Black/material /gazebo !-- 类似配置其他链接 --3.2 差分驱动插件核心驱动配置gazebo plugin namediff_drive filenamelibgazebo_ros_diff_drive.so ros namespace/agv/namespace /ros left_jointleft_wheel_joint/left_joint right_jointright_wheel_joint/right_joint wheel_separation0.3/wheel_separation wheel_diameter0.1/wheel_diameter max_wheel_torque20/max_wheel_torque max_wheel_acceleration5.0/max_wheel_acceleration command_topiccmd_vel/command_topic odometry_topicodom/odometry_topic odometry_frameodom/odometry_frame robot_base_framebase_link/robot_base_frame /plugin /gazebo关键参数说明参数说明推荐值wheel_separation两轮中心距0.2-0.4mwheel_diameter轮径0.08-0.15mmax_wheel_torque最大扭矩10-50Nmpublish_odom_tf发布TF变换true3.3 启动Gazebo世界创建启动文件agv_simulation/launch/gazebo.launch.pyfrom launch import LaunchDescription from launch_ros.actions import Node from launch.actions import ExecuteProcess def generate_launch_description(): return LaunchDescription([ ExecuteProcess( cmd[gazebo, --verbose, -s, libgazebo_ros_init.so], outputscreen ), Node( packagegazebo_ros, executablespawn_entity.py, arguments[-topic, robot_description, -entity, agv], outputscreen ) ])4. 运动控制实现4.1 键盘控制测试使用ROS2内置的键盘控制节点ros2 run teleop_twist_keyboard teleop_twist_keyboard \ --ros-args -r /cmd_vel:/agv/cmd_vel控制命令对照表按键功能对应消息i前进linear.x ,后退linear.x -j左转angular.z l右转angular.z -4.2 自主导航基础实现简单的点到点控制# agv_simulation/scripts/nav_controller.py import rclpy from rclpy.node import Node from geometry_msgs.msg import Twist from nav_msgs.msg import Odometry import math class AGVController(Node): def __init__(self): super().__init__(agv_controller) self.cmd_pub self.create_publisher(Twist, /agv/cmd_vel, 10) self.odom_sub self.create_subscription( Odometry, /agv/odom, self.odom_callback, 10) # 目标位置 [x, y, theta] self.target [2.0, 1.5, 0.0] self.current_pose [0.0, 0.0, 0.0] # 控制参数 self.linear_tolerance 0.05 self.angular_tolerance 0.1 self.max_linear_speed 0.5 self.max_angular_speed 1.0 self.timer self.create_timer(0.1, self.control_loop) def odom_callback(self, msg): # 提取当前位置和朝向 self.current_pose[0] msg.pose.pose.position.x self.current_pose[1] msg.pose.pose.position.y # 从四元数转换到欧拉角仅需偏航角 q msg.pose.pose.orientation siny_cosp 2 * (q.w * q.z q.x * q.y) cosy_cosp 1 - 2 * (q.y * q.y q.z * q.z) self.current_pose[2] math.atan2(siny_cosp, cosy_cosp) def control_loop(self): cmd Twist() # 计算位置误差 dx self.target[0] - self.current_pose[0] dy self.target[1] - self.current_pose[1] distance math.sqrt(dx**2 dy**2) # 计算目标角度 target_angle math.atan2(dy, dx) angle_error target_angle - self.current_pose[2] # 角度归一化到[-π, π] if angle_error math.pi: angle_error - 2 * math.pi elif angle_error -math.pi: angle_error 2 * math.pi # 控制逻辑 if distance self.linear_tolerance: if abs(angle_error) self.angular_tolerance: # 先调整方向 cmd.angular.z self.max_angular_speed * (1.0 if angle_error 0 else -1.0) else: # 直线前进 cmd.linear.x min(self.max_linear_speed, distance * 0.5) else: # 到达目标位置 self.get_logger().info(Target reached!) cmd.linear.x 0.0 cmd.angular.z 0.0 self.cmd_pub.publish(cmd) def main(argsNone): rclpy.init(argsargs) controller AGVController() rclpy.spin(controller) controller.destroy_node() rclpy.shutdown() if __name__ __main__: main()4.3 高级功能扩展4.3.1 添加激光雷达仿真在xacro中添加Hokuyo激光雷达模型link namelaser_link visual geometry box size0.05 0.05 0.05/ /geometry /visual collision geometry box size0.05 0.05 0.05/ /geometry /collision inertial mass value0.1/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.001/ /inertial /link joint namelaser_joint typefixed parent linkbase_link/ child linklaser_link/ origin xyz0.2 0 0.1 rpy0 0 0/ /joint gazebo referencelaser_link sensor typeray namelaser pose0 0 0 0 0 0/pose visualizetrue/visualize update_rate10/update_rate ray scan horizontal samples360/samples resolution1/resolution min_angle-3.14159/min_angle max_angle3.14159/max_angle /horizontal /scan range min0.1/min max10.0/max resolution0.01/resolution /range /ray plugin namelaser_controller filenamelibgazebo_ros_ray_sensor.so ros namespace/agv/namespace /ros output_typesensor_msgs/msg/LaserScan/output_type frame_namelaser_link/frame_name /plugin /sensor /gazebo4.3.2 添加IMU传感器gazebo referencebase_link sensor typeimu nameimu_sensor plugin filenamelibgazebo_ros_imu_sensor.so nameimu_plugin ros namespace/agv/namespace /ros frame_namebase_link/frame_name /plugin /sensor /gazebo5. 调试技巧与性能优化5.1 常见问题解决方案问题1模型在Gazebo中下坠或漂浮检查所有链接的inertial标签是否正确定义验证质量(mass)和惯性矩(inertia)值是否合理确保重力参数正确默认应为9.8 m/s²问题2差分驱动无响应确认插件名称正确libgazebo_ros_diff_drive.so检查关节名称是否与URDF中定义一致使用ros2 topic echo /agv/odom验证odometry数据问题3模型颜色不显示在xacro中同时定义material和gazebo标签检查Gazebo客户端的图形设置5.2 性能优化建议简化碰撞模型使用基本几何体代替复杂mesh减少碰撞体数量调整物理参数gazebo physics typeode max_step_size0.001/max_step_size real_time_update_rate1000/real_time_update_rate /physics /gazebo优化传感器更新率根据实际需要调整激光雷达/IMU的update_rate非必要时不启用visualize选项5.3 可视化调试工具推荐工具组合RViz2查看TF树、传感器数据PlotJuggler分析话题数据时序rqt_graph查看节点通信关系ros2 topic hz监测话题发布频率# 查看TF树 ros2 run tf2_tools view_frames.py # 监测话题频率 ros2 topic hz /agv/odom