背景
在 RViz 中有许多类型的数据已经有现有的可视化。然而,如果有一种消息类型尚未有插件来显示它,那么有两种选择可以在 RViz 中查看它。
将消息转换为另一种类型,例如
visualization_msgs/Marker
。编写自定义 RViz 显示。
使用第一个选项,会有更多的网络流量和数据表示的限制。它也快速且灵活。后一种选择在本教程中进行了说明。虽然需要一些工作,但可以带来更丰富的可视化效果。
本教程的所有代码都可以在此存储库 https://github.com/MetroRobots/rviz_plugin_tutorial 中找到。为了查看本教程中编写的插件的增量进展,存储库有不同的分支( step2
, step3
……),每个分支都可以在您进行时编译和运行。
cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select rviz_plugin_tutorial_msgs
Starting >>> rviz_plugin_tutorial_msgs
Finished <<< rviz_plugin_tutorial_msgs [24.6s]
Summary: 1 package finished [24.9s]
cxy@ubuntu2404-cxy:~/ros2_ws$ . install/setup.bash
cxy@ubuntu2404-cxy:~/ros2_ws$ colcon build --packages-select rviz_plugin_tutorial
Starting >>> rviz_plugin_tutorial
Finished <<< rviz_plugin_tutorial [25.8s]
Summary: 1 package finished [26.8s]
cxy@ubuntu2404-cxy:~/ros2_ws$ . install/setup.bash
cxy@ubuntu2404-cxy:~/ros2_ws$ ros2 run rviz2 rviz2
[INFO] [1720966890.438943145] [rviz2]: Stereo is NOT SUPPORTED
[INFO] [1720966890.439067206] [rviz2]: OpenGl version: 4.6 (GLSL 4.6)
[INFO] [1720966890.559429080] [rviz2]: Stereo is NOT SUPPORTED
Step By Step
点 2D 消息
我们将使用 rviz_plugin_tutorial_msgs
包中定义的玩具消息: Point2D.msg
:
std_msgs/Header header
float64 x
float64 y
基本插件的样板代码
系好安全带,这里有很多代码。您可以使用分支名称 step1
查看此代码的完整版本。
头文件
以下是 point_display.hpp
的内容
// 如果没有定义 RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_,则定义它
#ifndef RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_
#define RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_
// 包含 rviz_common 的消息过滤显示库
#include <rviz_common/message_filter_display.hpp>
// 包含 rviz_plugin_tutorial_msgs 的 Point2D 消息库
#include <rviz_plugin_tutorial_msgs/msg/point2_d.hpp>
// 定义 rviz_plugin_tutorial 命名空间
namespace rviz_plugin_tutorial
{
// 定义 PointDisplay 类,它是 rviz_common::MessageFilterDisplay 类的公共派生类
class PointDisplay
: public rviz_common::MessageFilterDisplay<rviz_plugin_tutorial_msgs::msg::Point2D>
{
// 使用 Qt 的元对象系统
Q_OBJECT
protected:
// 重写 processMessage 方法,该方法用于处理 Point2D 消息
void processMessage(const rviz_plugin_tutorial_msgs::msg::Point2D::ConstSharedPtr msg) override;
};
} // 结束 rviz_plugin_tutorial 命名空间的定义
// 结束 RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_ 的定义
#endif // RVIZ_PLUGIN_TUTORIAL__POINT_DISPLAY_HPP_
我们正在实现 MessageFilterDisplay 类,该类可用于任何带有
std_msgs/Header
的消息。该类使用我们的
Point2D
消息类型进行模板化。由于本教程范围之外的原因,您需要在其中使用
Q_OBJECT
宏才能使 GUI 的 QT 部分正常工作。processMessage
是唯一需要实现的方法,我们将在 cpp 文件中实现。
源文件
point_display.cpp
// 包含 rviz_plugin_tutorial 的 PointDisplay 库
#include <rviz_plugin_tutorial/point_display.hpp>
// 包含 rviz_common 的日志库
#include <rviz_common/logging.hpp>
// 定义 rviz_plugin_tutorial 命名空间
namespace rviz_plugin_tutorial
{
// 定义 PointDisplay 类的 processMessage 方法,该方法用于处理 Point2D 消息
void PointDisplay::processMessage(const rviz_plugin_tutorial_msgs::msg::Point2D::ConstSharedPtr msg)
{
// 使用 RVIZ_COMMON_LOG_INFO_STREAM 宏打印接收到的消息的帧ID
RVIZ_COMMON_LOG_INFO_STREAM("We got a message with frame " << msg->header.frame_id);
}
} // 结束 rviz_plugin_tutorial 命名空间的定义
// 包含 pluginlib 的类列表宏库
#include <pluginlib/class_list_macros.hpp>
// 使用 PLUGINLIB_EXPORT_CLASS 宏导出 PointDisplay 类,使其成为 rviz_common::Display 的插件
PLUGINLIB_EXPORT_CLASS(rviz_plugin_tutorial::PointDisplay, rviz_common::Display)
记录不是严格必要的,但有助于调试。
为了让 RViz 找到我们的插件,我们需要在代码中使用这个
PLUGINLIB
调用(以及下面的其他内容)。
package.xml
我们需要在我们的 package.xml 中包含以下三个依赖项: