【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)
文章目录
- 【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)
-
- 总结
前言:在先前的博客中,我们不仅完成了对机器人模型的建立和仿真,并且创建了机器人的工作空间,即仿真环境的设置,那么想要通过控制机器人传感器来完成对于机器人的控制就需要进一步研究,学会如何使用控制插件,通过编写代码在Gazebo中加载C++库完成对于机器人的实际控制。
一、控制插件的使用方法
1. 插件简介
- 目的:用于访问Gazebo的API,通过API执行目标任务,例如移动、添加对象、获取传感器数据等;
- 优点:在后期的Gazebo仿真开发中必不可少的部分,可以大大简化对于机器人的控制实现;
- 能让开发者控制几乎所有的Gazebo功能
- 独立的例行程序,易于分享
- 可以插入正在运行的系统或被其移除
- 使用场景:控制插件的使用场景较为广泛,我们应尽量通过插件简化仿真和控制流程;
- 以编程的方式来更改一个仿真,例如移动模型,对事件进行响应,插入有预先条件的模型
- 想要有一个到Gazebo的快速接口,不必经过传输层(transport layer),例如没有对消息进行序列化和反序列化
- 代码分享需求
- 插件类别:目前的插件主要可分为World,Model,Sensor,System,Visual,GUI六种,每个插件类型都由Gazebo的不同部分管理,系统插件在命令行中被指定,在Gazebo启动时首先加载。基于想实现的功能,我们应当选择不同的插件类型,比如我们想调整物理引擎,更改环境光,则需要世界插件。又或者想控制关节,和模型的状态,则需要模型插件。
2. 插件编写流程
sudo apt-get install libgazebo11-dev
mkdir ~/gazebo_plugin_tutorial
cd ~/gazebo_plugin_tutorial
gedit 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)
}
- 创建CMakeLists:
gedit ~/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})
\qquad
【注:从gazebo6的版本开始都需要c++11的flag,对应上述第六行代码】
mkdir ~/gazebo_plugin_tutorial/build
cd ~/gazebo_plugin_tutorial/build
cmake ../
make
- 2.6 添加共享库路径:在编译后,会产生
~/gazebo_plugin_tutorial/build/libhello_world.so
共享库,在仿真时插入,添加路径的方法如下:
export GAZEBO_PLUGIN_PATH=${GAZEBO_PLUGIN_PATH}:~/gazebo_plugin_tutorial/build
【编译完成后,就可以把它附加到SDF文件内的一个世界或一个模型。启动Gazebo会解析SDF文件,并定位插件,加载代码。所以需要指定插件完全路径,或让插件存在于GAZEBO_PLUGIN_PATH环境遍历路径中】
- 创建世界文件:
gedit ~/gazebo_plugin_tutorial/hello.world
- 编写世界文件:
<?xml version="1.0"?>
<sdf version="1.4">
<world name="default">
<plugin name="hello_world" filename="libhello_world.so"/>
</world>
</sdf>
gzserver ~/gazebo_plugin_tutorial/hello.world --verbose
Gazebo multi-robot simulator, version 9.16.0
Copyright (C) 2012 Open Source Robotics Foundation.
Released under the Apache 2 License.
http://gazebosim.org
[Msg] Waiting for master.
[Msg] Connected to gazebo master @ http://127.0.0.1:11345
[Msg] Publicized address: xxx.xxx.xxx.xxx
[Msg] Loading world file [/home/qqc/gazebo_plugin_tutorial/hello.world]
Hello World!
二、模型插件与世界插件
1. 模型插件
- 创建插件文件:
cd ~/gazebo_plugin_tutorial
gedit model_push.cc
- 编写插件文件:
#include <functional>
#include <gazebo/gazebo.hh>
#include <gazebo/physics/physics.hh>
#include <gazebo/common/common.hh>
#include <ignition/math/Vector3.hh>
namespace gazebo
{
class ModelPush : public ModelPlugin
{
public: void Load(physics::ModelPtr _parent, >sdf::ElementPtr )
{
this->model = _parent;
this->updateConnection = >event::Events::ConnectWorldUpdateBegin(
std::bind(&ModelPush::OnUpdate, this));
}
public: void OnUpdate()
{
this->model->SetLinearVel(ignition::math::Vector3d(.3, 0, 0));
}
private: physics::ModelPtr model;
private: event::ConnectionPtr updateConnection;
};
GZ_REGISTER_MODEL_PLUGIN(ModelPush)
}
- 打开原有文件:
gedit ~/gazebo_plugin_tutorial/CMakeLists.txt
- 在文件底部添加如下代码:
add_library(model_push SHARED model_push.cc)
target_link_libraries(model_push >${GAZEBO_LIBRARIES})
- 编译:共享库
~/gazebo_plugin_tutorial/build/libmodel_push.so
cd ~/gazebo_plugin_tutorial/build
cmake ../
make
- 打开文件:
cd ~/gazebo_plugin_tutorial
gedit model_push.world
- 编写世界文件:
<?xml version="1.0"?>
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<model name="box">
<pose>0 0 0.5 0 0 0</pose>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</visual>
</link>
<plugin name="model_push" filename="libmodel_push.so"/>
</model>
</world>
</sdf>
export GAZEBO_PLUGIN_PATH=$HOME/gazebo_plugin_tutorial/build:$GAZEBO_PLUGIN_PATH
cd ~/gazebo_plugin_tutorial/
gzserver -u model_push.world
gzclient
2. 世界插件
1)自动添加模型的世界插件
- 创建插件文件:
cd ~/gazebo_plugin_tutorial
gedit factory.cc
- 编写插件文件:
#include <ignition/math/Pose3.hh>
#include "gazebo/physics/physics.hh"
#include "gazebo/common/common.hh"
#include "gazebo/gazebo.hh"
namespace gazebo
{
class Factory : public WorldPlugin
{
public: void Load(physics::WorldPtr _parent, >sdf::ElementPtr )
{
_parent->InsertModelFile("model://box");
sdf::SDF sphereSDF;
sphereSDF.SetFromString(
"<sdf version ='1.4'>\
<model name ='sphere'>\
<pose>1 0 0 0 0 0</pose>\
<link name ='link'>\
<pose>0 0 .5 0 0 0</pose>\
<collision name ='collision'>\
<geometry>\
<sphere><radius>0.5</radius></sphere>\
</geometry>\
</collision>\
<visual name ='visual'>\
<geometry>\
<sphere><radius>0.5</radius></sphere>\
</geometry>\
</visual>\
</link>\
</model>\
</sdf>");
sdf::ElementPtr model = sphereSDF.Root()->GetElement("model");
model->GetAttribute("name")->SetFromString("unique_sphere");
_parent->InsertModelSDF(sphereSDF);
{
transport::NodePtr node(new transport::Node());
node->Init(_parent->Name());
transport::PublisherPtr factoryPub =
node->Advertise<msgs::Factory>("~/factory");
msgs::Factory msg;
msg.set_sdf_filename("model://cylinder");
msgs::Set(msg.mutable_pose(),
ignition::math::Pose3d(
ignition::math::Vector3d(1, -2, 0),
ignition::math::Quaterniond(0, 0, 0)));
factoryPub->Publish(msg);
}
}
};
GZ_REGISTER_WORLD_PLUGIN(Factory)
}
add_library(factory SHARED factory.cc)
target_link_libraries(factory
${GAZEBO_LIBRARIES}
)
cd ~/gazebo_plugin_tutorial/build
cmake ../
make
mkdir ~/gazebo_plugin_tutorial/models
cd ~/gazebo_plugin_tutorial/models
mkdir box cylinder
- 创建盒子模型:
cd box
gedit model.sdf
- 编写SDF文件:
<?xml version='1.0'?>
<sdf version ='1.6'>
<model name ='box'>
<pose>1 2 0 0 0 0</pose>
<link name ='link'>
<pose>0 0 .5 0 0 0</pose>
<collision name ='collision'>
<geometry>
<box><size>1 1 1</size></box>
</geometry>
</collision>
<visual name ='visual'>
<geometry>
<box><size>1 1 1</size></box>
</geometry>
</visual>
</link>
</model>
</sdf>
- 创建配置文件:
gedit model.config
- 编写配置文件:
<?xml version='1.0'?>
<model>
<name>box</name>
<version>1.0</version>
<sdf >model.sdf</sdf>
<author>
<name>me</name>
<email>somebody@somewhere.com</email>
</author>
<description>
A simple Box.
</description>
</model>
- SDF文件:
<?xml version='1.0'?>
<sdf version ='1.6'>
<model name ='cylinder'>
<pose>1 2 0 0 0 0</pose>
<link name ='link'>
<pose>0 0 .5 0 0 0</pose>
<collision name ='collision'>
<geometry>
<cylinder><radius>0.5</radius><length>1</length></cylinder>
</geometry>
</collision>
<visual name='visual'>
<geometry>
<cylinder><radius>0.5</radius><length>1</length>></cylinder>
</geometry>
</visual>
</link>
</model>
</sdf>
- Config文件:
<?xml version='1.0'?>
<model>
<name>cylinder</name>
<version>1.0</version>
<sdf>model.sdf</sdf>
<author>
<name>me</name>
<email>somebody@somewhere.com</email>
</author>
<description>
A simple cylinder.
</description>
</model>
export GAZEBO_MODEL_PATH=$HOME/gazebo_plugin_tutorial/models:$GAZEBO_MODEL_PATH
export GAZEBO_PLUGIN_PATH=$HOME/gazebo_plugin_tutorial/build:$GAZEBO_PLUGIN_PATH
cd ~/gazebo_plugin_tutorial
gedit factory.world
<?xml version="1.0"?>
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<plugin name="factory" filename="libfactory.so"/>
</world>
</sdf>
gazebo ~/gazebo_plugin_tutorial/factory.world
2)可编程的世界控制
cd ~/gazebo_plugin_tutorial
gedit world_edit.world
<?xml version ='1.0'?>
<sdf version ='1.4'>
<world name='default'>
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<plugin filename="libworld_edit.so" name="world_edit"/>
</world>
</sdf>
gedit world_edit.cc
#include <sdf/sdf.hh>
#include <ignition/math/Pose3.hh>
#include "gazebo/gazebo.hh"
#include "gazebo/common/Plugin.hh"
#include "gazebo/msgs/msgs.hh"
#include "gazebo/physics/physics.hh"
#include "gazebo/transport/transport.hh"
namespace gazebo
{
class WorldEdit : public WorldPlugin
{
public: void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
{
transport::NodePtr node(new transport::Node());
node->Init(_parent->Name());
transport::PublisherPtr physicsPub = node->Advertise<msgs::Physics>("~/physics");
msgs::Physics physicsMsg;
physicsMsg.set_type(msgs::Physics::ODE);
physicsMsg.set_max_step_size(0.01);
msgs::Set(physicsMsg.mutable_gravity(), ignition::math::Vector3d(0.01, 0, 0.1));
physicsPub->Publish(physicsMsg);
}
};
GZ_REGISTER_WORLD_PLUGIN(WorldEdit)
}
add_library(world_edit SHARED world_edit.cc)
target_link_libraries(world_edit ${GAZEBO_LIBRARIES})
cd ~/gazebo_plugin_tutorial/build
cmake ..
make
export GAZEBO_PLUGIN_PATH=${GAZEBO_PLUGIN_PATH}:~/gazebo_plugin_tutorial/build/
cd ~/gazebo_plugin_tutorial
gazebo world_edit.world
总结
- 内容分析:本篇博客主要介绍了Gazebo中如何编写并完成插件的配置,分别用一个helloworld的简易插件讲述了编写插件的流程,并紧接着使用模型插件和世界插件的例子完成对于插件编写和配置的深入研究,内容更多关注于代码和配置流程,故可读性一般,理解需认真钻研。
- 注意:本文参考了Gazebo官方网站以及古月居中的Gazebo有关教程,主要目的是方便自行查询知识,巩固学习经验,无任何商业用途。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)