Добрый день, уважаемые читатели! Продолжаю рассказывать о различных интересных и полезных возможностях робототехнической платформы Robot Operation System (ROS). В этом небольшом руководстве я расскажу о возможностях логирования средствами ROS при программировании на языке C++. Думаю, многие согласятся с тем, что вывод сообщений при выполнении программы имеет большое значение при разработке программ, особенно при отладке. ROS предоставляет удобное API для вывода различных типов сообщений в терминал с возможностью визуализации и фильтрации сообщений в специальных инструментах ROS. Давайте начнем!
Итак, напишем простой узел, который назовем logging_tutorial:
Добавим в CMakeLists.txt:
Теперь начнем писать код main.cpp. Импортируем в заголовке файла специальный заголовочный файл console.h с определением функций логирования:
Добавим простое сообщение в метод main:
Скомпилируем пакет и запустим его:
Вывод будет таким:
В начале сообщения добавляется “уровень” или тип и временная метка в секундах и наносекундах с 1 января 1970. В данном случае у нас сообщение с уровнем INFO.
Мы можем передавать в сообщение параметры аналогично методу printf:
Можно создать сообщение в виде стандартного потока подобно std::cout:
ROS поддерживает следующие «уровни подробности» (в порядке возрастания релевантности):
Для вывода сообщения определенного уровня используется соответствующая функция в формате: ROS_\<LEVEL\>. Сообщения различных типов выводятся с подсветкой определенным цветом: DEBUG — зеленым, INFO — белым, WARN — желтым, ERROR — красным, FATAL — фиолетовым. О предназначении каждого типа сообщений нетрудно догадаться по его названию. Так например, сообщения DEBUG полезны при отладке.
Добавим несколько различных сообщений и запустим все в цикле. У меня получился такой файл:
По умолчанию при выполнении программы отображаются сообщения всех типов кроме DEBUG. Это определяется минимальным уровнем, так называемым “уровнем важности”, с помощью параметра ROSCONSOLE_MIN_SEVERITY. Параметр ROSCONSOLE_MIN_SEVERITY ограничивает вывод сообщений таким образом, что выводятся все сообщения с уровнем равным или выше минимального. По умолчанию минимальный уровень установлен равным DEBUG. Можно изменить минимальный уровень присвоив ROSCONSOLE_MIN_SEVERITY значение одного из уровней сообщений (ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO и т. д.) либо ни одному из них (ROSCONSOLE_SEVERITY_NONE), с помощью макроса в начале файла узла:
Также можно задать уровень важности для всех узлов в пакете в файле CMakeLists.txt:
У данного способа есть одно ограничение: выводиться будут только сообщения уровня выше DEBUG, даже если мы прямо укажем ROSCONSOLE_SEVERITY_DEBUG. Решить эту проблему можно с помощью специального файла конфигурации. Создадим папку config и внутри нее файл custom_rosconsole.conf с таким содержимым:
Затем создадим launch файл logging.launch и укажем путь до файла custom_rosconsole.conf в переменной ROSCONSOLE_CONFIG_FILE:
Здесь мы добавили параметр output=«screen», что позволяет выводить сообщения уровней начиная с INFO.
Скомпилируем и запустим наш лаунч:
Мы получим подобный вывод:
Запустим утилиту rqt_console:
И запустим наш узел с помощью launch:
Окно rqt_console будет выглядеть так:
Здесь в таблице для каждого сообщения отображается его уровень, название узла, название файла и строка кода, где оно генерируется.
Двойным кликом на сообщении можно получить детальную информацию о нем:
Можно отфильтровать сообщения, исключив все сообщения о ошибках. Для этого добавим фильтр нажав на плюсик возле таблицы Exclude messages и выбрав опцию "...containing":
Или исключить сообщения с уровнем Info:
Также сообщения заданного уровня можно выделить среди всех использовав фильтры в секции Highlight Messages:
Таким образом, rqt_console позволяет гибко настраивать отображение сообщений из различных узлов и упростить отладку программ в ROS.
Надеюсь, данное руководство окажется полезным в работе и упростит решение возникающих проблем при программировании. Желаю всем успехов в работе с ROS и до новых встреч!
Использование методов библиотеки console.h для вывода сообщений в узле
Итак, напишем простой узел, который назовем logging_tutorial:
catkin_create_pkg logging_tutorial roscpp std_msgs
Добавим в CMakeLists.txt:
add_executable(logging_node src/main.cpp)
target_link_libraries(logging_node
${catkin_LIBRARIES}
)
Теперь начнем писать код main.cpp. Импортируем в заголовке файла специальный заголовочный файл console.h с определением функций логирования:
#include <ros/console.h>
Добавим простое сообщение в метод main:
int main(int argc, char** argv)
{
ros::init(argc, argv, "logging_node");
ros::NodeHandle n;
ROS_INFO("logging_node start");
return 0;
}
Скомпилируем пакет и запустим его:
cd ~/catkin_ws
catkin_make
source devel/setup.bash
rosrun logging_tutorial logging_node
Вывод будет таким:
[ INFO] [1492194213.009783103]: logging_node start
В начале сообщения добавляется “уровень” или тип и временная метка в секундах и наносекундах с 1 января 1970. В данном случае у нас сообщение с уровнем INFO.
Мы можем передавать в сообщение параметры аналогично методу printf:
int val = 5;
ROS_INFO("message with argument: %d", val);
Можно создать сообщение в виде стандартного потока подобно std::cout:
ROS_INFO_STREAM("message with argument: " << val);
ROS поддерживает следующие «уровни подробности» (в порядке возрастания релевантности):
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
Для вывода сообщения определенного уровня используется соответствующая функция в формате: ROS_\<LEVEL\>. Сообщения различных типов выводятся с подсветкой определенным цветом: DEBUG — зеленым, INFO — белым, WARN — желтым, ERROR — красным, FATAL — фиолетовым. О предназначении каждого типа сообщений нетрудно догадаться по его названию. Так например, сообщения DEBUG полезны при отладке.
Добавим несколько различных сообщений и запустим все в цикле. У меня получился такой файл:
#include <ros/ros.h>
#include <ros/console.h>
int main(int argc, char** argv)
{
ros::init(argc, argv, "logging_node");
ros::NodeHandle n;
ros::Rate rate (1);
while(ros::ok())
{
ROS_DEBUG("debug message");
ROS_INFO("logging_node start");
int val = 5;
ROS_INFO("message with argument: %d", val);
ROS_INFO_STREAM("stream message with argument: " << val);
ROS_WARN("My warning");
ROS_ERROR("Some error");
ROS_FATAL("Fatal error");
ros::spinOnce();
rate.sleep();
}
return 0;
}
По умолчанию при выполнении программы отображаются сообщения всех типов кроме DEBUG. Это определяется минимальным уровнем, так называемым “уровнем важности”, с помощью параметра ROSCONSOLE_MIN_SEVERITY. Параметр ROSCONSOLE_MIN_SEVERITY ограничивает вывод сообщений таким образом, что выводятся все сообщения с уровнем равным или выше минимального. По умолчанию минимальный уровень установлен равным DEBUG. Можно изменить минимальный уровень присвоив ROSCONSOLE_MIN_SEVERITY значение одного из уровней сообщений (ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO и т. д.) либо ни одному из них (ROSCONSOLE_SEVERITY_NONE), с помощью макроса в начале файла узла:
#define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG
Также можно задать уровень важности для всех узлов в пакете в файле CMakeLists.txt:
add_definitions(-DROSCONSOLE_MIN_SEVERITY=ROSCONSOLE_SEVERITY_ERROR)
У данного способа есть одно ограничение: выводиться будут только сообщения уровня выше DEBUG, даже если мы прямо укажем ROSCONSOLE_SEVERITY_DEBUG. Решить эту проблему можно с помощью специального файла конфигурации. Создадим папку config и внутри нее файл custom_rosconsole.conf с таким содержимым:
log4j.logger.ros.logging_tutorial=DEBUG
Затем создадим launch файл logging.launch и укажем путь до файла custom_rosconsole.conf в переменной ROSCONSOLE_CONFIG_FILE:
<launch>
<env name="ROSCONSOLE_CONFIG_FILE"
value="$(find logging_tutorial)/config/custom_rosconsole.conf"/>
<node pkg="logging_tutorial" type="logging_node" name="logging_node" output="screen"/>
</launch>
Здесь мы добавили параметр output=«screen», что позволяет выводить сообщения уровней начиная с INFO.
Скомпилируем и запустим наш лаунч:
cd ~/catkin_ws
catkin_make
roslaunch logging_tutorial logging.launch
Мы получим подобный вывод:
Использование rqt_console для вывода сообщений
Запустим утилиту rqt_console:
rosrun rqt_console rqt_console
И запустим наш узел с помощью launch:
roslaunch logging_tutorial logging.launch
Окно rqt_console будет выглядеть так:
Здесь в таблице для каждого сообщения отображается его уровень, название узла, название файла и строка кода, где оно генерируется.
Двойным кликом на сообщении можно получить детальную информацию о нем:
Можно отфильтровать сообщения, исключив все сообщения о ошибках. Для этого добавим фильтр нажав на плюсик возле таблицы Exclude messages и выбрав опцию "...containing":
Или исключить сообщения с уровнем Info:
Также сообщения заданного уровня можно выделить среди всех использовав фильтры в секции Highlight Messages:
Таким образом, rqt_console позволяет гибко настраивать отображение сообщений из различных узлов и упростить отладку программ в ROS.
Надеюсь, данное руководство окажется полезным в работе и упростит решение возникающих проблем при программировании. Желаю всем успехов в работе с ROS и до новых встреч!
Поделиться с друзьями
VJean
Отлично!
0. Что такое ROS?
1. Какая производительность логера при выводе в консоль, файл, по сети и <что там еще поддерживается>?
2. Какой формат логирования в файл: бинарный или текстовый?
3. Где посмотреть исходники логера и его QT-вьюера логов?
4. Какие платформы и ОС поддерживаются?
5. Какая лицензия?
Vooon
После 0 — вам это не надо.
А так, построено на базе log4cxx, плюс обвязка, чтобы выдавать через топик /rosout.
VJean
Краткий ликбез по ROS, либо расшифровка аббревиатуры в начале статьи не помешают.
В том числе описание и сравнение описываемого логгера с другими логгерами. На примере Сравнение библиотек логирования
Как всегда — комментарии информативнее статьи. Спасибо за ответ.
vovaekb90
Расшифровку ROS добавил.
Другие логгеры не пробовал.