文章目录
- 前言:为什么机器人开发离不开仿真?
- 一、环境准备:ROS2 与 Gazebo 安装配置
- 二、Gazebo 基础:启动与界面详解
- 三、机器人模型加载:URDF 与 SDF 格式
- 四、虚拟底盘运动控制:ROS2 话题通信
- 五、虚拟传感器数据获取:激光雷达与摄像头
- 六、仿真调试技巧与常见问题
- 七、总结与下期预告
前言:为什么机器人开发离不开仿真?
在嵌入式转型 ROS2 的过程中,很多工程师都会遇到一个痛点:硬件成本高、调试周期长、风险大。
- 每次修改代码都要烧录到硬件,重启机器人,效率极低
- 算法测试时可能会撞坏机器人或周围环境
- 多人协作开发时,硬件资源有限
- 极端场景(如高速运动、复杂地形)难以在现实中复现
Gazebo 正是为解决这些问题而生的。它是 ROS2 官方推荐的物理仿真引擎,能够:
- 精确模拟刚体物理、碰撞检测、重力、摩擦力等物理特性
- 提供丰富的传感器模型(激光雷达、摄像头、IMU、里程计等)
- 支持自定义机器人模型和环境场景
- 与 ROS2 无缝集成,使用相同的话题、服务和动作接口
核心优势:你在仿真环境中编写的 ROS2 代码,几乎不需要修改就能直接运行在真实机器人上。这也是为什么所有专业机器人团队都会先在仿真中完成 90% 的算法开发,再进行硬件验证。
一、环境准备:ROS2 与 Gazebo 安装配置
1.1 版本对应关系
ROS2 与 Gazebo 有严格的版本对应关系,错误的版本组合会导致各种奇怪的问题:
| ROS2 版本 | 推荐 Gazebo 版本 | 安装包名称 |
|---|---|---|
| Humble | Gazebo 11 | gazebo11 |
| Iron | Gazebo 11 | gazebo11 |
| Jazzy | Gazebo Harmonic | gazebo-harmonic |
本文以ROS2 Humble + Gazebo 11为例,这是目前工业界最稳定、使用最广泛的组合。
1.2 安装 Gazebo 与 ROS2 集成包
# 更新软件源
sudo apt update && sudo apt upgrade -y
# 安装Gazebo 11
sudo apt install gazebo11 libgazebo11-dev -y
# 安装ROS2与Gazebo的集成包
sudo apt install ros-humble-gazebo-ros-pkgs ros-humble-gazebo-ros2-control -y
# 安装机器人模型和控制器依赖
sudo apt install ros-humble-robot-state-publisher ros-humble-joint-state-publisher-gui -y
sudo apt install ros-humble-xacro ros-humble-urdf -y
1.3 验证安装
# 测试Gazebo是否能正常启动
gazebo --version
gazebo
# 测试ROS2-Gazebo集成
source /opt/ros/humble/setup.bash
ros2 launch gazebo_ros gazebo.launch.py
如果能成功启动 Gazebo 界面,说明环境配置正确。
二、Gazebo 基础:启动与界面详解
2.1 三种启动方式
Gazebo 有三种常用的启动方式,适用于不同场景:
方式 1:直接启动空世界
gazebo
这是最基础的启动方式,会打开一个只有地面和天空的空仿真环境。
方式 2:通过 ROS2 launch 启动
ros2 launch gazebo_ros gazebo.launch.py
这种方式会自动启动gazebo_ros节点,实现 ROS2 与 Gazebo 的通信。
方式 3:启动带预定义世界的仿真
# 启动官方示例世界
ros2 launch gazebo_ros gazebo.launch.py world:=/usr/share/gazebo-11/worlds/empty.world
ros2 launch gazebo_ros gazebo.launch.py world:=/usr/share/gazebo-11/worlds/warehouse.world
2.2 Gazebo 界面详解
Gazebo 界面主要分为以下几个区域:
-
左侧面板:模型库、世界树、属性编辑器
- 模型库:包含各种预定义的物体(盒子、球体、圆柱体、机器人等)
- 世界树:显示当前仿真环境中的所有物体及其层级关系
- 属性编辑器:编辑选中物体的位置、旋转、质量、摩擦系数等属性
-
中央 3D 视图:仿真环境的可视化窗口
- 鼠标左键:旋转视角
- 鼠标右键:平移视角
- 鼠标滚轮:缩放视角
- Shift + 左键:拖动选中的物体
-
顶部工具栏:仿真控制按钮
- 播放 / 暂停:控制仿真的运行和暂停
- 步进:单步执行仿真
- 重置:重置仿真到初始状态
- 时间显示:显示仿真时间和实时时间的比例
-
底部状态栏:显示仿真状态、帧率、内存使用等信息
三、机器人模型加载:URDF 与 SDF 格式
Gazebo 支持两种机器人模型格式:URDF和SDF。
- URDF:ROS 统一机器人描述格式,是 ROS 生态的标准格式,适合描述机器人的连杆和关节结构
- SDF:仿真描述格式,是 Gazebo 原生格式,支持更丰富的物理属性和环境描述
在实际开发中,我们通常使用URDF + Gazebo 扩展标签的方式来定义机器人模型。
3.1 加载官方示例机器人
我们先从加载官方提供的 TurtleBot3 机器人开始,这是学习 ROS2 仿真最常用的测试平台。
# 安装TurtleBot3仿真包
sudo apt install ros-humble-turtlebot3-gazebo -y
# 设置TurtleBot3模型
export TURTLEBOT3_MODEL=burger
# 启动TurtleBot3仿真
ros2 launch turtlebot3_gazebo turtlebot3_empty_world.launch.py
启动成功后,你会看到一个 TurtleBot3 机器人出现在空世界中。
3.2 加载自定义 URDF 模型
下面我们来学习如何加载自己编写的 URDF 机器人模型。
步骤 1:创建一个简单的差分驱动机器人 URDF
创建文件my_robot.urdf:
<?xml version="1.0"?>
<robot name="my_diffbot">
<!-- 底盘连杆 -->
<link name="base_link">
<visual>
<geometry>
<box size="0.5 0.3 0.1"/>
</geometry>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.5 0.3 0.1"/>
</geometry>
</collision>
<inertial>
<mass value="1.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</link>
<!-- 左轮 -->
<link name="left_wheel">
<visual>
<geometry>
<cylinder radius="0.05" length="0.02"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.05" length="0.02"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- 右轮 -->
<link name="right_wheel">
<visual>
<geometry>
<cylinder radius="0.05" length="0.02"/>
</geometry>
<material name="black">
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.05" length="0.02"/>
</geometry>
</collision>
<inertial>
<mass value="0.1"/>
<inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0001"/>
</inertial>
</link>
<!-- 左轮关节 -->
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.15 0" rpy="1.5708 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<!-- 右轮关节 -->
<joint name="right_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.15 0" rpy="1.5708 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<!-- Gazebo插件:差分驱动控制器 -->
<gazebo>
<plugin name="diff_drive" filename="libgazebo_ros_diff_drive.so">
<robotNamespace>/</robotNamespace>
<leftJoint>left_wheel_joint</leftJoint>
<rightJoint>right_wheel_joint</rightJoint>
<wheelSeparation>0.3</wheelSeparation>
<wheelDiameter>0.1</wheelDiameter>
<publishTf>true</publishTf>
<publishOdom>true</publishOdom>
<odometryTopic>odom</odometryTopic>
<commandTopic>cmd_vel</commandTopic>
</plugin>
</gazebo>
</robot>
步骤 2:创建 launch 文件加载模型
创建文件spawn_my_robot.launch.py:
import os
from launch import LaunchDescription
from launch.actions import ExecuteProcess
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
# 获取URDF文件路径
urdf_path = os.path.join(os.getcwd(), 'my_robot.urdf')
with open(urdf_path, 'r') as f:
robot_desc = f.read()
return LaunchDescription([
# 启动Gazebo空世界
ExecuteProcess(
cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_factory.so'],
output='screen'
),
# 启动机器人状态发布者
Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
output='screen',
parameters=[{'robot_description': robot_desc}]
),
# 生成机器人模型
Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=['-topic', 'robot_description', '-entity', 'my_diffbot'],
output='screen'
)
])
步骤 3:运行 launch 文件
source /opt/ros/humble/setup.bash
python3 spawn_my_robot.launch.py
如果一切正常,你会看到一个简单的蓝色差分驱动机器人出现在 Gazebo 中。
四、虚拟底盘运动控制:ROS2 话题通信
现在我们已经成功加载了机器人模型,接下来学习如何通过 ROS2 话题控制机器人运动。
4.1 查看可用话题
打开一个新终端,运行:
source /opt/ros/humble/setup.bash
ros2 topic list
你应该能看到以下关键话题:
/cmd_vel:速度命令话题,用于控制机器人运动/odom:里程计话题,发布机器人的位置和速度信息/tf:坐标变换话题,发布机器人各连杆之间的变换关系/joint_states:关节状态话题,发布机器人各关节的角度和速度
4.2 使用键盘控制机器人运动
ROS2 提供了一个非常方便的键盘控制节点teleop_twist_keyboard:
# 安装键盘控制包
sudo apt install ros-humble-teleop-twist-keyboard -y
# 运行键盘控制节点
ros2 run teleop_twist_keyboard teleop_twist_keyboard
按照终端提示,使用以下按键控制机器人:
i:前进,:后退j:左转l:右转k:停止q/z:增加 / 减少线速度w/x:增加 / 减少角速度
你会看到 Gazebo 中的机器人随着你的按键运动,这说明 ROS2 与 Gazebo 的通信已经正常工作。
4.3 编写 C++ 代码控制机器人
下面我们来编写一个简单的 C++ 节点,实现机器人的自动运动控制。
创建文件robot_controller.cpp:
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
class RobotController : public rclcpp::Node
{
public:
RobotController() : Node("robot_controller")
{
// 创建速度命令发布者
publisher_ = this->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10);
// 创建定时器,每100ms发布一次速度命令
timer_ = this->create_wall_timer(
std::chrono::milliseconds(100),
std::bind(&RobotController::timer_callback, this)
);
RCLCPP_INFO(this->get_logger(), "机器人控制器已启动");
}
private:
void timer_callback()
{
auto msg = geometry_msgs::msg::Twist();
// 设置线速度和角速度
msg.linear.x = 0.2; // 前进速度0.2m/s
msg.angular.z = 0.1; // 左转角速度0.1rad/s
publisher_->publish(msg);
}
rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<RobotController>());
rclcpp::shutdown();
return 0;
}
编译并运行这个节点,你会看到机器人开始做圆周运动。这就是我们在仿真环境中编写的第一个机器人控制程序!
五、虚拟传感器数据获取:激光雷达与摄像头
除了控制机器人运动,Gazebo 还能模拟各种传感器的数据,这是仿真环境最强大的功能之一。
5.1 添加激光雷达传感器
我们在之前的 URDF 模型中添加一个激光雷达传感器:
在my_robot.urdf的</robot>标签前添加以下内容:
<!-- 激光雷达连杆 -->
<link name="laser_link">
<visual>
<geometry>
<cylinder radius="0.03" length="0.05"/>
</geometry>
<material name="red">
<color rgba="1 0 0 1"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.03" length="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="0.05"/>
<inertia ixx="0.00001" ixy="0" ixz="0" iyy="0.00001" iyz="0" izz="0.00001"/>
</inertial>
</link>
<!-- 激光雷达关节 -->
<joint name="laser_joint" type="fixed">
<parent link="base_link"/>
<child link="laser_link"/>
<origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>
<!-- Gazebo激光雷达插件 -->
<gazebo reference="laser_link">
<sensor type="ray" name="laser_sensor">
<update_rate>10</update_rate>
<ray>
<scan>
<horizontal>
<samples>360</samples>
<resolution>1</resolution>
<min_angle>-3.14159</min_angle>
<max_angle>3.14159</max_angle>
</horizontal>
</scan>
<range>
<min>0.1</min>
<max>10.0</max>
<resolution>0.01</resolution>
</range>
</ray>
<plugin name="gazebo_ros_laser" filename="libgazebo_ros_ray_sensor.so">
<topic_name>scan</topic_name>
<frame_name>laser_link</frame_name>
</plugin>
</sensor>
</gazebo>
重新启动仿真,然后查看激光雷达数据:
bash
运行
# 查看激光雷达话题
ros2 topic list | grep scan
# 打印激光雷达数据
ros2 topic echo /scan
5.2 添加摄像头传感器
同样,我们可以添加一个摄像头传感器:
在 URDF 中添加以下内容:
<!-- 摄像头连杆 -->
<link name="camera_link">
<visual>
<geometry>
<box size="0.05 0.03 0.03"/>
</geometry>
<material name="green">
<color rgba="0 1 0 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.05 0.03 0.03"/>
</geometry>
</collision>
<inertial>
<mass value="0.02"/>
<inertia ixx="0.000001" ixy="0" ixz="0" iyy="0.000001" iyz="0" izz="0.000001"/>
</inertial>
</link>
<!-- 摄像头关节 -->
<joint name="camera_joint" type="fixed">
<parent link="base_link"/>
<child link="camera_link"/>
<origin xyz="0.25 0 0.15" rpy="0 0 0"/>
</joint>
<!-- Gazebo摄像头插件 -->
<gazebo reference="camera_link">
<sensor type="camera" name="camera_sensor">
<update_rate>30</update_rate>
<camera>
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
</camera>
<plugin name="gazebo_ros_camera" filename="libgazebo_ros_camera.so">
<topic_name>camera/image_raw</topic_name>
<frame_name>camera_link</frame_name>
</plugin>
</sensor>
</gazebo>
重新启动仿真,然后使用rqt_image_view查看摄像头图像:
bash
运行
# 安装rqt_image_view
sudo apt install ros-humble-rqt-image-view -y
# 运行rqt_image_view
rqt_image_view
在弹出的窗口中选择/camera/image_raw话题,你就能看到虚拟摄像头拍摄的画面了。
六、仿真调试技巧与常见问题
6.1 常用调试命令
# 查看Gazebo日志
gazebo --verbose
# 查看ROS2节点信息
ros2 node list
ros2 node info /gazebo
# 查看话题信息
ros2 topic info /cmd_vel
ros2 topic hz /scan # 查看话题发布频率
# 查看TF变换
ros2 run tf2_tools view_frames
6.2 常见问题及解决方法
问题 1:Gazebo 启动时卡在加载界面
原因:模型下载速度慢或模型文件损坏解决方法:
# 清理Gazebo模型缓存
rm -rf ~/.gazebo/models/*
# 手动下载常用模型
git clone https://github.com/osrf/gazebo_models.git ~/.gazebo/models
问题 2:机器人模型加载后消失或穿透地面
原因:惯性参数设置错误解决方法:检查 URDF 中所有<inertial>标签的质量和惯性矩阵值,确保它们是合理的正数。
问题 3:机器人运动不平稳或抖动
原因:物理参数设置不当或仿真步长太大解决方法:
- 调整 Gazebo 的物理参数:在 Gazebo 界面中点击
Edit -> World Properties -> Physics - 减小仿真步长(
max_step_size) - 增加迭代次数(
iters)
问题 4:传感器数据不发布
原因:插件配置错误或话题名称不匹配解决方法:
- 检查 URDF 中插件的
topic_name和frame_name参数 - 查看 Gazebo 日志,寻找插件加载错误信息
七、总结与下期预告
今天我们系统学习了 Gazebo 机器人仿真的基础知识,包括:
- Gazebo 的安装配置和启动方法
- URDF 机器人模型的编写和加载
- 通过 ROS2 话题控制虚拟底盘运动
- 激光雷达和摄像头等虚拟传感器的使用
- 仿真调试技巧和常见问题解决
核心收获:仿真环境是机器人开发的 "虚拟实验室",它能让你在没有硬件的情况下快速验证算法,大大提高开发效率。你今天编写的控制代码,未来可以直接移植到真实的嵌入式小车上。
📢 下期连载预告:【ROS2 速成 - Day24~Day28】完整 ROS2 实战项目落地|嵌入式遥控小车全项目
接下来的 5 天,我们将把前面所学的所有知识整合起来,从零开始完成一个完整的嵌入式遥控小车项目:
- Day24:项目整体架构设计与硬件选型
- Day25:STM32 底层驱动开发与 ROS2 通信
- Day26:小车底盘控制与里程计计算
- Day27:激光雷达 SLAM 建图与导航
- Day28:项目部署与实战演示
这将是本系列最有价值的部分,我会分享完整的工程代码和硬件对接细节,帮助你真正实现从嵌入式到 ROS2 的转型。
码字不易,欢迎点赞 + 收藏 + 关注,后续按【ROS2 速成 - DayX】持续连载更新 ROS2 嵌入式实战代码、硬件对接源码、项目工程模板,嵌入式转型 ROS2 不踩坑!
如果有任何问题,欢迎在评论区留言交流,我会一一回复。
1291

被折叠的 条评论
为什么被折叠?



