Please make sure you follow that post first since the client we will create here will call that server.
Creating the ROS Action Client
If you followed the post on how to create an Action Server, we should have the following output after running the tree . command on the ~/catkin_ws/srcfolder.
As you can see we have a scripts folder with our action_server.py there. We will create our action_client.py in the same folder. Let’s use the commands below for that:
cd ~/catkin_ws/src/actions_tutorial/scripts/
touch action_client.py
chmod +x action_client.py
With the code above we created an empty python file and gave it execute permissions. With the tree ~/catkin_ws/src command you should have something like:
Now let’s paste the following code on the action_client.py file:
#! /usr/bin/env python
import rospy
import actionlib
from actions_tutorial.msg import WashTheDishesAction, WashTheDishesGoal
def feedback_cb(msg):
print 'Feedback received:', msg
def call_server():
client = actionlib.SimpleActionClient('wash_dishes_as', WashTheDishesAction)
client.wait_for_server()
goal = WashTheDishesGoal()
goal.number_of_minutes = 7
client.send_goal(goal, feedback_cb=feedback_cb)
client.wait_for_result()
result = client.get_result()
return result
if __name__ == '__main__':
try:
rospy.init_node('action_client')
result = call_server()
print 'The result is:', result
except rospy.ROSInterruptException as e:
print 'Something went wrong:', e
In this file what we do is basically call the Action Server defined in the previous post and print the feedback and the result messages sent by the server.
Running the ROS Action Client
With everything in place, let’s now launch our server and our client and see they work together. To launch the server we can use the command below:
So, congratulations, you now know how to create an Action Server as well as an Action Client.
To make your life easier, we have also prepared a video showing all the process explained in this post.
I hope you have enjoyed the post and the video, if so, please consider giving us a thumbs up. You can also subscribe to our channel and press the bell so that you won’t miss our updates.
We love feedback, so, whether you like the video or not, please share your thoughts on the comments section of the video.
In this post, we will see what a ROS Action is. We’ll also see the difference between a ROS Service and a ROS Action.
Let’s go!
Step 1: Understand blocking and non-blocking activities: two possible ways to buy Pizza
Let’s assume you wish to order some pizza. There are two possible ways you could go about it:
Go the Pizza shop
Place your order.
Wait for the order.
Get the Pizza.
Order online.
Place your order.
Order confirmation notice.
Possibly cancel the order.
Check up your order status once in a while.
Do other things.
Pizza is delivered.
Option 1 is a blocking activity because you have to wait (in theory not able to do anything else) for the pizza, while option 2 is non-blocking because you can do some other things while your order is being processed.
Step 2: Apply blocking and non-blocking concept to ROS
Option 1 (Going to Pizza shop) is similar to a ROS Service, while option 2 is similar to a ROS Action. Not 100% the same, but I suppose you get the point. But what is a ROS Action specifically, in ROS terminology?
An action is an asynchronous call to another node’s functionality. “Asynchronous” means you don’t have to wait for the result. You can do other things pending the result.
The node that provides the functionality has to implement an Action Server (Pizza shop). The node that uses the functionality has to use an Action Client (online ordering system).
Step 3: Dive a bit deeper – ROSified pizza ordering
Now, let’s see what ROS calls each of the steps for buying pizza:
Go the Pizza shop
Place your order (request).
Wait for the order.
Get the Pizza (response).
Order online
Place your order (request).
Order confirmation notice (feedback).
Possibly cancel the order (cancel).
Check up your order status once in a while (status).
Do other things.
Pizza is delivered (response).
To wrap up, consider the image below, saying roughly saying the same thing we have been saying, only in a “thousand words”:
Extra: Video
Prefer to listen to the “sights and sounds” version of this post? We have one for you below; happy watching!
Further Learning
If you are a ROS beginner and want to learn ROS basics fast, we recommend you take any of the following courses on Robot Ignite Academy:
In today’s video we are going learn how to create a ROS Action Server.
The commands used in this video can be typed on your own computer if you already has ROS installed, but to make things easier, I’ll use Robot Ignite Academy, which is the best tool if you want to Learn ROS Really Fast.
Before we start, if you are new to ROS, I highly recommend you taking any of the following courses on Robot Ignite Academy:
When creating an Action Server you can use existing Action Messages, but since we are here to learn, we are going to create and use our own ROS Messages. We already have a post (https://www.theconstruct.ai/ros-5-mins-032-compile-ros-action-messages/) showing how to create your own ROS Messages and compile them. Please refer to it before proceeding in this post, since we will use the package and messages created there.
Creating the ROS Action Server
If you followed the post aforementioned on how to create your own ROS Messages, with the tree . command on the ~/catkin_ws/src folder you should have a package called actions_tutorial with the WashTheDishes.action action message, something like the output below:
In order to create the action server, let’s create a folder called scripts on our actions_tutorial package. On the scripts folder let’s create a file called action_server.py and make it executable. Let’s use the commands below to accomplish that:
cd ~/catkin_ws/src/actions_tutorial
mkdir scripts
cd scripts/
touch action_server.py
chmod +x action_server.py
Let’s insert the code below on our action_server.pyand see what it really does:
#! /usr/bin/env python
import rospy
import actionlib
from actions_tutorial.msg import WashTheDishesAction, WashTheDishesFeedback, WashTheDishesResult
class ActionServer():
def __init__(self):
self.a_server = actionlib.SimpleActionServer(
"wash_dishes_as", WashTheDishesAction, execute_cb=self.execute_cb, auto_start=False)
self.a_server.start()
def execute_cb(self, goal):
success = True
last_dish_washed = ''
feedback = WashTheDishesFeedback()
result = WashTheDishesResult()
rate = rospy.Rate(1)
for i in range(0, goal.number_of_minutes):
if self.a_server.is_preempt_requested():
self.a_server.set_preempted()
success = False
break
last_dish_washed = 'bowl-' + str(i)
feedback.last_dish_washed = last_dish_washed
result.dishes_washed.append(last_dish_washed)
self.a_server.publish_feedback(feedback)
rate.sleep()
if success:
self.a_server.set_succeeded(result)
if __name__ == "__main__":
rospy.init_node("action_server")
s = ActionServer()
rospy.spin()
In the first line, we tell Linux that our code is executed with Python. We then import rospy because we are creating our ROS program using python. Additionally, we import actionlib because it is necessary to create our ROS Action Server. Lastly, we import our own Action Messages that will allow our robot to “wash the dishes”.
Here we create our action server class, which we called ActionServer. We then have our default constructor where we define our a_server, which is an instance of actionlib.SimpleActionServer. The first parameter is the name of our server once it is running (we called wash_dishes_as), the second parameter is the specification of our action, in this case, WashTheDishesAction. The execute_cb parameter defines the function that will be executed once a client calls our server.
Now let’s dive into the execute_cb method:
def execute_cb(self, goal):
success = True
last_dish_washed = ''
feedback = WashTheDishesFeedback()
result = WashTheDishesResult()
rate = rospy.Rate(1)
for i in range(0, goal.number_of_minutes):
if self.a_server.is_preempt_requested():
self.a_server.set_preempted()
success = False
break
last_dish_washed = 'bowl-' + str(i)
feedback.last_dish_washed = last_dish_washed
result.dishes_washed.append(last_dish_washed)
self.a_server.publish_feedback(feedback)
rate.sleep()
if success:
self.a_server.set_succeeded(result)
Once the action server is called, our execute_cb method is executed with the goal provided by the user. In the first lines, we basically define the variables we are going to use.
Our action is supposed to wash dishes for the number of minutes provided by the user on the goal.number_of_minutes parameter, but since we are not really washing dishes, we are basically iterating on that number and sending a feedback message to the user.
A ROS Action normally takes a long time to finish, so the user can change his mind and cancel it at any time. We check if this is the case with if self.a_server.is_preempt_requested(): . If so, we break the loop and our server finishes its work.
If the user didn’t cancel, we keep doing our job, which will be washing dishes. We fill the feedback and resultvariables with the last dish washed. If you remember the post mentioned at the beginning, we see that our action has int32 number_of_minutes as the goal, string last_dish_washed as the feedback and string[] dishes_washed as a result.
Once the robot worked the for the time asked on the goal.number_of_minutesparameter, we just send the result to the user with self.a_server.set_succeeded(result).
The last part of the code (shown below) we basically instantiate our ROS Node as well as the Action Server. We call ros.spin() to keep our program running forever, until someone kills it with ctrl+c .
if __name__ == "__main__":
rospy.init_node("action_server")
s = ActionServer()
rospy.spin()
Awesome, we now have everything in place. Let’s now run our server and send it a goal.
Running the ROS Action Server
To launch our server, the messages need to be compiled. If you missed this step when creating your message, you can just do it with the commands below:
cd ~/catkin_ws/
catkin_make
If everything went ok, you should have a message at the end saying [100%] Built target actions_tutorial_generate_messages.
With the messages compiled, we need to source our catkin_ws just to make sure ROS can find our compiled messages. We will do that on the same shell (terminal) used to launch our server.
If no error message is shown, our service is running. We can confirm that by running the command rosnode list | grep server which should output /action_server, since is the name we defined on our default constructor.
We can confirm that our node is providing the wash the dishes service with rosnode info /action_server, which should output something like:
We see that our node publishes feedback, status and result. If we subscribe to the feedback topic we will see the feedback messages published when the user sends a goal. Let’s subscribe with the following command in a different shell: rostopic echo /wash_dishes_as/feedback
We can also see the result once the action is finished by subscribing to the result topic in a different shell. Let’s do it with the next command: rostopic echo /wash_dishes_as/result
With everything in place, we can now send our goal. With the rostopic info /action_server aforementioned, we see that our node is subscribed to the /wash_dishes_as/goal topic. This is exactly the topic we use to send goals.
In order to send a goal we can publish on that topic with rostopic pub /wash_dishes_as/goal TAB+TAB+TAB
By pressing TAB+TAB ROS automatically completes the type of the message as well as its fields. If everything goes ok you should have something like the output below:
You can see that in the last line we have number_of_minutes: 0. With the left arrow key you can reach that field and change its value. Let’s change it to 5 and after the " we write --once to publish the message only once. After that we press enter. To make sure we are doing right, before pressing enter we should have something like:
You will see nothing on the shell you execute this command, but if you go to the shell were you executedrostopic echo /wash_dishes_as/feedback, you should see 5 feedback messages saying that the dishes are being washed.
Also, if you go to the shell where you typed rostopic echo /wash_dishes_as/result, you should see the result message, like the one below:
user:~$ rostopic echo /wash_dishes_as/result
WARNING: no messages received and simulated time is active.
Is /clock being published?
header:
seq: 2
stamp:
secs: 4155
nsecs: 895000000
frame_id: ''
status:
goal_id:
stamp:
secs: 4150
nsecs: 891000000
id: "/action_server-2-4150.891000000"
status: 3
text: ''
result:
dishes_washed: [bowl-0, bowl-1, bowl-2, bowl-3, bowl-4]
---
Note that on the last line we have the name of the dishes washed: dishes_washed: [bowl-0, bowl-1, bowl-2, bowl-3, bowl-4]
A video to make your life easier
Congratulations. You now have an action server fully operational. If you liked the post, great, but if you want also to watch a video showing all the process described in this post, we have it here:
To conclude, if you liked the video, please give us a thumbs up on YouTube. Additionally, should you have any feedback messages, please leave them on the comments section of the video. You can also subscribe to our youtube channel and press the bell to be notified about the videos we publish every day.
In today’s tutorial we are going learn how to create a ROS Action specification file, how to compile ROS Action messages and how to import them.
You can run the commands used along the video in your own computer if you have ROS installed, but you can also use Robot Ignite Academy in case you don’t want to deal with ROS installation. Robot Ignite Academy, by the way, is the best tool if you want to Learn ROS Fast.
Before we start, if you are new to ROS and want complete courses on that subject, I highly recommend you taking any of the following courses on Robot Ignite Academy:
In order to create our custom ROS Action we need a package on the catkin_ws (catkin workspace), so let’s create one called actions_tutorial using the commands below:
Ok, so far so good. We now have package called actions_tutorial, now let’s move to the next step.
Creating a ROS Action file
Let’s suppose our robot is able to wash dishes, so, let’s create an action file called WashTheDishes.action and place it inside a folder called action which will be on the package we just created.
cd ~/catkin_ws/src/actions_tutorial
mkdir action
cd action/
touch WashTheDishes.action
Now let’s put some content on that WashTheDishes.action file. Please use the content below:
If you look carefully on the content of the WashTheDishes.action file you can find 3 sections. Goal, Result and Feedback. Goal is what we send to the Action Server, which in this case will be the number_of_minutes that our robot need to work, the Result is the list named dishes_washed that we will receive once the robot finishes working. Given that an action can take a long time depending on the goal parameter, we have a Feedback section that we will receive whenever the robot finishes washing a dish. The feedback in this case we named last_dish_washed.
Now let’s go to the next step
Compiling a ROS Action file
On our actions_tutorial package you have a file called CMakeLists.txt that is created automatically when we create a package. That file is used to compile our package. If we look at that file you can see some instructions on how to modify it to compile our own messages. The instructions on that file says that we have to modifly the package.xmlfile that is located inside our package folder and add message_generation and message_runtime on that file. To make it easier, below we have the full content of the package.xml after the modifications.
<?xml version="1.0"?>
<package format="2">
<name>actions_tutorial</name>
<version>0.0.0</version>
<description>The actions_tutorial package</description>
<!-- One maintainer tag required, multiple allowed, one person per tag -->
<!-- Example: -->
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
<maintainer email="user@todo.todo">user</maintainer>
<!-- One license tag required, multiple allowed, one license per tag -->
<!-- Commonly used license strings: -->
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
<license>TODO</license>
<!-- Use build_depend for packages you need at compile time: -->
<build_depend>message_generation</build_depend>
<!-- Use exec_depend for packages you need at runtime: -->
<exec_depend>message_runtime</exec_depend>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>actionlib_msgs</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_export_depend>actionlib_msgs</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>actionlib_msgs</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<!-- The export tag contains other, unspecified, tags -->
<export>
<!-- Other tools can request additional information be placed here -->
</export>
</package>
The CMakeLists.txt also says that we have to modify that file itself by doing the following:
Add message_generation to thefind_package() section
Add message_runtime to the catkin_package section
Add WashTheDishes.action to the add_action_files section
Uncomment the generate_messages section.
To make your life easier, below we have t he full content of that actions_tutorial/CMakeLists.txt file after our modifications:
cmake_minimum_required(VERSION 2.8.3)
project(actions_tutorial)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
actionlib_msgs
rospy
std_msgs
message_generation
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
add_action_files(
FILES
WashTheDishes.action
)
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
actionlib_msgs# std_msgs
)
################################################
## Declare ROS dynamic reconfigure parameters ##
################################################
## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed
## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
LIBRARIES actions_tutorial
CATKIN_DEPENDS actionlib_msgs rospy std_msgs
DEPENDS system_lib
DEPENDS message_runtime
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/actions_tutorial.cpp
# )
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/actions_tutorial_node.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# install(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables and/or libraries for installation
# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )
## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_actions_tutorial.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
Ok, now that we have our CMakeLists.txt and package.xml files modified, we can compile our message using the commands below:
cd ~/catkin_ws/
catkin_make
If everything goes ok, at the end you should see a message saying that your package has been 100% compiled:
user:~/catkin_ws$ catkin_make
Base path: /home/user/catkin_ws
Source space: /home/user/catkin_ws/src
Build space: /home/user/catkin_ws/build
Devel space: /home/user/catkin_ws/devel
Install space: /home/user/catkin_ws/install
####
#### Running command: "make cmake_check_build_system" in "/home/user/catkin_ws/build"
####
-- Using CATKIN_DEVEL_PREFIX: /home/user/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/kinetic
-- This workspace overlays: /opt/ros/kinetic
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Using CATKIN_ENABLE_TESTING: ON
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/user/catkin_ws/build/test_results
-- Found gmock sources under '/usr/src/gmock': gmock will be built
-- Found gtest sources under '/usr/src/gmock': gtests will be built
-- Using Python nosetests: /usr/local/bin/nosetests-2.7
-- catkin 0.7.14
-- BUILD_SHARED_LIBS is on
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~ traversing 1 packages in topological order:
-- ~~ - actions_tutorial
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'actions_tutorial'
-- ==> add_subdirectory(actions_tutorial)
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
-- Generating .msg files for action actions_tutorial/WashTheDishes /home/user/catkin_ws/src/actions_tutorial/action/WashTheDishes.action
-- actions_tutorial: 7 messages, 0 services
CMake Warning at /opt/ros/kinetic/share/catkin/cmake/catkin_package.cmake:166 (message):
catkin_package() DEPENDS on 'system_lib' but neither
'system_lib_INCLUDE_DIRS' nor 'system_lib_LIBRARIES' is defined.
Call Stack (most recent call first):
/opt/ros/kinetic/share/catkin/cmake/catkin_package.cmake:102 (_catkin_package)
actions_tutorial/CMakeLists.txt:105 (catkin_package)
...
Scanning dependencies of target actions_tutorial_generate_messages_cpp
[ 83%] Generating C++ code from actions_tutorial/WashTheDishesFeedback.msg
[ 86%] Generating C++ code from actions_tutorial/WashTheDishesGoal.msg
[ 89%] Generating C++ code from actions_tutorial/WashTheDishesActionResult.msg
[ 91%] Generating C++ code from actions_tutorial/WashTheDishesAction.msg
[ 94%] Generating C++ code from actions_tutorial/WashTheDishesResult.msg
[ 97%] Generating C++ code from actions_tutorial/WashTheDishesActionGoal.msg
[100%] Generating C++ code from actions_tutorial/WashTheDishesActionFeedback.msg
[100%] Built target actions_tutorial_generate_messages_cpp
Scanning dependencies of target actions_tutorial_generate_messages
[100%] Built target actions_tutorial_generate_messages
Once our package is successfully compiled, we have to source our catkin_ws in order to let ROS know how to locate our custom action. Let’s do it with the command below:
source ~/catkin_ws/devel/setup.bash
Ok, so far we have seen how to create and how to compile our custom action. Now let’s import it to make sure it has been successfully compiled. An easy way to do that is by running the command below:
python -c 'from actions_tutorial.msg import WashTheDishesAction; print "Hey, it worked!!!"'
After running the command I just mentioned you should be able to see the message “Hey, it worked!!!”.
This messages confirms that our message was successfully compiled and imported.
You can also use rosmsg list | grep Dishes to find your message. The output should be something like:
We are constantly adding new tutorials here and videos in our YouTube channel. If you like the content, please consider subscribing to our channel on YouTube, giving us a thumbs up there and even leaving comments on the comments section of the video.
By the way, below we have a video that shows the content of this post:
Step 1. Create a project in ROS Development Studio(ROSDS)
ROSDS helps you follow our tutorial in a fast pace without dealing without setting up an environment locally. If you haven’t had an account yet, you can create a free account here. Let’s create a new project and call it testing_action.
Step 2. Create package
At first, let’s create the package with dependencies
cd ~/catkin_ws/src
catkin_create_pkg test_action roscpp actionlib actionlib_msgs robot_calibration_msgs
Then we create a file called action_code.cpp under test_action/src folder with the following content from the question