In this post, you will learn how to create and use your own ros2 C++ library. I’ll show you how to create the library and then use it in a demo package.
Step 1: Fire up a system with ROS2 installation
“Hey, do you mean I have to install ros2 first?” Absolutely not! Just log in to The Construct to get access to virtual machines pre-installed with ROS.
Once logged in, click on My Rosjects, then Create a New Rosject, supply the information as shown in the video and click Create. Then RUN the rosject.
You might also want to try this on a local PC if you have ros2 installed. However, please note that we cannot support local PCs and you will have to fix any errors you run into on your own. The rest of the instruction assumes that you are working on The Construct; please adapt them to your local PC and ros2 installation.
Step 2: Create a new package that contains the library’s source code (logic)
Open a web shell and run the following commands to create the package.
cd ros2_ws/src source /opt/ros/humble/setup.bash/ ros2 pkg create my_value_converter_library --build-type ament_cmake --license BSD-3-Clause
Now that your package is created, we need to create a header file for the library. Move inside the include/my_value_converter_library
directory and create a header file named library_header.h
.
cd ~/ros2_ws/src/my_value_converter_library/include/my_value_converter_library touch library_header.h
Now head over to the Code Editor to make changes to the header file. Check the image below for how to open the Code Editor.
Locate the header file in the code editor: ros2_ws > src > my_value_converter_library > include > my_value_converter_library > library_header.h
and paste in the following code.
#ifndef MAP_VALUE_H #define MAP_VALUE_H double map_value(double x, double in_min, double in_max, double out_min, double out_max); #endif
Next, we create the C++ source code file for the library. In the same web shell:
cd ~/ros2_ws/src/my_value_converter_library/src touch my_value_converter_library.cpp
Locate the my_value_converter_library.cpp
file in the code editor and paste in the following code:
#include "my_value_converter_library/library_header.h" double map_value(double x, double in_min, double in_max, double out_min, double out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
Now we need to edit the CMakeLists.txt
file of our package to recognize the source code we have just added. Open the file ros2_ws > src > my_value_converter_library > CMakeLists.txt
and add the following lines before the ament_package()
call.
# let the compiler search for headers in the include folder include_directories(include) # define a library target called my_value_converter_library add_library(my_value_converter_library src/my_value_converter_library.cpp) # this line to exports the library ament_export_targets(my_value_converter_library HAS_LIBRARY_TARGET) # install the include/my_cpp_library directory to the install/include/my_cpp_library install( DIRECTORY include/my_value_converter_library DESTINATION include ) install( TARGETS my_value_converter_library EXPORT my_value_converter_library LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin INCLUDES DESTINATION include )
So much for all the hard work – now is the time to see if it works. Time to compile the code. In the same web shell, run the following commands:
cd ~/ros2_ws colcon build
Success! We have now created our library. Next, we are going to use it!
PS: if your code did not compile correctly, please go over the instructions and ensure you have created the files in the exact locations specified.
Step 3: Create a new package that uses the library you just created
Create the new package in the open shell. Note that my_value_converter_library
is passed as a dependency during the creation of the new package. This will simplify some of the work that needs to be done when modifying the CMakeLists.txt
file.
cd ros2_ws/src ros2 pkg create my_value_converter_node --build-type ament_cmake --license BSD-3-Clause --dependencies rclcpp std_msgs my_value_converter_library
Now verify that the dependencies have been properly added. If the build runs successfully, it is so. If not, please correct the errors before you proceed.
cd ~/ros2_ws colcon build
If you got to this point, great! Now we will create the C++ source code that will use your library.
cd ~/ros2_ws/src/my_value_converter_node/src touch my_value_converter_node.cpp
Now locate the my_value_converter_node.cpp
file in the code editor and paste in the following source code.
#include <memory> #include <string> #include "my_value_converter_library/library_header.h" #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/float32.hpp" class ConverterNode : public rclcpp::Node { public: explicit ConverterNode() : Node("converter_node") { auto callback = [this](const std_msgs::msg::Float32::SharedPtr input_msg) -> void { RCLCPP_DEBUG(this->get_logger(), "I heard: [%f]", input_msg->data); // Use the library // Map an value from 0 - 1023 range to -1.0 to +1.0 range double new_value = map_value(input_msg->data, 0, 1023, -1.0, 1.0); output_msg_ = std::make_unique<std_msgs::msg::Float32>(); output_msg_->data = new_value; RCLCPP_DEBUG(this->get_logger(), "Publishing: '%f'", output_msg_->data); pub_->publish(std::move(output_msg_)); }; sub_ = create_subscription<std_msgs::msg::Float32>("output_topic", 10, callback); // Create a publisher rclcpp::QoS qos(rclcpp::KeepLast(7)); pub_ = this->create_publisher<std_msgs::msg::Float32>("input_topic", qos); } private: std::unique_ptr<std_msgs::msg::Float32> output_msg_; rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr pub_; rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr sub_; }; int main(int argc, char *argv[]) { rclcpp::init(argc, argv); auto node = std::make_shared<ConverterNode>(); RCLCPP_INFO(node->get_logger(), "My value converter node started."); rclcpp::spin(node); rclcpp::shutdown(); return 0; }
As you might have expected, we need to modify the CMakeLists.txt
file for our new package. Locate the ros2_ws > src > my_value_converter_node > CMakeLists.txt
in the code editor and paste in the following code before the ament_package()
call.
# define the binary to be built and identify the source files with with which to build it add_executable(main src/my_value_converter_node.cpp) # tell CMake that the executable "main" depends on the library "my_value_converter_library" ament_target_dependencies(main my_value_converter_library rclcpp std_msgs) # install the executable in the lib folder to make it detectable through setup.bash install(TARGETS main DESTINATION lib/${PROJECT_NAME}/ )
Now build and use your package!
cd ~/ros2_ws colcon build source install/setup.bash ros2 run my_value_converter_node main
Step 4: Check your learning
Do you understand how to create a ros2 C++ library? If you don’t know it yet, please go over the post again, more carefully this time.
(Extra) Step 5: Watch the video to understand how to install a ros2 binary package
Here you go:
Feedback
Did you like this post? Do you have any questions about how to create a ros2 C++ library? Please leave a comment in the comments section below, so we can interact and learn from each other.
If you want to learn about other ROS2 topics, please let us know in the comments area and we will do a video or post about it.
Great tutorial! Thank you!