4、日志与诊断:ROS2日志级别、rqt_console、诊断消息发布与自定义诊断

调试自动驾驶系统,说白了就是跟各种信息打交道。传感器数据、算法输出、节点状态……这些信息就像汽车的仪表盘,你得看得懂,才能知道车跑得稳不稳。

我个人习惯,拿到一个陌生的Autoware系统,第一件事不是看代码,而是打开日志和诊断工具。为什么?因为日志告诉你系统「说了什么」,诊断告诉你系统「感觉怎么样」。两者结合,问题往往一目了然。

4.1 ROS2日志级别:从INFO到FATAL

ROS2的日志系统,其实就五个级别,从低到高:DEBUG、INFO、WARN、ERROR、FATAL。每个级别代表信息的严重程度。

级别 含义 我什么时候用
DEBUG 调试信息,最详细 开发阶段,排查具体变量值
INFO 正常状态信息 节点启动、参数加载成功
WARN 警告,可能有问题 传感器数据偶尔丢失、参数超出推荐范围
ERROR 错误,功能受影响 节点崩溃、重要话题接收不到
FATAL 致命错误,系统无法继续 内存耗尽、硬件故障

在代码里怎么用?很简单。比如你在写一个激光雷达点云处理节点:

RCLCPP_INFO(this->get_logger(), "点云接收成功,共 %d 个点", point_count);
RCLCPP_WARN(this->get_logger(), "点云时间戳异常,差值 %f 秒", time_diff);
RCLCPP_ERROR(this->get_logger(), "无法打开激光雷达设备");

嗯,这里要注意:生产环境别开DEBUG。我曾经在一个项目中,DEBUG日志全开,结果日志文件每小时写几个GB,直接把磁盘撑爆了。自动驾驶系统跑在路上,磁盘满了可不是闹着玩的。

避坑指南: 我曾经在调试时把日志级别设为DEBUG,忘了改回来就部署到测试车上。结果跑了半小时,日志文件把存储占满,导致感知模块异常退出。从那以后,我每次部署前都会检查日志级别配置。

4.2 rqt_console:实时日志查看利器

光有日志输出还不够,你得有个好工具去看。rqt_console就是ROS2自带的日志查看器。启动命令很简单:

rqt_console

打开后,你会看到一个实时滚动的日志列表。每个日志前面有个颜色标记:灰色是DEBUG,白色是INFO,黄色是WARN,红色是ERROR,深红是FATAL。一眼就能看出问题严重性。

我个人最常用的功能是过滤。比如我只想看某个节点的ERROR日志,就在过滤框里输入节点名和ERROR级别。这样就不会被INFO信息刷屏了。

你想想看,如果整个系统几十个节点同时输出日志,没有过滤功能,你根本找不到重点。rqt_console还支持正则表达式过滤,这个我后面会讲到。

小技巧: 在rqt_console里,你可以点击某个日志条目,然后按「Pause」按钮暂停滚动。这样就能仔细看某条日志的详细信息,不会被新日志冲走。

4.3 诊断消息发布:让系统告诉你它好不好

日志是「发生了什么」,诊断是「状态怎么样」。在Autoware里,我们通常用diagnostic_msgs包来发布诊断信息。

诊断消息的核心结构是这样的:

# 诊断状态
string OK=0
string WARN=1
string ERROR=2
string STALE=3

string level      # 状态级别
string name       # 诊断项名称
string message    # 描述信息
string hardware_id # 硬件ID

举个例子,我要发布一个激光雷达的诊断状态:

auto diag_msg = diagnostic_msgs::msg::DiagnosticStatus();
diag_msg.level = diagnostic_msgs::msg::DiagnosticStatus::OK;
diag_msg.name = "LiDAR Front";
diag_msg.message = "正常运行,帧率10Hz";
diag_msg.hardware_id = "lidar_001";

// 还可以添加键值对
diagnostic_msgs::msg::KeyValue kv;
kv.key = "点云数量";
kv.value = "115200";
diag_msg.values.push_back(kv);

发布诊断消息,我建议用diagnostic_updater这个工具。它帮你管理频率、超时检测,比自己手动发布省心多了。

#include <diagnostic_updater/diagnostic_updater.hpp>

diagnostic_updater::Updater updater(this);
updater.setHardwareID("lidar_system");

// 注册一个定期检查的回调
updater.add("LiDAR Status", this, &MyNode::check_lidar);

void MyNode::check_lidar(diagnostic_updater::DiagnosticStatusWrapper &stat) {
  if (lidar_ok) {
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::OK, "正常运行");
    stat.add("帧率", std::to_string(fps));
  } else {
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::ERROR, "连接断开");
  }
}

为什么推荐用updater?因为它会自动检测诊断消息是否超时。如果某个传感器节点挂了,updater会发布一个STALE状态,告诉你「这个诊断项已经过期了」。这在自动驾驶里非常重要——你不仅要检测错误,还要检测「该有消息却没有消息」的情况。

4.4 自定义诊断:按需定制你的监控项

Autoware自带的诊断项可能不够用。比如你想监控「感知模块的推理延迟」,或者「车道线检测的置信度」。这时候就需要自定义诊断。

自定义诊断其实很简单,就是定义你自己的诊断项名称和状态判断逻辑。我一般会这样做:

  1. 确定监控目标(比如:推理延迟 < 50ms)
  2. 编写诊断回调函数
  3. 注册到diagnostic_updater
  4. 设置更新频率(通常1-10Hz)

举个例子,监控感知模块的推理延迟:

void MyNode::check_inference_latency(diagnostic_updater::DiagnosticStatusWrapper &stat) {
  double latency = get_current_latency(); // 获取当前推理延迟
  
  if (latency < 0.05) { // 小于50ms
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::OK, "推理延迟正常");
  } else if (latency < 0.1) { // 50-100ms
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::WARN, "推理延迟偏高");
  } else { // 超过100ms
    stat.summary(diagnostic_msgs::msg::DiagnosticStatus::ERROR, "推理延迟超标");
  }
  
  stat.add("当前延迟(ms)", std::to_string(latency * 1000));
  stat.add("阈值(ms)", "50");
}

然后注册:

updater.add("Perception Inference Latency", this, &MyNode::check_inference_latency);

这样,在rqt_runtime_monitor或者diagnostics_aggregator里,你就能看到这个自定义诊断项了。

核心思路: 诊断的本质是「状态机」。每个诊断项都应该有明确的OK/WARN/ERROR判断标准。不要模棱两可,否则诊断就失去了意义。

4.5 知识体系总览

为了让你更直观地理解本章的知识结构,我画了一张图:

日志与诊断知识体系 日志系统 (Logging) 诊断系统 (Diagnostics) 日志级别 rqt_console 过滤与搜索 日志文件管理 诊断消息结构 diagnostic_updater 自定义诊断项 状态机判断 日志告诉你「发生了什么」 诊断告诉你「系统状态怎么样」

这张图把本章的核心内容串起来了。左边是日志系统,右边是诊断系统。两者相辅相成,缺一不可。

4.6 实战建议

最后,给你几个我在项目中总结的实战建议:

  • 日志别乱打:每个日志都要有明确的目的。不要为了打日志而打日志,否则日志会变成噪音。
  • 诊断项别太多:我见过有人给每个传感器定义了20多个诊断项,结果根本看不过来。建议每个模块3-5个核心诊断项就够了。
  • 善用rqt_console的过滤功能:按节点名、按级别、按关键词过滤,能帮你快速定位问题。
  • 诊断超时检测一定要开:这是诊断系统最强大的功能之一。节点挂了,诊断系统能立刻发现。

嗯,日志和诊断这部分,说白了就是给系统装上一双眼睛和一副听诊器。眼睛看状态,耳朵听日志。两者配合好了,调试效率能翻倍。

我的习惯: 每次启动Autoware,我都会同时打开rqt_console和rqt_runtime_monitor。一个看实时日志,一个看系统诊断。这样系统有任何风吹草动,我都能第一时间发现。

可可精品资料库