Rviz2的自定义插件开发基础知识

1. 简介

Rviz中有不同类型的插件,每个插件都必须具有相应的基本类型,才能被RViz识别

plugin typebase type
Displayrviz_common::Display
Panelrviz_common::Panel
Toolrviz_common::Tool
Frames transformation libraryrviz_common::transformation::FrameTransformer
View Controllerrviz_common::ViewController

1.1 display plugin (display插件)

为了编写一个display插件,需要从rviz_common::Displayrviz_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

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度探索 Elasticsearch 8.X:function_score 参数解读与实战案例分析

在 Elasticsearch 中&#xff0c;function_score 可以让我们在查询的同时对搜索结果进行自定义评分。 function_score 提供了一系列的参数和函数让我们可以根据需求灵活地进行设置。 近期有同学反馈&#xff0c;function_score 的相关参数不好理解&#xff0c;本文将深入探讨 f…

【数据动态填充到element表格;将带有标签的数据展示为文本格式】

一&#xff1a;数据动态填充到element表格&#xff1b; 二&#xff1a;将带有标签的数据展示为文本格式&#xff1b; 1、 <el-row><el-col :span"24"><el-tabs type"border-card"><el-tab-pane label"返回值"><el-…

基于OpenCV solvePnP函数估计头部姿势

人脸识别 文章目录 人脸识别一、姿势估计概述1、概述2、姿态估计3、在数学上表示相机运动4、姿势估计需要什么5、姿势估计算法6、Levenberg-Marquardt 优化 二、solvePnP函数1、函数原型2、参数详解 三、OpenCV源码1、源码路径 四、效果图像示例参考链接 一、姿势估计概述 1、…

Go语言学习笔记(狂神说)

Go语言学习笔记&#xff08;狂神说&#xff09; 视频地址&#xff1a;https://www.bilibili.com/video/BV1ae41157o9 1、聊聊Go语言的历史 聊聊Go语言的历史-KuangStudy-文章 2、Go语言能做什么 下面列举的是原生使用Go语言进行开发的部分项目。 Docker Docker 是一种操作…

【机器学习】西瓜书学习心得及课后习题参考答案—第4章决策树

这一章学起来较为简单&#xff0c;也比较好理解。 4.1基本流程——介绍了决策树的一个基本的流程。叶结点对应于决策结果&#xff0c;其他每个结点则对应于一个属性测试&#xff1b;每个结点包含的样本集合根据属性测试的结果被划分到子结点中&#xff1b;根结点包含样本全集&a…

Flutter 调试工具篇 | 壹 - 使用 Flutter Inspector 分析界面

theme: cyanosis 1. 前言 很多朋友可能在布局过程中、或者组件使用过程中&#xff0c;会遇到诸如颜色、尺寸、约束、定位等问题&#xff0c;可能会让你抓耳挠腮。俗话说&#xff0c;磨刀不误砍柴工&#xff0c;会使用工具是非常重要的&#xff0c;其实 Flutter 提供了强大的调试…

10分钟实现任务调度平台搭建

日常项目中&#xff0c;会有很多需要定时执行的任务&#xff0c;而这些任务的变化比较多&#xff0c;可能随时都要调整&#xff0c;那么对调度的灵活性要求比较高。我们传统的Spring Task或者Quartz&#xff0c;可以实现定时任务调度&#xff0c;但是内置在代码里&#xff0c;修…

JA64 1+2+3+...n

一、题目 求123...n_牛客题霸_牛客网 二、代码 1.使用静态成员变量构造函数 class SUM {private:static int _i;static int _ret;public:SUM(){_ret _ret _i;_i;}static int GetRet(){return _ret;} }; int SUM::_i1; int SUM::_ret0;class Solution { public:int Sum_So…

【java的类型数据】——八大类型数据

文章目录 前言字面常量字面常量的分类: 数据类型和变量变量的包装类和范围范围整型变量byteintshortlong 浮点型变量双精度浮点型double单精度浮点型float 字符型变量char布尔型变量 boolean 类型转换自动类型转换&#xff08;隐式&#xff09;强制类型转换&#xff08;显式&am…

一个字符驱动示例 -- 微秒级别周期 反转GPIO

仅作为自我记录的一个demo 本次GPIO以微妙级别频率的反转实验有以下几个启示&#xff1a; 一开始在应用层做延时&#xff0c;来实现2微妙周期&#xff0c;占空比50%的GPIO反转&#xff0c;发现波形的频率一直上不去&#xff0c;只能在25hz徘徊&#xff0c;后来索性去掉延时&am…

flink写入到kafka 大坑解析。

1.kafka能不能发送null消息&#xff1f; 能&#xff01; 2 flink能不能发送null消息到kafka&#xff1f; 不能&#xff01; public static void main(String[] args) throws Exception {StreamExecutionEnvironment env StreamExecutionEnvironment.getExecutionEnvironment(…

JavaWeb+jsp+Tomcat的叮当书城项目

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88123111?spm1001.2014.3001.5503 技术&#xff1a;ssm jsp JDK1.8 MySQL5.7 Tomcat8.3 源码数据库课程设计 功能&#xff1a;管理员与普通用户和超级管理员三个角色&#xff0c;管理员可…

浅谈 Spring AOP 思想

Spring AOP AOP 切面编程普通代理类JDK动态代理Cglib动态代理AOPAOP术语AOP切面编程的优势Advice通知类型&#xff08;5种&#xff09;通知的执行顺序 Order切入点表达式表达式execution注解annotation Spring事务管理Transactional 及 Transactional 的两个属性Transactional …

常用直线模组的类型

目前&#xff0c;直线模组的应用非常广泛&#xff0c;而且直线模组的种类也有很多可以满足每个行业的应用要求&#xff0c;那么常见的直线模组类型有哪些&#xff0c;大家知道吗&#xff1f; 1、全封闭滚珠丝杆直线模组&#xff1a; 在半封闭式的基础上增加了不锈钢带防尘结构…

[Angular] Import TranslateModule in Angular 16

1.Background Angular 更新至V16版后&#xff0c;支援 standalone&#xff0c;故移除了 NgModule&#xff0c;而TranslateModule 又要在AppModule中 import&#xff0c;那该如何做呢&#xff1f; 2.NPM packages installation npm install ngx-translate/core npm install n…

BUUCTF——reverse3 适合新手的关于base64加密算法代码的分析

作为一个逆向小白&#xff0c;学了点加密算法就来BUU找点乐子&#xff0c;前7题蛮简单的&#xff0c;然后做到了reverse3&#xff0c;典型的base64加密算法&#xff0c;让我折腾了好久&#xff0c;写篇博客记录一下 顺便说下很多博客并没有对这里的加密算法进行代码上的分析&a…

分享VMware Workstation Pro ESXI7创建虚拟机和配置硬盘空间(分享自己的学习历程意在帮助有需要的小伙伴)

背景&#xff1a;因公司项目需求改用VMware Workstation Pro&#xff0c;已经使用1个月目前除了中途出现过一次问题被解决后一直稳定运行至今&#xff0c; 1:这里贴出拿出现的问题提示及解决方法的链接&#xff1a;解决vmWare ESXI 7.3报错; 2:如果你是第一次接触VMware Work…

Echarts 文字太长用省略号代替

xAxis: [{type: category,data: [materialUserEchartsDate.value[0] ? materialUserEchartsDate.value[0].name : ,materialUserEchartsDate.value[1] ? materialUserEchartsDate.value[1].name : ,materialUserEchartsDate.value[2] ? materialUserEchartsDate.value[2].na…

二、前端高德地图、渲染标记(Marker)引入自定义icon,手动设置zoom

要实现这个效果&#xff0c;我们先看一下目前的页面展示&#xff1a; 左边有一个图例&#xff0c;我们可以方法缩小地图&#xff0c;右边是动态的marker标记&#xff0c;到时候肯定时候是后端将对应的颜色标识、文字展示、坐标点给咱们返回、我们肯定可以拿到一个list&#xf…

【广州华锐互动】无人值守变电站AR虚拟测控平台

无人值守变电站AR虚拟测控平台是一种基于增强现实技术的电力设备巡检系统&#xff0c;它可以利用增强现实技术将虚拟信息叠加在真实场景中&#xff0c;帮助巡检人员更加高效地完成巡检任务。这种系统的出现&#xff0c;不仅提高了巡检效率和准确性&#xff0c;还降低了巡检成本…