【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)

这篇具有很好参考价值的文章主要介绍了【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)

【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)

前言在先前的博客中,我们不仅完成了对机器人模型的建立和仿真,并且创建了机器人的工作空间,即仿真环境的设置,那么想要通过控制机器人传感器来完成对于机器人的控制就需要进一步研究,学会如何使用控制插件,通过编写代码在Gazebo中加载C++库完成对于机器人的实际控制。


一、控制插件的使用方法

1. 插件简介

  • 目的:用于访问Gazebo的API,通过API执行目标任务,例如移动、添加对象、获取传感器数据等;
  • 优点:在后期的Gazebo仿真开发中必不可少的部分,可以大大简化对于机器人的控制实现;
  1. 能让开发者控制几乎所有的Gazebo功能
  2. 独立的例行程序,易于分享
  3. 可以插入正在运行的系统或被其移除
  • 使用场景:控制插件的使用场景较为广泛,我们应尽量通过插件简化仿真和控制流程;
  1. 以编程的方式来更改一个仿真,例如移动模型,对事件进行响应,插入有预先条件的模型
  2. 想要有一个到Gazebo的快速接口,不必经过传输层(transport layer),例如没有对消息进行序列化和反序列化
  3. 代码分享需求
  • 插件类别:目前的插件主要可分为World,Model,Sensor,System,Visual,GUI六种,每个插件类型都由Gazebo的不同部分管理,系统插件在命令行中被指定,在Gazebo启动时首先加载。基于想实现的功能,我们应当选择不同的插件类型,比如我们想调整物理引擎,更改环境光,则需要世界插件。又或者想控制关节,和模型的状态,则需要模型插件。

2. 插件编写流程

  • 2.1 环境配置:安装Gazebo开发文件
sudo apt-get install libgazebo11-dev
  • 2.2 创建工作目录:
mkdir ~/gazebo_plugin_tutorial
cd ~/gazebo_plugin_tutorial
  • 2.3 编写插件代码:内容紧随其后,附逐行解析
gedit hello_world.cc 
#include <gazebo/gazebo.hh>
// gazebo/gazebo.hh包含了一组核心的基本Gazebo函数,所有的插件都必须在gazebo的命名空间内。
namespace gazebo
{
  //每个插件都必须继承自某个插件类型,在这里是WorldPlugin类
  class WorldPluginTutorial : public WorldPlugin
  {
    public: WorldPluginTutorial() : WorldPlugin()
            {
              printf("Hello World!\n");
            }
	//强制函数Load,接受被加载SDF文件内的元素和属性。
    public: void Load(physics::WorldPtr _world, sdf::ElementPtr _sdf)
            {
            }
  };
  // 插件必须使用宏GZ_REGISTER_WORLD_PLUGIN在模拟器中注册。这个宏的唯一参数就是插件的类。
  GZ_REGISTER_WORLD_PLUGIN(WorldPluginTutorial)
}
  • 2.4 编译插件:
  1. 创建CMakeLists:
gedit ~/gazebo_plugin_tutorial/CMakeLists.txt
  1. 编写编译文件:
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,对应上述第六行代码

  • 2.5 创建build目录并编译代码:
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环境遍历路径中】

  • 2.7 创建并编写世界文件:
  1. 创建世界文件:
gedit ~/gazebo_plugin_tutorial/hello.world
  1. 编写世界文件:
<?xml version="1.0"?>
<sdf version="1.4">
 <world name="default">
   <plugin name="hello_world" filename="libhello_world.so"/>
 </world>
</sdf>
  • 2.8 在gzserver打开世界文件:
gzserver ~/gazebo_plugin_tutorial/hello.world --verbose
  • 2.9 输出如下:
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. 模型插件

  • 创建并编写插件文件:
  1. 创建插件文件:
cd ~/gazebo_plugin_tutorial
gedit model_push.cc
  1. 编写插件文件:
#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 /*_sdf*/)
   {
     // Store the pointer to the model
     this->model = _parent;

     // Listen to the update event. This event is >broadcast every
     // simulation iteration.
     this->updateConnection = >event::Events::ConnectWorldUpdateBegin(
         std::bind(&ModelPush::OnUpdate, this));
   }

   // Called by the world update start event
   public: void OnUpdate()
   {
     // Apply a small linear velocity to the model.
     // 每次迭代设置_parent速度(.3,0,0)
     this->model->SetLinearVel(ignition::math::Vector3d(.3, 0, 0));
   }

   // Pointer to the model
   private: physics::ModelPtr model;

   // Pointer to the update event connection
   private: event::ConnectionPtr updateConnection;
 };

 // Register this plugin with the simulator
 GZ_REGISTER_MODEL_PLUGIN(ModelPush)
}
  • 修改编译规则文件:
  1. 打开原有文件:
gedit ~/gazebo_plugin_tutorial/CMakeLists.txt
  1. 在文件底部添加如下代码:
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
  • 修改世界文件:
  1. 打开文件:
cd ~/gazebo_plugin_tutorial
gedit model_push.world
  1. 编写世界文件:
<?xml version="1.0"?> 
<sdf version="1.4">
 <world name="default">

   <!-- Ground Plane -->
   <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
  • 新建终端启动GUI:
gzclient
  • 效果:方盒沿X轴进行匀速运动,图示如下:

【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)


2. 世界插件

1)自动添加模型的世界插件
  • 创建并编写插件文件:
  1. 创建插件文件:
cd ~/gazebo_plugin_tutorial
gedit factory.cc
  1. 编写插件文件:
#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 /*_sdf*/)
 {
   // 方法1: 基于在资源路径内的文件来加载模型,通过调用函数,从文件中插入模型
   // Option 1: Insert model from file via function call.
   // 文件名必须要在环境变量`GAZEBO_MODEL_PATH`中
   // The filename must be in the >GAZEBO_MODEL_PATH environment variable.
   _parent->InsertModelFile("model://box");

   // 方法2:通过调用函数,从字符串中插入模型
   // Option 2: Insert model from string via function call.
   // 从字符串插入一个球形模型
   // Insert a sphere model from string
   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>");
   // 自定义模型名称 Demonstrate using a custom model name.
   sdf::ElementPtr model = sphereSDF.Root()->GetElement("model");
   model->GetAttribute("name")->SetFromString("unique_sphere");
   _parent->InsertModelSDF(sphereSDF);

   // 方法3: 通过消息传递,从文件插入模型
   // Option 3: Insert model from file via message passing.
   {
     // 创造一个新的传输节点 Create a new transport node
     transport::NodePtr node(new transport::Node());

     // 用世界名初始化节点 Initialize the node with the world name
     node->Init(_parent->Name());

     // 在~/factory创建一个发布者publisher Create a publisher on the ~/factory topic
     transport::PublisherPtr factoryPub =
     node->Advertise<msgs::Factory>("~/factory");

     // 创建消息 Create the message
     msgs::Factory msg;

     // 加载模型文件 Model file to load
     msg.set_sdf_filename("model://cylinder");

     // 设置要初始化的模型的位置信息 Pose to initialize the model to
     msgs::Set(msg.mutable_pose(),
         ignition::math::Pose3d(
           ignition::math::Vector3d(1, -2, 0),
           ignition::math::Quaterniond(0, 0, 0)));

     // 发送消息 Send the message
     factoryPub->Publish(msg);
   }
 }
};

// Register this plugin with the simulator
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
  • 创建盒子模型并编写SDF文件:
  1. 创建盒子模型:
cd box
gedit model.sdf
  1. 编写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> 
  • 创建并编写配置文件:
  1. 创建配置文件:
gedit model.config
  1. 编写配置文件:
<?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>
  • 对圆柱体重复操作:
  1. 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>
  1. 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 ~/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"

/// \example examples/plugins/world_edit.cc
/// This example creates a WorldPlugin, initializes the Transport system by
/// creating a new Node, and publishes messages to alter gravity.
namespace gazebo
{
  class WorldEdit : public WorldPlugin
  {
    public: void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
    {
      // 新建一个运输节点 Create a new transport node
      transport::NodePtr node(new transport::Node());

      // 用世界名称初始化节点 Initialize the node with the world name
      node->Init(_parent->Name());

      // 在~/physics主题上创建一个发布者 Create a publisher on the ~/physics topic
      transport::PublisherPtr physicsPub = node->Advertise<msgs::Physics>("~/physics");

      msgs::Physics physicsMsg;
      physicsMsg.set_type(msgs::Physics::ODE);

      // 设置步长时间 Set the step time
      physicsMsg.set_max_step_size(0.01);

      // 改变重力 Change gravity
      msgs::Set(physicsMsg.mutable_gravity(), ignition::math::Vector3d(0.01, 0, 0.1));
      physicsPub->Publish(physicsMsg);
    }
  };

  // Register this plugin with the simulator
  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入门教程】第五讲 控制器插件的编写与配置(上)


总结

  • 内容分析:本篇博客主要介绍了Gazebo中如何编写并完成插件的配置,分别用一个helloworld的简易插件讲述了编写插件的流程,并紧接着使用模型插件和世界插件的例子完成对于插件编写和配置的深入研究,内容更多关注于代码和配置流程,故可读性一般,理解需认真钻研。

【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)文章来源地址https://www.toymoban.com/news/detail-400838.html

  • 注意:本文参考了Gazebo官方网站以及古月居中的Gazebo有关教程,主要目的是方便自行查询知识,巩固学习经验,无任何商业用途。

到了这里,关于【Gazebo入门教程】第五讲 控制器插件的编写与配置(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java程序设计入门教程--控制台输入数据

    控制台输入数据常用类 Scanner类        在 很多情况下,我们需要 Java 程序能够对我们指定的值进行计算,这样的话就需要我们的 Java 程序能够读取我们所输入的值。我们可以使用 Java 自带的 Scanner 类来从控制台获取 输入 。        Scanner 类在包 java.util 里。我们一般在程

    2024年02月07日
    浏览(43)
  • SpringMVC bean加载控制 -- SpringMVC入门保姆级教程(二)

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章

    2024年02月07日
    浏览(50)
  • JAVA输入语句与循环控制结构------JAVA入门基础教程

    import java.util.Scanner; class LogicExer {     static Scanner in = new Scanner(System.in);     public static void main(String args[])     {         int a;         int b;         a = b = 20;         boolean bo1 = (++a % 3 == 0) (a++ % 7 == 0);         System.out.println(a+\\\"+\\\"+bo1);         boolean b

    2024年02月01日
    浏览(58)
  • 【Git 入门教程】第四节、Git冲突:如何解决版本控制的矛盾

    Git是目前最流行的版本控制系统之一,它为团队协作开发提供了方便和高效的方式。然而,在多人同时修改同一个文件时,可能会出现代码 冲突(conflict) ,导致代码无法正确合并。那么,如何解决Git冲突呢? 在多分支并行处理时,每一个分支可能是基于不同版本的主干分

    2024年02月05日
    浏览(59)
  • k8s控制器之DaemonSet--第五弹更新 DaemonSet

    DaemonSet 有两种更新策略: OnDelete : 使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的 DaemonSet pods 之后,新的 DaemonSet Pod 才会 被自动创建。跟 Kubernetes 1.6 以前的版本类似。 RollingUpdate : 这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSe

    2024年02月11日
    浏览(40)
  • 4·ESP32-C3入门教程——从本地控制走向云端控制(TCP/IP UDP篇)

            距离实现一个完整的物联网小应用只差最后一步了,今天聊聊怎么样在手机上对ESP32芯片发送指令和接收数据,并借助ESP官方的接口——rainmaker,来实现远程控制和通信。我们也借由此进入智能家居时代1.0(部分物联网概念可以看看【序】在23年谈物联网)        

    2024年02月16日
    浏览(43)
  • SpringMVC bean加载控制 -- SpringMVC快速入门保姆级教程(二)

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章

    2024年02月07日
    浏览(42)
  • k8s控制器之job--第五弹Job的自动清理

    系统中已经完成的 Job 通常是不在需要里的,长期在系统中保留这些对象,将给 apiserver 带来很大的压力。如果通过更高级别的控制器(例如 CronJobs)来管理 Job,则 CronJob 可以根据其中定义的基于容量的清理策略(capacity-based cleanup policy)自动清理Job。 除了 CronJob 之外,TTL 机

    2024年02月11日
    浏览(43)
  • [入门教程]详细讲解STM32控制LED点阵屏(HUB75接口)

    本文适合初级入门的同学,大佬请绕道。讲解怎么用stm32驱动成品LED点阵屏显示一副七色无灰度的图片,有灰度的图片可以入门后继续研究。   使用软硬件: 软件:Keil5,程序在后面会给出 硬件:STM32F103最小系统、全彩色P4LED点阵屏(HUB75接口,16扫) 说下stm32驱动LED点阵屏用

    2024年01月19日
    浏览(91)
  • 第10章_瑞萨MCU零基础入门系列教程之中断控制单元简介

    本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id=728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总 : https://blog.csdn.net/qq_35181236/article/details/132779862 本书使用的RA处理器R7FAM5系

    2024年02月09日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包