Skip to content
wngjs3 edited this page Mar 16, 2018 · 5 revisions

Introduction

Gazebo 항목은 Google 프로토콜 메시지를 통해 통신합니다. 가제보가 제공하는 광범위한 메시지 유형 목록이 가제보 주제 구독 및 게시에 사용됩니다. 그러나, 당신이 당신 자신의 것을 만들고 싶어하는 많은 상황들이있다.

이 자습서는 사용자 정의 메시지를 작성하는 방법과 Gazebo 플러그인에서 구독하고 게시하는 방법의 예입니다.

About this code

이 프로젝트가 끝나면 Gazebo World의 2D 충돌 맵을 만들 수있는 플러그인이 있어야합니다. 플러그 인은 Gazebo에서 세계를 래스터 화합니다. RayShape를 사용하여이 격자 아래에서 광선 교차를합니다. 생성 된 이미지를 사용자 정의 항목에 게시하고 파일로 출력합니다. 이 플러그인의 소스 코드는 BitBucket에 있습니다.

개선을 위해 문제를 제기하거나 요청을 제출하십시오. 코드의 원래 작성자는 Stephen Brawner입니다.

mercurial을 사용하여 소스 코드를 다운로드 할 수 있습니다.

hg clone https://bitbucket.org/osrf/collision_map_creator_plugin

또는 코드를 복사하여 아래 설명 된대로 파일에 붙여 넣으십시오.

Writing your own message

Gazebo의 이미 사용 가능한 메시지 유형 중 하나에 구독자 / 게시자 메시지를 밀어 넣기가 너무 어렵다면 자신의 메시지를 작성하는 것이 좋습니다. 또한 복잡한 메시지를 작성하려는 경우 다양한 메시지 유형을 결합 할 수 있습니다. Gazebo에는 이미 메시지 라이브러리가 포함되어 있습니다. 설치된 메시지는 데비안 설치를 위해 / usr / include / gazebo- / gazebo / msgs / proto에서 찾을 수 있습니다. 이 자습서에서는 vector2d.proto 메시지를 사용합니다.

~ / collision_map_creator_plugin / msgs / collision_map_request.proto를보고 맞춤 메시지가 어떻게 선언되는지 확인할 수 있습니다.

package collision_map_creator_msgs.msgs;
import "vector2d.proto";

message CollisionMapRequest
{
  required gazebo.msgs.Vector2d   upperLeft  = 1;
  required gazebo.msgs.Vector2d   upperRight = 2;
  required gazebo.msgs.Vector2d   lowerRight = 3;
  required gazebo.msgs.Vector2d   lowerLeft  = 4;
  required double                 height     = 5;
  required double                 resolution = 6;
  optional string                 filename   = 7 [default = ""];
  optional int32                  threshold  = 8 [default = 255];
}

Code explained

먼저 package 선언과 함께이 메시지가 살아있는 네임 스페이스를 선언합니다.

package collision_map_creator_msgs.msgs;

Gazebo의 vector2d를 사용하므로 우리는 그것을 포함해야합니다 (메시지의 위치는 CMakeLists.txt에서 처리됩니다).

import "vector2d.proto";

이것이 실제 메시지 구조입니다.

message CollisionMapRequest{}

각 메세지 필드를 다음과 같이 선언하십시오.

["optional"/"required"] [field type] [field name] = [enum];

각 열거 형은 고유 한 숫자 여야합니다. 전체 패키지 이름은 외부 메시지 (이 경우 gazebo.msgs)를 지정하는 데 사용해야합니다.

required gazebo.msgs.Vector2d upperLeft = 1; required gazebo.msgs.Vector2d upperRight = 2; required gazebo.msgs.Vector2d lowerRight = 3; required gazebo.msgs.Vector2d lowerLeft = 4; required double height = 5; required double resolution = 6;

메시지에는 선택적 필드가 포함될 수 있습니다. 선택적 필드가 지정되지 않은 경우 선택적 필드에 기본값이 포함될 수 있습니다. 이것은 어떻게 그 방법의 예입니다.

optional string filename = 7 [default = ""]; optional int32 threshold = 8 [default = 255];

CMakeLists for custom messages

이 튜토리얼에서는 protobuf 메시지 정의에서 C ++ 코드를 생성 할 ~/collision_map_creator/msgs/CMakeLists.txt 도 제공합니다.

Code explained

CMake에게 Protobuf 패키지를 포함하도록 알려줍니다.

find_package(Protobuf REQUIRED)

이 섹션에서는 메시지가 설치된 위치를 찾습니다. 메시지 파일은 데비안 설치를 위해 /usr/include/gazebo-<YOUR_GAZEBO_VERSION>/gazebo/msgs/proto 에 저장되지만 사용자가 다른 곳에 설치했을 수도 있습니다. 이 코드는 gazebo-XX 폴더를 검색하고 이에 따라 PROTOBUF_IMPORT_DIRS 변수를 설정합니다. PROTOBUF_IMPORT_DIRS 는 추가 메시지 파일의 위치를 ​​지정합니다.

set(PROTOBUF_IMPORT_DIRS)
foreach(ITR ${GAZEBO_INCLUDE_DIRS})
  if(ITR MATCHES ".*gazebo-[0-9.]+$")
    set(PROTOBUF_IMPORT_DIRS "${ITR}/gazebo/msgs/proto")
  endif()
endforeach()

vector2d.proto 메시지, dependencies time.proto 및 header.proto 및 collision_map_request.proto 메시지와 함께 msgs 라는 목록을 작성합니다.

set (msgs
  collision_map_request.proto
  ${PROTOBUF_IMPORT_DIRS}/vector2d.proto
  ${PROTOBUF_IMPORT_DIRS}/header.proto
  ${PROTOBUF_IMPORT_DIRS}/time.proto
)

메시지에 필요한 C ++ 헤더와 소스 파일을 빌드하십시오.

PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${msgs})

이 메시지 라이브러리를 추가하여 다른 프로젝트의 링크에 연결할 수 있습니다. 라이브러리 이름은 아래의 다른 CMakeLists.txt 지정된 라이브러리 이름과 동일해야합니다.

add_library(collision_map_creator_msgs SHARED ${PROTO_SRCS})
target_link_libraries(collision_map_creator_msgs ${PROTOBUF_LIBRARY})

Collision Map Creator Plugin

이것은 사용자 정의 Gazebo 월드 플러그인 ( ~/collision_map_creator_plugin/collision_map_creator.cc )의 코드입니다.

#include <iostream>
#include <math.h>
#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/io/png_dynamic_io.hpp>
#include <boost/shared_ptr.hpp>        
#include <sdf/sdf.hh>
#include <ignition/math/Vector3.hh>

#include "gazebo/gazebo.hh"
#include "gazebo/common/common.hh"
#include "gazebo/msgs/msgs.hh"
#include "gazebo/physics/physics.hh"
#include "gazebo/transport/transport.hh"
#include "collision_map_request.pb.h"

namespace gazebo
{
typedef const boost::shared_ptr<
  const collision_map_creator_msgs::msgs::CollisionMapRequest>
    CollisionMapRequestPtr;

class CollisionMapCreator : public WorldPlugin
{
  transport::NodePtr node;
  transport::PublisherPtr imagePub;
  transport::SubscriberPtr commandSubscriber;
  physics::WorldPtr world;

  public: void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
  {
    node = transport::NodePtr(new transport::Node());
    world = _parent;
    // Initialize the node with the world name
    node->Init(world->Name());
    std::cout << "Subscribing to: " << "~/collision_map/command" << std::endl;
    commandSubscriber = node->Subscribe("~/collision_map/command",
      &CollisionMapCreator::create, this);
    imagePub = node->Advertise<msgs::Image>("~/collision_map/image");
  }

  public: void create(CollisionMapRequestPtr &msg)
  {
    std::cout << "Received message" << std::endl;

    std::cout << "Creating collision map with corners at (" <<
      msg->upperleft().x() << ", " << msg->upperleft().y() << "), (" <<
      msg->upperright().x() << ", " << msg->upperright().y() << "), (" <<
      msg->lowerright().x() << ", " << msg->lowerright().y() << "), (" <<
      msg->lowerleft().x() << ", " << msg->lowerleft().y() <<
        ") with collision projected from z = " <<
      msg->height() << "\nResolution = " << msg->resolution() << " m\n" <<
        "Occupied spaces will be filled with: " << msg->threshold() <<
        std::endl;

    double dX_vertical = msg->upperleft().x() - msg->lowerleft().x();
    double dY_vertical = msg->upperleft().y() - msg->lowerleft().y();
    double mag_vertical =
      sqrt(dX_vertical * dX_vertical + dY_vertical * dY_vertical);
    dX_vertical = msg->resolution() * dX_vertical / mag_vertical;
    dY_vertical = msg->resolution() * dY_vertical / mag_vertical;

    double dX_horizontal = msg->upperright().x() - msg->upperleft().x();
    double dY_horizontal = msg->upperright().y() - msg->upperleft().y();
    double mag_horizontal =
      sqrt(dX_horizontal * dX_horizontal + dY_horizontal * dY_horizontal);
    dX_horizontal = msg->resolution() * dX_horizontal / mag_horizontal;
    dY_horizontal = msg->resolution() * dY_horizontal / mag_horizontal;

    int count_vertical = mag_vertical / msg->resolution();
    int count_horizontal = mag_horizontal / msg->resolution();

    if (count_vertical == 0 || count_horizontal == 0)
    {
      std::cout << "Image has a zero dimensions, check coordinates"
                << std::endl;
      return;
    }
    double x,y;

    boost::gil::gray8_pixel_t fill(255-msg->threshold());
    boost::gil::gray8_pixel_t blank(255);
    boost::gil::gray8_image_t image(count_horizontal, count_vertical);

    double dist;
    std::string entityName;
    ignition::math::Vector3d start, end;
    start.Z(msg->height());
    end.Z(0.001);

    gazebo::physics::PhysicsEnginePtr engine = world->Physics();
    engine->InitForThread();
    gazebo::physics::RayShapePtr ray =
      boost::dynamic_pointer_cast<gazebo::physics::RayShape>(
        engine->CreateShape("ray", gazebo::physics::CollisionPtr()));

    std::cout << "Rasterizing model and checking collisions" << std::endl;
boost::gil::fill_pixels(image._view, blank);

    for (int i = 0; i < count_vertical; ++i)
    {
  std::cout << "Percent complete: " << i * 100.0 / count_vertical
            << std::endl;
  x = i * dX_vertical + msg->lowerleft().x();
  y = i * dY_vertical + msg->lowerleft().y();
      for (int j = 0; j < count_horizontal; ++j)
  {
    x += dX_horizontal;
    y += dY_horizontal;

    start.X(x);
    end.X(x);
    start.Y(y);
    end.Y(y);
    ray->SetPoints(start, end);
    ray->GetIntersection(dist, entityName);
    if (!entityName.empty())
    {
      image._view(i,j) = fill;
    }
  }
}

std::cout << "Completed calculations, writing to image" << std::endl;
if (!msg->filename().empty())
{
  boost::gil::gray8_view_t view = image._view;
  boost::gil::png_write_view(msg->filename(), view);
    }
  }
};

// Register this plugin with the simulator
GZ_REGISTER_WORLD_PLUGIN(CollisionMapCreator)
}

Code Explained

포함 할 필수 시스템 헤더

#include <iostream>
#include <math.h>
#include <boost/shared_ptr.hpp>

이것들은 우리가 필요로하는 필요한 가제보 (Gazebo) 헤더입니다.

#include "gazebo/gazebo.hh"
#include "gazebo/common/common.hh"
#include "gazebo/math/Vector3.hh"
#include "gazebo/msgs/msgs.hh"
#include "gazebo/physics/physics.hh"
#include "gazebo/transport/transport.hh"
#include "collision_map_request.pb.h"

우리의 collision_map_request 메시지를 사용하려면 생성 된 헤더 파일을 포함시켜야합니다.

#include "collision_map_request.pb.h"

이들은 .png 파일을 쓰는 데 사용됩니다.

#include <boost/gil/gil_all.hpp>
#include <boost/gil/extension/io/png_dynamic_io.hpp>

플러그인은 Gazebo 네임 스페이스에 있습니다.

namespace gazebo
{

이것은 콜백 메소드에 전송 될 객체입니다. 이를위한 typedef를 만드는 것이 편리합니다.

typedef const boost::shared_ptr<const collision_map_creator_msgs::msgs::CollisionMapRequest>             CollisionMapRequestPtr;

Gazebo WorldPlugin의 파생 클래스 만들기. NodePtr , PublisherPtr , SubcriberPtr 및 WorldPtr 을 유지해야하므로 클래스 변수로 추가해야합니다.

class CollisionMapCreator : public WorldPlugin { transport::NodePtr node; transport::PublisherPtr imagePub; transport::SubscriberPtr commandSubscriber; physics::WorldPtr world;

World Plugin의 Load 메소드. 노드, 세계, 구독자 및 게시자를 설정합니다.

public: void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf)
{
  node = transport::NodePtr(new transport::Node());
  world = _parent;
  // Initialize the node with the world name
  node->Init(world->GetName());
  std::cout << "Subscribing to: " << "~/collision_map/command" << std::endl;

node->Subscribe 은 주제, 콜백 함수 및이 플러그인 객체에 대한 포인터로 호출됩니다. node->Advertise , 메시지 유형의 템플리트 인수 및 광고 할 주제 매개 변수가 필요합니다.

    commandSubscriber = node->Subscribe("~/collision_map/command", &CollisionMapCreator::create, this);
    imagePub = node->Advertise<msgs::Image>("~/collision_map/image");

이것은 콜백 메소드입니다. 이전에 사용한 typedef를 포함합니다. 콜백에는 참조가 전달되므로 &msg 를 사용해야합니다.

public: void create(CollisionMapRequestPtr &msg)

CollisionMapRequestPtr 은 shared_ptr을 높이기 때문에 실제 필드를 얻으려면 아래에서와 같이 구조 참조 ( '.') 대신 구조체 참조 해제 ( '->')를 사용해야합니다. 객체의 필드를 얻으려면 get 함수를 호출해야합니다 (예 : field() ).

    double z = msg->height();

그러나 잠깐 물어보십시오. 왜 직접 하위 필드를 참조 할 수 있습니까? 그것은 shared_ptrs가 내부에 없기 때문에 우리가 보낸 메시지입니다.

    double dX_vertical = msg->upperleft().x() - msg->lowerleft().x();
    double dY_vertical = msg->upperleft().y() - msg->lowerleft().y();
    double mag_vertical = sqrt(dX_vertical * dX_vertical + dY_vertical * dY_vertical);
    dX_vertical = msg->resolution() * dX_vertical / mag_vertical;
    dY_vertical = msg->resolution() * dY_vertical / mag_vertical;

이것은 사용 된 물리 엔진을 호출하여 단일 광선 추적을 수행하는 방법의 예입니다. 이 코드는 gazebo::physics::World::GetEntityBelowPoint(Vector3)

    gazebo::physics::PhysicsEnginePtr engine = world->GetPhysicsEngine();
    engine->InitForThread();
    gazebo::physics::RayShapePtr ray = boost::dynamic_pointer_cast<gazebo::physics::RayShape>(
          engine->CreateShape("ray", gazebo::physics::CollisionPtr()));

객체가있는 곳과없는 곳을 결정하기 위해 격자를 래스터 화합니다.

    for (int i = 0; i < count_vertical; ++i)
    {

... for (int j = 0; j < count_horizontal; ++j) { ... } ... }

이렇게하면 이미지 메시지가 만들어지고 필요한 필드가 채워집니다. 각 필드에 대한 setter 메소드는 set_field(something) 와 같은 형식으로되어 있습니다.

    msgs::Image image;
    image.set_width(count_horizontal);
    image.set_height(count_vertical);
    image.set_pixel_format(0);
    image.set_step(count_horizontal);
    image.set_data(data);

    imagePub->Publish(image);

플러그인을 시뮬레이터에 등록하십시오.

// Register this plugin with the simulator GZ_REGISTER_WORLD_PLUGIN(CollisionMapCreator) }

Request Publisher Executable

이 실행 파일은 전망대 외부에서 실행되지만 Gazebo에서 필요한 라이브러리를 가져 와서 사용자 정의 빌드 된 메시지 유형으로 전망대 항목에 게시하는 방법을 보여줍니다. 플러그인 자습서에서 설명하지 않은 몇 가지 추가 단계가 필요합니다. ~/collision_map_creator_plugin/request_publisher.cc 파일을 열어 소스 코드를 볼 수 있습니다.

#include #include <math.h> #include #include <sdf/sdf.hh>

#include "gazebo/gazebo.hh" #include "gazebo/common/common.hh" #include "gazebo/transport/transport.hh" #include "gazebo/physics/physics.hh" #include "gazebo/msgs/msgs.hh"

#include "collision_map_request.pb.h" #include "vector2d.pb.h"

using namespace std;

bool createVectorArray(const char * vectorString, dequegazebo::msgs::Vector2d* corners) { dequegazebo::msgs::Vector2d*::iterator it;

string cornersStr = vectorString;
size_t opening=0;
size_t closing=0;
for (it = corners.begin(); it != corners.end(); ++it)
{
    opening = cornersStr.find('(', closing);
    closing = cornersStr.find(')', opening);
    if (opening == string::npos || closing == string::npos)
    {
        std::cout << "Poorly formed string: " << cornersStr << std::endl;
        std::cout << "( found at: " << opening << " ) found at: " << closing << std::endl;
        return false;
    }
    string oneCornerStr = cornersStr.substr(opening + 1, closing - opening - 1);
    size_t commaLoc = oneCornerStr.find(",");
    string x = oneCornerStr.substr(0,commaLoc);
    string y = oneCornerStr.substr(commaLoc + 1, oneCornerStr.length() - commaLoc);
    (*it)->set_x(atof(x.c_str()));
    (*it)->set_y(atof(y.c_str()));
}
return true;

}

int main(int argc, char * argv[]) { if (argc > 4) { collision_map_creator_msgs::msgs::CollisionMapRequest request; dequegazebo::msgs::Vector2d* corners;

    corners.push_back(request.mutable_upperleft());
    corners.push_back(request.mutable_upperright());
    corners.push_back(request.mutable_lowerright());
    corners.push_back(request.mutable_lowerleft());

    if (!createVectorArray(argv[1],corners))
    {
        return -1;
    }

    request.set_height(atof(argv[2]));
    request.set_resolution(atof(argv[3]));
    request.set_filename(argv[4]);

    if (argc == 6)
    {
        request.set_threshold(atoi(argv[5]));
    }

    gazebo::transport::init();
    gazebo::transport::run();
    gazebo::transport::NodePtr node(new gazebo::transport::Node());
    node->Init("default");

    std::cout << "Request: " <<
                 " UL.x: " << request.upperleft().x() <<
                 " UL.y: " << request.upperleft().y() <<
                 " UR.x: " << request.upperright().x() <<
                 " UR.y: " << request.upperright().y() <<
                 " LR.x: " << request.lowerright().x() <<
                 " LR.y: " << request.lowerright().y() <<
                 " LL.x: " << request.lowerleft().x() <<
                 " LL.y: " << request.lowerleft().y() <<
                 " Height: " << request.height() <<
                 " Resolution: " << request.resolution() <<
                 " Filename: " << request.filename() <<
                 " Threshold: " << request.threshold() << std::endl;

    gazebo::transport::PublisherPtr imagePub =
            node->Advertise<collision_map_creator_msgs::msgs::CollisionMapRequest>(
                                                        "~/collision_map/command");
    imagePub->WaitForConnection();
    imagePub->Publish(request);

    gazebo::transport::fini();
    return 0;
}
return -1;

}

Code Explained

필요한 표준 c ++ 헤더 포함

#include #include <math.h> #include <boost/shared_ptr.hpp> #include <sdf/sdf.hh> #include <boost/gil/gil_all.hpp> #include <boost/gil/extension/io/png_dynamic_io.hpp> 이것들은 우리 실행 파일에 필요한 전망대 헤더입니다. #include "gazebo/gazebo.hh" #include "gazebo/common/common.hh" #include "gazebo/math/Vector3.hh" #include "gazebo/transport/transport.hh" #include "gazebo/physics/physics.hh" #include "gazebo/msgs/msgs.hh" #include "collision_map_request.pb.h" 이것은 사용자 정의 메시지 유형과 연관된 헤더입니다. #include "collision_map_request.pb.h"

이 함수는 "(x1, y1) (x2, y2) (x3, y3) (x4, y4)"에 의해 정의 된 좌표 문자열을 Vector2d 메시지의 양키로 파싱합니다.

bool createVectorArray(const char * vectorString, dequegazebo::msgs::Vector2d* corners) deque 반복자를 초기화합니다. dequegazebo::msgs::Vector2d*::iterator it;

Iterate through the corners deque

... for (it = corners.begin(); it != corners.end(); ++it) { ... } 코너 인 Vector2d에 대해 우리는 x와 y에 대해 발견 된 문자열을 float로 변환하여 X와 Y를 설정합니다 (*it)->set_x(atof(x.c_str())); (*it)->set_y(atof(y.c_str()));

The main function, which is called when the executable is run.

int main(int argc, char * argv[]) { ... } 이 실행 파일에는 여러 가지 인수가 필요하며 적어도 4 개 이상인 경우에만 진행하십시오. if (argc > 4) { ... } CollisionMapRequest 메시지를 생성합니다. 이 메시지를 보내기 전에 작성해야합니다. 또한 Vector2d 메시지의 deque를 초기화하여 createVectorArray 함수에 전달할 수 있습니다. collision_map_creator_msgs::msgs::CollisionMapRequest request; dequegazebo::msgs::Vector2d* corners; 메시지 필드가 단순한 경우 (double, int32, string) 연관된 set_field() 메소드로 직접 설정할 수 있습니다. 필드가 메시지 유형 자체 인 경우, 해당 mutable_field() 메소드를 통해 액세스해야합니다. Vector2d는 그 자체로 별도의 메시지이기 때문에 우리가 여기에있는 것처럼 가변 함수 호출로부터 먼저 포인터를 가져와야합니다.

    corners.push_back(request.mutable_upperleft());
    corners.push_back(request.mutable_upperright());
    corners.push_back(request.mutable_lowerright());
    corners.push_back(request.mutable_lowerleft());

Vector2d 포인터의 deque와 첫 번째 argv 문자열을 createVectorArray 합니다. 실패 할 경우 입력 형식이 잘못 지정된 것 같습니다. 이 경우 프로그램을 종료하십시오. if (!createVectorArray(argv[1],corners)) { return -1; } 간단한 필드의 경우 set_field 메소드를 호출하여 값을 직접 설정할 수 있습니다.

    request.set_height(atof(argv[2]));
    request.set_resolution(atof(argv[3]));
    request.set_filename(argv[4]);

선택적 임계 값 필드의 경우 명령 인수에 지정된 경우이를 설정합니다. if (argc == 6) { request.set_threshold(atoi(argv[6])); }

이것은 주요 방법의 매우 중요한 부분입니다. 이것은 gazebo 전송 시스템을 초기화합니다. 플러그인을 위해, Gazebo는 이미 이것을 처리하지만, 우리 자신의 실행 파일을 위해 우리는 스스로 해결해야합니다. 또한 우리가 정자 여야 네임 스페이스를 사용하지 않기 때문에 명시해야합니다.

    gazebo::transport::init();
    gazebo::transport::run();
    gazebo::transport::NodePtr node(new gazebo::transport::Node());
    node->Init("default");

~/collision_map/command 항목에서 요청 게시자를 초기화합니다.

    gazebo::transport::PublisherPtr imagePub =
            node->Advertise<collision_map_creator_msgs::msgs::CollisionMapRequest>(
                                                        "~/collision_map/command");

메시지를 게시하려면 먼저 게시자가 마스터에 연결될 때까지 기다려야합니다. 그런 다음 우리는 직접 메시지를 게시 할 수 있습니다.

    imagePub->WaitForConnection();
    imagePub->Publish(request);

종료하기 전에, 프로그램은 transport::fini() 를 호출하여 모든 것을 떼어 내야한다. gazebo::transport::fini();

CMakeLists for Plugin and Executable

아래에서 플러그인과 실행 파일을 컴파일하는 데 필요한 CMakeLists.txt 파일을 찾을 수 있습니다.

2.8.8 required to use PROTOBUF_IMPORT_DIRS

cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR) FIND_PACKAGE( Boost 1.40 COMPONENTS system REQUIRED ) set (CMAKE_CXX_FLAGS "-g -Wall -std=c++11")

include (FindPkgConfig) if (PKG_CONFIG_FOUND) pkg_check_modules(GAZEBO gazebo) pkg_check_modules(SDF sdformat) endif() include_directories( ${GAZEBO_INCLUDE_DIRS} ${SDF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/msgs ) link_directories(${GAZEBO_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/msgs) add_subdirectory(msgs)

add_executable (request_publisher request_publisher.cc) target_link_libraries(request_publisher collision_map_creator_msgs ${GAZEBO_LIBRARIES} ${Boost_LIBRARIES} ${SDF_LIBRARIES}) add_dependencies(request_publisher collision_map_creator_msgs)

add_library(collision_map_creator SHARED collision_map_creator.cc ) target_link_libraries(collision_map_creator collision_map_creator_msgs ${Boost_LIBRARIES} ${GAZEBO_LIBRARIES} ${SDF_LIBRARIES}) add_dependencies(collision_map_creator collision_map_creator_msgs)

Code Explained

Boost는 플러그인의 콜백 함수에서 필요합니다. 이것은 이미지 작성자에게도 사용됩니다.

FIND_PACKAGE( Boost 1.40 COMPONENTS system REQUIRED )

msgs 디렉토리는 실행 파일과 플러그인 모두에서 사용하기 때문에 include 디렉토리에 추가해야합니다.

include_directories( ${GAZEBO_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/msgs )

GAZEBO_LIBRARY_DIRS 표준 외에도 msgs 디렉토리에 링크해야합니다. add_subdirectory 지시어는 CMake에게 CMakeLists.txt 파일을 찾도록 지시합니다. link_directories(${GAZEBO_LIBRARY_DIRS} ${SDF_LIBRARY_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/msgs) add_subdirectory(msgs) 실행 파일 request_publisher 를 makefile에 추가하십시오. collision_map_creator_msgs , GAZEBO_LIBRARIES 및 Boost_LIBRARIES 와 연결해야합니다. add_dependencies 지시어는 CMake에게 먼저 collision_map_creator_msgs 를 빌드 add_dependencies 지시한다.

add_executable (request_publisher request_publisher.cc) target_link_libraries(request_publisher collision_map_creator_msgs ${GAZEBO_LIBRARIES} ${Boost_LIBRARIES} ${SDF_LIBRARIES}) add_dependencies(request_publisher collision_map_creator_msgs)

이 플러그인은 우리 플러그인을 만들고, 표준 WorldPlugin CMakeLists.txt와 매우 비슷합니다. 단, collision_map_creator_msgs 와 연결하고이를 종속성으로 추가해야합니다. add_library(collision_map_creator SHARED collision_map_creator.cc ) target_link_libraries(collision_map_creator collision_map_creator_msgs ${Boost_LIBRARIES} ${GAZEBO_LIBRARIES} ${SDF_LIBRARIES}) add_dependencies(collision_map_creator collision_map_creator_msgs)

Build and Deploy

먼저, protobuf-compiler라는 종속 패키지를 설치해야합니다. sudo apt-get install protobuf-compiler

이 프로젝트를 빌드하려면 빌드 디렉토리를 만들고 CMake를 실행 한 다음 make를 실행하십시오.

cd ~/collision_map_creator_plugin mkdir build cd build cmake ../ make 이 플러그인을 gazebo 플러그인 경로에 추가해야합니다. 환경 변수를 변경하여이 빌드 디렉토리를 참조하거나,

export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:collision_map_creator_plugin/build

또는 플러그인을 플러그인 디렉토리에 복사 할 수 있습니다.

sudo cp libcollision_map_creator.so /usr/lib/gazebo-<YOUR-GAZEBO_VERSION>/plugins/

Running

모든 것이 잘되었다고 가정하면, 아마 대략 거친 가정 일 것입니다. (진지하게는 이것은 길었습니다), 사용자 정의 wold 파일로 Gazebo를 실행해야합니다.

model://ground_plane
   <include>
        <uri>model://sun</uri>
      </include>

   <include>
     <uri>model://willowgarage</uri>
   </include>

   <plugin filename="libcollision_map_creator.so" name="collision_map_creator"/>
 </world>

Run Gazebo with this world:

gazebo ~/collision_map_creator_plugin/map_creator.world

~/collision_map_creator_plugin/build/request_publisher "(-10,10)(10,10)(10,-10)(-10,-10)" 10 0.01 ~/map.png

실행 가능한 터미널이 Gazebo에 연결되어 있는지 확인하고 요청 메시지를 표시해야합니다. 전망대 터미널에 메시지가 표시되고 완료 될 때까지 퍼센트 완료 통계가 표시되어야합니다. map.png는 다음과 같이 표시되어야합니다.

© 2014 오픈 소스 로봇 공학 재단

Gazebo는 Apache 2.0에서 라이센스가 공개 된 오픈 소스입니다. Google+ YouTube YouTube ~/collision_map_creator_plugin/build/request_publisher "(-10,10)(10,10)(10,-10)(-10,-10)" 10 0.01 ~/map.png

실행 가능한 터미널이 Gazebo에 연결되어 있는지 확인하고 요청 메시지를 표시해야합니다. gazebo 터미널에 메시지가 표시되고 완료 될 때까지 퍼센트 완료 통계가 표시되어야합니다.

Table of Contents




Clone this wiki locally