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

news2024/9/21 4:32:08

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_DEPENDS
  rclcpp   
  rviz_common 
  pluginlib
  Qt5
)
​
include_directories(
  include
)
​
#动态链接库
add_library( ${PROJECT_NAME} SHARED
  src/rviz_plugin_demo.cpp
  include/rviz_plugin_demo/rviz_plugin_demo.h
  include/rviz_plugin_demo/ui_rviz_plugin_demo.h
  ui/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 lib
  ARCHIVE DESTINATION lib
  RUNTIME 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.coloradmin.cn/o/802533.html

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

相关文章

有哪些虚拟机好用?并且对电脑没有伤害

在当今数字化时代&#xff0c;虚拟化技术越来越受到人们的关注和使用。虚拟机作为一种强大的工具&#xff0c;可以在一台计算机上模拟多个独立的操作系统环境&#xff0c;为用户提供了灵活性和便利性。然而&#xff0c;有人担心使用虚拟机可能会对电脑造成损害&#xff0c;尤其…

多普勒气泡监测与分级方法

Ultrasound detection of vascular decompression bubbles the influence of new technology and considerations on bubble load 多普勒气泡检测方法&#xff1a; 听觉多普勒超声监测法视觉二维超声成像谐波超声成像&#xff08;2的变种&#xff09; 多普勒气泡分级方法&…

objectarx编译Debug版arx遇到的问题

错误一链接错误 1>pietdoginterface_s.lib(Msg.obj) : error LNK2001: 无法解析的外部符号 “class ATL::CTraceCategory ATL::atlTraceException” (?atlTraceExceptionATL3VCTraceCategory1A) 1>pietdoginterface_s.lib(Msg.obj) : error LNK2001: 无法解析的外部符号…

【洁洁送书第二期】Python机器学习:基于PyTorch和Scikit-Learn

前言 近年来&#xff0c;机器学习方法凭借其理解海量数据和自主决策的能力&#xff0c;已在医疗保健、 机器人、生物学、物理学、大众消费和互联网服务等行业得到了广泛的应用。自从AlexNet模型在2012年ImageNet大赛被提出以来&#xff0c;机器学习和深度学习迅猛发展&#xf…

Element-UI 10个技巧

el-scrollbar 滚动条 看到这个组件是不是有点陌生&#xff0c;陌生就对了&#xff0c;因为它从来没有出现在 element 官网上&#xff08;估计是性能问题&#xff09;&#xff0c;但好东西怎么能藏着掖着&#xff0c;来上效果图。 是不是比原生的滚动条美观多了&#xff0c;使用…

【2】-第一个Locust脚本

创建&执行第一个locustfile.py 在ide中创建我们的loucst项目&#xff0c;并创建第一个测试脚本&#xff0c;代码如下 ## /mylocust/locustfiles/first_locustfile.py import os from locust import HttpUser, task# 继承locust的HttpUser类&#xff0c;这样我们就可以使用…

argo workflows archived 日志设置

由于工作需要配置argo workflows archived 归档日志&#xff0c;介绍一下大致步骤: 文章目录 1.没有设置前&#xff0c;归档日志是不能展示的2.编辑configmap3 配置数据库用户名和密码&#xff1a;4.把workflow这个pod删掉&#xff0c;让他重新生成一个解决用户权限问题 1.没有…

[VRTK4.0]将Unity输入系统与VRTKv4结合使用

学习目标&#xff1a; 展示了如何在Unity项目中设置Unity输入系统&#xff0c;以及如何导入输入系统Tilia包以支持VRTKTilia包与新的Unity输入系统操作一起工作。 流程&#xff1a; 步骤一&#xff1a; 首先我们需要再次检查项目设置是否具有新的Unity输入系统。通过Project S…

浅谈现代通信技术

目录 1.传统通信方法 2.传统通信方式的缺点 3.现代通信技术 4.现代通信技术给人类带来的福利 1.传统通信方法 传统通信方法指的是在数字化通信之前使用的传统的通信方式。以下是一些常见的传统通信方法&#xff1a; 1. 书信&#xff1a;通过邮件或快递等方式发送纸质信件。这…

JVM调优详解

SneakyThrowspublic static void main(String[] args) {HashMap hashMap new HashMap();ArrayList arrayList new ArrayList();Byte[] e new Byte[1024];while (true) {Thread.sleep(10);arrayList.add(e);}} java执行代码 C:\WINDOWS\System32>jps -l 26576 org/netbea…

0基础系列C++教程 从0开始 第三课

0基础系列C教程 从0开始 第三课来了&#xff01; 这节课只是课后习题的解答 第四课讲变量 第二课课后习题 代码请自行写注释 写完后发在评论区 我会看的 习题代码&#xff1a; /*课后习题 不做注释 自行查看上节课的内容 题目&#xff1a;输出一下内容 114514 19191919 81…

前后端项目分离开发

问题说明&#xff1a; 开发人员同时负责前端和后端代码开发&#xff0c;分工不明确开发效率低前后端代码混合在一个工程中&#xff0c;不便于管理对开发人员要求高&#xff0c;人员招聘困难 解决方法&#xff1a; 前后端分离开发 介绍 前后端分离开发&#xff0c;就是在项…

【java】【面对对象高级2】继承

目录 1、概念 2、继承的执行原理 3、继承有啥好处 3.1 People父类 3.2 Teacher子类 3.3 主程序 4、继承的相关注意事项 4.1 权限修饰符 4.2 单继承、Object类 4.2.1 单继承 4.2.2 Object类 4.3 方法重写&#xff08;声明不变、重新实现&#xff09; 4.3.1 认识方法重写…

2023JAVA 架构师面试 130 题含答案:JVM+spring+ 分布式 + 并发编程》...

此文包含 Java 面试的各个方面&#xff0c;史上最全&#xff0c;苦心整理最全 Java 面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等&#xff0c;使用层面广&#xff0c;知识量大&#xff0c;涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的…

selenium等待的三种方式(详细)

1.强制等待 time.sleep(3) 这种方式会是操作强行等待3s才会进行下一步操作&#xff0c;但是这种放法&#xff0c;可能会延长测试的时间&#xff0c;如果元素在1s中出现&#xff0c;就会浪费2s的时间&#xff0c;并且这种放法单次有效&#xff0c;每次需要等待元素的操作都需要…

如何打造亚马逊一流新品运营方案?

优化亚马逊新品运营方案需要商家采取一系列策略&#xff0c;以在激烈的市场竞争中脱颖而出。以下是一些针对亚马逊新品运营的优化建议&#xff1a; 1.深入了解产品和市场&#xff1a; 在上线新品之前&#xff0c;商家需要对产品和市场进行深入了解。了解目标客户群体、市场需…

重要通知|关于JumpServer开源堡垒机V2版本产品生命周期的相关说明

JumpServer&#xff08;https://github.com/jumpserver&#xff09;开源项目创立于2014年6月&#xff0c;已经走过了九年的发展历程。经过长期的产品迭代&#xff0c;JumpServer已经成为广受欢迎的开源堡垒机。 JumpServer堡垒机遵循GPL v3开源许可协议&#xff0c;是符合4A&a…

微信小程序radio单选按钮选中与取消

wxml <view bindtapcheckedTap><radio checked"{{checked}}">设为默认</radio> </view> wxss <style lang"less" > radio .wx-radio-input {border-radius: 50%; /* 圆角 */width: 24rpx;border: 2rpx solid #5e5e5f;hei…

网安周报 | 银行业成为开源软件供应链攻击的目标

网安周报是棱镜七彩推出的安全资讯专栏&#xff0c;旨在通过展示一周内发生的与开源安全、软件供应链安全相关攻击事件&#xff0c;让用户了解开源及软件供应链威胁&#xff0c;提高对安全的重视&#xff0c;做好防御措施。 1、银行业成为开源软件供应链攻击的目标 网络安全研…

nn.BCELoss与nn.CrossEntropyLoss

BCELoss与CrossEntropyLoss都是用于分类问题。可以知道&#xff0c;BCELoss是Binary CrossEntropyLoss的缩写&#xff0c;BCELoss是CrossEntropyLoss的一个特例&#xff0c;只用于二分类问题&#xff0c;而CrossEntropyLoss可以用于二分类&#xff0c;也可以用于多分类&#xf…