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

Create an RViz dockable panel w/ catkin and Qt5

asked 2015-03-11 08:19:25 -0500

anonymous user

Anonymous

updated 2015-03-11 10:46:29 -0500

Hi everyone,

These past days, I'm trying to write an RViz dockable panel following the tutorial here.
My goal is basically to display – for now – an empty panel (the strict minimum, for a beginning).
The problem is that all the tutorial is writing with both rosbuild and Qt4, while I would like to use catkin and Qt5. Each time I'm trying to compile, I keep having this error message :

[ERROR] [1426085794.672184440]: PluginlibFactory: The plugin for class 'plugin_panel/Hi' failed to load.  Error: Failed to load library /home/mdufour/catkin_ws_test/devel/lib/libplugin_panel.so. Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the library code, and that names are consistent between this macro and your XML. Error string: Could not load library (Poco exception = /home/mdufour/catkin_ws_test/devel/lib/libplugin_panel.so: undefined symbol: _ZTVN8my_panel11PluginPanelE)

My package directory looks like this :

plugin_panel/
|__ CMakeLists.txt
|__ package.xml
|__ plugin_description.xml
|__ src/
    |__ plugin_panel.cpp

All the code is in the .cpp file, for simplification.
Here's my CMakeLists.txt :

cmake_minimum_required(VERSION 2.8.11)

project(plugin_panel)

find_package(Qt4 REQUIRED)
find_package(catkin REQUIRED)

include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})

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

target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})

This is my .cpp (very basic!) :

#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>

#include <rviz/panel.h>

namespace my_panel
{
    class PluginPanel: public rviz::Panel
    {
        Q_OBJECT

    public:
        PluginPanel(QWidget* parent = 0):
            rviz::Panel(parent)
            {
                QHBoxLayout* topic_layout = new QHBoxLayout;
                topic_layout->addWidget(new QLabel("Hi!"));
            }
    };
}

#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(my_panel::PluginPanel, rviz::Panel)

The package.xml (overloaded for sure) :

<?xml version="1.0"?>
<package>
    <name>plugin_panel</name>

    <version>0.0.0</version>

    <description>
        An additional (yet empty) panel in RViz.
    </description>

    <maintainer email="none@none.none">Matthieu</maintainer>

    <license>BSD</license>

    <buildtool_depend>catkin</buildtool_depend>

    <build_depend>roscpp</build_depend>
    <build_depend>roslib</build_depend>
    <build_depend>rviz</build_depend>
    <build_depend>pluginlib</build_depend>
    <build_depend>class_loader</build_depend>

    <run_depend>roscpp</run_depend>
    <run_depend>roslib</run_depend>
    <run_depend>rviz</run_depend>
    <run_depend>pluginlib</run_depend>
    <run_depend>class_loader</run_depend>

    <export>
        <rviz plugin="${prefix}/plugin_description.xml"/>
    </export>
<package>

And finally the plugin_description.xml :

<library path="lib/libplugin_panel">
    <class name="plugin_panel/Hi"
           type="my_panel::PluginPanel"
           base_class_type="rviz::Panel">
        <description>
            An empty panel.
        </description>
    </class>
</library>

Phew! Sorry, that was heavy…
I'm certainly missing something in one of those files, but I can't figure out what.

Thanks for your answers.

edit retag flag offensive close merge delete

4 Answers

Sort by » oldest newest most voted
1

answered 2015-03-11 10:26:39 -0500

gvdhoorn gravatar image

updated 2015-03-11 11:01:43 -0500

target_link_libraries(${PROJECT_NAME} Qt5::Widgets ${catkin_LIBRARIES})

I'm not too familiar with Qt5, but I'm not sure whether Qt5::Widgets is an actual library name under Linux.

according to Using CMake with Qt 5 - Building Qt 5 projects with CMake, linking to Qt5 libraries with CMake should be done as follows (for the QtWidgets component):

target_link_libraries(YOUR_TARGET [..] ${Qt5Widgets_LIBRARIES})

That page has a lot of information on using CMake with Qt5 actually.

Also: according to Developing with Qt - The Transition from Qt 4.x to Qt 5, Qt5 could make use of C++11 features. Afaik, ROS (still) doesn't support that, and binary compatibility may not be guaranteed when mixing and matching (non)C++11 compatible object files/libraries.


Edit3:

find_package(catkin REQUIRED)

Shouldn't at least rviz be listed as COMPONENTS here?

Looking at the CMakeLists.txt of the catkinized version of the plugin tutorial package you linked to it would seem that you are missing some important parts:

find_package(catkin REQUIRED COMPONENTS rviz)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
link_directories(${catkin_LIBRARY_DIRS})

## This plugin includes Qt widgets, so we must include Qt like so:
find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED)
include(${QT_USE_FILE})

## I prefer the Qt signals and slots to avoid defining "emit", "slots",
## etc because they can conflict with boost signals, so define QT_NO_KEYWORDS here.
add_definitions(-DQT_NO_KEYWORDS)

## Here we specify which header files need to be run through "moc",
## Qt's meta-object compiler.
qt4_wrap_cpp(MOC_FILES
  src/drive_widget.h
  src/imu_display.h
  src/plant_flag_tool.h
  src/teleop_panel.h
)

## Here we specify the list of source files, including the output of
## the previous command which is stored in ``${MOC_FILES}``.
set(SOURCE_FILES
  src/drive_widget.cpp
  src/imu_display.cpp
  src/imu_visual.cpp
  src/plant_flag_tool.cpp
  src/teleop_panel.cpp 
  ${MOC_FILES}
)

## An rviz plugin is just a shared library, so here we declare the
## library to be called ``${PROJECT_NAME}`` (which is
## "rviz_plugin_tutorials", or whatever your version of this project
## is called) and specify the list of source files we collected above
## in ``${SOURCE_FILES}``.
add_library(${PROJECT_NAME} ${SOURCE_FILES})

target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})
edit flag offensive delete link more

Comments

Thanks for replying!

Unfortunately, I just re-wrote my CMakeLists.txt to follow the standards of Qt4 (using find_package(Qt4 REQUIRED) etc), and I still have the error message :(

anonymous userAnonymous ( 2015-03-11 10:41:30 -0500 )edit

Ok, well, could you update your question then (CMakeLists.txt, etc)? Perhaps there is some other issue going on here.

gvdhoorn gravatar image gvdhoorn  ( 2015-03-11 10:43:17 -0500 )edit

Please don't use answers as comments, use comments for that (this is not a traditional top-down forum).

You say "nothing happened at all": which bits did you copy, and what didn't happen?

gvdhoorn gravatar image gvdhoorn  ( 2015-03-11 11:43:58 -0500 )edit

"I'm not too familiar with Qt5, but I'm not sure whether Qt5::Widgets is an actual library name under Linux." It's called a target generator or something like that and is the recommended way now (since CMake 2.8.11/12), it will add includes, libs, flags, .. http://doc.qt.io/qt-5/cmake-manual.html

Simon Schmeisser gravatar image Simon Schmeisser  ( 2015-08-17 07:59:05 -0500 )edit
3

answered 2015-08-17 10:02:00 -0500

Simon Schmeisser gravatar image

I just stumbled across this error as well (while porting rviz to qt5) and will note the answer here for documentation purposes.

So the error you got from pluginloader tells you that your plugin shared object (.so) is not linked to everything it expects. This is because moc, the Meta Object Compiler is used by Qt to create some meta information about what classes, functions, signals, slots exist. moc reads header files searching for classes with the Q_OBJECT macro (short version ;) ). It then outputs a new cpp code file containing this information. This file has to be compiled and linked into your plugin.

The traditional way is what gvdhoorn wrote, the more modern way would be to add

set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

and you are done (works for qt4 and qt5).

If some errors remain, it might be because automoc is not perfect. It then helps to just add the header file to the sources list

Writing rviz plugins in Qt5 and loading them in a rviz that was compiled with Qt4 does not work. Neither does the other way around. But the code should be almost the same, so you can just recompile once rviz got ported to qt5

edit flag offensive delete link more

Comments

1

Your comment "If some errors remain, it might be because automoc is not perfect. It then helps to just add the header file to the sources list" saved my day. After battling with this error for hours, this finally worked. Cheers!

Huibuh gravatar image Huibuh  ( 2016-07-11 09:10:32 -0500 )edit

That saved my day too... Thank you so much for that comment.

chwimmer gravatar image chwimmer  ( 2017-01-17 08:07:34 -0500 )edit
0

answered 2015-03-13 15:28:52 -0500

anonymous user

Anonymous

@inflo :
Okay, so here's my final package. I organized it this way :

plugin_panel/
|__ CMakeLists.txt
|__ package.xml
|__ plugin_description.xml
|__ include/
    |__ plugin_panel.h
|__ src/
    |__ plugin_panel.cpp

The plugin displays a simple dockable panel with two QPushButton.
- CMakeLists.txt :

cmake_minimum_required(VERSION 2.8.11)

project(plugin_panel)

find_package(catkin REQUIRED)
find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui)

include(${QT_USE_FILE})
include_directories(include/)

qt4_wrap_cpp(QT_MOC include/plugin_panel.h)
set(SOURCES src/plugin_panel.cpp ${QT_MOC})

add_library(${PROJECT_NAME} ${SOURCES})

target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES} ${catkin_LIBRARIES})

- package.xml :

<?xml version="1.0"?>
<package>
    <name>plugin_panel</name>

    <version>1.0.0</version>

    <description>
        An additional panel in RViz.
    </description>

    <maintainer email="none@none.none">Matthieu</maintainer>

    <license>BSD</license>

    <buildtool_depend>catkin</buildtool_depend>

    <build_depend>rviz</build_depend>

    <run_depend>rviz</run_depend>

    <export>
        <rviz plugin="${prefix}/plugin_description.xml"/>
    </export>
</package>

- plugin_description.xml :

<library path="lib/libplugin_panel">
    <class name="plugin_panel/HelloWorld"
           type="PluginPanel"
           base_class_type="rviz::Panel">
        <description>
            An empty panel.
        </description>
    </class>
</library>

- include/plugin_panel.h :

#include <QtGui>

#include <rviz/panel.h>

class PluginPanel: public rviz::Panel
{
    Q_OBJECT

public:
    PluginPanel(QWidget* parent = 0);

protected:
    QVBoxLayout* _vbox;

    QPushButton* _button1;
    QPushButton* _button2;
};

- src/plugin_panel.cpp :

#include <pluginlib/class_list_macros.h>

#include "plugin_panel.h"

PluginPanel::PluginPanel(QWidget* parent):
    rviz::Panel(parent)
{
    _vbox = new QVBoxLayout();

    _button1 = new QPushButton(tr("Button 1"));
    _button2 = new QPushButton(tr("Button 2"));

    _button1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    _button2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    _vbox->addWidget(_button1);
    _vbox->addWidget(_button2);

    setLayout(_vbox);
}

PLUGINLIB_EXPORT_CLASS(PluginPanel, rviz::Panel)

That's it!
That's the minimum code I found after many iterations, each time trying to remove as much thing as possible from any files.

edit flag offensive delete link more

Comments

hi, many thanks for re-posting.

But i got the problem that it seemed nothing to build when i run "catkin_make" in the catkin_ws directory ?

i can also not tab-complete the package after typing "catkin_make plug" tab tab ?

how do you build the package and do you do anything else (copy files,etc ?

inflo gravatar image inflo  ( 2015-03-14 07:28:36 -0500 )edit

hi, it builds the lib and i can find it in /home/ros/catkin_ws/devel/lib/libplugin_panel.so but when i run, rosrun rviz rviz, , its not there?

i sourced devel/setup.bash before, and my ROS_PACKAGE_PATH=/home/ros/catkin_ws/src:/opt/ros/indigo/share:/opt/ros/indigo/stacks

what do i wrong? flo

inflo gravatar image inflo  ( 2015-03-14 08:53:41 -0500 )edit

From my side, once I have run catkin_make in my catkin_ws folder, the only thing I have to do next is to run RViz (rosrun rviz rviz), then Add panel inside RViz.

anonymous userAnonymous ( 2015-03-15 08:52:08 -0500 )edit

hi, i got it, i am an idiot,i was always trying to add a "display" instead of the panel.

thanks alot for your help flo

inflo gravatar image inflo  ( 2015-03-15 09:06:35 -0500 )edit
0

answered 2015-03-13 10:10:27 -0500

inflo gravatar image

updated 2015-03-13 10:31:41 -0500

Hi, when i use your posted code and then do in the workspace a "catkin_make" it returns:

Invalid package manifest "/home/ros/catkin_ws/src/plugin_panel/package.xml": The manifest contains invalid XML: no element found: line 34, column 0

Did you change your package.xml after your posting here ??

could you post the package.xml and the new CMakeLists.txt file again please ?

thanks flo

EDIT: the end tag is </package> with a / infront of package.

But after re-catkin_make and running rosrun rviz rviz it is not there, when i click on the "Add" button in rviz ?

could you please post you CMakeListst.txt and package.xml file again ? would help me much

thanks flo

edit flag offensive delete link more

Comments

Hi flo,
I'm currently updating all my files to make them as light as possible, and running too!
I will post it here as soon as I get something satisfying :)

anonymous userAnonymous ( 2015-03-13 14:19:19 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2015-03-11 08:19:25 -0500

Seen: 2,611 times

Last updated: Aug 17 '15