Gazebo是ROS系统中最为常用的三维物理仿真平台,支持动力学引擎,可以实现高质量的图形渲染,不仅可以模拟机器人及周边环境,还可以加入摩擦力、弹性系数等物理属性。
类似Gazebo这样的仿真平台,可以帮助我们验证机器人算法、优化机器人设计、测试机器人场景应用,为机器人开发提供更多可能。
为了确保系统中已经完整安装了Gazebo相关的功能包,可以通过这样一个命令,简单直接的把和gazebo相关的包都给装上:
sudo apt install ros-humble-gazebo-*
星号为通配符,表示“ros-humble-gazebo-”开头的所有相关包都安装。
通过这句命令就可以启动:
ros2 launch gazebo_ros gazebo.launch.py
启动时可能遇到无法启动的问题,根据deepseek老师所言,是图形渲染加载失败,导致启动失败。这应该主要是环境内不能直接检索到一些gazebo的相关指令导致的。可以运行以下语句将gazebo添加到终端环境:
source /usr/share/gazebo/setup.sh
然后就可以正常启动了。
为方便之后的处理,可以将该语句也加入到home(即~)目录下的.bashrc文件内。
此外,可以将自己下载的外部模型导入到gazebo里,具体路径在~/.gazebo/models内,其中.gazebo文件夹是一个隐藏文件夹,需要打开查看隐藏文件夹才可以看到。将模型文件移入对应地方后,就可以在gazebo页面左侧标签栏的insert标签里找到对应模型了。
仿真使用XACRO进行机器人建模。这是一个类似上一期URDF的建模方式,但更加专业与深入,能更自由地实现更多功能。
相对URDF,XACRO增加的优点有:
宏定义,一个小车有4个轮子,每个轮子都一样,我们就没必要创建4个一样的link,像函数定义一样,做一个可重复使用的模块就可以了。
文件包含,复杂机器人的模型文件可能会很长,为了切分不同的模块,比如底盘、传感器,我们还可以把不同模块的模型放置在不同的文件中,然后再用一个总体文件做包含调用。
可编程接口,比如在XACRO模型文件中,定义一些常量,描述机器人的尺寸,定义一些变量,在调用宏定义的时候传递数据,还可以在模型中做数据计算,甚至加入条件语句,比如你的机器人叫A,就有摄像头,如果叫B,就没有摄像头。
XACRO建模过程就像写代码一样,功能更为丰富。
首先用这句命令安装必要的功能包:
sudo apt install ros-humble-xacro
XACRO文件语法:
可以用<xacro:property>标签用来定义一些常量。比如这样定义一个PI的常量名为“M_PI”,值为“3.14159”,在调用的时候,通过$加大括号,里边就可以使用定义好的常量了:

如果需要做数学计算,同样是在“${}”中进行,比如某一个位置,我们可以通过这两个常量做运算得到,就加入了加法和除法运算:

尽量都写作公式计算,既方便理清思路,以后看到能想到数据怎么来的,也能在修改参数时自动随公式更新一些关键数据。
xacro的宏定义功能,其定义方式是通过这个<xacro:macro>标签描述的,还可以像函数一样,设置里边会用到的一些参数,比如这里的A、B、C。

当需要使用这个宏的时候,就可以像这样,通过宏名字的标签,来调用,同时要记得把几个参数设置好。
(图片有点小误差,其实调用应该是<xacro:name 参数传递/>这样子,需要在名字前加上xacro。)
车轮宏定义和调用示例:


然后是文件包含,和c/c++中的include一样,包含其他文件后就可以使用其他文件定义的宏定义等了,这也属于一种宏定义的嵌套。

仿真还需要一些必备的模块和参数 。
- 完善物理参数:因为Gazebo是物理仿真平台,必要的物理参数是一定需要的,所以确保每一个link都有惯性参数和碰撞属性。
- 添加Gazebo标签:主要是为了可以在gazebo中渲染每一个link的颜色,因为URDF中的颜色系统和gazebo中的不同,所以得做一步这样的冗余配置。
- 配置传动装置:给运动的joint配置传动装置,可以理解为仿真了一个电机。
- 添加控制器插件:添加一个gazebo的控制器插件,小车是差速控制的,那就添加差速控制器插件,这样在不同角度下两个电机的速度分配,就可以交给控制器插件来完成了。
在launch中启动gazebo并加载模型的一个示例代码如下:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch_ros.actions import Node
def generate_launch_description():
# Include the robot_state_publisher launch file, provided by our own package. Force sim time to be enabled
# !!! MAKE SURE YOU SET THE PACKAGE NAME CORRECTLY !!!
package_name='learning_gazebo' #<--- CHANGE ME
world_file_path = 'worlds/neighborhood.world'
pkg_path = os.path.join(get_package_share_directory(package_name))
world_path = os.path.join(pkg_path, world_file_path)
# Pose where we want to spawn the robot
spawn_x_val = '0.0'
spawn_y_val = '0.0'
spawn_z_val = '0.0'
spawn_yaw_val = '0.0'
mbot = IncludeLaunchDescription( # 配置机器人模型
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory(package_name),'launch','mbot.launch.py' # 调用另一个launch文件
)]), launch_arguments={'use_sim_time': 'true', 'world':world_path}.items()
)
# Include the Gazebo launch file, provided by the gazebo_ros package
gazebo = IncludeLaunchDescription( # 启动gazebo,但是一个空的、没有任何模型的gazebo
PythonLaunchDescriptionSource([os.path.join(
get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')]),
)
# Run the spawner node from the gazebo_ros package. The entity name doesn't really matter if you only have a single robot.
spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py', # 启动一个加载模型的节点
arguments=['-topic', 'robot_description', # 表示机器人模型文件的管理路径
'-entity', 'mbot', # 加载后机器人的名字
'-x', spawn_x_val, # 放出机器人的位置
'-y', spawn_y_val,
'-z', spawn_z_val,
'-Y', spawn_yaw_val],
output='screen')
# Launch them all!
return LaunchDescription([
mbot,
gazebo,
spawn_entity,
])
配置机器人模型时,启动了另一个launch文件,其内容如下:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
import xacro
def generate_launch_description():
# Check if we're told to use sim time
use_sim_time = LaunchConfiguration('use_sim_time')
# Process the URDF file
pkg_path = os.path.join(get_package_share_directory('learning_gazebo'))
xacro_file = os.path.join(pkg_path,'urdf','mbot_gazebo.xacro') # 指定模型路径
robot_description_config = xacro.process_file(xacro_file)
# Create a robot_state_publisher node
params = {'robot_description': robot_description_config.toxml(), 'use_sim_time': use_sim_time} # 创建一个参数保存模型的地址
node_robot_state_publisher = Node( # 运行一个节点
package='robot_state_publisher', # 一个常用于维护机器人关系的包
executable='robot_state_publisher', # 一个常用于维护机器人关系的节点
output='screen',
parameters=[params]
)
# Launch!
return LaunchDescription([ # 启动launch文件
DeclareLaunchArgument( # 设置仿真参数
'use_sim_time', # 控制是否使用仿真时间的一个参数
default_value='false', # 不使用
description='Use sim time if true'),
node_robot_state_publisher # 启动上面定义的node_robot_state_publisher节点
])
启动该程序可以分别在两个命令行窗口分别用以下两条语句:
ros2 launch learning_gazebo load_urdf_into_gazebo.launch.py
ros2 run teleop_twist_keyboard teleop_twist_keyboard
第一个指令启动并渲染仿真界面,第二个指令启动按键控制。
需要注意的是,第一个指令内用到了许多官方模型,gazebo会自动联网下载并存放在前文提到的~/.gazebo/models地址。不过由于官网地址在国外,虚拟机内直接自行连接并下载大概率会失败,导致启动失败,此时需要自己从别处下载并放置在对应文件夹下。
这边使用的是物理机下载,并通过finalshell传输给虚拟机。
在物理机的命令行窗口运行:
git clone https://github.com/osrf/gazebo_models.git
即可实现模型的下载。通过finalshell将模型文件传输至指定地点后,上面的命令就可以正常运行了。
随着技术的进步,Gazebo仿真平台也在不断迭代,新一代的Gazebo命名为Ignition,从渲染效果和仿真流畅度上都有较大的变化。
可以在命令行窗口通过以下方式下载:
sudo apt install ros-humble-ros-ign
然后通过以下方式打开:
ros2 launch ros_ign_gazebo_demos rgbd_camera_bridge.launch.py