Logging in the ROS program

    Good afternoon, dear readers! I continue to talk about various interesting and useful features of the Robot Operation System (ROS) robotic platform. In this small tutorial I will talk about the possibilities of logging with ROS tools when programming in C ++. I think many would agree that the display of messages during program execution is of great importance when developing programs, especially when debugging. ROS provides a convenient API for outputting various types of messages to a terminal with the ability to visualize and filter messages in special ROS tools. Let's start!

    Using console.h library methods to display messages in the node


    So, we write a simple node, which we call logging_tutorial:

    catkin_create_pkg logging_tutorial roscpp std_msgs
    

    Add to CMakeLists.txt:

    add_executable(logging_node src/main.cpp)
    target_link_libraries(logging_node                                                                            
       ${catkin_LIBRARIES}                                                                                        
    )
    

    Now let's start writing the main.cpp code. We import a special header file console.h in the file header with the definition of logging functions:

    #include<ros/console.h>

    Add a simple message to the main method:

    intmain(int argc, char** argv){
    	ros::init(argc, argv, "logging_node");
    	ros::NodeHandle n;
            ROS_INFO("logging_node start");
            return0;
    }
    

    Compile the package and run it:

    cd ~/catkin_ws
    catkin_make
    source devel/setup.bash
    rosrun logging_tutorial logging_node
    

    The output will be:

    [ INFO] [1492194213.009783103]: logging_node start
    

    At the beginning of the message is added a “level” or type and time stamp in seconds and nanoseconds from January 1, 1970. In this case, we have a message with an INFO level.

    We can pass parameters to the message in the same way as the printf method:

    int val = 5;
    ROS_INFO("message with argument: %d", val);
    

    You can create a message as a standard stream like std :: cout:

    ROS_INFO_STREAM("message with argument: " << val);
    

    ROS supports the following “levels of detail” (in order of increasing relevance):

    • DEBUG
    • INFO
    • WARN
    • ERROR
    • Fatal

    To display a message of a certain level, the corresponding function is used in the format: ROS _ \ <LEVEL \>. Messages of various types are displayed with a certain color with highlighting: DEBUG - green, INFO - white, WARN - yellow, ERROR - red, FATAL - purple. The purpose of each type of message is easy to guess by its name. For example, DEBUG messages are useful for debugging.

    Add a few different messages and run everything in a loop. I got this file:

    #include<ros/ros.h>#include<ros/console.h>intmain(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();
        }
    	return0;
    }
    

    By default, when executing a program, messages of all types are displayed except for DEBUG. This is determined by the minimum level, the so-called “severity level,” using the ROSCONSOLE_MIN_SEVERITY parameter. The ROSCONSOLE_MIN_SEVERITY parameter limits the output of messages in such a way that all messages with a level equal to or higher than the minimum are displayed. By default, the minimum level is set to DEBUG. You can change the minimum level by assigning ROSCONSOLE_MIN_SEVERITY the value of one of the message levels (ROSCONSOLE_SEVERITY_DEBUG, ROSCONSOLE_SEVERITY_INFO, etc.) or none of them (ROSCONSOLE_SEVERITY_NONE) using the macro at the beginning of the node file:

    #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG

    You can also set the level of importance for all nodes in the package in the CMakeLists.txt file:

    add_definitions(-DROSCONSOLE_MIN_SEVERITY=ROSCONSOLE_SEVERITY_ERROR)
    

    This method has one limitation: only messages of a higher level than DEBUG will be displayed, even if we directly specify ROSCONSOLE_SEVERITY_DEBUG. You can solve this problem using a special configuration file. Create a config folder and inside it a custom_rosconsole.conf file with the following contents:

    log4j.logger.ros.logging_tutorial=DEBUG
    

    Then create the launch logging.launch file and specify the path to the custom_rosconsole.conf file in the ROSCONSOLE_CONFIG_FILE variable:

    <launch><envname="ROSCONSOLE_CONFIG_FILE"value="$(find logging_tutorial)/config/custom_rosconsole.conf"/><nodepkg="logging_tutorial"type="logging_node"name="logging_node"output="screen"/></launch>

    Here we have added the parameter output = “screen”, which allows displaying messages of levels starting from INFO.

    Compile and run our launch:

    cd ~/catkin_ws
    catkin_make
    roslaunch logging_tutorial logging.launch
    

    We will get a similar conclusion:

    image

    In ROS, it is possible to assign names to messages. By default, messages get the host name. Users can give names to various messages through the ROS _ \ <LEVEL \> [_ STREAM] _NAMED function:

    ROS_INFO_STREAM_NAMED("named_msg", "named info stream message with argument: " << val);
    


    Names allow you to assign different minimum levels to each named message in the configuration file and modify them individually. The message name is indicated after the package name:

    log4j.logger.ros.logging_tutorial.named_msg = ERROR
    


    Conditional messages can also be useful if executed under a certain condition. To do this, use the ROS _ \ <LEVEL \> [_ STREAM] _COND [_NAMED] function:

    ROS_INFO_STREAM_COND(val < 2, "conditional stream message shown when val (" << val << ") < 2");
    


    Messages can be output at a specific frequency using the ROS _ \ <LEVEL \> [_ STREAM] _THROTTLE [_NAMED] function. The first parameter is the frequency in seconds:

    ROS_INFO_THROTTLE(3, "throttled message with period 3 seconds");
    


    Using rqt_console to display messages


    Run the rqt_console utility:

    rosrun rqt_console rqt_console
    

    And launch our node using launch:

    roslaunch logging_tutorial logging.launch
    

    The rqt_console window will look like this:

    image

    Here in the table for each message its level, node name, file name and line of code are displayed, where it is generated.

    Double click on the message you can get detailed information about it:

    image

    You can filter messages by excluding all error messages. To do this, add a filter by clicking on the plus sign next to the Exclude messages table and selecting the "... containing" option:

    image

    Or exclude messages with the Info level:

    image

    You can also select messages of a given level among all by using filters in the Highlight Messages section:

    image

    Thus, rqt_console allows you to flexibly configure displaying messages from various nodes and simplify debugging programs in ROS.

    I hope this manual will be useful in the work and will simplify the solution of problems encountered during programming. I wish you all success in your work with ROS and see you soon!

    Also popular now: