Search this site
Embedded Files
No Boredom
  • Home
    • Computer Geek
    • Learning
    • Math Geek
    • Projects
No Boredom
  • Home
    • Computer Geek
    • Learning
    • Math Geek
    • Projects
  • More
    • Home
      • Computer Geek
      • Learning
      • Math Geek
      • Projects

Building Nodes

< Back to ROS Beginner tutorials
Definitions
Message
Topics
Making a Node using C++
Programming the Node
Building the node
Running the node
Making a node using Python
Programming the node
Executing the node
Preview of how the codes look
Debugging in ROS Nodes
Preview of how the codes look
Configuring the debugging level
Using C++ Code
Using configuration files

Definitions

Message

A message is basically any predefined datatype that can be used for communication. Images, simple numbers, primitive messages like float, integer, String, even a collection of other messages. You can get a list of messages available by:

  1. Open a terminal
  2. Type in the following commands into the terminal and press Enter after every command to execute it
    • rosmsg list
      • This generates a list of available messages for the current ROS installation on the terminal.
      • Try knowing a little more about them, try the following commands to get more insight into this
        • rosmsg info std_msgs/ColorRGBA
        • rosmsg info std_msgs/Header
        • rosmsg info sensor_msgs/PointCloud
  3. To know the list of packages that have messages, use the rosmsg packages command.

Here's the output of the commands. As you can see, a message is basically data that can be moved from one place to another. We'll later see how to create our own messages.

Topics

  • These are the pathways of messages. Think of them as notice boards where programs put up messages (these programs are called publishers) and other programs read these messages (these programs are called subscribers). Remember that a topic comes into existence only after permission by the ROS server and dissolves after the ROS server is shut down.
  • It's not predefined in structure like a message. This makes it extremely flexible during runtime. Any number of nodes can publish to a topic and any number of nodes can subscribe to a topic.
You can inspect the list of topics running in the dry run which you'll do in the next page.

Making a Node using C++

Every node in C++ has a particular structure to follow. Let's discuss this in brief while making a simple node that prints out all the arguments passed. We'll discuss more complicated nodes later. Here are the things that you must follow while making a node using C++. These are made using roscpp (API here).

Programming the Node

Code here

I'll be writing all this code in a file named "ArgumentParser.cpp" inside the src folder of the package intro_pkg1. We created this folder in the previous tutorial.

  1. Include the ROS header file ("ros/ros.h"). This contains all other header files for the functioning of ROS nodes.
    • You can view the content of this header file at the location /opt/ros/melodic/include/ros/ros.h on your local system.
  2. Define the main function (with the arguments in parameter list)
  3. In the main function, initialize the node using ros::init function. The parameters of main function and the name of the node must be passed.
    • This function registers the node with the ROS server.
    • There are additional parameters as well, you can find them here.
  4. Write your code inside this main function.
    • We'll only be printing out the details about the arguments passed here
  5. You could put something to hold the execution, else the node will quit after it's work is done. This depends upon the type of application.
Code here

Building the node

Open the "CMakeLists.txt" file of the package intro_pkg1 and do the following amendments

  1. Scroll to the section named "Build" and add an add_executable line specifying the name of the executable. I've done this:
    • add_executable(ArgumentParser src/ArgumentParser.cpp)
    • This specifies that the code we wrote (ArgumentParser.cpp) must be converted into an executable (named "ArgumentParser"). You declare C++ executables here.
  2. Link the catkin libraries with the executable. This is done using target_link_libraries function. I've done this:
    • target_link_libraries(ArgumentParser ${catkin_LIBRARIES})
    • This specifies the libraries to be used. This is generally put for every executable
  3. Now open a terminal and navigate to the workspace home directory. Call the following command there
    • catkin_make
      • You can alternatively also call catkin_make -pkg intro_pkg1. This would invoke catkin_make only on intro_pkg1.
      • You'd see no errors if everything went fine
      • After this command, you'll see the executable file in the "devel/lib/intro_pkg1" directory in your workspace. This is the executable node that is built after the command.
In the end, your "CMakeLists.txt" file in the package must look something like this.

Running the node

  1. Start the roscore on a terminal. Make sure that roscore is running before running any ROS nodes
  2. On another terminal try out the following commands
    • rosrun intro_pkg1 ArgumentParser
      • This runs the node, you'll observe that one argument is always passed and it's the path to the executable. You can verify this using Files application.
    • rosrun intro_pkg1 ArgumentParser -a Arg1 -b Arg2
      • This will tell you that 5 arguments are passed. Inspect the output carefully

Output of the two commands suggested while running the node. Note that the name of the executable is what we specified in the add_executable function.

Making a node using Python

Just like C++ nodes, even nodes made using Python have a structure to follow and a few things that must be taken care of. One thing to remember is that python is interpreted, not compiled. Thus no need to build the workspace to run Python nodes, they only need to be made executable. These are made using rospy (API here)

Programming the node

  1. Create a file named "ArgsParser.py" in a folder named scripts in the intro_pkg1 folder, so the file path is src/intro_pkg1/scripts/ArgsParser.py from the workspace home directory.
  2. The first line in every ROS executable python script is "#!/usr/bin/env python". This is for the python environment and python interpreter. In standard code, it's a comment, but it's important for ROS to recognize and apply some settings for execution of the node. It's called a shebang line and is important to parse the node.
  3. We'll import rospy in the next line
    • We also import sys for parsing arguments passed
  4. Call rospy.init_node function to initialize the node, just like the ros::init in C++. The function parameters are here.
    • If you want to run multiple instances of the same node, then set the function argument "anonymous" to True, else make it False.
  5. Write your code
    • It's just printing out the arguments in our case
  6. You could put something to hold the execution, else the node will quit after it's work is done. This depends upon the type of application.
  7. Save and close the file

Executing the node

  1. Before we execute it, we have to make the node executable. We do this using the command line tool chmod. This allows us to make the script executable. Type the following in a terminal and hit Enter after every command to execute it:
    • roscd intro_pkg1/scripts/
      • This changes the present working directory into the scripts folder of the intro_pkg1 package.
    • ls -la
      • List all files. This isn't mandatory to do.
    • chmod +x *.py
      • Make all python files (files with extension py) executable. You could also directly use names. For more information, you can run man chmod and check the output (or click here).
    • ls -la
      • List all files again. Notice that the files would be executable now. This isn't mandatory to do.
  2. Run the roscore on a terminal if it's not already running. Make sure that roscore is running before running any ROS nodes.
  3. Run the python program using the following commands and observe the output for the different trials
    • rosrun intro_pkg1 ArgsParser.py
      • No arguments, but the program path and name still exists. Note that there is no executable made in the devel folder for this. It's directly the script itself.
    • rosrun intro_pkg1 ArgsParser.py -a ABC --help -b --clear
      • Arguments passed


Preview of how the codes look

CPP code for argument Parser

Python code for argument parser

Debugging in ROS Nodes

ROS has various options to debug and get insights into what your code is actually doing. It's generally a good idea to put out messages so that you get information about what's happening during the execution of your program, irrespective of it being written in C++ or python.

ROS Debugger

You can check out the outputs of the C++ code and Python code written for this. The ultimate "CMakeLists.txt" file must look like this. Do not forget to do the essentials for building and executing the C++ or python node as we discussed earlier.

  • You might see the use of Rate class. This is to maintain a particular frequency in transmission, we'll discuss more about this later.
  • You might also see ros::NodeHandle, this is to make a communication link between node and server in a node made using C++. We'll discuss more about this later.

Note that when you run either of the codes, you'll not be able to see the messages of DEBUG level priority on the command line. This is the default setting. To enable the DEBUG messages as well, do the following:

  • If you're running the node made using python, then:
    • Open a terminal and run rosnode list. This will give you the name of the python script assigned by the master server. It's assigned at random by the ros server during runtime. It's "/Debugger_Python_14141_1544275364681" for me.
    • Run the following command to set the minimum output level from INFO to DEBUG:
      • rosconsole set /Debugger_Python_14141_1544275364681 rosout debug
  • If you're running the node made using C++, then:
    • Get the name of the node using the same method listed above. It is "/DebuggerCheck" for me.
    • Run the following command to set the minimum output level from INFO to DEBUG:
      • rosconsole set /DebuggerCheck ros.intro_pkg1 debug
        • This will let you see the debug level messages
  • You can optionally play around with other options using the rqt_logger_level command.

Preview of how the codes look

Python code

C++ Code

Configuring the debugging level

There are several ways in which you can set the debugger level (other than the use of rosconsole as shown above). Let's explore a few of them

Using C++ Code

We use the rosconsole C++ API for this. The function set_logger_level is used. Here's an example

Setting the logger level to DEBUG

Using configuration files

ROS logger is made on top of log4cxx and log4j libraries. These use configuration files. The default configuration file used by ROS (for C++) is present in $ROS_ROOT/config/rosconsole.config (basically, /opt/ros/melodic/share/ros/config/rosconsole.config). You can create a folder named "config" in your package and redeclare the variables. More on this for C++ here and for Python here. Here's a short summary of what to do:

  • For C++
    • Set the value of log4j.logger.ros.intro_pkg1 to DEBUG in the file rosconsole_cpp.conf (stored in the config directory of the package).
      • You could choose any name for the ".conf" file, rosconsole_cpp is just an example.
    • Assign an environment variable named "ROSCONSOLE_CONFIG_FILE" to the path of the rosconsole_cpp.conf file in the launch file.
  • For Python
    • Open the directory /opt/ros/melodic/etc/ros/ and open the file named python_logging.conf (stored in the config directory of the package).
    • Copy the contents into a config file that you made for this (let it be rosconsole_python.conf). Make all the modifications that you want to.
      • Again, the name of the ".conf" file can be anything
    • Then set the environment variable "ROS_PYTHON_LOG_CONFIG_FILE" to the path of the rosconsole_python.conf file in the launch file.

An example is given below

Launch file above


You'll learn more about launch files later on, for now you can skip this section and come back later if you don't completely get this.

  • A configuration file tells the libraries what to do (settings to be applied).
  • For C++, the file is stored in /opt/ros/melodic/share/ros/config/rosconsole.config is used and the environment variable ROSCONSOLE_CONFIG_FILE can be used to override the file location.
  • For Python, the file stored in /opt/ros/melodic/etc/ros/python_logging.conf is used and the environment variable ROS_PYTHON_LOG_CONFIG_FILE can be used to override the file location.

Note that the override is on the file location hence the complete list of contents must be available in the ".conf" file that you make. In C++ there are just two and there exist internal definitions, so you can omit the first one (log4j.logger.ros) can be omitted, but for Python, you have to declare the entire thing. It's best that you come here every time you want to change the logger levels for C++ and Python and read this text block.

For more on C++ config file, check out this page (Scroll to section named "2. Configuration")

You can set the environment variables however you want, through launch files is just one method. You can come back here after learning about launch files later. This same section is attached in the end of that page as well (check the Additional > Configuring the Debugger levels of launched nodes on this page).

< Back to ROS Beginner tutorials
Google Sites
Report abuse
Page details
Page updated
Google Sites
Report abuse