添加rviz自定义插件

一、创建工作空间

选择【New Project】创建项目。

。 选择【其他项目】,选择【ROS Workspace】,点击【Choose...】按钮

 写入【Name:】名称,选择【Workspace Path:】工作空间路径,点击【下一步】按钮。

点击【完成】按钮,完成工作空间的创建。

 

二、添加自定义消息

1.创建消息包以及文件

在工作空间src下创建存放消息的包,右击【src】,选择【添加新文件...】。

 选择【ROS】,选择【Package】,点击【Choose...】按钮。

写入【Name:】名称,写入【Catkin:】依赖,消息依赖于 std_msgs和message_generation。

点击【完成】按钮。

 

 找到创建的消息包【plugin_msg】文件夹,在此新建文件夹,名称为【msg】,目录结构如下:

 

右击【msg】,选择【添加新文件...】。

 

 选择【ROS】,选中【Basic msg file】,点击【Choose...】按钮。

 写入【名称:】,点击【下一步】按钮。

点击【完成】按钮。

 2.修改消息内容

修改ProgressBarMsg.msg内容:

std_msgs/Header header
string context
uint32 value

std_msgs/Header header:

数据类型的标准元数据,通常用于在特定坐标系中传达时间戳数据。 

包含字段

uint32 seq //表示序列 ID

time stamp //表示时间戳

string frame_id //和frame有关,序列id

3.修改package.xml内容

添加编译时的依赖

<build_depend>message_generation</build_depend>

添加执行时的依赖

<exec_depend>message_runtime</exec_depend>

<exec_depend>message_generation</exec_depend>

<?xml version="1.0"?>
<package format="2">
  <name>plugin_msg</name>
  <version>0.1.0</version>
  <description>The plugin_msg package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  <maintainer email="[email protected]">root</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>Apache 2.0</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/plugin_msg</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="[email protected]">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>
  <exec_depend>message_generation</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>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>

4.修改CMakeLists.txt内容

catkin_package中添加依赖

CATKIN_DEPENDS message_runtime

#指定项目所需的最低 CMake 版本。
cmake_minimum_required(VERSION 3.0.2)
#定义项目的名称
project(plugin_msg)

#查找并导入外部依赖库。
find_package(catkin REQUIRED COMPONENTS
  std_msgs
  message_generation #增加message编译时依赖模块到(message_generation)
)

#增加自定义的msg文件
add_message_files(
  FILES
  ProgressBarMsg.msg
)

#生成msg需要依赖的消息以及服务
generate_messages(
  DEPENDENCIES
  std_msgs
)

#这用于指定包的依赖关系,由依赖于这个包的其他软件包使用。
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES custom_msg
  CATKIN_DEPENDS message_runtime #增加message运行时依赖模块message_runtime
#  DEPENDS system_lib
)

 三、添加自定义插件(rviz::Display类型)

1.创建插件包以及文件

右击【src】,选择【添加新文件...】。

 

 选择【ROS】,选择【Package】,点击【Choose..】按钮。

 写入【Name:】包名称,写入【Catkin:】依赖,点击【下一步】按钮。

 

 点击【完成】按钮。

 

右击【progressBar_display】包下的【src】 ,选择【添加新文件...】。

 

选择【C++】,选择【C++ Class】,点击【Choose...】按钮。

 写入【Class name:】类名称,点击【下一步】按钮。

 点击【完成】按钮。

同上述相同步骤添加C++类ProgressBar_Visual。

创建完成之后,手动将progressbar_visual.h和progressbar_display.h两个头文件移动到功能包下的include文件夹下的progressBar_display文件夹下。

此时目录结构如下:

2.添加类代码

progressbar_visual.h

#ifndef PROGRESSBAR_VISUAL_H
#define PROGRESSBAR_VISUAL_H

#include <OGRE/OgreVector3.h>
#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <OGRE/OgreBillboard.h>
#include <OGRE/OgreBillboardSet.h>
#include <rviz/properties/string_property.h>
#include <rviz/ogre_helpers/movable_text.h>
#include <rviz/ogre_helpers/shape.h>
#include <rviz/display_context.h>

#include "plugin_msg/ProgressBarMsg.h"

namespace Ogre
{
    class Vector3;
    class Quaternion;
    class BillboardSet;
    class SceneManager;
    class SceneNode;
    class ColourValue;
}

namespace rviz
{
    class MovableText;
    class Shape;
    class IntProperty;
}

namespace progressBar_plugin {

class ProgressBar_Visual
{
public:
    ProgressBar_Visual(Ogre::SceneManager* SceneManager, Ogre::SceneNode* ParentNode);

    virtual ~ProgressBar_Visual();

    void setMessage(const plugin_msg::ProgressBarMsg::ConstPtr& Msg);
    void createProgressBarShape(double PowerRatio);

    void setFramePosition(const Ogre::Vector3& Position);
    void setFrameOrientation(const Ogre::Quaternion& Orientation);

    void setTextColor(const Ogre::ColourValue& Color);
    void setTextColor(float Red, float Green, float Blue, float Alpha);
    void setBackgroundColor(float Red, float Green, float Blue, float Alpha);
    void setProgressBarColor(float Red, float Green, float Blue, float Alpha);
    void setHeaderColor(float Red, float Green, float Blue, float Alpha);

    void setTextSize(float Size);
    void setGraphSize(float Size);

    void setOffsets(const Ogre::Vector3& Offsets);
    void setOrientation(const Ogre::Vector3& Orientation);

private:
    float size_{ 1.0 };
    std::shared_ptr<Ogre::Vector3> base_pose_{ nullptr };
    std::shared_ptr<Ogre::Vector3> offsets_{ nullptr };
    std::shared_ptr<Ogre::Vector3> orientation_{ nullptr };
    // the object implementing the actual text
    std::shared_ptr<rviz::MovableText> progressBar_info_{ nullptr };
    // the object of ProgressBar shape
    std::vector<std::shared_ptr<rviz::Shape>> ProgressBar_shape_;

    // a SceneNode whose pose is set to match the coordinate frame of the plugin_msg::ProgressBarMsg message header
    Ogre::SceneNode* frame_node_{ nullptr };

    // the SceneManager, kept here only so the destructor can ask it to destroy the `frame_node_`
    Ogre::SceneManager* scene_manager_{ nullptr };

    Ogre::ColourValue background_color;
    Ogre::ColourValue ProgressBar_color;
    Ogre::ColourValue header_color;
};

}


#endif // PROGRESSBAR_VISUAL_H

progressbar_visual.cpp

#include "progressBar_display/progressbar_visual.h"

namespace progressBar_plugin
{

ProgressBar_Visual::ProgressBar_Visual(Ogre::SceneManager *SceneManager, Ogre::SceneNode *ParentNode)
{
    scene_manager_ = SceneManager;

    frame_node_ = ParentNode->createChildSceneNode();

    progressBar_info_.reset(new rviz::MovableText("?\%"));
    progressBar_info_->setCharacterHeight(0.5);
    frame_node_->attachObject(progressBar_info_.get());

    //create shape of ProgressBar
    base_pose_ = std::make_shared<Ogre::Vector3>(Ogre::Vector3::ZERO);
    offsets_ = std::make_shared<Ogre::Vector3>(Ogre::Vector3::ZERO);
    orientation_ = std::make_shared<Ogre::Vector3>(Ogre::Vector3(float(0.0), float(90.0), float(0.0)));

    background_color = Ogre::ColourValue(1, 0.5, 0.5, 0.5);
    ProgressBar_color = Ogre::ColourValue(1, 1, 0.5, 1);
    header_color = Ogre::ColourValue(0.5, 1, 1, 1);
    createProgressBarShape(1.0);
}

ProgressBar_Visual::~ProgressBar_Visual()
{
    scene_manager_->destroySceneNode(frame_node_);
}

void ProgressBar_Visual::setMessage(const plugin_msg::ProgressBarMsg::ConstPtr &Msg)
{
    int h = 0;
    int v = 0;
    progressBar_info_->setTextAlignment((rviz::MovableText::HorizontalAlignment)h, (rviz::MovableText::VerticalAlignment)v);
    rviz::StringProperty text("text", (std::to_string(Msg->value) + "\%").c_str());
    progressBar_info_->setCaption(text.getStdString());
    progressBar_info_->setLineSpacing(0.5);
}

void ProgressBar_Visual::createProgressBarShape(double PowerRatio)
{
    for (auto& it : ProgressBar_shape_)
    {
        it.reset();
    }
    ProgressBar_shape_.clear();
    ProgressBar_shape_.resize(3);

    Ogre::Matrix3 mat;
    mat.FromEulerAnglesXYZ(Ogre::Degree(orientation_->x), Ogre::Degree(orientation_->y), Ogre::Degree(orientation_->z));
    Ogre::Quaternion orientation;
    orientation.FromRotationMatrix(mat);

    //background
    ProgressBar_shape_[0].reset(new rviz::Shape(rviz::Shape::Cylinder,scene_manager_));
    ProgressBar_shape_[0]->setScale(Ogre::Vector3(float(0.5 * size_),float(3 * size_),float(0.5 * size_)));
    ProgressBar_shape_[0]->setPosition(Ogre::Vector3(base_pose_->x + offsets_->x,
                                                base_pose_->y + offsets_->y,
                                                base_pose_->z + offsets_->z));
    ProgressBar_shape_[0]->setOrientation(orientation);
    ProgressBar_shape_[0]->setColor(background_color);

    //ProgressBar
    float length = 2.8 * size_;
    //ProgressBar center pos
    Ogre::Vector3 ProgressBar_vec3(0.0,- float(0.5 * length *(1 - PowerRatio)),0.0);
    Ogre::Vector3 ProgressBar_pos = orientation * ProgressBar_vec3;
    ProgressBar_shape_[1].reset(new rviz::Shape(rviz::Shape::Cylinder,scene_manager_));
    ProgressBar_shape_[1]->setScale(Ogre::Vector3(float(0.3 * size_),length * PowerRatio,float(0.3 * size_)));
    ProgressBar_shape_[1]->setPosition(Ogre::Vector3(base_pose_->x + ProgressBar_pos.x + offsets_->x,
                                                base_pose_->y + ProgressBar_pos.y + offsets_->y,
                                                base_pose_->z + ProgressBar_pos.z + offsets_->z));
    ProgressBar_shape_[1]->setOrientation(orientation);
    ProgressBar_shape_[1]->setColor(ProgressBar_color);

    //header
    float head_length = 0.1 * size_ * 0.5;
    //header center pos
    Ogre::Vector3 head_vec3(0.0,- float(0.5 * length *(1 - 2 * PowerRatio)) + head_length * 0.5,0.0);
    Ogre::Vector3 head_pos = orientation * head_vec3;
    ProgressBar_shape_[2].reset(new rviz::Shape(rviz::Shape::Cube,scene_manager_));
    ProgressBar_shape_[2]->setScale(Ogre::Vector3(float(0.3 * size_),head_length,float(0.3 * size_)));
    ProgressBar_shape_[2]->setPosition(Ogre::Vector3(base_pose_->x + head_pos.x + offsets_->x,
                                                base_pose_->y + head_pos.y + offsets_->y,
                                                base_pose_->z + head_pos.z + offsets_->z));
    ProgressBar_shape_[2]->setOrientation(orientation);
    ProgressBar_shape_[2]->setColor(header_color);
}

void ProgressBar_Visual::setFramePosition(const Ogre::Vector3 &Position)
{
    *base_pose_ = Position;
    frame_node_->setPosition(Position);
}

void ProgressBar_Visual::setFrameOrientation(const Ogre::Quaternion &Orientation)
{
    frame_node_->setOrientation(Orientation);
}

void ProgressBar_Visual::setTextColor(const Ogre::ColourValue &Color)
{
    progressBar_info_->setColor(Color);
}

void ProgressBar_Visual::setTextColor(float Red, float Green, float Blue, float Alpha)
{
    setTextColor(Ogre::ColourValue(Red, Green, Blue, Alpha));
}

void ProgressBar_Visual::setBackgroundColor(float Red, float Green, float Blue, float Alpha)
{
    background_color = Ogre::ColourValue(Red, Green, Blue, Alpha);
}

void ProgressBar_Visual::setProgressBarColor(float Red, float Green, float Blue, float Alpha)
{
    ProgressBar_color = Ogre::ColourValue(Red, Green, Blue, Alpha);
}

void ProgressBar_Visual::setHeaderColor(float Red, float Green, float Blue, float Alpha)
{
    header_color = Ogre::ColourValue(Red, Green, Blue, Alpha);
}

void ProgressBar_Visual::setTextSize(float Size)
{
    progressBar_info_->setCharacterHeight(Size);
}

void ProgressBar_Visual::setGraphSize(float Size)
{
    size_ = Size;
}

void ProgressBar_Visual::setOffsets(const Ogre::Vector3 &Offsets)
{
    *offsets_ = Offsets;

    progressBar_info_->setLocalTranslation(Ogre::Vector3(-offsets_->y, offsets_->z, -offsets_->x));
}

void ProgressBar_Visual::setOrientation(const Ogre::Vector3 &Orientation)
{
    *orientation_ = Orientation;
}

}

progressbar_display.h

#ifndef PROGRESSBAR_DISPLAY_H
#define PROGRESSBAR_DISPLAY_H

#ifndef Q_MOC_RUN
#include <boost/circular_buffer.hpp>

#include <rviz/message_filter_display.h>
#include <rviz/panel_dock_widget.h>

#include "plugin_msg/ProgressBarMsg.h"
#endif

namespace Ogre
{
    class SceneNode;
    class ColourValue;
}

namespace rviz
{
    class ColorProperty;
    class FloatProperty;
    class IntProperty;
    class VectorProperty;
    class BoolProperty;
    class StringProperty;
}

namespace progressBar_plugin {

class ProgressBar_Visual;

class ProgressBar_Display: public rviz::MessageFilterDisplay<plugin_msg::ProgressBarMsg>
{
    Q_OBJECT
public:
    ProgressBar_Display();
    virtual ~ProgressBar_Display();

protected:
    virtual void onInitialize();
    // a helper function to clear this display back to the initial state
    virtual void reset();

private Q_SLOTS:
    // these Qt slots get connected to signals indicating changes in the user-editable properties
    void updateTextColorAndAlpha();
    void updateBackgroundrColor();
    void updateProgressBarColor();
    void updateHeaderColor();
    void updateHistoryLength();
    void updateTextSize();
    void updateGraphSize();
    void updateOffsets();
    void updateOrientation();

private:
    // function to handle an incoming ROS message
    void processMessage(const plugin_msg::ProgressBarMsg::ConstPtr& Msg);

private:
    // storage for the list of visuals. It is a circular buffer,
    // where data gets popped from the front (oldest) and pushed to the back (newest)
    boost::circular_buffer<std::shared_ptr<ProgressBar_Visual>> visuals_;

    // user-editable property variables
    rviz::ColorProperty* text_color_property_;
    rviz::FloatProperty* text_alpha_property_;
    rviz::ColorProperty* background_color_property_;
    rviz::ColorProperty* progressBar_color_property_;
    rviz::ColorProperty* header_color_property_;
    rviz::IntProperty* history_length_property_;
    rviz::FloatProperty* text_size_property_;
    rviz::FloatProperty* graph_size_property_;
    rviz::VectorProperty* offsets_property_;
    rviz::VectorProperty* orientation_property_;

};

}


#endif // PROGRESSBAR_DISPLAY_H

progressbar_display.cpp

#include "progressBar_display/progressbar_display.h"
#include "progressBar_display/progressbar_visual.h"

#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>

#include <rviz/window_manager_interface.h>
#include <rviz/visualization_manager.h>
#include <rviz/properties/color_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/int_property.h>
#include <rviz/properties/vector_property.h>
#include <rviz/properties/bool_property.h>
#include <rviz/properties/string_property.h>
#include <pluginlib/class_list_macros.h>

namespace progressBar_plugin
{
ProgressBar_Display::ProgressBar_Display()
{
    text_color_property_ = new rviz::ColorProperty("Text Color", QColor(138, 226, 52),
                                                   "Color of progressBar info text.",
                                                   this, SLOT(updateTextColorAndAlpha()));

    text_alpha_property_ = new rviz::FloatProperty("Text Alpha", 1.0,
                                                    "0 is fully transparent, 1.0 is fully opaque.",
                                                   this, SLOT(updateTextColorAndAlpha()));

    text_size_property_ = new rviz::FloatProperty("Text Size", 0.5,
                                                  "Character size of progressBar info text.",
                                                  this, SLOT(updateTextSize()));

    background_color_property_ = new rviz::ColorProperty("Background Color", QColor(255,128,128),
                                                         "Color of progressBar background.",
                                                         this, SLOT(updateBackgroundrColor()));

    progressBar_color_property_ = new rviz::ColorProperty("ProgressBar Color", QColor(255,255,128),
                                                     "Color of progressBar.",
                                                     this, SLOT(updateProgressBarColor()));

    header_color_property_ = new rviz::ColorProperty("Header Color", QColor(128,255,255),
                                                     "Color of progressBar header.",
                                                     this, SLOT(updateHeaderColor()));

    graph_size_property_ = new rviz::FloatProperty("Graph Size", 1.0,
                                                   "Character size of progressBar graph.",
                                                   this, SLOT(updateGraphSize()));


    history_length_property_ = new rviz::IntProperty("History Length", 1,
                                                     "Number of prior measurements to display.",
                                                     this, SLOT(updateHistoryLength()));
    history_length_property_->setMin(1);
    history_length_property_->setMax(100000);

    offsets_property_ = new rviz::VectorProperty("Offsets", Ogre::Vector3::ZERO,
                                                 "Offsets to frame",
                                                 this, SLOT(updateOffsets()));

    orientation_property_ = new rviz::VectorProperty("Orientation", Ogre::Vector3(float(0.0), float(90.0), float(0.0)),
                                                     "Orientation of progressBar symbol",
                                                     this, SLOT(updateOrientation()));
}

ProgressBar_Display::~ProgressBar_Display()
{

}

// after the top-level rviz::Display::initialize() does its own setup,
// it calls the subclass's onInitialize() function
// this is where all the workings of the class is instantiated
// make sure to also call the immediate super-class's onInitialize() function,
// since it does important stuff setting up the message filter
//
// note that "MFDClass" is a typedef of `MessageFilterDisplay<message type>`,
// to save typing that long templated class name every time the superclass needs to be refered
void ProgressBar_Display::onInitialize()
{
    MFDClass::onInitialize();
    updateTextColorAndAlpha();
    updateHistoryLength();
    updateTextSize();
    updateGraphSize();
    updateOffsets();
    updateOrientation();
}

// clear the visuals by deleting their objects
void ProgressBar_Display::reset()
{
    MFDClass::reset();
    visuals_.clear();
}

// set the current color and alpha values for each visual
void ProgressBar_Display::updateTextColorAndAlpha()
{
    float alpha = text_alpha_property_->getFloat();
    Ogre::ColourValue color = text_color_property_->getOgreColor();

    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setTextColor(color.r, color.g, color.b, alpha);
    }
}

void ProgressBar_Display::updateBackgroundrColor()
{
    Ogre::ColourValue color = background_color_property_->getOgreColor();

    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setBackgroundColor(color.r, color.g, color.b, 0.5);
    }
}

void ProgressBar_Display::updateProgressBarColor()
{
    Ogre::ColourValue color = progressBar_color_property_->getOgreColor();

    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setProgressBarColor(color.r, color.g, color.b, 1);
    }
}

void ProgressBar_Display::updateHeaderColor()
{
    Ogre::ColourValue color = header_color_property_->getOgreColor();

    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setHeaderColor(color.r, color.g, color.b, 1);
    }
}

// set the number of past visuals to show
void ProgressBar_Display::updateHistoryLength()
{
    visuals_.rset_capacity(history_length_property_->getInt());
}

void ProgressBar_Display::updateTextSize()
{
    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setTextSize(text_size_property_->getFloat());
    }
}

void ProgressBar_Display::updateGraphSize()
{
    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setGraphSize(graph_size_property_->getFloat());
    }
}

void ProgressBar_Display::updateOffsets()
{
    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setOffsets(offsets_property_->getVector());
    }
}

void ProgressBar_Display::updateOrientation()
{
    for (size_t i = 0; i < visuals_.size(); ++i)
    {
        visuals_[i]->setOrientation(orientation_property_->getVector());
    }
}

void ProgressBar_Display::processMessage(const plugin_msg::ProgressBarMsg::ConstPtr& Msg)
{
    // call the rviz::FrameManager to get the transform from the fixed frame to the frame in the header of this progressBar message
    // if it fails, do nothing and return
    Ogre::Quaternion orientation;
    Ogre::Vector3 position;
    if (!context_->getFrameManager()->getTransform(Msg->header.frame_id,Msg->header.stamp, position, orientation))
    {
        ROS_DEBUG("error transforming from frame '%s' to frame '%s'",
                  Msg->header.frame_id.c_str(), qPrintable(fixed_frame_));
        return;
    }

    // keeping a circular buffer of visual pointers
    // this gets the next one, or creates and stores it if the buffer is not full
    std::shared_ptr<ProgressBar_Visual> visual;
    if (visuals_.full())
    {
        visual = visuals_.front();
    }
    else
    {
        visual.reset(new ProgressBar_Visual(context_->getSceneManager(), scene_node_));
    }

    // set or update the contents of the chosen visual
    float alpha = text_alpha_property_->getFloat();
    Ogre::ColourValue color = text_color_property_->getOgreColor();
    visual->setTextColor(color.r, color.g, color.b, alpha);

    color = background_color_property_->getOgreColor();
    visual->setBackgroundColor(color.r, color.g, color.b, 0.5);

    color = progressBar_color_property_->getOgreColor();
    visual->setProgressBarColor(color.r, color.g, color.b, 1);

    color = header_color_property_->getOgreColor();
    visual->setHeaderColor(color.r, color.g, color.b, 1);

    visual->createProgressBarShape(Msg->value / 100.0);
    visual->setMessage(Msg);
    visual->setFramePosition(position);
    visual->setFrameOrientation(orientation);

    // send it to the end of the circular buffer
    visuals_.push_back(visual);
}
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(progressBar_plugin::ProgressBar_Display, rviz::Display)

}
注册插件

#include <pluginlib/class_list_macros.h>

PLUGINLIB_EXPORT_CLASS(progressBar_plugin::ProgressBar_Display, rviz::Display)

3.添加plugin_description.xml文件

内容如下:

<library path="lib/libprogressBar_display">
  <class name="progressBar_plugin/ProgressBar"
         type="progressBar_plugin::ProgressBar_Display"
         base_class_type="rviz::Display">
    <description>
      display progressBar information
    </description>
  </class>
</library>

plugin_description.xml文件各字段含义 :

path:动态链接库路径
name:插件名称
type:插件的完整类型
base_class_type:插件完整类型父类
description:功能描述

4.修改package.xml文件

修改内容如下:

<?xml version="1.0"?>
<package format="2">
  <name>progressBar_display</name>
  <version>0.1.0</version>
  <description>The progressBar_display package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  <maintainer email="[email protected]">root</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>Apache 2.0</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/progressBar_display</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="[email protected]">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>qtbase5-dev</build_depend>
  <build_depend>rviz</build_depend>

  <exec_depend>libqt5-core</exec_depend>
  <exec_depend>libqt5-gui</exec_depend>
  <exec_depend>libqt5-widgets</exec_depend>
  <exec_depend>rviz</exec_depend>

  <build_depend>plugin_msg</build_depend>
  <build_export_depend>plugin_msg</build_export_depend>
  <exec_depend>plugin_msg</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->
    <rviz plugin="${prefix}/plugin_description.xml"/>
  </export>
</package>

5.修改CMakeLists.txt文件

修改内容如下:

#指定项目所需的最低 CMake 版本。
cmake_minimum_required(VERSION 3.0.2)
#定义项目的名称
project(progressBar_display)

#查找并导入外部依赖库
find_package(catkin REQUIRED COMPONENTS
  rviz
  plugin_msg
)

## This plugin includes Qt widgets, so we must include Qt like so:
find_package(Qt5 REQUIRED Core Widgets)
set(QT_LIBRARIES Qt5::Widgets)

#添加头文件搜索路径,编译器使用这些目录来查找头文件,第一个参数“include”表示包中的include/目录也是路径的一部分。
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

## 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)

# 设置相关变量
# 自动添加当前目录至路径中
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 自动生成moc文件,自动运行moc
set(CMAKE_AUTOMOC ON)
# 自动运行uic
#set(CMAKE_AUTOUIC ON)
# 自动运行rcc
set(CMAKE_AUTORCC ON)


#用来匹配指定路径下所有符合通配符条件的文件的命令。具体来说,GLOB_RECURSE 是递归查找目录下的所有文件,file() 命令则可以用来获取文件列表。
file(GLOB_RECURSE SOURCE_CPP
 "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
file(GLOB_RECURSE SOURCE_H
  "${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/*.h"
)

#生成库
add_library(${PROJECT_NAME}
  ${SOURCE_H}
  ${SOURCE_CPP}
)

#在定义消息类型时,编译的库依赖这些动态生成的代码
add_dependencies(${PROJECT_NAME} plugin_msg_generate_messages_cpp)

#设置链接库,需要用到系统或者第三方库函数时候进行配置,第一个参数是可执行文件名,后面依次写入需要链接的库
#设置生成库依赖的库
target_link_libraries(${PROJECT_NAME}
  ${catkin_LIBRARIES}
  ${QT_LIBRARIES}
)

四、添加自定义插件(rviz::Panel类型)

1.创建插件包以及文件

创建名为progressBar_panel的插件包,以及名为ProgressBar_Panel的c++类,步骤同上。

创建带有UI界面的类步骤如下:

选择【Qt】,选择【Qt设计师界面类】,点击【Choose...】按钮。

 选择【Widget】,点击【下一步】按钮

 输入【类名:】,点击【下一步】按钮。

 点击【完成】按钮。

 同上将.h文件移到include下的progressBar_panel文件夹下。在src和include的同级目录下创建ui文件夹,将.ui文件移到ui文件夹下。

此时目录结构如下:

 2.添加类代码

ui界面

界面如下:

 panel_widget.h

#ifndef PANEL_WIDGET_H
#define PANEL_WIDGET_H

#include <QWidget>

namespace Ui {
class Panel_Widget;
}

namespace progressBar_panel {

class Panel_Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Panel_Widget(QWidget *parent = 0);
    ~Panel_Widget();

Q_SIGNALS:
    void sigToUpdateTopicAndProgressBarValue(QString topic,float value);

private:
    Ui::Panel_Widget *ui;
};

}

#endif // PANEL_WIDGET_H

panel_widget.cpp

#include "progressBar_panel/panel_widget.h"
#include "ui_panel_widget.h"

namespace progressBar_panel {

Panel_Widget::Panel_Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Panel_Widget)
{
    ui->setupUi(this);

    connect(ui->topic_name,&QLineEdit::editingFinished,this,[=](){
        Q_EMIT sigToUpdateTopicAndProgressBarValue(ui->topic_name->text(),ui->progressBar_value->text().toFloat());
    });
    connect(ui->progressBar_value,&QLineEdit::editingFinished,this,[=](){
        Q_EMIT sigToUpdateTopicAndProgressBarValue(ui->topic_name->text(),ui->progressBar_value->text().toFloat());
    });
    connect(ui->pushButton_add,&QPushButton::clicked,this,[=](){
        ui->progressBar_value->setText(QString::number(ui->progressBar_value->text().toFloat() + 5));
        Q_EMIT sigToUpdateTopicAndProgressBarValue(ui->topic_name->text(),ui->progressBar_value->text().toFloat());
        if(ui->progressBar_value->text().toFloat() == 100)
            ui->progressBar_value->setText("0");
    });
}

Panel_Widget::~Panel_Widget()
{
    delete ui;
}

}

progressbar_panel.h

#ifndef PROGRESSBAR_PANEL_H
#define PROGRESSBAR_PANEL_H

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

#include "panel_widget.h"
#include "plugin_msg/ProgressBarMsg.h"

namespace progressBar_panel {

class ProgressBar_Panel: public rviz::Panel
{
public:
    ProgressBar_Panel(QWidget* parent = 0 );

    virtual void load( const rviz::Config& config );
    virtual void save( rviz::Config config ) const;

public Q_SLOTS:
    void updateTopicAndProgressBarValue(QString topic,float value);

private:
    Panel_Widget *panel_widget;

    // The current name of the output topic.
    QString output_topic_;

    // The ROS publisher for the command velocity.
    ros::Publisher progressBar_publisher_;

    // The ROS node handle.
    ros::NodeHandle nh_;
};

}

#endif // PROGRESSBAR_PANEL_H

progressbar_panel.cpp

#include "progressBar_panel/progressbar_panel.h"

#include <rviz/properties/bool_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/string_property.h>
#include <rviz/window_manager_interface.h>
#include <rviz/display_context.h>
#include <QVBoxLayout>
#include <QDebug>
#include <QDateTime>

namespace progressBar_panel
{

ProgressBar_Panel::ProgressBar_Panel(QWidget* parent): rviz::Panel( parent )
{
    panel_widget = new Panel_Widget;
    connect(panel_widget,&Panel_Widget::sigToUpdateTopicAndProgressBarValue,this,&ProgressBar_Panel::updateTopicAndProgressBarValue);
    QVBoxLayout* layout = new QVBoxLayout;
    layout->addWidget(panel_widget);
    setLayout(layout);
}

void ProgressBar_Panel::load(const rviz::Config &config)
{
    rviz::Panel::load( config );
}

void ProgressBar_Panel::save(rviz::Config config) const
{
    rviz::Panel::save( config );
}

void ProgressBar_Panel::updateTopicAndProgressBarValue(QString topic, float value)
{
    if( topic != output_topic_ )
    {
        output_topic_ = topic;
        // If the topic is the empty string, don't publish anything.
        if( output_topic_ == "" )
        {
            progressBar_publisher_.shutdown();
        }
        else
        {
            // The old ``velocity_publisher_`` is destroyed by this assignment,
            // and thus the old topic advertisement is removed.  The call to
            // nh_advertise() says we want to publish data on the new topic
            // name.
            progressBar_publisher_ = nh_.advertise<plugin_msg::ProgressBarMsg>( output_topic_.toStdString(), 1 );
        }
        // rviz::Panel defines the configChanged() signal.  Emitting it
        // tells RViz that something in this panel has changed that will
        // affect a saved config file.  Ultimately this signal can cause
        // QWidget::setWindowModified(true) to be called on the top-level
        // rviz::VisualizationFrame, which causes a little asterisk ("*")
        // to show in the window's title bar indicating unsaved changes.
        Q_EMIT configChanged();
    }


    if( ros::ok() && progressBar_publisher_ )
    {
        plugin_msg::ProgressBarMsg msg;
        msg.header.frame_id = "map";//output_topic_.toStdString();
        msg.header.stamp = ros::Time(QDateTime::currentSecsSinceEpoch());
        msg.value = value;
        progressBar_publisher_.publish( msg );
        //qDebug()<<"publisher msg";
    }

}

}

// 声明此类是一个rviz的插件
#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(progressBar_panel::ProgressBar_Panel,rviz::Panel )

 3.添加plugin_description.xml文件

内容如下:

<library path="lib/libprogressBar_panel">
  <class name="progressBar_panel/ProgressBarPanel"
         type="progressBar_panel::ProgressBar_Panel"
         base_class_type="rviz::Panel">
    <description>
      panel progressBar information
    </description>
  </class>
</library>

4.修改package.xml文件

修改内容如下:

<?xml version="1.0"?>
<package format="2">
  <name>progressBar_panel</name>
  <version>0.1.0</version>
  <description>The progressBar_panel package</description>

  <!-- One maintainer tag required, multiple allowed, one person per tag -->
  <!-- Example:  -->
  <!-- <maintainer email="[email protected]">Jane Doe</maintainer> -->
  <maintainer email="[email protected]">root</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>Apache 2.0</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/progressBar_panel</url> -->


  <!-- Author tags are optional, multiple are allowed, one per tag -->
  <!-- Authors do not have to be maintainers, but could be -->
  <!-- Example: -->
  <!-- <author email="[email protected]">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>qtbase5-dev</build_depend>
  <build_depend>rviz</build_depend>

  <exec_depend>libqt5-core</exec_depend>
  <exec_depend>libqt5-gui</exec_depend>
  <exec_depend>libqt5-widgets</exec_depend>
  <exec_depend>rviz</exec_depend>

  <build_depend>custom_msg</build_depend>
  <build_export_depend>custom_msg</build_export_depend>
  <exec_depend>custom_msg</exec_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->
    <rviz plugin="${prefix}/plugin_description.xml"/>
  </export>
</package>

5.修改CMakeLists.txt文件

修改内容如下:

#指定项目所需的最低 CMake 版本。
cmake_minimum_required(VERSION 3.0.2)
#定义项目的名称
project(progressBar_panel)

#查找并导入外部依赖库
find_package(catkin REQUIRED COMPONENTS
  rviz
  plugin_msg
)

## This plugin includes Qt widgets, so we must include Qt.
## We'll use the version that rviz used so they are compatible.
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)
  ## pull in all required include dirs, define QT_LIBRARIES, etc.
  include(${QT_USE_FILE})
  macro(qt_wrap_ui)
    qt4_wrap_ui(${ARGN})
  endmacro()
else()
  message(STATUS "Using Qt5 based on the rviz_QT_VERSION: ${rviz_QT_VERSION}")
  find_package(Qt5 ${rviz_QT_VERSION} EXACT REQUIRED Core Widgets)
  ## make target_link_libraries(${QT_LIBRARIES}) pull in all required dependencies
  set(QT_LIBRARIES Qt5::Widgets)
  macro(qt_wrap_ui)
    qt5_wrap_ui(${ARGN})
  endmacro()
endif()

#添加头文件搜索路径,编译器使用这些目录来查找头文件,第一个参数“include”表示包中的include/目录也是路径的一部分。
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

## 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)

## 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)

# 设置相关变量
# 自动添加当前目录至路径中
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 自动生成moc文件,自动运行moc
set(CMAKE_AUTOMOC ON)
# 自动运行uic
#set(CMAKE_AUTOUIC ON)
# 自动运行rcc
set(CMAKE_AUTORCC ON)

qt_wrap_ui(UIC_FILES
  ui/panel_widget.ui
)

#用来匹配指定路径下所有符合通配符条件的文件的命令。具体来说,GLOB_RECURSE 是递归查找目录下的所有文件,file() 命令则可以用来获取文件列表。
file(GLOB_RECURSE SOURCE_CPP
 "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
file(GLOB_RECURSE SOURCE_H
  "${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}/*.h"
)

#生成库
add_library(${PROJECT_NAME}
  ${SOURCE_H}
  ${SOURCE_CPP}
  ${UIC_FILES}
)

#在定义消息类型时,编译的库依赖这些动态生成的代码
add_dependencies(${PROJECT_NAME} plugin_msg_generate_messages_cpp)

#设置链接库,需要用到系统或者第三方库函数时候进行配置,第一个参数是可执行文件名,后面依次写入需要链接的库
#设置生成库依赖的库
target_link_libraries(${PROJECT_NAME}
  ${catkin_LIBRARIES}
  ${QT_LIBRARIES}
)

五、编译

在工作空间下打开终端,输入命令

catkin_make

六 、运行

在终端输入命令,设置环境

source devel/setup.bash

在打开rviz之前需另开一个终端打开ros环境

roscore

 输入命令打开rviz可视化工具

rviz

七 、rviz的使用

1.打开Panel类型插件

点击菜单栏的【Panel】选项,点击【Add New Panel】按钮。

 选择【progressBar_panel】下的【ProgressBarPanel】插件,点击【OK】按钮。

此时在rviz中显示出该插件。

 

 2.添加Display类型插件

点击【Displays】视口的【Add】按钮。

选择【progressBar_display】下的【ProgressBar】插件,点击【OK】按钮。

 此时在rviz的Displays视口显示该插件。

 

3.插件的使用

 首先在Panel插件中输入一个topic name(推送的话题名称)。

 在Display插件中选择订阅的话题,如下图:

 

 此时修改slider value的值即可看到并修改中间部分的进度条。

需要注意的是:

推送的消息中会设置frame id,本次设置的为map,所以不需修改此值,如果推送的消息中不为map,需要一致。

 

资源链接

https://download.csdn.net/download/m0_67254672/88225745?spm=1001.2014.3001.5501

猜你喜欢

转载自blog.csdn.net/m0_67254672/article/details/132293004