水彩(仮)

NULLPointerExceptionガッ

Gazebo入門4

さて,今回はせっかくなので,ちょっと実戦向きなことをしてみましょう.

今回行うことは

メインはプラグインの作成になります.プラグインの作成については

gazebosim.org

を参考にしています.

さて、まずはプラグインの作成ということで,Cameraのプラグインを作りましょう.

ソースコードは以下となります.

以下に表示されるCameraPlugin.cc, CameraPlugin.hhはApache License, version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) の元で公開されています.

CameraPlugin.cc

/*
 * Copyright (C) 2012-2016 Open Source Robotics Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
#ifdef _WIN32
  // Ensure that Winsock2.h is included before Windows.h, which can get
  // pulled in by anybody (e.g., Boost).
#include <Winsock2.h>
#endif

#include "gazebo/sensors/DepthCameraSensor.hh"
#include "CameraPlugin.hh"

using namespace gazebo;
GZ_REGISTER_SENSOR_PLUGIN(CameraPlugin)

/////////////////////////////////////////////////
CameraPlugin::CameraPlugin()
: SensorPlugin(), width(0), height(0), depth(0)
{
}

/////////////////////////////////////////////////
CameraPlugin::~CameraPlugin()
{
  this->parentSensor.reset();
  this->camera.reset();
}

/////////////////////////////////////////////////
void CameraPlugin::Load(sensors::SensorPtr _sensor, sdf::ElementPtr /*_sdf*/)
{
  if (!_sensor)
    gzerr << "Invalid sensor pointer.\n";

  this->parentSensor =
    std::dynamic_pointer_cast<sensors::CameraSensor>(_sensor);

  if (!this->parentSensor)
  {
    gzerr << "CameraPlugin requires a CameraSensor.\n";
    if (std::dynamic_pointer_cast<sensors::DepthCameraSensor>(_sensor))
      gzmsg << "It is a depth camera sensor\n";
  }

  this->camera = this->parentSensor->Camera();

  if (!this->parentSensor)
  {
    gzerr << "CameraPlugin not attached to a camera sensor\n";
    return;
  }

  this->width = this->camera->ImageWidth();
  this->height = this->camera->ImageHeight();
  this->depth = this->camera->ImageDepth();
  this->format = this->camera->ImageFormat();

  this->newFrameConnection = this->camera->ConnectNewImageFrame(
      std::bind(&CameraPlugin::OnNewFrame, this,
        std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
        std::placeholders::_4, std::placeholders::_5));

  this->parentSensor->SetActive(true);
}

/////////////////////////////////////////////////
void CameraPlugin::OnNewFrame(const unsigned char * _image,
                              unsigned int /*width*/,
                              unsigned int /*_height*/,
                              unsigned int /*_depth*/,
                              const std::string &/*_format*/)
{
  rendering::Camera::SaveFrame(_image, this->width,
    this->height, this->depth, this->format,
    "me.jpg");

}

CameraPlugin.hh

/*
 * Copyright (C) 2012-2016 Open Source Robotics Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
#ifndef _GAZEBO_CAMERA_PLUGIN_HH_
#define _GAZEBO_CAMERA_PLUGIN_HH_

#include <string>

#include "gazebo/common/Plugin.hh"
#include "gazebo/sensors/CameraSensor.hh"
#include "gazebo/rendering/Camera.hh"
#include "gazebo/util/system.hh"

namespace gazebo
{
  class GAZEBO_VISIBLE CameraPlugin : public SensorPlugin
  {
    public: CameraPlugin();

    /// \brief Destructor
    public: virtual ~CameraPlugin();

    public: virtual void Load(sensors::SensorPtr _sensor, sdf::ElementPtr _sdf);

    public: virtual void OnNewFrame(const unsigned char *_image,
                              unsigned int _width, unsigned int _height,
                              unsigned int _depth, const std::string &_format);

    protected: unsigned int width, height, depth;
    protected: std::string format;

    protected: sensors::CameraSensorPtr parentSensor;
    protected: rendering::CameraPtr camera;

    private: event::ConnectionPtr newFrameConnection;
  };
}
#endif

さて,このプログラムはxml(あるいはworld)で定義されたCameraのフレームごとにカメラが見ている画像をカレントディレクトリにme.jpgとして保存します.

ソースコードの解説の前に動かしてみましょう.

コンパイルするために以下のCMakeLists.txtを用意してください.

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(CameraPlugin SHARED CameraPlugin.cc)
target_link_libraries(CameraPlugin ${GAZEBO_LIBRARIES})

そして次に以下のコマンドでコンパイルをします.

mkdir build
cd build
cmake ../
make

コンパイルに成功するとbuildの中にlibCameraPlugin.soファイルが出来上がっていると思います.

そして次のxmlファイルを用意します.名前は何でも良いです.

<sdf version='1.6'>
  <world name='default'>
    <include>
        <uri>model://ground_plane</uri>
    </include>
    <include>
        <uri>model://sun</uri>
    </include>
    <model name="camera">
    <link name="link">
      <gravity>false</gravity>
      <pose>0.05 0.05 0.05 0 0 0</pose>
      <inertial>
        <mass>0.1</mass>
      </inertial>
      <visual name="visual">
        <geometry>
          <box>
            <size>0.1 0.1 0.1</size>
          </box>
        </geometry>
      </visual>
      <sensor name="camera" type="camera">
        <camera>
          <horizontal_fov>1.047</horizontal_fov>
          <image>
            <width>320</width>
            <height>240</height>
          </image>
          <clip>
            <near>0.1</near>
            <far>100</far>
          </clip>
        </camera>
        <always_on>1</always_on>
        <update_rate>30</update_rate>
        <visualize>true</visualize>
        <!-- プラグインの挿入 -->
        <plugin name="CameraPlugin" filename="libCameraPlugin.so"/>
      </sensor>
    </link>
    </model>
  </world>
</sdf>

ここまで用意をして,GAZEBO_PLUGIN_PATHの環境変数をlibCameraPlugin.soがあるディレクトリに設定をして,

gazebo <world file name> --verbose

そうすると

f:id:syoamakase:20160823140019p:plain

こんな感じの画面が起動します.

カレントディレクトリを見てみるとme.jpgというのがあると思います.

カメラの前にモデルを置くと画像も変わるかと思います.

ソースコードばかりでなかなかわかりにくいかと思いますが,以上でカメラのプラグインの作成ができます.