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.
Source the ROS 2 Lyrical environment in a fresh terminal.
- 2.
Read the nodes in c++17 example and identify what each line does.
- 3.
Build only the affected package, source the workspace overlay, and run the example.
- 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.The ros2 commands query the running graph; they do not prove that a node's internal behavior is correct.
- 2.Build from the workspace root, then source install/setup.bash so the shell can discover the new package.
- 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.
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 startedStuck? 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
Source /opt/ros/lyrical/setup.bash, build from the workspace root, then source install/setup.bash in that terminal.
Confirm both terminals use Lyrical, the same ROS_DOMAIN_ID, and compatible network/discovery settings.