## For instruction on writing tutorials ## http://www.ros.org/wiki/WritingTutorials #################################### ##FILL ME IN #################################### ## for a custom note with links: ## note = ## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links ## note.0=[[rosjava/Tutorials/indigo/Installation|Installation]] ## note.1=[[rosjava_build_tools/Tutorials/indigo/Creating Rosjava Packages|Creating Rosjava Packages]] ## descriptive title for the tutorial ## title = A RosJava Service Client and Server (Catkin Style) ## multi-line description to be displayed in search ## description = It shows how to create, compile and execute a service (both server and client) in Rosjava. ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link=[[rosjava_build_tools/Tutorials/indigo/Building RosJava Libraries|Building RosJava Libraries]] ## next.1.link= ## what level user is this tutorial for ##level= ## keywords = Rosjava, service #################################### <<IncludeCSTemplate(TutorialCSHeaderTemplate)>> {{{#!wiki solid/blue '''Note:''' Tutorial under development }}} == Creating and Compiling the Custom Service == In this tutorial we will generate the Java artifacts for a custom service inside a standard ROS package, and we will use them afterwards in a Rosjava package. === Creating the Service's package === In order to create a new package into a new Rosjava workspace, we open a terminal and typing the following commands: {{{ mkdir -p ~/rosjava_srv_ws/src cd ~/rosjava_srv_ws/src catkin_create_pkg rosjava_custom_srv message_generation message_runtime std_msgs -V 0.1.0 }}} Then we have to modify the CMakeLists.txt file in order to compile the custom Service Open the CMakeLists.txt from the previously created package and add the following: {{{ find_package(catkin REQUIRED COMPONENTS message_generation message_runtime std_msgs ) add_service_files( DIRECTORY srv ) generate_messages(DEPENDENCIES std_msgs) }}} === Creating the Service === We now create a new folders inside the rosjava_custom_srv package: {{{ cd ~/rosjava_srv_ws/src/rosjava_custom_srv mkdir srv }}} And inside the srv folder we create the CustomService.srv file with the following content: {{{ int32 size --- int64[] res }}} The service above sends as request an integer in order to create an array with this size. The service sends as a response this array which includes a numeric series to the size of the request. For example if the Client sends the number 5 as request, the Server will return the following array: {{{ 0 1 2 3 4 }}} Finally we are able to compile the new service by executing the following in a new terminal: {{{ cd ~/rosjava_srv_ws catkin_make }}} == Creating the RosJava Client/Server == In the workspace we created above, we shall create a Rosjava package and a sub-project where the Service will be embedded. Remember to source your Rosjava installation workspace first to have the command line tools available (e.g. `source ~/rosjava/devel/setup.bash`). Then, execute the following commands from a command line: {{{ cd ~/rosjava_srv_ws/src catkin_create_rosjava_pkg tutorial_custom_srv cd tutorial_custom_srv catkin_create_rosjava_project client_server cd ~/rosjava_srv_ws catkin_make }}} === Add the Service into the rosjava_core package === Open the build.gradle from the `client_server` project (`~/rosjava_srv_ws/src/tutorial_custom_srv/client_server/build.gradle`) and add the following lines as dependencies: {{{ dependencies { compile 'org.ros.rosjava_core:rosjava:[0.3,0.4)' compile 'org.ros.rosjava_messages:rosjava_custom_srv:[0.1, 0.2)' } }}} This way, we will be able to import the custom service into the sub-package. The [0.1, 0.2) from the rosjava_custom_srv is referred to the version of the package (package.xml). Finally in the rosjava_tutorial_custom_services, delete the src and create a new sub-directory with two java files, the `Client.java` and the `Server.java` inside of the rosjava_tutorial_services folder {{{ cd rosjava_srv_ws/src/tutorial_custom_srv/client_server mkdir -p src/main/java/org/ros/rosjava_tutorial_services }}} === Creating the Service/Server === The Server.java file will embed the following code: {{{#!java block=server /* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.ros.rosjava_tutorial_custom_services; import org.ros.namespace.GraphName; import org.ros.node.AbstractNodeMain; import org.ros.node.ConnectedNode; import org.ros.node.NodeMain; import org.ros.node.service.ServiceResponseBuilder; import org.ros.node.service.ServiceServer; import java.io.Console; import rosjava_custom_srv.CustomService; import rosjava_custom_srv.CustomServiceRequest; import rosjava_custom_srv.CustomServiceResponse; /** * A simple {@link ServiceServer} {@link NodeMain}. The original code is created by: * * @author damonkohler@google.com (Damon Kohler) * The custom implementation is created by v.s.moisiadis@gmail.com(Vasileios Moisiadis) */ public class Server extends AbstractNodeMain { @Override public GraphName getDefaultNodeName() { return GraphName.of("rosjava_tutorial_custom_services/server"); } @Override public void onStart(final ConnectedNode connectedNode) { connectedNode.newServiceServer("CustomService", CustomService._TYPE, new ServiceResponseBuilder<CustomServiceRequest, CustomServiceResponse>() { @Override public void build(CustomServiceRequest request, CustomServiceResponse response) { //Create an array with the size of request.getSize() long[] tmpArray=new long[request.getSize()]; for(int i=0; i<request.getSize();i++){ tmpArray[i]=i; } response.setRes(tmpArray); connectedNode.getLog().info( String.format("The size of the array will be "+request.getSize())); } }); } } }}} ==== The Code Explained ==== The only difference with the original implementation is that we have imported our new custom service <<CodeRef(server,26,28)>> Also add the dynamic array creation <<CodeRef(server,51,60)>> === Creating the Service/Client === The Client.java file will embed the following code. {{{#!java block=client /* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.ros.rosjava_tutorial_custom_services; import org.ros.exception.RemoteException; import org.ros.exception.RosRuntimeException; import org.ros.exception.ServiceNotFoundException; import org.ros.namespace.GraphName; import org.ros.node.AbstractNodeMain; import org.ros.node.ConnectedNode; import org.ros.node.NodeMain; import org.ros.node.service.ServiceClient; import org.ros.node.service.ServiceResponseListener; import rosjava_custom_srv.CustomServiceResponse; import rosjava_custom_srv.CustomServiceRequest; import rosjava_custom_srv.CustomService; /** * A simple {@link ServiceClient} {@link NodeMain}. The original code is created by: * * @author damonkohler@google.com (Damon Kohler) * The custom implementation is created by v.s.moisiadis@gmail.com(Vasileios Moisiadis) */ public class Client extends AbstractNodeMain { @Override public GraphName getDefaultNodeName() { return GraphName.of("rosjava_tutorial_custom_custom_services/client"); } @Override public void onStart(final ConnectedNode connectedNode) { ServiceClient<CustomServiceRequest, CustomServiceResponse> serviceClient; try { serviceClient = connectedNode.newServiceClient("CustomService", CustomService._TYPE); } catch (ServiceNotFoundException e) { throw new RosRuntimeException(e); } final CustomServiceRequest request = serviceClient.newMessage(); //set the request/size request.setSize(10); serviceClient.call(request, new ServiceResponseListener<CustomServiceResponse>() { @Override public void onSuccess(CustomServiceResponse response) { connectedNode.getLog().info( String.format("The response is : ")); for (long l : response.getRes()) { connectedNode.getLog().info(l); } } @Override public void onFailure(RemoteException e) { throw new RosRuntimeException(e); } }); } } }}} ==== The Code Explained ==== The only difference at the Service/Client is that we have to set a size to the requested array in order to receive it. <<CodeRef(client,58,58)>> Also we use a for loop to demonstrate the incoming data. <<CodeRef(client,62,69)>> == Running the Service == Before executing the service we have to build it first, and run the Master node. Open a new terminal and type the following commands (remember to source your rosjava installation workspace first!): {{{ cd ~/rosjava_srv_ws catkin_make roscore }}} Then we open two more terminals and we execute separately. For the Server: {{{ cd ~/rosjava_srv_ws source devel/setup.bash rosrun tutorial_custom_srv client_server org.ros.rosjava_tutorial_custom_services.Server # select option 2 when prompted }}} For the Client: {{{ cd ~/rosjava_srv_ws source devel/setup.bash rosrun tutorial_custom_srv client_server org.ros.rosjava_tutorial_custom_services.Client # select option 2 when prompted }}} ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE