> jbohren.com <
  • home
  • articles
  • tutorials
  • projects
  • contact

 

ros2 C++ Hello World (The Simplest ros2 Tutorial)

posted 2021.11.26

  • ros
  • tutorial
  • c++

Introduction

There are a lot of ros2 tutorials out there. This is the simplest one.

This is the sequel to my ROS(1) tutorial of the same name. This tutorial demonstrates how to build a ros2 “Hello world” executable written in C++ without getting into the details of ros2 packages, workspaces, launchfiles, or other standard practices. This tutorial is meant to demonstrate the bare minimum of what is required to interact with a ros2 system. It is not meant to be an example of good ros2 development practices, but rather is meant to be useful for someone new to ros2 and software development in general. That being said, this could be informative for someone who wants to integrate with ros2 without pulling in the entire build and process management system.

NOTE: This tutorial was written for the ros2 Galactic Distribution. Assuming the commands are still accurate, if you wish to follow this tutorial with a different distribution of ros2, any time galactic is mentioned, simply replace it with the shortname for that distribution.

Pre-Requisites

  • A computer running Ubuntu Linux1 20.04 installation
  • Minimal experience with the Linux and the command-line interface
  • Minimal experience with C++

Tools Used

  • Ubuntu Linux1
  • The bash shell2
  • C++3
  • The GNU Compiler Collection (GCC)4
  • Any plain-text editor (I like vim5).

ros2 Packages Used

  • rclcpp

Number of Windows Needed

  • Browser for these instructions
  • Window for your text editor
  • Terminal to run hello_world_node
  • Terminal to run introspection commands like ros2 node and ros2 topic

Contents

  • Introduction
    • Pre-Requisites
    • Tools Used
    • ros2 Packages Used
    • Number of Windows Needed
  • Installing ROS2 (if it hasn’t already been installed)
  • Create THE SIMPLEST ROS2 (C++) PROGRAM
  • Compile the simplest ros2 (C++) program
  • Run the simplest ros2 (C++) program (and fail)
  • Inspecting the simplest ROS (C++) program
  • Distributed Logging with rosconsole
  • Play Around
  • Conclusion

Installing ROS2 (if it hasn’t already been installed)

For Ubuntu Linux, you can follow these instructions, and for other platforms, see the main ros2 installation instructions.

Install pre-requisites and add the universe repository if it’s not already enabled:

sudo apt update && sudo apt install locales curl gnupg lsb-release software-properties-common
sudo add-apt-repository universe

Get the ros GPG key and authorize it:

sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key  -o /usr/share/keyrings/ros-archive-keyring.gpg

Add the ROS repository:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

Update sources and install the base set of ros2 packages.

sudo apt update
sudo apt install ros-galactic-ros-base

Create THE SIMPLEST ROS2 (C++) PROGRAM

After you’ve installed the pre-requisites listed above, you can create a new directory for this tutorial. You can call this directory anything you want, but in this case, we’ll call it hello_world_tutorial and make it anywhere. Then, enter the directory:

mkdir hello_world_tutorial
cd hello_world_tutorial

The first step is writing the simplest C++ program that can interact with ros2 in a meaningful way. All it does is prepare to announce itself as a ros2 node called hello_world_node, then broadcast a Hello-world message over the standard /rosout topic, and then wait for a SIGINT or ctrl-c.

This program will be built from single file named hello_world_node.cpp with the following contents:

hello_world_node.cpp
// Include the ros2 c++ APIs
#include "rclcpp/rclcpp.hpp"

int main(int argc, char * argv[]) {
  // Process ros2-related command-line arguments and initialize ros2 for this process
  rclcpp::init(argc, argv);
  // Create a ros2 node, which owns one or more ros2 interfaces
  auto node = std::make_shared<rclcpp::Node>("hello_world_node");
  // Broadcast a simple log message
  RCLCPP_INFO(node->get_logger(), "Hello, world!");
  // Process ros2 callbacks until receiving a SIGINT (ctrl-c)
  rclcpp::spin(node);
  // Stop the node's resources
  rclcpp::shutdown();
  // Exit tranquilly
  return 0;
}

Compile the simplest ros2 (C++) program

Since we’re building a program with C++, we need to compile it into an executable that we can actually run. In this very simple case, this can be done by invoking g++ directly with the following build command (make sure to get all of it):

g++ --std=c++17 hello_world_node.cpp -o hello_world_node -I/opt/ros/galactic/include/ -L/opt/ros/galactic/lib -Wl,-rpath,/opt/ros/galactic/lib -lrclcpp -lrcutils

If you are unfamiliar with command-line usage of g++, the arguments passed to g++ have the following meanings:

  • hello_world_node.cpp The source file(s) to compile
  • -o hello_world_node The name of the output file (the executable, in this case)
  • -I/opt/ros/galactic/include An instruction to look for C++ header files in /opt/ros/galactic/include
  • -L/opt/ros/galactic/lib An instruction to look for static libraries in /opt/ros/galactic/lib
  • -Wl,-rpath,/opt/ros/galactic/lib An instruction to look for shared libraries in /opt/ros/galactic/lib
  • -lrclcpp Link against the library librclcpp.so (ros2 C++ bindings)
  • -lrcutils Link against the library librcutils.so (ros2 C utilities)

NOTE: The standard method to build software in ROS/ros2 is to use ROS packages and catkin/ament/colcon. This tutorial avoids using these tools for simplicity, as they are not needed to use the ros2 middleware.

Run the simplest ros2 (C++) program (and fail)

After successfully compiling the program, you can run it right away.

./hello_world_node

If you’ve been following this tutorial verbatim, then you’ll get an error message like the following:

./hello_world_node: error while loading shared libraries: libament_index_cpp.so: cannot open shared object file: No such file or directory

This error is due to the ros2’s special installation to /opt/ros/galactic. Specifically, the rclcpp library depends on the ament_index_cpp library and others. Take a look at ldd hello_world_node to see the rest. There are a few.

To add the appropriate paths to LD_LIBRARY_PATH so that those libraries can be found, source the ros2 setup script:

source /opt/ros/galactic/setup.sh

At this point, you can try running hello_world_node again:

./hello_world_node

You should see the following output (with different timestamps and network interfaces):

1638160396.202275 [0] hello_worl: using network interface wlp4s0 (udp/192.168.0.128) selected arbitrarily from: wlp4s0, lxcbr0, lxdbr0
[INFO] [1638160396.207924768] [hello_world_node]: Hello, world!

Inspecting the simplest ROS (C++) program

In a new shell with a proper environment, you can now inspect your node running in the first shell with standard ros2 command-line tools.

One of the simplest, ros2 node, is a command-line program for listing and querying information about ros2 nodes. For example, the info subcommand will give you all the metadata ros2 knows about a given node. You can get the info for /hello_world_node like so:

ros2 node info /hello_world_node

This will give you information similar to the following:

/hello_world_node
  Subscribers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
  Publishers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log
  Service Servers:
    /hello_world_node/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /hello_world_node/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /hello_world_node/get_parameters: rcl_interfaces/srv/GetParameters
    /hello_world_node/list_parameters: rcl_interfaces/srv/ListParameters
    /hello_world_node/set_parameters: rcl_interfaces/srv/SetParameters
    /hello_world_node/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
  Service Clients:

  Action Servers:

  Action Clients:

Note that if you ctrl-c hello_world_node in the other window, and try to re-run this command, you will see something similar to the following:

Unable to find node '/hello_world_node'

Distributed Logging with rosconsole

Simple as it may be, hello_world_node is actually doing much more than announcing itself to the ros2 master and then outputting “Hello, world!” to the console. This is actually being broadcast to any other ros2 nodes which have subscribed to the standard ros2 log message topic6 called /rosout.

To see this, first make sure hello_world_node is terminated. Then, run the following rostopic command in another window to display any messages on the /rosout topic:

ros2 topic echo /rosout

If you run hello_world_node in another shell, in the window running ros2 topic, you should now see the content of a single rosgraph_msgs/Log message beneath the ros2 topic command, with content similar to the following:

stamp:
  sec: 1638160674
  nanosec: 252424895
level: 20
name: hello_world_node
msg: Hello, world!
file: hello_world_node.cpp
function: HelloWorldNode
line: 8

This is the ros2 message generated by the RCLCPP_INFO(...) command in hello_world_node.cpp! You’ve just transmitted your first ros2 message from a publisher (hello_world_node) to a subscriber (ros2 topic).

You’ll notice that this message contains far more than just the string passed to RCLCPP_INFO(...), it also contains metadata about on which line and in which function the message was generated. This can be very useful both when debugging your own code, or when inspecting errors in code written by others.

Play Around

Now that you’ve been given some tools, play around with different messages and the ros2 node and ros2 topic tools. Note that both of these tools have built-in documentation that you can read by passing the --help argument in the following way:

ros2 topic --help
ros2 topic echo --help

Conclusion

This tutorial has hopefully introduced you to some of the core ros2 concepts like the ros2 environment, ros2 nodes, and distributed logging with rosconsole and the /rosout topic. Additionally, it has hopefully introduced you to how ros2 libraries are installed on a Linux system, which environment variables are needed to use those libraries, and how to set those environment variables with the provided ros2 setup files.

references

  1. The Ubuntu Linux Distribution ↩ ↩2

  2. The Bourne Again Shell ↩

  3. The C++ Programming Language ↩

  4. The GNU Compiler Collection ↩

  5. The VIM Text Editor ↩

  6. ROS Topics ↩

 
Except where otherwise noted, content on this site is licensed under a
Creative Commons Attribution-ShareAlike 3.0 License.
Privacy Policy