1. ROS日志级别概述
|
日志级别 |
宏命令 |
使用场景 |
颜色 |
|---|---|---|---|
|
DEBUG |
|
详细调试信息,默认不输出 |
灰色 |
|
INFO |
|
一般信息,程序运行状态 |
绿色 |
|
WARN |
|
警告信息,可能的问题 |
黄色 |
|
ERROR |
|
错误信息,功能受影响 |
红色 |
|
FATAL |
|
致命错误,程序终止 |
紫色 |
2. 基本日志输出方法
基础日志输出
// 简单消息输出
ROS_INFO("程序开始执行");
ROS_WARN("温度过高: %.1f°C", temperature);
ROS_ERROR("传感器%d连接失败", sensor_id);
// 流式输出(推荐)
ROS_INFO_STREAM("当前位置: x=" << x << ", y=" << y);
ROS_ERROR_STREAM("检测到异常值: " << abnormal_value);
条件日志输出
// 条件满足时才输出
ROS_INFO_COND(distance < 10.0, "接近目标点");
ROS_WARN_COND(velocity > max_speed, "超速警告: %f", velocity);
// 条件流式输出
ROS_INFO_STREAM_COND(battery < 20, "电量不足: " << battery << "%");
频率控制输出
// 控制输出频率,避免日志刷屏
ROS_INFO_THROTTLE(1.0, "定期状态报告"); // 每秒最多输出1次
ROS_DEBUG_THROTTLE(0.5, "高频调试信息"); // 每0.5秒最多输出1次
// 带条件的频率控制
ROS_WARN_COND_THROTTLE(1.0, is_obstacle_near, "附近有障碍物");
3. 高级调试技巧
一次性输出(只显示第一次)
// 某些信息只需要显示一次
ROS_INFO_ONCE("初始化完成,版本: %s", version.c_str());
ROS_WARN_ONCE("使用默认参数配置");
命名调试(按组件分类)
// 为不同组件创建命名的logger
ros::console::set_logger_level("move_base", ros::console::levels::Debug);
// 使用命名logger输出
ROS_DEBUG_NAMED("navigation", "路径规划中...");
ROS_INFO_NAMED("sensor", "激光雷达数据接收");
过滤调试(按条件过滤)
// 只在特定条件下输出详细信息
ROS_DEBUG_STREAM_FILTER(
[&](const ros::console::LogLocation& loc) {
return debug_mode && error_count > 0;
},
"详细错误信息: " << error_details
);
4. 日志配置和管理
运行时日志级别控制
# 动态调整节点日志级别
rosservice call /node_name/set_logger_level "logger: 'rosout' level: 'debug'"
# 或使用rqt_logger_level工具
rosrun rqt_logger_level rqt_logger_level
启动文件中的日志配置
<!-- 在launch文件中设置日志级别 -->
<node pkg="your_package" type="your_node" name="your_node" output="screen">
<env name="ROSCONSOLE_CONFIG_FILE"
value="$(find your_pkg)/config/custom_rosconsole.config"/>
</node>
自定义日志配置文件
# custom_rosconsole.config
log4j.logger.ros.your_node=DEBUG
log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern=[%d] %-5p %c %x - %m%n
5. 实际调试案例
案例1:状态机调试
void stateMachineCallback() {
static int last_state = -1;
ROS_DEBUG_THROTTLE(0.5, "当前状态: %d, 目标: %d", current_state, target_state);
if (current_state != last_state) {
ROS_INFO("状态转换: %d -> %d", last_state, current_state);
last_state = current_state;
}
ROS_DEBUG_STREAM_COND(debug_path, "路径点数量: " << path_points.size());
}
案例2:性能监控
void processData(const sensor_msgs::LaserScan& scan) {
ros::Time start_time = ros::Time::now();
// 数据处理...
processLaserData(scan);
ros::Duration processing_time = ros::Time::now() - start_time;
ROS_DEBUG_STREAM("数据处理耗时: " << processing_time.toSec() * 1000 << "ms");
if (processing_time > ros::Duration(0.1)) {
ROS_WARN_THROTTLE(5.0, "处理时间过长: %.1fms", processing_time.toSec() * 1000);
}
}
案例3:异常检测
bool validateData(const nav_msgs::Odometry& odom) {
if (std::isnan(odom.pose.pose.position.x)) {
ROS_ERROR_STREAM("接收到非法里程计数据: " << odom);
ROS_DEBUG("数据来源: %s", odom.header.frame_id.c_str());
return false;
}
ROS_DEBUG_STREAM("里程计数据有效: " <<
"x=" << odom.pose.pose.position.x <<
", y=" << odom.pose.pose.position.y);
return true;
}
6. 最佳实践建议
✅ 推荐的调试模式
// 1. 使用不同级别合理分级
ROS_DEBUG("算法内部变量: %f", internal_var); // 详细调试
ROS_INFO("当前状态: %s", state_name.c_str()); // 运行状态
ROS_WARN("边界条件: %f", boundary_value); // 需要注意
ROS_ERROR("功能异常: %s", error_msg.c_str()); // 错误情况
// 2. 使用流式输出提高可读性
ROS_INFO_STREAM("坐标: (" << x << ", " << y << "), 方向: " << theta);
// 3. 合理控制输出频率
ROS_DEBUG_THROTTLE(0.1, "高频数据: %f", high_freq_data);
ROS_INFO_THROTTLE(1.0, "系统状态正常");
❌ 避免的常见错误
// 错误:在循环中无控制地输出
for (int i = 0; i < 1000; i++) {
ROS_INFO("处理第%d个数据", i); // 会导致日志刷屏
}
// 正确:使用条件或频率控制
ROS_DEBUG_THROTTLE(1.0, "已处理%d个数据", processed_count);
7. 调试工作流总结
- 1.
开发阶段:大量使用
ROS_DEBUG进行详细调试 - 2.
测试阶段:使用
ROS_INFO监控关键状态,ROS_WARN关注异常 - 3.
部署阶段:保留必要的
ROS_INFO和ROS_WARN,关闭DEBUG输出 - 4.
问题排查:临时开启
DEBUG级别进行详细诊断
通过合理使用ROS日志系统,可以大大提高代码的可调试性和可维护性。
1174

被折叠的 条评论
为什么被折叠?



