Creating ROS2 Action in C++
Below are the steps to create a ROS2 action. Notice that we are going to have two packages involved: 1) a package called “my_package” which contains the action file, and 2) a package called “action_nodes_cpp” which contains the action server and client nodes. Separating the package which contains the action file(s) like this, in general, is a good practice.
Step 1: Creating an action file.
Create a folder called “action” (if you still don’t have it) inside a package folder called “my_package”. And then make the action file (.action) called “ActionFile.action”. For example, if the action is to compute Fibonacci numbers, you may call it “Fibonacci.action” which looks like below:
1 2 3 4 5 6 7 8 |
#goal definition int32 order --- #result definition int32[] sequence --- #feedback int32[] partial_sequence |
The lines of three dashes above separate between the request variable(s), the result variable(s), and the feedback variable(s).
Step 2: Add the following in package.xml
1 2 3 |
<buildtool_depend>rosidl_default_generators</buildtool_depend> <depend>action_msgs</depend> <member_of_group>rosidl_interface_packages</member_of_group> |
Step 3: Add the following in CMakeLists.txt, before ament_package().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
find_package(rosidl_default_generators REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "action/ActionFile.action") add_library(action_server SHARED src/my_action_server.cpp) target_include_directories(action_server PRIVATE &<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> &<INSTALL_INTERFACE:include>) target_compile_definitions(action_server PRIVATE "ACTION_NODES_CPP_BUILDING_DLL") ament_target_dependencies(action_server "my_package" "rclcpp" "rclcpp_action" "rclcpp_components") rclcpp_components_register_node(action_server PLUGIN "action_nodes_cpp::MyActionServer" EXECUTABLE my_action_server) install(TARGETS action_server ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) add_library(action_client SHARED src/my_action_client.cpp) target_include_directories(action_client PRIVATE &<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> &<INSTALL_INTERFACE:include>) target_compile_definitions(action_client PRIVATE "ACTION_NODES_CPP_BUILDING_DLL") ament_target_dependencies(action_client "my_package" "rclcpp" "rclcpp_action" "rclcpp_components") rclcpp_components_register_node(action_client PLUGIN "action_nodes_cpp::MyActionClient" EXECUTABLE my_action_client) install(TARGETS action_client ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) |
Step 4: Write the “action_server” node.
Write the action_server node in a file namely “my_action_server.cpp”, inside “src” folder of the package.
Step 5: Write the “action_client” node.
Write the action_client node in a file namely “my_action_client.cpp”, inside “src” folder of the package.
Example of action_server and action_client nodes in C++ can be found here: https://docs.ros.org/en/foxy/Tutorials/Actions/Writing-a-Cpp-Action-Server-Client.html#actionscpp
Step 6: Build the package by using “colcon build” command.
Running the action
Type the following in the terminal to run the “action_server” node:
1 |
ros2 run action_nodes_cpp my_action_server |
Type the following in the terminal to run the “action_client” node:
1 |
ros2 run action_nodes_cpp my_action_client |
To show the stream of the action feedback:
1 |
ros2 topic echo /action_name/feedback |
Official documentation: