CodeTheRobot

ROS 2 Lyrical Luth · Lesson 06 of 86

Nodes in C++17

rclcpp::Node, init/spin/shutdown, logging macros and the node graph.

Estimated time · 60–90 min

Learning goals

What you will understand

  • Explain nodes in c++17 in your own words
  • Use it in a small robotics example
  • Verify the result instead of assuming it worked

Understand the idea first

The mental model

A node is a process participant that does one job, such as reading a sensor or planning a path. In C++ it is a class derived from rclcpp::Node; main() calls rclcpp::init, spins the node (the event loop), and calls rclcpp::shutdown. Build with C++17 (set(CMAKE_CXX_STANDARD 17)).

Keep each node small and give it a clear name. Everything the node owns (publishers, timers, parameters) is a member so its lifetime equals the node's. Inspect running nodes with ros2 node list and ros2 node info.

Guided lesson

Work through these steps

  1. 1.

    Source the ROS 2 Lyrical environment in a fresh terminal.

  2. 2.

    Read the nodes in c++17 example and identify what each line does.

  3. 3.

    Build only the affected package, source the workspace overlay, and run the example.

  4. 4.

    Inspect the result from a second terminal with the ros2 CLI or RViz2 and compare it with the expected result.

Worked example

Read it before you run it

#include "rclcpp/rclcpp.hpp"
// The main rclcpp header.
class HelloNode : public rclcpp::Node {
// Our node IS-A rclcpp::Node.
public:
// Public interface.
  HelloNode() : Node("hello_node") {
// The base constructor takes the node name.
    RCLCPP_INFO(get_logger(), "node started");
// Log an INFO message with the node's logger.
  }
// End of the constructor.
};
// End of the class.
int main(int argc, char** argv) {
// Program entry point.
  rclcpp::init(argc, argv);
// Start the client library and parse ROS arguments.
  rclcpp::spin(std::make_shared<HelloNode>());
// Run the node's event loop until Ctrl+C.
  rclcpp::shutdown();
// Release ROS resources.
}
// End of main.

What the example is doing

  1. 1.The ros2 commands query the running graph; they do not prove that a node's internal behavior is correct.
  2. 2.Build from the workspace root, then source install/setup.bash so the shell can discover the new package.
  3. 3.Use a second sourced terminal to inspect nodes and interfaces while the example runs.

Watch it run · Messages between nodes

See what this code does

The terminal types this lesson's practice solution and runs it. The scene shows the kind of robot behaviour that code drives. It plays by itself and loops.

/topicpublishersubscribersubscribermessages delivered: 0MESSAGES BETWEEN NODES

Demo for Nodes in C++17. Expected result: [INFO] [hello_node]: node started

Practice code

Now type it yourself

Copy the starter into your ROS 2 package, replace every TODO, then build with colcon build and run it from a sourced terminal.

// robot_nodes/src/hello_node.cpp
#include "rclcpp/rclcpp.hpp"

class HelloNode : public rclcpp::Node {
 public:
  // TODO: call the Node constructor with the name "hello_node" and log "node started"
};

int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<HelloNode>());
  rclcpp::shutdown();
  return 0;
}

Expected output

[INFO] [hello_node]: node started
Stuck? Show the full solution (try it yourself first)
// robot_nodes/src/hello_node.cpp
#include "rclcpp/rclcpp.hpp"

class HelloNode : public rclcpp::Node {
 public:
  HelloNode() : Node("hello_node") { RCLCPP_INFO(get_logger(), "node started"); }
};

int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<HelloNode>());
  rclcpp::shutdown();
  return 0;
}

Expected result

How you know it worked

  • ROS_DISTRO is lyrical in every terminal used for the exercise.
  • The complete package from the exercise builds and the expected graph entity appears in a second terminal.

Practical exercise

Apply the lesson

Add HelloNode to robot_nodes, register it in CMakeLists.txt with add_executable, ament_target_dependencies and install, then run it and check ros2 node list and ros2 node info /hello_node from a second terminal.

Before you continue

  • ROS_DISTRO reports lyrical in every terminal you used
  • The example builds and runs without errors
  • You checked the result with a ros2 command, RViz2 or a test, not just by reading the code

If something goes wrong

ros2 cannot find a package or executable.

Source /opt/ros/lyrical/setup.bash, build from the workspace root, then source install/setup.bash in that terminal.

Nodes run but cannot discover each other.

Confirm both terminals use Lyrical, the same ROS_DOMAIN_ID, and compatible network/discovery settings.