您正在阅读的是开发版本的文档。有关最新发布的版本,请访问 Jazzy.

定制 RViz 显示屏

背景介绍

RViz 中已有许多可视化数据类型。但是,如果有一种信息类型还没有插件来显示它,那么有两种选择可以在 RViz 中看到它。

  1. 将信息转换为另一种类型,例如 可视化_msgs/标记.

  2. 编写自定义 RViz 显示。

第一种方案的网络流量更大,数据表示方式也受到限制。但它同样快速灵活。本教程将解释后一种方案。它需要一些工作,但能带来更丰富的可视化效果。

本教程的所有代码都可以在 此存储库.为了查看本教程中编写的插件的增量进度,版本库中有不同的分支 (步骤2, 步骤3......),每个都可以编译并运行。

Point2D 信息

我们将使用在 rviz_plugin_tutorial_msgs 包装 Point2D.msg:

std_msgs/页眉 页眉
浮点64 x
浮点64 y

基本插件的模板

请注意,这里有很多代码。您可以通过分支名称查看完整版代码 步骤1.

文件头

以下是 point_display.hpp

#ifndef RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_
#define RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_

#include <rviz_common/message_filter_display.hpp>;
#include <rviz_plugin_tutorial_msgs/msg/point2_d.hpp>;

命名空间 rviz_plugin_tutorial
{
 点显示
  :  rviz_common::信息过滤显示<;rviz_plugin_tutorial_msgs::信息::Point2D>;
{
  Q_OBJECT

受保护的:
  空白 处理信息( rviz_plugin_tutorial_msgs::信息::Point2D::ConstSharedPtr 信息) 否决;
};
}  // 名称空间 rviz_plugin_tutorial

#endif  // rviz_plugin_tutorial__point_display_hpp_
  • 我们正在实施 信息过滤显示 类,该类可用于任何带有 std_msgs/Header.

  • 该类使用我们的 Point2D 信息类型。

  • 由于本教程范围之外的原因您需要 Q_OBJECT 宏,以使图形用户界面的 QT 部分正常工作。

  • 处理信息 是唯一需要实现的方法,我们将在 cpp 文件中实现该方法。

源文件

point_display.cpp

#include <rviz_plugin_tutorial/point_display.hpp>;
#include <rviz_common/logging.hpp>;

命名空间 rviz_plugin_tutorial
{
空白 PointDisplay::processMessage( rviz_plugin_tutorial_msgs::信息::Point2D::ConstSharedPtr 信息)
{
  rviz_common_log_info_stream("我们收到一条带框架的信息"; <<; 信息->;页眉.frame_id);
}
}  // 名称空间 rviz_plugin_tutorial

#include <pluginlib/class_list_macros.hpp>;
pluginlib_export_class(rviz_plugin_tutorial::点显示, rviz_common::显示屏)
  • 记录日志并非绝对必要,但有助于调试。

  • 为了让 RViz 找到我们的插件,我们需要这样做 PLUGINLIB 调用(以及下面的其他内容)。

package.xml

我们需要在 package.xml 中加入以下三个依赖项:

<依赖>;插件库依赖</depend>;
<依赖>;rviz_common依赖</depend>;
<依赖>;rviz_plugin_tutorial_msgs依赖</depend>;

rviz_common_plugins.xml

图书馆 path="point_display";>;
  类别 type="rviz_plugin_tutorial::PointDisplay"; base_class_type="rviz_common::Display";>;
    <description></description>;
  </class>;
</library>;
  • 这是标准 插件库 代码

    • 图书馆 是我们将在 CMake 中指定的库名。

    • 该类应与 PLUGINLIB 从上面调用。

  • 我保证,我们稍后会再来描述的。

CMakeLists.txt

在标准模板顶部添加以下几行。

查找软件包(ament_cmake_ros 要求)
查找软件包(插件库 要求)
查找软件包(rviz_common 要求)
查找软件包(rviz_plugin_tutorial_msgs 要求)

设置(CMAKE_AUTOMOC 关于)
qt5_wrap_cpp(MOC_FILES
  include/rviz_plugin_tutorial/point_display.hpp
)

add_library(点显示 src/point_display.cpp ${MOC_FILES})
目标包含目录(点显示 公众
  $<;BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>;
  $<;INSTALL_INTERFACE:include>;
)
ament_target_dependencies(点显示
  插件库
  rviz_common
  rviz_plugin_tutorial_msgs
)
安装(目标 点显示
        出口 export_rviz_plugin_tutorial
        存档 目的地 lib
        图书馆 目的地 lib
        运行时间 目的地 箱柜
)
安装(目录 包括
        目的地 包括
)
安装(文件 rviz_common_plugins.xml
        目的地 分享/${项目名称}
)
ament_export_include_directories(包括)
输出目标(export_rviz_plugin_tutorial)
pluginlib_export_plugin_description_file(rviz_common rviz_common_plugins.xml)
  • 要生成合适的 Qt 文件,我们需要

    • 转弯 CMAKE_AUTOMOC 上。

    • 通过调用 qt5_wrap_cpp 的每个标头 Q_OBJECT 中。

    • 包括 MOC_FILES 和其他 cpp 文件一起放在库中。

  • 请注意,如果不封装头文件,在运行时尝试加载插件时可能会收到错误信息,大致如下

    [rviz2]:PluginlibFactory:类 'rviz_plugin_tutorial::PointDisplay' 的插件加载失败。Error:Failed to load library /home/ros/ros2_ws/install/rviz_plugin_tutorial/lib/libpoint_display.so.请确保在库代码中调用了 PLUGINLIB_EXPORT_CLASS 宏,并确保该宏和 XML 名称一致。错误字符串:无法加载库 LoadLibrary error:/home/ros/ros2_ws/install/rviz_plugin_tutorial/lib/libpoint_display.so: undefined symbol:_ZTVN20rviz_plugin_tutorial12PointDisplayE, at /tmp/binarydeb/ros-foxy-rcutils-1.1.4/src/shared_library.c:84
    
  • 许多其他代码确保插件部分正常工作。也就是说,调用 pluginlib_export_plugin_description_file 是让 RViz 找到新插件的关键。

测试

编译代码并运行 rviz2.通过点击 添加 左下角,然后选择软件包/插件。

添加显示屏的截图

起初,显示屏将处于错误状态,因为您尚未分配主题。

错误状态截图

如果我们把主题 /点 在这种情况下,加载应该正常,但不会显示任何内容。

空显示屏功能截图

您可以使用以下命令发布消息:

玫瑰2 主题 酒吧 /点 rviz_plugin_tutorial_msgs/msg/Point2D "{header:{frame_id: map}, x: 1, y: 2}"; -r 0.5

这样,"我们收到一条信息 "日志就会出现在 数据输出 的 RViz。

实际可视化

您可以查看此步骤的完整版本,分支名称为 步骤2.

首先,您需要在 CMakeLists.txtpackage.xml 包装上 rviz_rendering.

我们需要在头文件中添加三行:

  • #include <rviz_rendering/objects/shape.hpp>; - 有 rviz_rendering 软件包中有很多选项 对象来构建可视化。这里我们使用的是一个简单的形状。

  • 类中,我们将添加一个新的 受保护的 虚拟方法: 空白 onInitialize() 覆盖;

  • 我们还为形状对象添加了一个指针: std::unique_ptr<rviz_rendering::Shape>; 点形状;

然后在 cpp 文件中定义 初始化时 方法:

空白 PointDisplay::onInitialize()
{
  中频分类::初始化时();
  点形状 =
    标准::make_unique<;rviz_rendering::形状>;(rviz_rendering::形状::类型::立方体, 场景管理器,
      场景节点);
}
  • 中频分类别名 到模板化的父类,以方便使用。

  • 形状对象必须在此处的 初始化时 方法,而不是构造函数,因为否则 场景管理器场景节点 还没有准备好。

我们还更新了 处理信息 方法:

空白 PointDisplay::processMessage( rviz_plugin_tutorial_msgs::信息::Point2D::ConstSharedPtr 信息)
{
  rviz_common_log_info_stream("我们收到一条带框架的信息"; <<; 信息->;页眉.frame_id);

  食人魔::向量3 位置;
  食人魔::四元数 方向;
  如果 (!上下文_->;getFrameManager()->;获取变换(信息->;页眉, 位置, 方向)) {
    rviz_common_log_debug_stream("Error transforming from frame '"; <<; 信息->;页眉.frame_id <<;
        "'to frame '"; <<; qPrintable(固定框架) <<; "'";);
  }

  场景节点->;设置位置(位置);
  场景节点->;设置方向(方向);

  食人魔::向量3 point_pos;
  point_pos.x = 信息->;x;
  point_pos.y = 信息->;y;
  点形状->;设置位置(point_pos);
}
  • 我们需要为我们的信息获取适当的框架,并将其转换为 场景节点 因此。这样可以确保可视化效果不会总是相对于固定框架显示。

  • 最后四行才是真正的可视化:我们设置了可视化的位置,使其与信息的位置相匹配。

结果应该是这样的

功能显示屏截图

如果方框没有出现在该位置,可能是因为:

  • 您目前没有发布该主题

  • 该信息在过去 2 秒内未被发布。

  • 您没有在 RViz 中正确设置主题。

有选择真好

如果要允许用户自定义可视化的不同属性,则需要添加 rviz_common::Property 对象.

您可以查看此步骤的完整版本,分支名称为 步骤3.

标题更新

包含颜色属性的头文件: #include <rviz_common/properties/color_property.hpp>;.颜色只是您可以设置的众多属性之一。

添加 更新样式,每当通过 Qt 的 SIGNAL/SLOT 框架更改图形用户界面时都会调用它:

私人 Q_SLOTS:
  空白 更新样式();

添加一个新属性来存储属性本身: std::unique_ptr<rviz_common::properties::ColorProperty>; color_property_;

Cpp 更新

  • #include <rviz_common/properties/parse_color.hpp>; - 包含将属性转换为 OGRE 颜色的辅助函数。

  • 致我们的 初始化时 我们加上

颜色属性 = 标准::make_unique<;rviz_common::属性::颜色属性>;(
    "点颜色";, QColor(36, 64, 142), 绘制点的颜色;, , 位子(更新样式()));
更新样式();
  • 这将构建包含名称、默认值、描述和回调的对象。

  • 我们称之为 更新样式 这样,即使在属性更改之前,颜色也会在开始时设置。

  • 然后我们定义回调。

空白 PointDisplay::updateStyle()
{
  食人魔::颜色值 颜色 = rviz_common::属性::qtToOgre(颜色属性->;获取颜色());
  点形状->;设置颜色(颜色);
}

结果应该是这样的

带有颜色属性的截图

哦,粉红色

颜色改变后的截图

现状报告

您可以查看此步骤的完整版本,分支名称为 步骤4.

您还可以设置显示屏的状态。举个简单的例子,当 x 坐标为负数时,显示屏会显示警告,为什么不呢?在 处理信息:

如果 (信息->;x <; 0) {
  设置状态(状态属性::警告, "信息";,
      "我会抱怨 x 值为负的点;);
} 不然 {
  设置状态(状态属性::好的, "信息";, "确定";);
}
  • 我们假设以前 使用 rviz_common::properties::StatusProperty; 申报。

  • 将状态视为键/值对,键是某个字符串(这里我们使用 "信息";),值是状态级别(错误/警告/正常)和描述(其他字符串)。

确定状态的截图 警告状态截图

清理

现在是时候清理一下了。这可以让东西看起来更漂亮,使用起来更方便,但并非严格要求。您可以查看此步骤的完整版本,分支名称为 步骤5.

首先,我们更新插件声明。

图书馆 path="point_display";>;
  类别 名称"Point2D"; type="rviz_plugin_tutorial::PointDisplay"; base_class_type="rviz_common::Display";>;
    <描述>;教程  展示 a </description>;
    <消息类型>;rviz_plugin_tutorial_msgs/msg/Point2D</message_type>;
  </class>;
</library>;
  • 我们添加了 名字 字段到 标签。这会更改 RViz 中显示的名称。在代码中,将其称为 点显示 但在 RViz 中,我们希望简化。

  • 我们在描述中加入了实际文字。别偷懒

  • 在此声明特定的信息类型后,当您尝试添加 "按主题显示 "时,它将为该类型的主题推荐此插件。

我们还在以下位置为插件添加了一个图标 icons/classes/Point2D.png.文件夹是硬编码,文件名应与插件声明中的名称一致(如未指定,则与类名一致)。 [图标来源]

我们需要在 CMake 中安装映像文件。

安装(文件 icons/classes/Point2D.png
        目的地 分享/${项目名称}/图标/类别
)

现在,当您添加显示屏时,它应该会显示一个图标和说明。

添加了图标和说明的截图

以下是尝试按主题添加时的显示:

按主题添加对话框截图

最后,这是标准界面中的图标:

标准界面图标截图

注意,如果更改插件名称,以前的 RViz 配置将不再有效。