模型与环境创建
在机器人仿真领域,模型与环境的创建是至关重要的一步。Gazebo 提供了强大的工具和功能,帮助用户创建复杂的机器人模型和逼真的环境。本节将详细介绍如何在 Gazebo 中创建和管理模型与环境,包括模型文件的编写、环境的构建以及如何使用 Gazebo 的图形用户界面 (GUI) 进行交互。
模型文件编写
Gazebo 使用 SDF (Simulation Description Format) 文件来描述机器人模型。SDF 是一种基于 XML 的文件格式,用于定义机器人的几何形状、物理属性、传感器和其他组件。以下是一个简单的 SDF 文件示例,描述了一个带有两个轮子的差动驱动机器人模型。
示例 SDF 文件
<?xml version="1.0" ?>
<sdf version="1.6">
<model name="simple_robot">
<link name="base_link">
<pose>0 0 0.1 0 0 0</pose>
<visual name="visual">
<geometry>
<box>
<size>0.5 0.3 0.1</size>
</box>
</geometry>
<material>
<color rgba="0.8 0 0 1"/>
</material>
</visual>
<collision name="collision">
<geometry>
<box>
<size>0.5 0.3 0.1</size>
</box>
</geometry>
</collision>
</link>
<link name="left_wheel">
<pose>-0.2 -0.15 0 0 0 1.5708</pose>
<visual name="visual">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.1</length>
</cylinder>
</geometry>
<material>
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision name="collision">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.1</length>
</cylinder>
</geometry>
</collision>
</link>
<link name="right_wheel">
<pose>0.2 -0.15 0 0 0 1.5708</pose>
<visual name="visual">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.1</length>
</cylinder>
</geometry>
<material>
<color rgba="0 0 0 1"/>
</material>
</visual>
<collision name="collision">
<geometry>
<cylinder>
<radius>0.05</radius>
<length>0.1</length>
</cylinder>
</geometry>
</collision>
</link>
<joint name="left_wheel_joint" type="revolute">
<parent>base_link</parent>
<child>left_wheel</child>
<axis>
<xyz>0 1 0</xyz>
</axis>
</joint>
<joint name="right_wheel_joint" type="revolute">
<parent>base_link</parent>
<child>right_wheel</child>
<axis>
<xyz>0 1 0</xyz>
</axis>
</joint>
</model>
</sdf>
文件结构解析
-
根元素
<sdf>
:version="1.6"
:指定 SDF 文件的版本。
-
模型元素
<model>
:name="simple_robot"
:模型的名称。
-
链接元素
<link>
:-
name="base_link"
:链接的名称。 -
<pose>
:链接的初始位置和姿态。 -
<visual>
:定义链接的视觉效果。-
<geometry>
:几何形状。-
<box>
:矩形。<size>
:矩形的尺寸。
-
-
<material>
:材质属性。<color>
:颜色。
-
-
<collision>
:定义链接的碰撞属性。-
<geometry>
:几何形状。-
<box>
:矩形。<size>
:矩形的尺寸。
-
-
-
-
关节元素
<joint>
:-
name="left_wheel_joint"
:关节的名称。 -
type="revolute"
:关节类型(旋转关节)。 -
<parent>
:关节的父链接。 -
<child>
:关节的子链接。 -
<axis>
:关节的轴向。<xyz>
:轴向的向量。
-
使用 Gazebo GUI 创建模型
Gazebo 提供了一个图形用户界面 (GUI),用户可以通过拖拽和放置来创建和修改模型。以下是使用 Gazebo GUI 创建模型的步骤:
-
启动 Gazebo:
-
打开终端,输入
gazebo
命令启动 Gazebo。 -
Gazebo 启动后,会显示一个默认的空世界。
-
-
插入模型:
-
在 Gazebo 界面的左上角,点击
Insert
菜单。 -
选择
Models
选项卡,浏览可用的模型库。 -
拖拽所需的模型(如矩形、圆柱等)到仿真环境中。
-
-
编辑模型:
-
选择插入的模型,右键点击并选择
Edit
选项。 -
在弹出的编辑窗口中,可以修改模型的名称、位置、姿态、材质等属性。
-
也可以添加新的链接和关节。
-
-
保存模型:
- 编辑完成后,点击
File
菜单,选择Save As
选项,保存模型为 SDF 文件。
- 编辑完成后,点击
创建自定义环境
Gazebo 的环境可以通过多种方式创建,包括使用内置的环境模型、自定义环境文件以及通过编程接口动态生成环境。以下是一个使用 SDF 文件创建自定义环境的示例。
示例 SDF 环境文件
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<model name="wall">
<pose>0 0 0.5 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>10 0.1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>10 0.1 1</size>
</box>
</geometry>
<material>
<color rgba="0.5 0.5 0.5 1"/>
</material>
</visual>
</link>
</model>
<model name="obstacle">
<pose>2 2 0 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
</collision>
<visual name="visual">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
<material>
<color rgba="0.8 0.3 0.3 1"/>
</material>
</visual>
</link>
</model>
</world>
</sdf>
文件结构解析
-
根元素
<sdf>
:version="1.6"
:指定 SDF 文件的版本。
-
世界元素
<world>
:name="default"
:世界的名称。
-
包含元素
<include>
:-
<uri>model://ground_plane</uri>
:包含地面平面模型。 -
<uri>model://sun</uri>
:包含太阳光源模型。
-
-
模型元素
<model>
:-
name="wall"
:墙模型的名称。 -
name="obstacle"
:障碍物模型的名称。 -
<pose>
:模型的初始位置和姿态。
-
-
链接元素
<link>
:-
name="link"
:链接的名称。 -
<collision>
:定义链接的碰撞属性。-
<geometry>
:几何形状。-
<box>
:矩形。<size>
:矩形的尺寸。
-
<sphere>
:球体。<radius>
:球体的半径。
-
-
-
<visual>
:定义链接的视觉效果。-
<geometry>
:几何形状。-
<box>
:矩形。<size>
:矩形的尺寸。
-
<sphere>
:球体。<radius>
:球体的半径。
-
-
<material>
:材质属性。<color>
:颜色。
-
-
使用 Gazebo API 动态生成环境
Gazebo 提供了丰富的 API,允许用户在仿真过程中动态生成和修改环境。以下是一个使用 Gazebo API 生成一个动态障碍物的 C++ 示例。
示例代码
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <sdf/sdf.hh>
// 定义一个函数来生成障碍物
void spawnObstacle(gazebo::transport::NodePtr node, const std::string &model_name, const std::string &model_sdf)
{
// 创建一个消息来描述模型
gazebo::msgs::Model model_msg;
model_msg.set_name(model_name);
model_msg.set_sdf(model_sdf);
// 创建一个模型插入请求消息
gazebo::msgs::ModelRequest req_msg;
req_msg.set_request(gazebo::msgs::ModelRequest::INSERT);
req_msg.set_model(model_msg);
// 发送模型插入请求
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request");
pub->WaitForConnection();
pub->Publish(req_msg);
}
int main(int argc, char **argv)
{
// 初始化 Gazebo 客户端
gazebo::client::setup(argc, argv);
// 创建一个节点
gazebo::transport::NodePtr node(new gazebo::transport::Node());
node->Init();
// 定义障碍物的 SDF 文件内容
std::string obstacle_sdf = R"(
<sdf version="1.6">
<model name="obstacle">
<pose>2 2 0 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
</collision>
<visual name="visual">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
<material>
<color rgba="0.8 0.3 0.3 1"/>
</material>
</visual>
</link>
</model>
</sdf>
)";
// 生成障碍物
spawnObstacle(node, "obstacle", obstacle_sdf);
// 保持程序运行,直到用户手动关闭
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// 关闭 Gazebo 客户端
gazebo::client::shutdown();
return 0;
}
代码解析
-
头文件包含:
-
#include <gazebo/gazebo_client.hh>
:Gazebo 客户端库。 -
#include <gazebo/msgs/msgs.hh>
:Gazebo 消息库。 -
#include <gazebo/transport/transport.hh>
:Gazebo 传输库。 -
#include <sdf/sdf.hh>
:SDF 文件解析库。
-
-
函数定义
spawnObstacle
:-
gazebo::msgs::Model model_msg
:创建一个模型消息对象。 -
model_msg.set_name(model_name)
:设置模型的名称。 -
model_msg.set_sdf(model_sdf)
:设置模型的 SDF 文件内容。 -
gazebo::msgs::ModelRequest req_msg
:创建一个模型请求消息对象。 -
req_msg.set_request(gazebo::msgs::ModelRequest::INSERT)
:设置请求类型为插入模型。 -
req_msg.set_model(model_msg)
:设置请求中的模型消息。 -
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request")
:创建一个发布者,发布模型请求消息。 -
pub->WaitForConnection()
:等待发布者连接。 -
pub->Publish(req_msg)
:发布模型请求消息。
-
-
主函数
main
:-
gazebo::client::setup(argc, argv)
:初始化 Gazebo 客户端。 -
gazebo::transport::NodePtr node(new gazebo::transport::Node())
:创建一个节点。 -
node->Init()
:初始化节点。 -
std::string obstacle_sdf
:定义障碍物的 SDF 文件内容。 -
spawnObstacle(node, "obstacle", obstacle_sdf)
:调用spawnObstacle
函数生成障碍物。 -
while (true)
:保持程序运行,直到用户手动关闭。 -
gazebo::client::shutdown()
:关闭 Gazebo 客户端。
-
模型与环境的管理
在 Gazebo 中,模型和环境的管理是一个重要的环节。用户可以通过 Gazebo 的命令行工具和 API 来管理模型,包括加载、删除和修改模型。
使用命令行工具管理模型
Gazebo 提供了 gz
命令行工具,用户可以通过该工具来管理模型。以下是一些常用的命令:
-
加载模型:
gz model -f <model_file> -m <model_name>
:从文件加载模型并命名为model_name
。
-
删除模型:
gz model -d <model_name>
:删除指定名称的模型。
-
修改模型位置:
gz model -m <model_name> --pos <x> <y> <z>
:修改模型的位置。
示例命令
# 加载模型
gz model -f simple_robot.sdf -m simple_robot
# 删除模型
gz model -d simple_robot
# 修改模型位置
gz model -m simple_robot --pos 3 3 0
使用 API 管理模型
Gazebo API 提供了丰富的功能来管理模型。以下是一个使用 Gazebo API 修改模型位置的 C++ 示例。
示例代码
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <gazebo/math/Vector3.hh>
// 定义一个函数来修改模型的位置
void setModelPose(gazebo::transport::NodePtr node, const std::string &model_name, const gazebo::math::Vector3 &position)
{
// 创建一个模型状态消息对象
gazebo::msgs::Model model_msg;
model_msg.set_name(model_name);
// 设置模型的新位置
gazebo::msgs::Set(&model_msg.pose(), position);
// 创建一个模型状态请求消息对象
gazebo::msgs::ModelRequest req_msg;
req_msg.set_request(gazebo::msgs::ModelRequest::SET);
req_msg.set_model(model_msg);
// 发布模型状态请求消息
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request");
pub->WaitForConnection();
pub->Publish(req_msg);
}
int main(int argc, char **argv)
{
// 初始化 Gazebo 客户端
gazebo::client::setup(argc, argv);
// 创建一个节点
gazebo::transport::NodePtr node(new gazebo::transport::Node());
node->Init();
// 定义新的位置
gazebo::math::Vector3 new_position(3, 3, 0);
// 修改模型的位置
setModelPose(node, "simple_robot", new_position);
// 保持程序运行,直到用户手动关闭
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// 关闭 Gazebo 客户端
gazebo::client::shutdown();
return 0;
}
代码解析
-
头文件包含:
-
#include <gazebo/gazebo_client.hh>
:Gazebo 客户端库。 -
#include <gazebo/msgs/msgs.hh>
:Gazebo 消息库。 -
#include <gazebo/transport/transport.hh>
:Gazebo 传输库。 -
#include <gazebo/math/Vector3.hh>
:Gazebo 数学库中的向量类。
-
-
函数定义
setModelPose
:-
gazebo::msgs::Model model_msg
:创建一个模型消息对象。 -
model_msg.set_name(model_name)
:设置模型的名称。 -
gazebo::msgs::Set(&model_msg.pose(), position)
:设置模型的新位置。 -
gazebo::msgs::ModelRequest req_msg
:创建一个模型请求消息对象。 -
req_msg.set_request(gazebo::msgs::ModelRequest::SET)
:设置请求类型为设置模型状态。 -
req_msg.set_model(model_msg)
:设置请求中的模型消息。 -
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request")
:创建一个发布者,发布模型请求消息。 -
pub->WaitForConnection()
:等待发布者连接。 -
pub->Publish(req_msg)
:发布模型请求消息。
-
-
主函数
main
:-
gazebo::client::setup(argc, argv)
:初始化 Gazebo 客户端。 -
gazebo::transport::NodePtr node(new gazebo::transport::Node())
:创建一个节点。 -
node->Init()
:初始化节点。 -
gazebo::math::Vector3 new_position(3, 3, 0)
:定义新的位置。 -
setModelPose(node, "simple_robot", new_position)
:调用setModelPose
函数修改模型的位置。 -
while (true)
:保持程序运行,直到用户手动关闭。 -
gazebo::client::shutdown()
:关闭 Gazebo 客户端。
-
模型与环境的高级管理
除了基本的模型管理功能,Gazebo 还提供了更高级的管理工具和 API,用于复杂环境的构建和动态管理。以下是一些高级管理的例子:
动态添加和删除模型
在仿真过程中,用户可能需要根据特定条件动态添加或删除模型。这可以通过 Gazebo API 来实现。
示例代码
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <sdf/sdf.hh>
#include <gazebo/math/Vector3.hh>
#include <thread>
// 定义一个函数来生成障碍物
void spawnObstacle(gazebo::transport::NodePtr node, const std::string &model_name, const std::string &model_sdf)
{
// 创建一个消息来描述模型
gazebo::msgs::Model model_msg;
model_msg.set_name(model_name);
model_msg.set_sdf(model_sdf);
// 创建一个模型插入请求消息
gazebo::msgs::ModelRequest req_msg;
req_msg.set_request(gazebo::msgs::ModelRequest::INSERT);
req_msg.set_model(model_msg);
// 发送模型插入请求
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request");
pub->WaitForConnection();
pub->Publish(req_msg);
}
// 定义一个函数来删除模型
void deleteModel(gazebo::transport::NodePtr node, const std::string &model_name)
{
// 创建一个模型删除请求消息
gazebo::msgs::ModelRequest req_msg;
req_msg.set_request(gazebo::msgs::ModelRequest::DELETE);
req_msg.set_model_name(model_name);
// 发布模型删除请求消息
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request");
pub->WaitForConnection();
pub->Publish(req_msg);
}
int main(int argc, char **argv)
{
// 初始化 Gazebo 客户端
gazebo::client::setup(argc, argv);
// 创建一个节点
gazebo::transport::NodePtr node(new gazebo::transport::Node());
node->Init();
// 定义障碍物的 SDF 文件内容
std::string obstacle_sdf = R"(
<sdf version="1.6">
<model name="obstacle">
<pose>2 2 0 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
</collision>
<visual name="visual">
<geometry>
<sphere>
<radius>0.5</radius>
</sphere>
</geometry>
<material>
<color rgba="0.8 0.3 0.3 1"/>
</material>
</visual>
</link>
</model>
</sdf>
)";
// 生成障碍物
spawnObstacle(node, "obstacle", obstacle_sdf);
// 等待一段时间后删除障碍物
std::this_thread::sleep_for(std::chrono::seconds(5));
deleteModel(node, "obstacle");
// 保持程序运行,直到用户手动关闭
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// 关闭 Gazebo 客户端
gazebo::client::shutdown();
return 0;
}
代码解析
-
头文件包含:
-
#include <gazebo/gazebo_client.hh>
:Gazebo 客户端库。 -
#include <gazebo/msgs/msgs.hh>
:Gazebo 消息库。 -
#include <gazebo/transport/transport.hh>
:Gazebo 传输库。 -
#include <sdf/sdf.hh>
:SDF 文件解析库。 -
#include <gazebo/math/Vector3.hh>
:Gazebo 数学库中的向量类。 -
#include <thread>
:C++ 标准库中的线程类。
-
-
函数定义
spawnObstacle
:-
gazebo::msgs::Model model_msg
:创建一个模型消息对象。 -
model_msg.set_name(model_name)
:设置模型的名称。 -
model_msg.set_sdf(model_sdf)
:设置模型的 SDF 文件内容。 -
gazebo::msgs::ModelRequest req_msg
:创建一个模型请求消息对象。 -
req_msg.set_request(gazebo::msgs::ModelRequest::INSERT)
:设置请求类型为插入模型。 -
req_msg.set_model(model_msg)
:设置请求中的模型消息。 -
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request")
:创建一个发布者,发布模型请求消息。 -
pub->WaitForConnection()
:等待发布者连接。 -
pub->Publish(req_msg)
:发布模型请求消息。
-
-
函数定义
deleteModel
:-
gazebo::msgs::ModelRequest req_msg
:创建一个模型请求消息对象。 -
req_msg.set_request(gazebo::msgs::ModelRequest::DELETE)
:设置请求类型为删除模型。 -
req_msg.set_model_name(model_name)
:设置要删除的模型名称。 -
gazebo::transport::PublisherPtr pub = node->Advertise<gazebo::msgs::ModelRequest>("~/model/request")
:创建一个发布者,发布模型请求消息。 -
pub->WaitForConnection()
:等待发布者连接。 -
pub->Publish(req_msg)
:发布模型请求消息。
-
-
主函数
main
:-
gazebo::client::setup(argc, argv)
:初始化 Gazebo 客户端。 -
gazebo::transport::NodePtr node(new gazebo::transport::Node())
:创建一个节点。 -
node->Init()
:初始化节点。 -
std::string obstacle_sdf
:定义障碍物的 SDF 文件内容。 -
spawnObstacle(node, "obstacle", obstacle_sdf)
:调用spawnObstacle
函数生成障碍物。 -
std::this_thread::sleep_for(std::chrono::seconds(5))
:等待 5 秒。 -
deleteModel(node, "obstacle")
:调用deleteModel
函数删除障碍物。 -
while (true)
:保持程序运行,直到用户手动关闭。 -
gazebo::client::shutdown()
:关闭 Gazebo 客户端。
-
总结
Gazebo 提供了多种工具和 API 来创建和管理机器人模型和环境。通过 SDF 文件,用户可以详细定义机器人的几何形状、物理属性和传感器等组件。使用 Gazebo GUI,用户可以方便地进行模型的拖拽和放置操作。通过 Gazebo API,用户可以在仿真过程中动态生成和修改环境。这些功能使得 Gazebo 成为了一个强大的机器人仿真平台,适用于各种复杂的仿真任务。