學會使用日志(log)系統,做ROS大型項目的主治醫生
通過顯示進程的運行狀態是好的習慣,但需要確定這樣做不會影響到軟件的運行效率和輸出的清晰度。ROS 日志 (log) 系統的功能就是讓進程生成一些日志消息,顯示在屏幕上、發送到特定 topic 或者儲存在特定 log 文檔中,以方便調試、記錄、報警等。下面簡單介紹如何生成和查看日志消息。
日志消息
在ROS中,有一個特殊的話題叫作/rosout,它承載着所有節點的所有日志消息。/rosout消息的類型是rosgraph_msgs/Log:
rosgraph_msgs/Log消息用來讓各個節點發布日志消息,這樣一來就能讓網絡上的任何一個人都看到。可以認為/rosout是一個加強版的print():他不是向終端輸出字符串,可以將字符串和元數據放到一個消息中,發送到網絡上的任何一個人。ROS節點應該向/rosout發布日志消息,這樣一來這些消息就能被所有人看到。rospy客戶端提供了多個函數來發布rosgraph_msgs/Log消息:
1 |
if battery_voltage < 11.0: |
rospy.logwarn()函數實現了三件事請:
- 輸出一個格式化的字符串到終端
- 輸出更詳細的警告到日志文檔中,這個文檔一般在~/.ros/log中
- 構建並發布一條消息到/rosout話題,其中包括警告以及節點元數據
日志等級
ROS有5個日志記錄標准級別,這些名稱是輸出信息的函數的一部分,他們遵循以下語法:ROS_<LEVEL>[_<OTHER>]
每個消息級別用於不同的目的:
- DEBUG(調試):只在調試時用,此消息不出現在部署的應用中,僅用於測試。
- INFO(信息):標准消息,說明重要步驟或節點所正在執行的操作。
- WARN(警告):提醒一些錯誤,缺失或者不正常,但進程仍能運行。
- ERROR(錯誤):提示錯誤,盡管節點仍可在這里恢復,但對節點的行為設置了一定期望。
- FATAR(致命):這些消息通常表示阻止節點繼續運行的錯誤。
生成基本的日志消息
由五個 C++ 宏來產生日志消息,每個宏對應一個級別:
1 |
ROS_DEBUG_STREAM(message); |
編寫如下 C++ 進程:
1 |
|
編譯、執行之后結果如下:
生成一次性日志消息
ROS 提供了可以僅僅生成一次日志消息的宏:
1 |
ROS_DEBUG_STREAM_ONCE(message); |
將上述 C++ 進程中的 log 命令替換一下,得到如下的執行結果:
可以看到每個日志只生成了一次。
生成頻率受控的日志消息
1 |
ROS_DEBUG_STREAM_THROTTLE(interval, message); |
參數 interval 是 double 型,表示相鄰日志消息出現的最小時間間隔,以秒為單位。得到如下的執行結果:
查看日志消息
日志消息有三個不同的輸出目的地,包括屏幕、rosout topic、log 文檔。其中發布到 rosout topic 的 msg 類型是 rosgraph_msgs/Log。除了 topic echo,還可以通過 rqt_console 查看日志消息:
啟用和禁用日志消息
ROS 默認只處理 INFO 或者更高級別消息,DEBUG 級別的消息會被忽略。可以通過命令行設置顯示的日志級別:rosservice call /node-name/set_logger_level package-name level
其中:
- set_logger_level服務由各個節點自動提供;
- node-name 期望設置日志級別的節點名稱;
- package-name 擁有這個節點的 package 名稱;
- level 是五個級別中的一個。
另外也可以通過圖形接口設置日志級別:rqt_logger_level
圖中列出了節點列表、日志記錄器列表、日志級別列表。在圖中操作與 rosservice 命令的效果一致。
另外,也可以在 C++ 進程中設置日志級別。ROS node 改變自身日志級別最直接的方式是使用 log4cxx 提供的接口:
1 |
#include <log4cxx/logger.h> |
其中 Debug 可以替換為 Info、Warn、Error、Fatal。
后記
對於大型ROS項目的調試必須要利用到日志系統,所有成熟的框架都為開發者提供了代碼進程的調試工具,學會這些工具能夠很大程度上幫助我們少走彎路節省時間,所以我們要能夠利用這些輔助工具來作為開發過程中的左膀右臂,達到事半功倍的效果。