ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
2

Compiling a Simple Plugin in ROS2

asked 2021-06-11 18:50:33 -0500

GusBus gravatar image

updated 2021-06-11 20:07:34 -0500

I am trying to work through the simple plugin example (http://wiki.ros.org/pluginlib/Tutoria...) but cannot get it to build for ROS2.

Trying to use https://docs.ros.org/en/foxy/Guides/A... and the details in the tutorial, but I have limited CMake experience and cannot get it to build. Are there available examples that use ROS2?

Any help would be greatly appreciated.

EDIT

Been trying to piece together a few different resources and have got things to build, but now the library can't be found so I must be doing something wrong.

The plugin failed to load for some reason. Error: %sCould not find library corresponding to plugin

I've set up two packages, once containing the base class and one containing the plugins

Folder structure

src
-controller
 -include
  -Controller.h
 -src
  -ControlFramework.cpp
 CMakeLists.txt
 package.xml
-linear_controller
 -include
  -LinearController1.h
  -LinearController2.h
 -src
  -LinearController1.cpp
  -LinearController2.cpp
 CMakeLists.txt
 linear_controller_plugins.xml
 package.xml

Base Class

Controller.h

#pragma once

namespace control_base
{
    class Controller
    {
    public:
        Controller() {};
        virtual ~Controller() {};

        virtual bool initialize(double p, double i, double d) = 0;
        virtual double computeFeedback(double error) = 0;
    };
}

ControlFramework.cpp

#include <iostream>
#include <pluginlib/class_loader.hpp>
#include <controller/Controller.h>


using namespace std;

int main(int argc, char** argv)
{
  pluginlib::ClassLoader<control_base::Controller> poly_loader("linear_controller", "control_base::Controller");

  try
  {
    std::shared_ptr<control_base::Controller> triangle = poly_loader.createSharedInstance("control_plugins::LinearController1");
    triangle->initialize(10.0, 0.0, 0.0);

    std::shared_ptr<control_base::Controller> square = poly_loader.createSharedInstance("control_plugins::LinearController2");
    square->initialize(5.0, 0.0, 0.0);

    cout << "Triangle area: %.2f" << triangle->computeFeedback(2.0);
    cout << "Square area: %.2f" << square->computeFeedback(2.0);
  }
  catch(pluginlib::PluginlibException& ex)
  {
    cout << "The plugin failed to load for some reason. Error: %s" << ex.what();
  }

  return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(controller)

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(pluginlib REQUIRED)

#Include directories
include_directories(
  include
)

set(plugins_dependencies
  pluginlib
)

add_executable(${PROJECT_NAME} 
  src/ControlFramework.cpp
)
ament_target_dependencies(${PROJECT_NAME} ${plugins_dependencies})


install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME}
)

install(DIRECTORY include/
  DESTINATION include/
)

ament_package()

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>controller</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="angus@todo.todo">angus</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>pluginlib</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

Plugin Package

LinearController1.h

#pragma once

#include <pluginlib/class_list_macros.hpp>
#include <controller/Controller.h>                      // Inheriting the base class

namespace control_plugins
{
  class LinearController1 : public control_base::Controller {
  public:
    LinearController1() {};                               // Constructor
                                                          // No destructor!
    bool initialize(double p, double i, double d);         
    double computeFeedback(double error);

  private:
    double _p_gain{0};
    double _i_gain{0};
    double _d_gain{0};
  };
}

LinearController1.cpp

#include <linear_controller/LinearController1.h>

namespace control_plugins 
{
  bool LinearController1::initialize(double p, double i, double d)
  {
    _p_gain = p;
    _i_gain = i;
    _d_gain = d;

    return true;
  }

  double LinearController1::computeFeedback(double ...
(more)
edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
0

answered 2021-06-14 18:51:49 -0500

GusBus gravatar image

So Using the diff_drive_controller I made quite a few changes to get things working:

Created Separate packages for plugins, base and executable: linear_controller (Contains Plugins) controller (Contains Base Class) control_framework (Contains Executable)

I then got the controller CMake to look very similar tot he controller_interface CMake and treated it as an exported library

One error I had in the code that I think was actually a large part of the problem was:

pluginlib::ClassLoader<control_base::Controller> ctrl_loader("linear_controller", "control_base::Controller");

Changed to name the right package containing the base class:

pluginlib::ClassLoader<control_base::Controller> ctrl_loader("controller", "control_base::Controller");

Thanks for the help and pointing me in the right direction!

edit flag offensive delete link more
0

answered 2021-06-11 20:56:13 -0500

404RobotNotFound gravatar image

Using the diff_drive_controller as an example, from what I can see these are potential fixes:

  • You want to specify a SHARED library for your plugins (this is not the default anymore in ROS 2 like it is in ROS 1 when you make a library). You can do this by changing

add_library(${PROJECT_NAME} src/LinearController1.cpp src/LinearController1.cpp )

to

add_library(${PROJECT_NAME} SHARED src/LinearController1.cpp src/LinearController1.cpp )

  • The xml where you specify the plugins, the library path shouldn't be "/liblinear_controller". instead it should probably just be "linear_controller".

  • The pluginlib_export_plugin_description_file(linear_controller linear_controller_plugins.xml) line in the CMakeLists.txt for your plugin package I believe should be pluginlib_export_plugin_description_file(controller linear_controller_plugins.xml)

edit flag offensive delete link more

Comments

Thanks very much for the info and direction. I think your fixes were definitely necessary but still getting the same error.

Interestingly enough I still need to manually include the control/Controller.h file for it to build, so I think I am doing something wrong in the package containing my base class! So working through the controller_interface example as well. Will post when I get things working.

GusBus gravatar image GusBus  ( 2021-06-14 17:11:02 -0500 )edit

Question Tools

4 followers

Stats

Asked: 2021-06-11 18:50:33 -0500

Seen: 863 times

Last updated: Jun 14 '21