livox_ros_driver2 日志系统工作原理解析:DRIVER_INFO/DRIVER_ERROR 宏设计的完整指南
【免费下载链接】livox_ros_driver2Livox device driver under Ros(Compatible with ros and ros2), support Lidar HAP and Mid-360.项目地址: https://gitcode.com/GitHub_Trending/li/livox_ros_driver2
livox_ros_driver2 是乐鑫(Livox)官方第二代激光雷达 ROS 驱动,同时兼容 ROS 与 ROS2,支持 HAP、MID360 等机型。它通过 DRIVER_INFO、DRIVER_ERROR 等日志宏实现统一的日志输出,让同一份业务代码在两种框架下无缝编译运行。本文将带你快速看懂这套日志系统的工作原理。
一、为什么需要 DRIVER_INFO / DRIVER_ERROR 日志宏?🔍
ROS1 和 ROS2 的日志 API 完全不同:
- ROS1使用
ROS_INFO()、ROS_ERROR()等全局宏,底层基于ros::console; - ROS2使用
RCLCPP_INFO(logger, ...)等宏,每条日志都必须绑定一个节点自带的 logger。
如果业务代码直接调用原生宏,就得为 ROS1/ROS2 各维护一套代码。livox_ros_driver2 的解法很巧妙:定义一层DRIVER_前缀的日志宏作为统一日志接口,把平台差异全部收进头文件里,业务代码一行都不用改。
二、日志宏的整体架构:3 个头文件的分工
日志系统的核心是 src/include/ 下的 3 个头文件:
| 文件 | 职责 |
|---|---|
| ros_headers.h | 总入口,根据编译开关自动选择 ROS1 或 ROS2 头文件 |
| ros1_headers.h | 定义 ROS1 版的 DRIVER_ 系列日志宏 |
| ros2_headers.h | 定义 ROS2 版的 DRIVER_ 系列日志宏 |
ros_headers.h 的核心逻辑只有几行条件编译:
#ifdef BUILDING_ROS1 #include "ros1_headers.h" #elif defined BUILDING_ROS2 #include "ros2_headers.h" #endif也就是说,编译期由BUILDING_ROS1/BUILDING_ROS2这两个开关决定日志宏展开到哪一套 API,而业务代码只看到统一的DRIVER_*名称。
三、DRIVER_INFO / DRIVER_ERROR 宏在不同平台下的展开方式
ros1_headers.h 中的定义非常直接,把 node 参数直接忽略掉:
#define DRIVER_INFO(node, ...) ROS_INFO(__VA_ARGS__) #define DRIVER_ERROR(node, ...) ROS_ERROR(__VA_ARGS__)而 ros2_headers.h 中,node 参数派上了用场——取节点的 logger 传给 RCLCPP 宏:
#define DRIVER_INFO(node, ...) RCLCPP_INFO((node).get_logger(), __VA_ARGS__) #define DRIVER_ERROR(node, ...) RCLCPP_ERROR((node).get_logger(), __VA_ARGS__)这就是同一个调用DRIVER_INFO(livox_node, "xxx")在两端都能编译的关键:ROS1 端 node 被丢弃,ROS2 端 node 被用来获取 logger。
EXTRA 变体:一次/节流输出技巧
两个头文件里还各有一套_EXTRA宏,例如 DRIVER_INFO_EXTRA。它利用 C 预处理的##记号拼接能力,把中间参数拼进宏名:
#define DRIVER_INFO_EXTRA(node, EXTRA, ...) RCLCPP_INFO_##EXTRA((node).get_logger(), __VA_ARGS__)这样就能灵活展开成RCLCPP_INFO_ONCE(只打印一次)、RCLCPP_INFO_THROTTLE(节流打印)等原生变体,非常适合高频数据流中避免日志刷屏的场景。
四、编译期开关:CMake 如何决定日志走向
开关来自 CMakeLists.txt 中的编译定义:
- ROS1 构建时注入
-DBUILDING_ROS1(见 CMakeLists.txt) - ROS2 构建时注入
-DBUILDING_ROS2(见 CMakeLists.txt)
构建脚本根据 ROS1 / ROS2 / humble / jazzy 等不同参数选择分支,最终只有对应的日志宏集合生效。整个链路是:
构建脚本 → CMake 定义宏 → ros_headers.h 条件包含 → 平台专属日志宏 → ROS/ROS2 原生日志系统
五、源码中的真实日志调用示例
节点类型定义在 driver_node.h 中,ROS1 下DriverNode继承ros::NodeHandle,ROS2 下继承rclcpp::Node——这正是两种平台都能调用.get_logger()的前提。
在主入口 livox_ros_driver2.cpp 中能看到典型用法:
- 启动时打印版本:
DRIVER_INFO(livox_node, "Livox Ros Driver2 Version: %s", ...)(第 51 行) - 打印配置信息:
DRIVER_INFO(*this, "Config file : %s", user_config_path.c_str())(第 167 行) - 初始化失败报错:
DRIVER_ERROR(*this, "Init lds lidar fail!");(第 178 行) - 参数非法提示:
DRIVER_ERROR(livox_node, "Invalid data src (%d), please check the launch file", data_src);(第 105 行)
另外,ROS1 分支在main()开头还会主动把日志级别调高到 Debug(第 42-44 行),方便用户排查问题时看到更详细的输出。数据分发模块 lddc.cpp 中也大量使用DRIVER_INFO打印 bag 文件创建、多话题模式等状态信息(如 第 189 行)。
六、新手上手建议 💡
- 看日志级别选型:正常状态用
DRIVER_INFO,可恢复的异常用DRIVER_WARN,致命问题用DRIVER_ERROR/DRIVER_FATAL,与 ROS 日志级别一一对应; - 高频路径慎用 INFO:点云回调中每帧都打印会刷屏,可参考
_EXTRA变体的思路使用节流或一次性输出; - 排查启动问题:程序启动时版本、
Config file、Data Source三条 INFO 日志是最快的自检清单,任何一条缺失都说明配置或参数有问题; - 阅读源码路径:想深入日志设计,按 ros_headers.h → ros1_headers.h / ros2_headers.h 的顺序阅读即可,全文不超过 100 行。
这套"统一宏名 + 条件编译分流"的设计,是 livox_ros_driver2 能一份源码同时支持 ROS 和 ROS2 的关键技巧之一,也很适合你在自己的双框架兼容项目中借鉴。
【免费下载链接】livox_ros_driver2Livox device driver under Ros(Compatible with ros and ros2), support Lidar HAP and Mid-360.项目地址: https://gitcode.com/GitHub_Trending/li/livox_ros_driver2
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考