Intro
References
- The Robotics Back-End- Write a Minimal ROS2 Cpp Node
- https://turtlebot.github.io/turtlebot4-user-manual/tutorials/first_node_cpp.html#creating-your-first-node-c
Create a ROS2 C++ Package
- If you don’t have a ROS2 C++ package, follow Create a ROS package (C++)
Create a Minimal ROS Node
- Create a
my_cpp_nodenode using the rclcpp API by creating asrc/my_cpp_node.cppfile in the package
my_cpp_node.cpp#include "rclcpp/rclcpp.hpp" int main(int argc, char **argv) { // Initiate ROS2 communication rclcpp::init(argc, argv); // Create shared pointer (of type std::shared_ptr<rclcpp::Node> ) to a new ROS node auto node = std::make_shared<rclcpp::Node>("my_node_name"); // Keep node alive to process callbacks (subscribers, timers, services, etc.) rclcpp::spin(node); // Shutdown ROS2 communication and clean up resources rclcpp::shutdown(); return 0; }
rclcpp::init- Note on Smart Pointer: ROS2 uses std::shared_ptr for most ROS objects like nodes to simplify lifecycle management
Add a ROS2 Executable in CMakeLists.txt
• In, CMakeLists.txt, add the executable and name it my_cpp_node (build the node from source): 1
# executable name source file
add_executable(my_cpp_node src/my_cpp_node.cpp)• Link required ROS2 dependencies (e.g. rclcpp, std_msgs):
ament_target_dependencies(my_cpp_node
rclcpp
std_msgs
)• Install the executable so it can be run using ros2 run:
install(TARGETS my_cpp_node
DESTINATION lib/${PROJECT_NAME}
)
CMakeLists.txtcmake_minimum_required(VERSION 3.8) project(my_package) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() # find dependencies find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) add_executable(my_cpp_node src/my_cpp_node.cpp) ament_target_dependencies(my_cpp_node rclcpp std_msgs ) install(TARGETS my_cpp_node DESTINATION lib/${PROJECT_NAME} ) ament_package()
Build and Run
- From the root of your workspace (
ros2_ws), compile the package
colcon build
# colcon build --packages-select my_package- Source the ROS2 workspace setup script
source install/setup.bash- Run the
my_cpp_nodenode
ros2 run my_package my_cpp_node
my_packageis the package namemy_cpp_nodeis the name of the executable you defined inCMakeLists.txt
Add Functionality
#include "rclcpp/rclcpp.hpp"
std::shared_ptr<rclcpp::Node> node = nullptr;
void timerCallback()
{
RCLCPP_INFO(node->get_logger(), "Test");
}
int main(int argc, char** argv){
// Initialize ROS communications
rclcpp::init(argc, argv);
// Instantiate a node
node = std::make_shared<rclcpp::Node>("my_node_name");
// Write a message
auto timer = node->create_wall_timer(std::chrono::milliseconds(200), timerCallback);
// Keep alive
rclcpp::spin(node);
// Destroy node
rclcpp::shutdown();
return 0;
} ROS2 C++ Node with OOP
#include "rclcpp/rclcpp.hpp"
class MyNode: public rclcpp::Node
{
public:
MyNode() : Node("my_node") {}
private:
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<MyNode>();
RCLCPP_INFO(node->get_logger(), "OOP test");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
Add Functionality
- Make node print “Hello World” at 5 Hz
#include "rclcpp/rclcpp.hpp"
class MyNode : public rclcpp::Node
{
public:
MyNode() : Node("my_node")
{
// timer_ = this->create_wall_timer(std::chrono::milliseconds(200), std::bind(&MyNode::timerCallback, this));
// Use C++11 lambda function instead
timer_ = this->create_wall_timer(
std::chrono::milliseconds(200),
[this]() {
this->timerCallback();
}
);
}
private:
// _timer
void timerCallback()
{
RCLCPP_INFO(this->get_logger(), "Hello World");
}
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared<MyNode>();
rclcpp::spin(node);
rclcpp::shutdown();
}- Used a C++ Lambda Function instead of
std::bindfor the timerCallback



