1. 简介
Rviz中有不同类型的插件,每个插件都必须具有相应的基本类型,才能被RViz识别
plugin type | base type |
---|---|
Display | rviz_common::Display |
Panel | rviz_common::Panel |
Tool | rviz_common::Tool |
Frames transformation library | rviz_common::transformation::FrameTransformer |
View Controller | rviz_common::ViewController |
1.1 display plugin (display插件)
为了编写一个display插件,需要从rviz_common::Display
或rviz_common::RosTopicDisplay
派生。
其中在不订阅ros的情况下编写display时,从rviz_common::display
派生。
当编写一个topic类型的display,从rviz_common::RosTopicDisplay
派生。
1.2 panel plugin (panel插件)
要编写自定义面板,从rviz_common::panel
派生。
1.3 tool plugin (tool插件)
-
编写一个tool插件,从
rviz_common::Tool
派生 -
快捷键可以通过
shortcut_key_
来设置 -
通过将函数
getPropertyContainer()
的返回值作为相关属性的父级传递,可以将属性添加到“工具属性”面板中(有关示例,请参见rviz_default_plugins::tools::MeasureTool
) -
用于插件的自定义光标、图标等可通过
rviz_common/load_resource
获得
1.4 view controller plugin (视图控制器插件)
-
为了编写一个独立于tf帧的自定义视图控制器,请从rviz_common::ViewController派生
-
如果视图控制器应该能够跟踪场景中的tf帧,请从rviz_common::FramePositionTrackingViewController派生,它已经包含了跟踪目标帧的便利功能
-
如果自定义视图控制器环绕焦点运行,那么从rviz_default_plugins:OrbitViewController派生
1.5 transformation library plugin (转换库插件)
-
要编写转换器插件,必须实现
rviz_common::transformation::FrameTransformer
类(请参阅头文件中包含的API文档) -
如果您的插件还需要额外的功能,或者您想提供对库本身某些部分的直接访问,那么您也可以实现
rviz_common::transformation::TransformerLibraryConnector
的子类(例如,请参阅rviz_default_plugins::transformation::TFWrapper
)
2. Rviz的API概述
2.1 rviz_rendering
rviz_rendering包应该包含所有涉及渲染的功能:
-
要添加到场景图中的视觉效果和对象,如子文件夹对象中的箭头、形状或文本对象(其中许多对象是从文件夹ogre_helpers中移植的)
-
渲染窗口,包括一些暴露其内部的函数(RenderWindowOgreAdapter)。如果可能的话,不要使用RenderWindowOgreAdapter,因为它将来可能会被弃用和删除
-
便利功能去工作使用materials(material_manager.hpp)或其他与orge相关的功能(例如viewport_projection_filter.hpp中的光线跟踪)
-
用于测试的便利类,允许设置一个工作的grge环境和场景图内省的助手
2.2 rviz_common
rviz_common包包含大量可用于插件开发的rviz:
-
主应用程序和rendering队列(不暴露)
-
插件开发的主要入口点-panels、view controllers、displays和tools的基类
-
使用位于rviz_common/properties中的各种视图(如display panel)中的属性的便捷类
-
可选类型的主要类SelectionHandlers(位于rviz_common/interaction中)
-
ROS 2的接入点。目前,RViz只使用一个节点,可以通过ros_integration访问。未来,可能需要进一步的改变,以将ROS 2访问完全抽象为ROS_integration
2.3 rviz_default_plugins
rviz_default_plugins包含rviz附带的所有插件(view controllers, tools, displays and in the future, panels) 其中大多数是从rviz的default_plugins文件夹移植的)。
-
当开发简单的插件时,没有必要在这个包中使用任何东西。
-
当开发类似于现有插件的更复杂的插件时,使用甚至从这个包中包含的类派生可能是有益的,以简化您的开发。
2.4 rviz_visual_testing_framework
rviz_visual_testing_framework包含编写插件可视化测试的主干。如果您想编写自动屏幕截图测试,那么只需要将此包用作测试依赖项。有关进一步的帮助,请参阅软件包中的文档。
3. Panel插件开发流程
3.1 创建一个工作空间
ros2 pkg create package_name --build-type ament_cmake --dependencies rclcpp
3.2 QT程序设计
-
新建Qt Widgets Application
-
一直下一步,Base class选择Qwidget
-
QT文件目录结构
双击.ui文件进行可视化界面设计
-
ui设计界面
左侧为常用界面控件,如布局、按钮等;
右侧设置不同控件的属性和值
为了适配不同的屏幕尺寸,在进行设计时需要给画布中的按钮、列表等设置最大或最小值;例如在按钮控件上右键,选择大小限定。
界面布局:通常将各类控件放入布局(Layout)中,可以适应不同屏幕比例变化,全画布的布局可以通过画布右键向选择
-
信号和槽
发送者->做出事件动作->接收者->给出事件回应
private slots:void on_pushButton_clicked();
void Widget::on_pushButton_clicked() {close();delete(this);//彻底关闭插件 }
3.3 ROS环境下的代码
rviz_plugin_demo.h
/** @Author: sunqingshun sunqingshun@foton.com.cn* @Date: 2023-07-20 16:34:47* @LastEditors: sunqingshun sunqingshun@foton.com.cn* @LastEditTime: 2023-07-25 15:11:41* @FilePath: /rviz_plugin_demo/src/rviz_plugin_demo/include/rviz_plugin_demo/rviz_plugin_demo.h* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ #ifndef WIDGET_H #define WIDGET_H #include<rclcpp/rclcpp.hpp> #include<rviz_common/panel.hpp> #include <QWidget> // QT_BEGIN_NAMESPACE namespace Ui { class Widget; } // QT_END_NAMESPACE namespace rviz_plugin_demo { class Widget : public rviz_common::Panel{Q_OBJECT public:Widget(QWidget *parent = nullptr);~Widget(); private slots:void on_pushButton_clicked(); private:Ui::Widget *ui; }; } // namespace rvzi_plugin_demo #endif // WIDGET_H
ui_rviz_plugin_demo.h
通过以下命令可以将QT的ui文件转换成.h代码文件,output.h:要输出的文件,input.ui:输入的ui文件
uic -o output.h input.ui
/******************************************************************************** ** Form generated from reading UI file 'rviz_plugin_demo.ui' ** ** Created by: Qt User Interface Compiler version 5.12.8 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ #ifndef UI_RVIZ_PLUGIN_DEMO_H #define UI_RVIZ_PLUGIN_DEMO_H #include <QtCore/QVariant> #include <QtWidgets/QApplication> #include <QtWidgets/QGridLayout> #include <QtWidgets/QPushButton> #include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE class Ui_Widget { public:QGridLayout *gridLayout;QPushButton *pushButton; void setupUi(QWidget *Widget){if (Widget->objectName().isEmpty())Widget->setObjectName(QString::fromUtf8("Widget"));Widget->resize(161, 99);gridLayout = new QGridLayout(Widget);gridLayout->setObjectName(QString::fromUtf8("gridLayout"));pushButton = new QPushButton(Widget);pushButton->setObjectName(QString::fromUtf8("pushButton"));pushButton->setMinimumSize(QSize(100, 27));pushButton->setMaximumSize(QSize(100, 27)); gridLayout->addWidget(pushButton, 0, 0, 1, 1); retranslateUi(Widget); QMetaObject::connectSlotsByName(Widget);} // setupUi void retranslateUi(QWidget *Widget){Widget->setWindowTitle(QApplication::translate("Widget", "Widget", nullptr));pushButton->setText(QApplication::translate("Widget", "Hello!", nullptr));} // retranslateUi }; namespace Ui {class Widget: public Ui_Widget {}; } // namespace Ui QT_END_NAMESPACE #endif // UI_RVIZ_PLUGIN_DEMO_H
rviz_plugin_demo.cpp
/** @Author: sunqingshun sunqingshun@foton.com.cn* @Date: 2023-07-20 16:34:39* @LastEditors: sunqingshun sunqingshun@foton.com.cn* @LastEditTime: 2023-07-25 15:14:04* @FilePath: /rviz_plugin_demo/src/rviz_plugin_demo/src/rviz_plugin_demo.cpp* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE*/ #include "rviz_plugin_demo/rviz_plugin_demo.h" #include "rviz_plugin_demo/ui_rviz_plugin_demo.h" namespace rviz_plugin_demo { Widget::Widget(QWidget *parent): rviz_common::Panel(parent), ui(new Ui::Widget) {ui->setupUi(this); } Widget::~Widget() {delete ui; } void Widget::on_pushButton_clicked() {close();delete(this); } } // namespace rviz_plugin_demo #include <pluginlib/class_list_macros.hpp> // plugin宏声明 PLUGINLIB_EXPORT_CLASS(rviz_plugin_demo::Widget, rviz_common::Panel)
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(rviz_plugin_demo) # Default to C99 if(NOT CMAKE_C_STANDARD)set(CMAKE_C_STANDARD 99) endif() # 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() set(CMAKE_AUTOMOC ON)#cmake自动处理Moc文件 # find dependencies find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(rviz_common REQUIRED) find_package(pluginlib REQUIRED) find_package(Qt5 COMPONENTS Widgets Core REQUIRED) set (THIS_PACKAGE_INCLUDE_DEPENDSrclcpp rviz_common pluginlibQt5 ) include_directories(include ) #动态链接库 add_library( ${PROJECT_NAME} SHAREDsrc/rviz_plugin_demo.cppinclude/rviz_plugin_demo/rviz_plugin_demo.hinclude/rviz_plugin_demo/ui_rviz_plugin_demo.hui/rviz_plugin_demo.ui ) ament_target_dependencies(${PROJECT_NAME} ${THIS_PACKAGE_INCLUDE_DEPENDS}) target_include_directories(${PROJECT_NAME} PUBLIC${Qt5Widgets_INCLUDE_DIRS} ) target_link_libraries(${PROJECT_NAME} Qt5::Widgets ) #导出插件描述文件 pluginlib_export_plugin_description_file(rviz_common plugin_description.xml) install(TARGETS ${PROJECT_NAME}EXPORT ${PROJECT_NAME}LIBRARY DESTINATION libARCHIVE DESTINATION libRUNTIME DESTINATION bin ) # 在ament中导出项目的头文件、库、目标和依赖项 ament_export_include_directories(include) # 将include目录中的头文件导出 ament_export_libraries(${PROJECT_NAME}) # 将项目名称指定的库导出 ament_export_targets(${PROJECT_NAME} ) # 将项目名称指定的目标导出 ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS}) # 将此包的依赖项导出 if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)# the following line skips the linter which checks for copyrights# uncomment the line when a copyright and license is not present in all source files#set(ament_cmake_copyright_FOUND TRUE)# the following line skips cpplint (only works in a git repo)# uncomment the line when this package is not in a git repo#set(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies() endif() 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>rviz_plugin_demo</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="sunqingshun@foton.com.cn">sun</maintainer><license>TODO: License declaration</license> <buildtool_depend>ament_cmake</buildtool_depend> <depend>rclcpp</depend> <test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><depend>pluginlib</depend><depend>rviz_common</depend> <exec_depend>libqt5-core</exec_depend><exec_depend>libqt5-gui</exec_depend><exec_depend>libqt5-widgets</exec_depend> <export><build_type>ament_cmake</build_type></export> </package>
plugin_description.xml
<!-- path:动态链接库路径 name:插件名称type:插件类base_class_type:基类description:功能描述 --> <library path="rviz_plugin_demo"> <class name="rviz_plugin_demo/Demo"type="rviz_plugin_demo::Widget" base_class_type="rviz_common::Panel"><description>A panel demo.</description></class> </library>
4.附录文件
rviz2的官方源码:https://github.com/ros2/rviz
ros2中cmake的配置说明:https://docs.ros.org/en/foxy/How-To-Guides/Ament-CMake-Documentation.html