ROS2 visualization_msgs::msg::Marker 使用指南

1. Marker 简介

visualization_msgs::msg::Marker 是 ROS2 中用于在 RViz 可视化各种图形(如点、线、面、模型等)的消息类型,用来表示一个单独的可视化对象(比如一个点、一条线、一个球体等)。通过发布 Marker 消息,可以在 RViz 中动态显示调试信息、地图、轨迹等。

2. 常用 Marker 类型

  • POINTS:显示一组点

  • LINE_STRIP:显示一条折线

  • LINE_LIST:显示多条线段

  • SPHERECUBECYLINDER:显示几何体,分别为3D球体,立方体和圆柱体

  • TRIANGLE_LIST:显示三角面片

  • SPHERE_LIST:显示一组球体

  • CUBE_LIST:显示一组立方体

  • CYLINDER_LIST:显示一组圆柱体

3. 代码示例

以下代码展示了如何在 ROS2 中发布点云(POINTS 类型)的 Marker:

// 1. 包含必要的头文件
#include <rclcpp/rclcpp.hpp>
#include <visualization_msgs/msg/marker.hpp>
#include <visualization_msgs/msg/marker_array.hpp>
#include <geometry_msgs/msg/point.hpp>

// 2. 创建 Marker 消息
visualization_msgs::msg::Marker marker;
marker.header.frame_id = "map"; // 坐标系名称,需与 RViz 保持一致
marker.header.stamp = node->now(); // 时间戳
marker.ns = "example_points";      // 命名空间,可用于分组
marker.id = 0;                     // Marker 的唯一ID,同一ns下不能重复
marker.type = visualization_msgs::msg::Marker::POINTS; // Marker 类型:点云
marker.action = visualization_msgs::msg::Marker::ADD;  // 动作:添加

// 3. 设置点的大小(宽和高,单位:米)
marker.scale.x = 0.2; // 点的宽度
marker.scale.y = 0.2; // 点的高度
marker.scale.z = 0.2; // 点的深度
// 对 POINTS 类型,marker.scale.z 无效

// 4. 设置点的颜色(RGBA,范围0~1)
marker.color.r = 1.0f; // 红色分量
marker.color.g = 0.0f; // 绿色分量
marker.color.b = 0.0f; // 蓝色分量
marker.color.a = 1.0f; // 透明度(1为不透明)

// 5. 添加点数据
geometry_msgs::msg::Point p1, p2;
p1.x = 1.0; p1.y = 2.0; p1.z = 0.0;
p2.x = 2.0; p2.y = 3.0; p2.z = 0.0;
marker.points.push_back(p1);
marker.points.push_back(p2);

// 6. 发布 Marker
visualization_msgs::msg::MarkerArray marker_array;
marker_array.markers.push_back(marker);
marker_pub->publish(marker_array);

详细注释说明

  • header.frame_id:指定 Marker 所在的坐标系,RViz 必须有该坐标系。
  • header.stamp:时间戳,建议用 node->now()
  • nsid:用于唯一标识一个 Marker,更新/删除时需一致。
  • type:Marker 的类型,决定显示方式。
  • scale.x/y:点的宽高,必须都大于 0。
  • color:点的颜色和透明度。
  • points:点的坐标列表。
  • action:常用为 ADD,也可用 DELETE 删除。

4. 面色

有时需要将地图某一部分区域绘制出来,此时可以采用三角形“扇形剖分”的方式填充出来,将Marker类型设置为TRIANGLE_LIST,然后设置颜色进行显示。

**部分代码**
rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr map_area_markers_pub_ = this->create_publisher<visualization_msgs::msg::MarkerArray>("/map/map_area_markers", 10);

visualization_msgs::msg::MarkerArray map_area_marker_array;
if (polygon_points.size() >= 3)
        {
            visualization_msgs::msg::Marker fill_marker;
            fill_marker.header.frame_id = "map";
            fill_marker.header.stamp = this->now();
            fill_marker.ns = "ad_area_fill";
            fill_marker.type = visualization_msgs::msg::Marker::TRIANGLE_LIST;
            fill_marker.action = visualization_msgs::msg::Marker::ADD;
            fill_marker.id = id++;
            fill_marker.scale.x = 1.0;
            fill_marker.scale.y = 1.0;
            fill_marker.scale.z = 1.0;
            fill_marker.color.r = 0.0f;
            fill_marker.color.g = 1.0f;
            fill_marker.color.b = 0.0f;
            fill_marker.color.a = 0.3f;

            // 简单扇形三角剖分(以第一个点为中心)
            const auto &center = polygon_points[0];
            for (size_t i = 1; i + 1 < polygon_points.size(); ++i)
            {
                fill_marker.points.push_back(center);
                fill_marker.points.push_back(polygon_points[i]);
                fill_marker.points.push_back(polygon_points[i + 1]);
            }
            map_area_marker_array.markers.push_back(fill_marker);
        }
map_area_markers_pub_.publish(map_area_marker_array)

5.常见问题

  1. 什么时候使用MarkerArray

    • 当需要一次性发布多个可视化对象(比如一组点、一组线、多个不同的 marker)时,就用 MarkerArray,这样可以减少 topic 的数量和管理的复杂度。
  2. 点不显示?

    • 检查 scale.xscale.y 是否都大于 0。
  • 检查 color.a 是否大于 0。
  • 检查 frame_id 是否与 RViz 坐标系一致。
  • 检查 points 是否有数据。
  1. Marker 不更新?

    • nsid 必须与之前发布的一致,才能被覆盖。
  2. RViz 没有显示?

    • RViz 需添加 MarkerMarkerArray 显示,并订阅正确的 topic。