#################################### ##FILL ME IN #################################### ## links to any required tutorials ## note.0= [[ROS/Tutorials/ExaminingPublisherSubscriber|examining the simple publisher and subscriber]] ## descriptive title for the tutorial ## title = Writing a Simple Service and Client ## multi-line description to be displayed in search ## description = This tutorial covers how to write a service and client node in C++. ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link= [[roscpp_tutorials/Tutorials/Parameters|Using Parameters in roscpp]] ## next.1.link= ## what level user is this tutorial for ## level= BeginnerCategory #################################### <> <> <> ##startpage == Writing a Service Node == Here we'll create the service ("add_two_ints_server") node which will receive two ints and return the sum. {{{{#!wiki buildsystem rosbuild Change directory into the beginner_tutorials package, you created previously in the [[ROS/Tutorials/CreatingPackage|creating a rosbuild package]] tutorial: {{{ roscd beginner_tutorials }}} }}}} {{{{#!wiki buildsystem catkin Change directories to your beginner_tutorials package you created in your catkin workspace previous tutorials: {{{ roscd beginner_tutorials }}} }}}} Please make sure you have followed the directions in the previous tutorial for creating the service needed in this tutorial, [[ROS/Tutorials/CreatingMsgAndSrv#Creating_a_srv|creating the AddTwoInts.srv]] (be sure to choose the right version of build tool you're using at the top of wiki page in the link). === The Code === Create the src/add_two_ints_server.cpp file within the beginner_tutorials package and paste the following inside it: {{{ #!cplusplus block=service #include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" bool add(beginner_tutorials::AddTwoInts::Request &req, beginner_tutorials::AddTwoInts::Response &res) { res.sum = req.a + req.b; ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b); ROS_INFO("sending back response: [%ld]", (long int)res.sum); return true; } int main(int argc, char **argv) { ros::init(argc, argv, "add_two_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_two_ints", add); ROS_INFO("Ready to add two ints."); ros::spin(); return 0; } }}} === The Code Explained === Now, let's break the code down. <> `beginner_tutorials/AddTwoInts.h` is the header file generated from the srv file that we created earlier. <> This function provides the service for adding two ints, it takes in the request and response type defined in the srv file and returns a boolean. <> Here the two ints are added and stored in the response. Then some information about the request and response are logged. Finally the service returns true when it is complete. <> Here the service is created and advertised over ROS. == Writing the Client Node == === The Code === Create the src/add_two_ints_client.cpp file within the beginner_tutorials package and paste the following inside it: {{{ #!cplusplus block=client #include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" #include int main(int argc, char **argv) { ros::init(argc, argv, "add_two_ints_client"); if (argc != 3) { ROS_INFO("usage: add_two_ints_client X Y"); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient("add_two_ints"); beginner_tutorials::AddTwoInts srv; srv.request.a = atoll(argv[1]); srv.request.b = atoll(argv[2]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_two_ints"); return 1; } return 0; } }}} === The Code Explained === Now, let's break the code down. <> This creates a client for the `add_two_ints` service. The `ros::ServiceClient` object is used to call the service later on. <> Here we instantiate an autogenerated service class, and assign values into its request member. A service class contains two members, `request` and `response`. It also contains two class definitions, `Request` and `Response`. <> This actually calls the service. Since service calls are blocking, it will return once the call is done. If the service call succeeded, `call()` will return true and the value in `srv.response` will be valid. If the call did not succeed, `call()` will return false and the value in `srv.response` will be invalid. {{{{#!wiki buildsystem rosbuild == Building your nodes == Again edit the beginner_tutorials CMakeLists.txt: {{{ $ rosed beginner_tutorials CMakeLists.txt }}} and add the following at the end: {{{ rosbuild_add_executable(add_two_ints_server src/add_two_ints_server.cpp) rosbuild_add_executable(add_two_ints_client src/add_two_ints_client.cpp) }}} This will create two executables, "add_two_ints_server" and "add_two_ints_client", which by default will go into the "bin" directory. For more information on using CMake with ROS, see [[CMakeLists]] Now run make: {{{ $ make }}} }}}} {{{{#!wiki buildsystem catkin == Building your nodes == Again edit the beginner_tutorials CMakeLists.txt located at `~/catkin_ws/src/beginner_tutorials/CMakeLists.txt` and add the following at the end: <> This will create two executables, `add_two_ints_server` and `add_two_ints_client`, which by default will go into package directory of your [[catkin/workspaces#Development_.28Devel.29_Space|devel space]], located by default at `~/catkin_ws/devel/lib/`. You can invoke executables directly or you can use rosrun to invoke them. They are not placed in '/bin' because that would pollute the PATH when installing your package to the system. If you wish for your executable to be on the PATH at installation time, you can setup an install target, see: [[catkin/CMakeLists.txt]] For more detailed description of the [[catkin/CMakeLists.txt|CMakeLists.txt]] file see: [[catkin/CMakeLists.txt]] Now run `catkin_make`: {{{ # In your catkin workspace cd ~/catkin_ws catkin_make }}} }}}} If your build fails for some reason: * make sure you have followed the directions in the previous tutorial: [[ROS/Tutorials/CreatingMsgAndSrv#Creating_a_srv|creating the AddTwoInts.srv]]. {{{#!wiki buildsystem rosbuild * type `rosls beginner_tutorials/srv_gen/cpp/include/beginner_tutorials/` and check that the `.h` file matches the include in the client and server `.cpp` files. }}} == Running the nodes == Running nodes requires you have a ROS core started. Open a new shell, and type: {{{ roscore }}} If all goes well, you should see an output that looks something like this: {{{ ... logging to /u/takayama/.ros/logs/83871c9c-934b-11de-a451- 001d927076eb/roslaunch-ads-31831.log ... loading XML file [/wg/stor1a/rosbuild/shared_installation/ros/tools/roslaunch/roscore.xml] Added core node of type [rosout/rosout] in namespace [/] started roslaunch server http://ads:54367/ SUMMARY ====== NODES changing ROS_MASTER_URI to [http://ads:11311/] for starting master locally starting new master (master configured for auto start) process[master]: started with pid [31874] ROS_MASTER_URI=http://ads:11311/ setting /run_id to 83871c9c-934b-11de-a451-001d927076eb +PARAM [/run_id] by /roslaunch +PARAM [/roslaunch/uris/ads:54367] by /roslaunch process[rosout-1]: started with pid [31889] started core service [/rosout] +SUB [/time] /rosout http://ads:33744/ +SERVICE [/rosout/get_loggers] /rosout http://ads:33744/ +SERVICE [/rosout/set_logger_level] /rosout http://ads:33744/ +PUB [/rosout_agg] /rosout http://ads:33744/ +SUB [/rosout] /rosout http://ads:33744/ }}} Now everything is set to run server and client. === Running the Server === {{{{#!wiki buildsystem catkin Start by running the server. Open a new shell and type: {{{ rosrun beginner_tutorials add_two_ints_server }}} You should see something similar to: {{{ Ready to add two ints. }}} }}}} === Running the Client === {{{{#!wiki buildsystem catkin Now let's run the client with the necessary arguments, in another shell: {{{ $ rosrun beginner_tutorials add_two_ints_client 1 3 }}} In the client's shell, you should see something similar to: {{{ Sum: 4 }}} In the server's shell, instead, you should see something similar to: {{{ request: x=1, y=3 sending back response: [4] }}} }}}} ##endpage '''Next Tutorial:''' [[roscpp_tutorials/Tutorials/Parameters|Using Parameters in roscpp]] ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE