Skip to content

Tutorial Creating a Custom Plugin

Olivier Michel edited this page Jun 21, 2021 · 7 revisions

Since webots_ros2 1.1.0 the package includes the webots_ros2_driver. The main objectives of the sub-package are:

  • It automatically creates a ROS 2 interface out of a Webots robot model.
  • It allows users to configure the ROS 2 interface in URDF files.
  • It allows users to extend the interface using the pluginlib plugin mechanism.

In this tutorial, we will explain how to create a custom plugin that utilizes the webots_ros2_driver plugin mechanism.

webots_ros2_driver Architecture

Please take a look at the picture below to get a better idea of the plugin system architecture.

webots_ros2_driver architecture

Plugin File Structure

The tree below depicts the minimal file structure for a custom plugin.

.
├── include
│   └── webots_ros2_plugin_example
│       └── WebotsRos2PluginExample.hpp
├── src
│   └── WebotsRos2PluginExample.cpp
├── webots_ros2_plugin_example.xml
├── CMakeLists.txt
└── package.xml

Plugin Files

This section shows the critical files used for creating a Webots plugin package (and pluginlib packages in general).

Plugin C++ Header File

#ifndef WEBOTS_ROS2_PLUGIN_EXAMPLE_HPP
#define WEBOTS_ROS2_PLUGIN_EXAMPLE_HPP

#include "rclcpp/macros.hpp"
#include "webots_ros2_driver/PluginInterface.hpp"
#include "webots_ros2_driver/WebotsNode.hpp"

namespace webots_ros2_plugin_example
{
  class WebotsRos2PluginExample : public webots_ros2_driver::PluginInterface
  {
  public:
    // Your plugin has to override step() and init() methods
    void step() override;
    void init(webots_ros2_driver::WebotsNode *node, std::unordered_map<std::string, std::string> &parameters) override;
  };
}
#endif

Plugin C++ Implementation File

#include "webots_ros2_plugin_example/WebotsRos2PluginExample.hpp"

namespace webots_ros2_plugin_example
{
  void WebotsRos2PluginExample::init(webots_ros2_driver::WebotsNode *node, std::unordered_map<std::string, std::string> &parameters)
  {
    // This method is executed once the plugin is loaded by the `webots_ros2_driver` package.
    // The `webots_ros2_driver::WebotsNode` inherits the `rclcpp::Node`, so you have all methods available from there.
    // In addition, from the `webots_ros2_driver::WebotsNode` instance you can also get a `webots::Robot` reference (`node.robot()`).
  }
  void WebotsRos2PluginExample::step()
  {
    // This method is executed on each Webots step
  }
}

// The class has to be exported with `PLUGINLIB_EXPORT_CLASS` macro.
// The first argument is the name of your class, while the second is always `webots_ros2_driver::PluginInterface`
#include "pluginlib/class_list_macros.hpp"
PLUGINLIB_EXPORT_CLASS(webots_ros2_plugin_example::WebotsRos2PluginExample, webots_ros2_driver::PluginInterface)

pluginlib Description File

This file is necessary for the pluginlib to be able to find your Webots ROS 2 plugin.

<library path="webots_ros2_plugin_example">
  <!-- The `type` attribute is a reference to the plugin class. -->
  <!-- The `base_class_type` attribute is always `webots_ros2_driver::PluginInterface`. -->
  <class type="webots_ros2_plugin_example::WebotsRos2PluginExample" base_class_type="webots_ros2_driver::PluginInterface">
    <description>
      This is a Webots ROS 2 plugin example
    </description>
  </class>
</library>

Plugin CMake File

The CMake file slightly differs from typical ROS 2 CMake files as it includes Webots header files and pluginlib.

cmake_minimum_required(VERSION 3.5)
project(webots_ros2_plugin_example)

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

# Besides the package specific dependencies we also need the `pluginlib` and `webots_ros2_driver`
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(pluginlib REQUIRED)
find_package(webots_ros2_driver REQUIRED)

# Include the Webots header files
list(GET webots_ros2_driver_INCLUDE_DIRS 0 webots_ros2_driver_INCLUDE)
include_directories(
  ${webots_ros2_driver_INCLUDE}/webots/cpp
)

# Export the plugin configuration file
pluginlib_export_plugin_description_file(webots_ros2_driver webots_ros2_plugin_example.xml)

# The rest is standard ROS 2 packaging description
add_library(
  ${PROJECT_NAME}
  SHARED
  src/WebotsRos2PluginExample.cpp
)
target_include_directories(
  ${PROJECT_NAME}
  PRIVATE
  include
)
ament_target_dependencies(
  ${PROJECT_NAME}
  pluginlib
  rclcpp
  webots_ros2_driver
)
install(TARGETS
  ${PROJECT_NAME}
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)
ament_export_include_directories(
  include
)
ament_export_libraries(
  ${PROJECT_NAME}
)
ament_package()
Clone this wiki locally