【ROS-Gazebo】仿真插件编写教程(1)——概述

1024
2
2020年5月13日 15时42分

前言

本系列教程的主要是对 Gazebo的官网教程 的翻译与理解。之前查找国内的中文资料,发现并没有关于如何编写Gazebo插件的教程。据我猜测,大概是因为这个技能属于“两不管”地带:刚入门的爱好者直接调用Gazebo自带的控制和传感器插件即可,不需要自己编写插件;而等到要用到自定义插件的时候,已经不屑于写这种基础的教程了。

 

因此,本系列教程的定位是:你已经有了一定的Gazebo仿真经验,使用过部分自带的插件,但你的研究工作需要你对已有插件进行修改或编写新的插件,并且略微有些C++基础。

 

对于刚入门的新手,还是建议先学习调用自带插件,自带插件能够满足大部分基本功能需求。教程推荐古月居的 ROS探索总结(二十四)——使用gazebo中的插件

 

Gazebo插件概述

Gazebo插件实际上是一个共享的代码库。在仿真时,插件可以通过标准的C++类来实现Gazebo的相关功能。旧版本的Gazebo使用控制器(controllers)来完成类似的工作。区别在于控制器是静态编译的,而插件更灵活,允许用户选择自己需要的那部分功能。

 

插件的优点包括:

 

  • 让开发人员能够从各个层面对Gazebo进行控制
  • 自带例程,且易于共享
  • 可以在运行的系统中插入或删除

插件的适用情况如下:

 

  • 你想通过编程来控制仿真,如移动模型、响应事件、在给定情况下插入新模型
  • 你想要一个快速的Gazebo接口,没有传输层的开销,如消息的序列化和反序列化
  • 你有一些代码想要分享给他人

插件类型

目前有6种类型的插件

 

  1. World
  2. Model
  3. Sensor
  4. System
  5. Visual
  6. GUI

 

应根据所需的功能选择插件类型。例如,使用World插件来控制世界属性,例如物理引擎、环境光等;使用Model插件来控制关节和模型的状态;使用Sensor插件获取传感器信息并控制传感器属性等。

 

下面以一个例子说明如何编写插件。

 

Hello World! 插件的编写

插件代码的结构十分简单,基本的world插件只包含一个C++类以及一些成员函数。

 

首先,如果你是从debians安装的Gazebo,请确保你已经安装了Gazebo开发文件。如果你是从源安装的Gazebo,则可以忽略此步骤。如果你有gazebo9以外的版本,请将9替换为您拥有的版本号。

 

sudo apt-get install libgazebo9-dev

 

接下来,在某目录下(如~/Documents/)中新创建一个目录和.cc文件:

 

$ cd ~/Documents/
$ mkdir gazebo_plugin_tutorial
$ cd gazebo_plugin_tutorial/
$ gedit hello_world.cc

 

将以下内容复制到hello_world.cc中:

 

#include <gazebo/gazebo.hh>
namespace gazebo
{
  class WorldPluginTutorial : public WorldPlugin
  {
    public: WorldPluginTutorial() : WorldPlugin()
            {
              printf("Hello World!\n");
            }

    public: void Load(physics::WorldPtr _world, sdf::ElementPtr _sdf)
            {
            }
  };
  GZ_REGISTER_WORLD_PLUGIN(WorldPluginTutorial)
}

 

代码解释

#include <gazebo/gazebo.hh>
namespace gazebo
{

 

gazebo/gazebo.hh 文件包含了一些gazebo的基础函数,但有时可能还会需要包含 gazebo/physics/physics.hh 、 gazebo/rendering/rendering.hh、gazebo/sensors/sensors.hh 等。所有的插件都必须位于 gazebo 命名空间中。

 

class WorldPluginTutorial : public WorldPlugin
  {
    public: WorldPluginTutorial() : WorldPlugin()
            {
              printf("Hello World!\n");
            }

 

每个插件都需要继承一个插件类,在这里我们继承了 WorldPlugin 类。

 

public: void Load(physics::WorldPtr _world, sdf::ElementPtr _sdf)
            {
            }

 

另一个不可缺少的函数是Load(),它用于接收SDF文件中指定的元素和属性。

 

GZ_REGISTER_WORLD_PLUGIN(WorldPluginTutorial)

 

最后,必须使用 GZ_REGISTER_WORLD_PLUGIN 宏在模拟器中注册插件,用插件类的名称 WorldPluginTutorial 作为参数。每类插件都有与之匹配宏,例如:GZ_REGISTER_MODEL_PLUGIN、 GZ_REGISTER_SENSOR_PLUGIN、 GZ_REGISTER_GUI_PLUGIN、 GZ_REGISTER_SYSTEM_PLUGIN、GZ_REGISTER_VISUAL_PLUGIN。

 

接下来对插件进行编译。

 

编译插件

首先在同一目录下创建 CMakeLists.txt :

 

$ gedit ~/Documents/gazebo_plugin_tutorial/CMakeLists.txt

 

在文件中填写以下内容:

 

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
find_package(gazebo REQUIRED)
include_directories(${GAZEBO_INCLUDE_DIRS})
link_directories(${GAZEBO_LIBRARY_DIRS})
list(APPEND CMAKE_CXX_FLAGS "${GAZEBO_CXX_FLAGS}")
add_library(hello_world SHARED hello_world.cc)
target_link_libraries(hello_world ${GAZEBO_LIBRARIES})

 

创建build目录:

 

$ mkdir ~/Documents/gazebo_plugin_tutorial/build
$ cd ~/Documents/gazebo_plugin_tutorial/build

 

编译代码:

 

$ cmake ../
$ make

 

编译完成后,将会在 build 目录下生成一个共享库 libhello_world.so。为了能够在Gazebo中插入该库,我们需要将库的路径添加到环境变量 GAZEBO_PLUGIN_PATH 中。我们打开 ~/.bashrc 文件,将下面一行添加到文件中并保存:

 

gedit ~/.bashrc

 

在文件末尾添加以下代码

 

export GAZEBO_PLUGIN_PATH=${GAZEBO_PLUGIN_PATH}:~/Documents/gazebo_plugin_tutorial/build/

 

使用插件

重新打开终端使环境变量加载生效,在终端中输入以下命令以创建一个世界文件,也可以在已有的世界文件中直接进行加载。

 

$ gedit ~/Documents/gazebo_plugin_tutorial/hello.world

 

在世界文件中添加以下代码并保存:

 

<?xml version="1.0"?>
<sdf version="1.6">
  <world name="default">
    <plugin name="hello_world" filename="libhello_world.so"/>
  </world>
</sdf>

 

接下来利用 gzserver 测试插件:

 

$ gzserver ~/Documents/gazebo_plugin_tutorial/hello.world --verbose

 

结果如下,成功返回我们在插件中定义的”Hello World!”语句

 

【ROS-Gazebo】仿真插件编写教程(1)——概述插图

 

刚开始琢磨gazebo的自定义插件,很多地方还不是很明白。先大致翻译,以后深入理解了再回来补充。

 

参考资料

[1] 官网教程: Tutorial : Plugins 101

发表评论

后才能评论

评论列表(2条)