Skip to content

RViz Marker 点和线

目标: 展示如何用 visualization_msgs/msg/Marker 消息向 RViz 发送点和线。

教程级别: 中级

预计时长: 15 分钟

注意: 本教程假设你已经完成了 Marker:发送基本形状。

在 Marker:发送基本形状 中,你学会了如何用可视化 Marker 向 RViz 发送简单形状。除了基本形状,Marker 还能展示更多内容。本教程将介绍 POINTS、LINE_STRIP 和 LINE_LIST 这三种 Marker 类型。完整的类型列表请参阅 Marker:Display 类型。

使用 Points、Line Strips 和 Line Lists

Section titled “使用 Points、Line Strips 和 Line Lists”

POINTS、LINE_STRIP 和 LINE_LIST Marker 都使用 visualization_msgs/msg/Marker 消息的 points 成员。POINTS 类型会在每个添加的坐标处绘制一个点;LINE_STRIP 类型将各点依次连接成一条连续的线——点 0 连到点 1,点 1 连到点 2,依此类推;LINE_LIST 类型则将点两两配对,生成彼此独立的线段,例如点 0–1、点 2–3 等。

从 visualization_tutorials 仓库 获取本教程对应的包。代码位于 visualization_marker_tutorials 包中,完整源文件可在此查看:points_and_lines.cpp。

下面逐步解析代码,跳过之前教程中已经解释过的部分。程序最终呈现的效果是一条旋转的螺旋线,每个顶点上方还附带一条竖直线段。

先来看节点所需的头文件,包括用于螺旋线计算的 cmath,以及 Marker 和点的消息定义。

#define _USE_MATH_DEFINES
#include <chrono>
#include <cmath>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/point.hpp"
#include "visualization_msgs/msg/marker.hpp"

这些头文件你应该已经很熟悉了。接下来初始化 ROS 2,创建一个节点,在 visualization_marker 话题上创建发布者,并设置循环频率。

rclcpp::init(argc, argv);
auto node = rclcpp::Node::make_shared("points_and_lines");
auto marker_pub = node->create_publisher<visualization_msgs::msg::Marker>(
"visualization_marker", 10);
rclcpp::Rate loop_rate(30);

此外还定义了一个浮点变量,用来随时间驱动螺旋线的旋转动画。

float f = 0.0f;

在主循环内部,创建三条 visualization_msgs/msg/Marker 消息,并初始化它们共有的字段。Marker 消息默认包含一个单位四元数姿态,因此只需设置本教程关心的字段。

visualization_msgs::msg::Marker points, line_strip, line_list;
points.header.frame_id = line_strip.header.frame_id = line_list.header.frame_id = "my_frame";
points.header.stamp = line_strip.header.stamp = line_list.header.stamp = rclcpp::Clock().now();
points.ns = line_strip.ns = line_list.ns = "points_and_lines";
points.action = line_strip.action = line_list.action = visualization_msgs::msg::Marker::ADD;

这里为三个 Marker 分配了不同的 ID。使用 points_and_lines 命名空间可以避免与其他 Marker 发布者冲突。

points.id = 0;
line_strip.id = 1;
line_list.id = 2;

接下来将 Marker 类型设置为 POINTS、LINE_STRIP 和 LINE_LIST。

points.type = visualization_msgs::msg::Marker::POINTS;
line_strip.type = visualization_msgs::msg::Marker::LINE_STRIP;
line_list.type = visualization_msgs::msg::Marker::LINE_LIST;

scale 成员对不同 Marker 类型含义不同。POINTS Marker 用 x 和 y 分别表示点的宽度和高度,而 LINE_STRIP 和 LINE_LIST Marker 只用 x 分量指定线宽。缩放值的单位是米。

points.scale.x = 0.2;
points.scale.y = 0.2;
line_strip.scale.x = 0.1;
line_list.scale.x = 0.1;

这里将点设为绿色,线段(LINE_STRIP)设为蓝色,独立线段(LINE_LIST)设为红色。与其他 Marker 一样,alpha 通道值必须为非零。

points.color.g = 1.0f;
points.color.a = 1.0;
line_strip.color.b = 1.0;
line_strip.color.a = 1.0;
line_list.color.r = 1.0;
line_list.color.a = 1.0;

接下来为点和线创建顶点。我们用正弦和余弦函数生成螺旋线。POINTS 和 LINE_STRIP Marker 每个顶点只需一个点,而 LINE_LIST Marker 每条线段需要两个点。

for (uint32_t i = 0; i < 100; ++i) {
float y = 5 * sin(f + i / 100.0f * 2 * M_PI);
float z = 5 * cos(f + i / 100.0f * 2 * M_PI);
geometry_msgs::msg::Point p;
p.x = static_cast<int32_t>(i) - 50;
p.y = y;
p.z = z;
points.points.push_back(p);
line_strip.points.push_back(p);
// The line list needs two points for each line
line_list.points.push_back(p);
p.z += 1.0;
line_list.points.push_back(p);
}

填写完 Marker 消息后,将三者全部发布。

marker_pub->publish(points);
marker_pub->publish(line_strip);
marker_pub->publish(line_list);

随后休眠等待,推进动画相位,回到循环开头。

loop_rate.sleep();
f += 0.04f;

在工作空间中编译该包:

Terminal window
$ colcon build --packages-select visualization_marker_tutorials

然后 source 工作空间并运行节点:

Terminal window
$ source install/setup.bash
$ ros2 run visualization_marker_tutorials points_and_lines

现在运行 RViz:

Terminal window
$ source install/setup.bash
$ ros2 run rviz2 rviz2

如果你从未使用过 RViz,请先阅读 RViz 用户指南。

按照上一个教程的方式配置 RViz。由于我们没有设置任何坐标变换,请将 Fixed Frame 设为 my_frame。然后添加一个 Marker Display,默认话题 visualization_marker 与节点发布的话题一致。

你应该能看到一条旋转的螺旋线,效果类似于:

{/* 截图:points_and_lines Marker 教程 */}

想了解 RViz 支持的更多 Marker 类型和选项,请继续阅读 Marker:Display 类型。不妨动手试试其他 Marker 类型。