首页 > 技术文章 > Rviz 实现 pannel 插件

TIANHUAHUA 2018-01-23 21:32 原文

这个是鉴于另一个Github上的项目学习的

https://github.com/chaoli2/rviz_teleop_commander/tree/master/src

其中代码注释很清楚,大家也可以去看源代码

首先是CmakeList.txt文件

cmake_minimum_required(VERSION 2.8.3)
project(bing_pannel)
find_package(catkin REQUIRED COMPONENTS rviz)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
link_directories(${catkin_LIBRARY_DIRS})

set(CMAKE_AUTOMOC ON)

if(rviz_QT_VERSION VERSION_LESS "5")
  message(STATUS "Using Qt4 based on the rviz_QT_VERSION: ${rviz_QT_VERSION}")
  find_package(Qt4 ${rviz_QT_VERSION} EXACT REQUIRED QtCore QtGui)
  include(${QT_USE_FILE})
else()
  message(STATUS "Using Qt5 based on the rviz_QT_VERSION: ${rviz_QT_VERSION}")
  find_package(Qt5 ${rviz_QT_VERSION} EXACT REQUIRED Core Widgets)
  set(QT_LIBRARIES Qt5::Widgets)
endif()

add_definitions(-DQT_NO_KEYWORDS)
set(SOURCE_FILES
  src/bing_pannel.cpp ##这里是你的主文件
  ${MOC_FILES}
)
add_library(${PROJECT_NAME} ${SOURCE_FILES})

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

install(TARGETS
  ${PROJECT_NAME}
  ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

install(FILES
  plugin_discription.xml ##这里是你的plugin_discription.xml
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})

只要在workspace下catkin_make后,这个包里的插件便直接安装了。package.xml文件应该如下:

<?xml version="1.0"?>
<package format="1">
  <name>bing_pannel</name>
  <version>0.0.0</version>
  <description>The bing_pannel package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
  <maintainer email="bing@todo.todo">bing</maintainer>


  <!-- One license tag required, multiple allowed, one license per tag -->
  <!-- Commonly used license strings: -->
  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
  <license>TODO</license>


  <!-- Url tags are optional, but multiple are allowed, one per tag -->
  <!-- Optional attribute type can be: website, bugtracker, or repository -->
  <!-- Example: -->
  <!-- <url type="website">http://wiki.ros.org/bing_pannel</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->


  <!-- The *depend tags are used to specify dependencies -->
  <!-- Dependencies can be catkin packages or system dependencies -->
  <!-- Examples: -->
  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
  <!--   <depend>roscpp</depend> -->
  <!--   Note that this is equivalent to the following: -->
  <!--   <build_depend>roscpp</build_depend> -->
  <!--   <exec_depend>roscpp</exec_depend> -->
  <!-- Use build_depend for packages you need at compile time: -->
  <!--   <build_depend>message_generation</build_depend> -->
  <!-- Use build_export_depend for packages you need in order to build against this package: -->
  <!--   <build_export_depend>message_generation</build_export_depend> -->
  <!-- Use buildtool_depend for build tool packages: -->
  <!--   <buildtool_depend>catkin</buildtool_depend> -->
  <!-- Use exec_depend for packages you need at runtime: -->
  <!--   <exec_depend>message_runtime</exec_depend> -->
  <!-- Use test_depend for packages you need only for testing: -->
  <!--   <test_depend>gtest</test_depend> -->
  <!-- Use doc_depend for packages you need only for building documentation: -->
  <!--   <doc_depend>doxygen</doc_depend> -->
  <buildtool_depend>catkin</buildtool_depend>

  <build_depend>roscpp</build_depend>
  <build_depend>rviz</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>rviz</run_depend>
  <run_depend>std_msgs</run_depend>

  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->
      <rviz plugin="${prefix}/plugin_discription.xml"/>
    <!-- 这里面可以修改plugin_discription.xml -->
  </export>
</package>    

而真正描述的plugin_discription.xml为如下:

<library path="lib/libbing_pannel">
  <class name="bing_pannel/BingPannel"
         type="bing_rviz_plugin::BingPannel"
         base_class_type="rviz::Panel">
    <description>
      Bing test pannel.
    </description>
  </class>
</library>
<class name="bing_pannel/BingPannel"
         type="bing_rviz_plugin::BingPannel"
         base_class_type="rviz::Panel">
中name中的bing_pannel/BingPannel里,写的是package的名字加class type中是namespace加class名。

 

我们在src文件夹下加入bing_pannel.cpp和bing_pannel.h。这个package的文件夹如下。

我们先看.h文件。

#ifndef BING_PANNEL_H
#define BING_PANNEL_H

#include <ros/ros.h>
#include <ros/console.h>
#include <rviz/panel.h>

class QLineEdit;

namespace bing_rviz_plugin
{
  class  BingPannel: public rviz::Panel
  {
      Q_OBJECT
      public:
        BingPannel( QWidget* parent = 0 );
        virtual void load( const rviz::Config& config );
        virtual void save( rviz::Config config ) const;

      public Q_SLOTS:
        void setTopic( const QString& topic );

      protected Q_SLOTS:
        void sendVel();
        void update_Linear_Velocity();
        void update_Angular_Velocity();
        void updateTopic();

      protected:
        QLineEdit* output_topic_editor_;
        QString output_topic_;
        QLineEdit* output_topic_editor_1;
        QString output_topic_1;

        ros::Publisher velocity_publisher_;
        ros::NodeHandle nh_;
        float linear_velocity_;
  };
}

#endif

 头文件中,rviz/panel.h 就是 pannel头文件。插件显示如下图。在rviz中加入pannel的话,要在标题栏中,找到Panels 〉Add New Panel。选择并加入需要的pannel。

 选择添加的Pannel。

我们这里的插件会通过文本框里的输入发送一个输入的Topic名字的消息。在后面需要填写速度X和速度Y,并且回车就可以发布消息了。 

回车后,rostopic list会显示/test_velocity。我们这里发布的是geometry_msgs::Twist。

下面我们的代码,里面是.h文件。

#ifndef BING_PANNEL_H
#define BING_PANNEL_H

#include <ros/ros.h>
#include <ros/console.h>
#include <rviz/panel.h>

class QLineEdit;

namespace bing_rviz_plugin
{
  class  BingPannel: public rviz::Panel
  {
      Q_OBJECT
      public:
    //用QWigdet的实例来实现GUI界面 BingPannel( QWidget
* parent = 0 ); virtual void load( const rviz::Config& config ); virtual void save( rviz::Config config ) const; public Q_SLOTS:
    //当填写完时候,回车后,执行会调函数
void setTopic( const QString& topic ); protected Q_SLOTS: void sendVel(); void update_Linear_Velocity_X(); void update_Linear_Velocity_Y(); void updateTopic(); protected:
    //这里是三个显示的文字框的定义 QLineEdit
* output_topic_editor_; QString output_topic_; QLineEdit* output_topic_editor_1; QString output_topic_1; QLineEdit* output_topic_editor_2; QString output_topic_2;     //Ros消息发布 ros::Publisher velocity_publisher_; ros::NodeHandle nh_;

    //x速度,y速度
float linear_velocity_X; float linear_velocity_Y; }; } #endif

相应的.cpp文件如下:

#include <stdio.h>

#include <QPainter>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>

#include <geometry_msgs/Twist.h>
#include <QDebug>

#include "bing_pannel.h"

namespace bing_rviz_plugin{
  BingPannel::BingPannel( QWidget* parent ): rviz::Panel( parent ), linear_velocity_X( 0 ),linear_velocity_Y( 0 ){
  //topic窗口
    QVBoxLayout* topic_layout = new QVBoxLayout;
    topic_layout->addWidget( new QLabel( "Teleop Topic:" ));
    output_topic_editor_ = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_ );
  //xvelocity窗口
    topic_layout->addWidget( new QLabel( "Linear Velocity X:" ));
    output_topic_editor_1 = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_1 );
  //yvelocity窗口
    topic_layout->addWidget( new QLabel( "Linear Velocity Y:" ));
    output_topic_editor_2 = new QLineEdit;
    topic_layout->addWidget( output_topic_editor_2 );

    QHBoxLayout* layout = new QHBoxLayout;
    layout->addLayout( topic_layout );
    setLayout( layout );

    QTimer* output_timer = new QTimer( this );
  
  
  //回车回调函数,设置信号连接 connect( output_topic_editor_, SIGNAL( editingFinished() ),
this, SLOT( updateTopic() )); connect( output_topic_editor_1, SIGNAL( editingFinished() ), this, SLOT( update_Linear_Velocity_X() )); connect( output_topic_editor_1, SIGNAL( editingFinished() ), this, SLOT( update_Linear_Velocity_Y() ));
  //定时器回调,定时运行sendVel()
   connect( output_timer, SIGNAL( timeout() ),
this, SLOT( sendVel() )); output_timer->start( 100 ); }   //读取x速度 void BingPannel::update_Linear_Velocity_X() { QString temp_string = output_topic_editor_1->text(); float lin = temp_string.toFloat(); linear_velocity_X = lin; }
  //读取y速度
void BingPannel::update_Linear_Velocity_Y() { QString temp_string = output_topic_editor_2->text(); float lin = temp_string.toFloat(); linear_velocity_Y = lin; }   //更新topic void BingPannel::updateTopic() { setTopic( output_topic_editor_->text() ); }   //topic名字 void BingPannel::setTopic( const QString& new_topic ) { if( new_topic != output_topic_ ) { output_topic_ = new_topic; if( output_topic_ == "" ) { velocity_publisher_.shutdown(); } else { velocity_publisher_ = nh_.advertise<geometry_msgs::Twist>( output_topic_.toStdString(), 1 ); } Q_EMIT configChanged(); } } void BingPannel::sendVel() { if( ros::ok() && velocity_publisher_ ) { geometry_msgs::Twist msg; msg.linear.x = linear_velocity_X; msg.linear.y = linear_velocity_Y ; msg.linear.z = 0; msg.angular.x = 0; msg.angular.y = 0; msg.angular.z = 1; velocity_publisher_.publish( msg ); } } void BingPannel::save( rviz::Config config ) const { rviz::Panel::save( config ); config.mapSetValue( "Topic", output_topic_ ); } void BingPannel::load( const rviz::Config& config ) { rviz::Panel::load( config ); QString topic; if( config.mapGetString( "Topic", &topic )) { output_topic_editor_->setText( topic ); updateTopic(); } } } #include <pluginlib/class_list_macros.h> PLUGINLIB_EXPORT_CLASS(bing_rviz_plugin::BingPannel,rviz::Panel )

保存后,catkin_make 就可以在rviz里找到了。

 

 

参考:

http://www.guyuehome.com/945

推荐阅读