How to Run a Node in ROS Noetic

How to Run a C++ Node

Ok, now that we have built our nodes, let’s run them.

Open up a new terminal window and launch the ROS Master.

roscore

In a new terminal tab, type the following command to run the publisher node:

rosrun noetic_basics_part_1 simple_publisher_node

Here is the output:

13-publisher-node-outputJPG

Now, let’s run the subscriber node. Type the following command in a new terminal tab.

rosrun noetic_basics_part_1 simple_subscriber_node
14-subsriber-node-outputJPG

You’ll notice that the syntax for running a node in ROS is:

rosrun package-name executable-name

In a new terminal tab, check to see which nodes are running.

rosnode list
15-rostopic-listJPG

The /rosout node is a special node that starts up automatically when you launch the ROS Master. It is responsible for managing ROS-specific output messages to the terminal window.

If you want to find out information about the publisher node, you can type:

rosnode info /simple_publisher_node

That command aboves gives you a full account of what the node is all about. To find out more information about the subscriber node, type:

rosnode info /simple_subscriber_node

There are a bunch of commands for ROS nodes.

To list all active topics, type:

rostopic list

You can see the /message topic is currently active.

Now try these commands, and see what you get:

rostopic info message
rostopic type /message
rostopic bw /message

You can find out what all these commands mean at the ROS website here.

To visualize the publish-subscribe relationships between the nodes, type the following command:

rqt graph
16-node-graphJPG

An incoming arrow indicates that a node subscribed to the topic. An outgoing arrow indicates that a node publishes to the topic.

You can close all terminal windows when you’re ready by pressing CTRL + C on your keyboard on each window.

How to Run a Python Node

In a new terminal window, launch ROS.

roscore

Open a new terminal window, and execute simple_python_publisher.py.

rosrun noetic_basics_part_1 simple_python_publisher.py

Here is the output:

13b-python-publisher-outputJPG-1

Open another terminal window and type:

rosrun noetic_basics_part_1 simple_python_subscriber.py
13c-python-subscriber-outputJPG-1

To stop the program, type CTRL+C in all terminal windows.

How to Build a Node in ROS Noetic

How to Build a C++ Node

Now that we’ve created our two nodes, we need to build them. Building ROS nodes means getting them in a format that enables ROS to use them.

The first thing we need to do is to edit the CMakeLists.txt file inside the noetic_basics_part_1 package. 

The CMakeLists.txt file is the file inside the noetic_basics_part_1 package that was automatically generated when we created the package. CMakeLists.txt says how to build the code we wrote (i.e. the nodes we just created).

Let’s edit the CMakeLists.txt file for the noetic_basics_part_1 package. Open a new terminal window, and type this command:

roscd noetic_basics_part_1 
gedit CMakeLists.txt

You should see a file that looks like this:

9-file-that-looks-like-thisJPG

Now add these lines to the bottom of the CMakeLists.txt file:

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

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

In the code above, we have done the following:

  • Create two executables, simple_publisher_node and simple_subscriber_node, which will by default go into the ~/catkin_ws/devel/lib/noetic_basics_part_1 folder.
  • Make sure the nodes get linked to the catkin libraries (i.e. ROS-related libraries).

Now save and close the CMakeLists.txt file.

Open a new terminal window, and type the following commands to build all the nodes in the noetic_basics_part_1 package:

cd ~/catkin_ws
catkin_make 

That command above will build all nodes inside all the packages in your catkin workspace.

11-build-the-packagesJPG

Now, open a new terminal window and go to the catkin_ws/devel/lib/noetic_basics_part_1/ folder.

cd ~/catkin_ws/devel/lib/noetic_basics_part_1/

Type dir to see the files listed. You will see the publisher and subscriber executables. Feel free to close the terminal window now.

12-there-they-areJPG

How to Build a Python Node

Navigate to the scripts folder inside your package. 

roscd noetic_basics_part_1/scripts

Make the files executable. Type these commands, pressing Enter after each.

chmod +x simple_python_publisher.py
chmod +x simple_python_subscriber.py

Open a new terminal window, and type the following commands to build all the nodes in the noetic_basics_part_1 package:

cd ~/catkin_ws
catkin_make 

How to Create a Subscriber Node in ROS Noetic

How to Create a Subscriber Node in C++

Let’s look at how to create a subscriber node in ROS.

We will write a subscriber node in C++ that will subscribe to the /message topic so that it can receive the string messages published by the publisher node (simple_publisher_node) we created in the previous section.

Open up a new terminal window.

Move to the src folder of the package: noetic_basics_part_1.

roscd noetic_basics_part_1/src

Let’s create a C++ program named simple_subscriber_node.cpp. The name for this node in ROS will be simple_subscriber_node. The purpose of this node is to subscribe to the topic named /message.

Ok, now type this command to open a brand new C++ file.

gedit simple_subscriber_node.cpp

Type the code below into the file, one line at a time so that you read all the comments and know what is going on. Creating a node in ROS that can subscribe to a topic is something you’ll do again and again as you work with ROS.

/**
 * A basic program to subscribe to messages that are published on a ROS topic
 * @author Addison Sears-Collins (https://automaticaddison.com/)
 * @version 1.0 
 */ 
 
 // Include the header file that has declarations for the standard ROS classes
 #include "ros/ros.h"

// Header file for messages of type std_msgs::String
// Each type of message you use in a program will have a C++ header file you
// need to include. The syntax is #include <package_name/type_name.h>
// Here we want to subscribe to messages of type String that are owned by the
// std_msgs package (http://wiki.ros.org/std_msgs)
#include "std_msgs/String.h"

/**
 * This function is known as a callback function. A program that subscribes to
 * to a topic (i.e. subscriber node) doesn't know when messages will be 
 * arriving. If you have code that needs to process an incoming message 
 * (e.g. most often sensor data in robotics), you place that code inside a 
 * callback function. A callback function is a function that is called once f
 * or each message that arrives.  
 * The syntax for a subscriber callback function is:
 *   void function_name(const package_name::type_name &msg) {
 *	   [insert your code here]
 *   }
 * The function below is executed each time a new message arrives.
 *   Topic Name: /message
 *   Message Type: std_msgs/String
 */
void messageCallback(const std_msgs::String::ConstPtr& msg) {
	
  // Display the message that was received to the terminal window
  ROS_INFO("The message I received was: [%s]", msg->data.c_str());
}

/**
 * Main method
 */
int main(int argc, char **argv) {

  // Initialize the node and set the name.
  // The ros::init() function needs to see argc and argv.
  // The third argument is the name of the node.
  ros::init(argc, argv, "simple_subscriber_node");	
  
  // Create the main access point for the node
  // This piece of code enables the node to communicate with the ROS system.
  ros::NodeHandle n;  
  
  // This code below is how we subscribe to a topic.
  // The syntax is:
  //   ros::Subscriber sub = node_handle.subscribe(
  //     topic_name_without_leading_slash,
  //     queue_size, callback_function);
  // I like to use a large number like 1000 for the queue size.
  // When new messages arrive on a topic, they line up in a queue until the
  // callback function is executed by ROS. If the queue is full when a new 
  // message arrives, the oldest unprocessed messages are removed to create
  // space for the new message.
  // To prevent overflow of the queue, you'll need to frequently run the 
  // ros::spinOnce or ros::spin function to make sure the callback 
  // function is executed.  
  ros::Subscriber sub = n.subscribe("message", 1000, messageCallback);
	
  // This code enters a loop, continually processing messages that arrive
  // in the queue. If you don't have this code, messages that are waiting in
  // the queue will never be processed.
  // Note, if you use ros::spinOnce() instead of ros::spin(), unprocessed 
  // messages will be processed and then the code below this line will 
  // start executing. 
  // With ros::spin(), you want ROS to wait for messages and
  // process those messages until you either hit Ctrl + C on your keyboard
  // or close down this node.
  // Here we use ros::spin() because the node's sole job is to echo (to the 
  // (terminal window) the message that it receives. However, if you have a 
  // node that needs to do something other than just printing
  // messages to a terminal screen, use 
  // ros::spinOnce(), since that gives you more control when you want the node
  // to process incoming messages.
  ros::spin();
  
  // Code was executed successfully
  return 0;
	
}

In a nutshell, what we did above was:

  • Initialize the ROS system
  • Subscribe to the message topic (i.e. /message)
  • Spin, waiting for new messages to arrive
  • When a new message arrives, call the callback function to process it (i.e. messageCallback())

How to Create a Subscriber Node in Python

Go to your package.

roscd noetic_basics_part_1

Go to the scripts folder.

cd scripts

Open a new file.

gedit simple_python_subscriber.py

Type the following code in it.

#!/usr/bin/env python3
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
    
def receive_message():

    # In ROS, nodes are uniquely named. If two nodes with the same
    # name are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'simple_python_subscriber' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('simple_python_subscriber', anonymous=True)

    rospy.Subscriber("message_py", String, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    receive_message()

Save the file and close it.

You should now have two Python files in your scripts folder of your noetic_basics_part_1 package.