Raw services are aren't interface with a request response architecture which nodes can use to communicate
with each other.
Service nodes have two parts to them.
You'll have a service client which makes a request and a service server which will process the request
and then send a response back to the client.
In this lecture we will implement our own simple ROS service, which give it an integer number.
We'll return whether or not it is an odd or even number.
To do this, we will create our very own custom ROS service interface.
If we open up a terminal and run the Ross to Interface list command.
We are given a list of interfaces.
If we head over to the services section.
We can see service interface types currently available to us if we run Ross to interface show.
We can see the contents of these particular interfaces.
In this case I will look at the standard services set bool interface.
Here we can see two sections separated by three dashes.
The section above is the request, which in this case is a boolean called data.
Then we see some notes written about it, which are indicated by the pound symbol.
The bottom section is the response, which contains a boolean called success and a string called Message.
We are going to create our very own service interface type, which follows this format.
So I'll go ahead and close my terminal and open up Visual Studio Code.
Since we will be creating a service interface type, we will put it in a folder within our package called
S.
So I'll go ahead and create that now.
Then I'll create a new file in this folder and call it odd even check CRV.
Note that the naming convention for interface files in Ross is Upper Camel case.
All right.
For our odd even check service, I want the request to be an integer so I can use the int 64 message
type here.
And the right is a picture of available types for you to use when creating custom interfaces.
You can find a detailed list of available types in the ROS two tutorials page on interfaces.
All right, now I need to associate this type with a name.
In this case, I will just call it number.
Then I'll create our response, which I signify by using three dashes.
Then we will want a response from the server once it decides if the number is odd or even so, I will
use the string message type and call it decision.
Right.
With that, we have created our custom service file, so let's go ahead and save the file.
And now we need to configure our package so it knows we have custom interface types so it can generate
the code needed to use these custom interfaces within our Python code.
So I'll go ahead and open our package XML file so we can add in some dependencies.
I'll go ahead and put these new dependencies under the meant build tool dependent lines.
These new dependencies will include a build dependency for Ross idle default generators.
Here idle stands for interactive data language.
Then we will need to include the exec dependency ROS idle default runtime so that the interactive data
language code created can be used at node runtime.
Then lastly, we will want to include our newly created interface with our group of other ROS to interfaces,
so we will create a member of group tag which contains ROS idle interface packages.
All right, that's it for the dependencies in our package XML file, so we can go ahead and save it
and head over to our make list text file here.
We will have to include the ROS idle default generators packet.
Then we will have to tell our compiler exactly what new interface files we created that need to have
idle code generated for it.
We do this with the ROS idle generate interfaces function which takes in the name of our package which
is stored in the project name variable, followed by the actual file locations within the package.
In this case we will include the file that is in our CRV folder named Odd even check dot.
Great.
With that, we have set up our package to be able to use this new service interface we created.
You can go ahead and save this file and we'll go ahead and recompile our workspace.
All right.
So that's gone ahead and compiled.
And notice it's taken a bit longer than usual to compile our package.
That's because our package had to generate all the idle code for our custom odd even check service file.
So now I can go ahead and close this head over to terminal and I'll source it.
And now if I run the Ross to Interface list command, we can see a new interface listed for our Utme
rescue package called Odd even check.
We can also use the RAS two interface show command on our service to see the code we just put within
our RV file.
OC.
We created a custom service interface.
Now let's create our python nodes to use it.
The first node we will create will be the server node, which processes the request and sends the response.
So I will create a new file in our scripts folder called service underscore server dot pie.
As usual, I will set the script up to execute our Python three environment and include my ROS client
library functionality.
Then I will import my newly created service, which is called odd even check.
Then to save some time I will copy the contents of our main function and if name equals two main section
of my code from the publisher script we created earlier to initialize and spin our node.
I will go ahead and change the variable names to be service node.
And modify the print statement to say that my odd even check service server is running.
Now let's go ahead and create this odd even check server class above.
As usual, we will reference the node class from our client library and we'll initialize the node as
odd even service server node.
Then I will create a service variable to hold my service, which I can create using the create service
function.
This function takes in three arguments.
The first is my custom service class, which in this case is odd.
Even check.
The second is the name of the service topic name which I will call odd even check.
And the third argument is the name of the callback function that will get executed when a service request
is received.
I will call my callback function determine odd even.
Now let's go ahead and create this determine odd even function below.
This callback function will take in the self variable of our class, the request object of the service
and the response object.
The first thing I will do is create a print statement saying the request was received just so I'm aware
of what is happening when we run this node in terminal, then to check if the number submitted in the
request is odd or even I will use the remainder operator, which is the percent symbol to see what the
remainder of the number is after I divide it by two.
So I'll create an if statement to check if the remainder of the number attribute of the request is zero.
If it is, then I will set the decision attribute of the response to the string.
Even note that the attribute names of the request and response must match the attribute names we defined
in the SRI file.
So the request we have number and for the response we have decision.
So that's why I am calling number here and decision here.
Now if the remainder of the number sent by the request is instead one, then the number is odd.
So I'll set the response position to odd then to make sure we don't get a weird input that does not
meet either of these criteria.
I will have an L statement which sets the response to error just so that you can visualize how this
information is getting processed.
As it goes through this callback.
I'll create two print statements afterward which prints the request and response object.
Then lastly, we will end the callback by returning the response object.
Well, and I just realized I forgot to do one more thing, which was go into our make list text file
and be sure to add this new script within our install directory where we're installing our individual
scripts.
Great with that.
We have created our service server node so we can go ahead and save this file and I'll rebuild my workspace
so we can test this new node.
All right, so I'll open up my terminal.
Clear the screen.
And this terminal environment's already sourced, so I can just go ahead and run our service server
node using the ROS to run command OC.
We see the print statement saying that the odd even check server is running.
Now I can open a new terminal tab and source our workspace and I can list the available services to
make sure our node is running as intended.
Using the RAR to service list Command.
So here we see our odd even check service, which we defined here in our create service call.
And here we have some other things attributed to the service server node, which are related to the
parameters we talked about earlier.
Now, it's also worth noting, since we're using Visual Studio Code in the ROS extension, if we hit
the F one key, it brings up this command panel.
We can type in ROS to see some of the ROS commands available to us in that extension.
One of the most prominent ones are the show Status Command.
So if I go ahead and click on that, it opens up this sidebar right here on the right.
And so this is just helps us a little nice dashboard so we don't have to keep running these types of
commands to see what nodes, topics and services are available to us.
So here we see the same type of information.
If we ran a ROS to node list, so we see the odd even service server node and we don't have any other
topics since we're just running our service and we see our odd even checked service just like we did
in terminal here.
So that's just a little side note, just so that you're aware of it.
It's a little handy feature to interact with my service server node.
I can use the ROS to service call command.
This command takes in the service topic name, which in this case is forward slash, not even check.
Then we point it to the service interface file, which is within our package.
So I can start typing Udemy and if I hit the tab key it'll auto complete the correct service message,
which is our odd-even check.
And then the last parameter will be to include the request arguments.
In this case, my request only has one attribute named number.
So if I start typing and um and then hit the tab key, it all completes to this format.
Here I can simply edit the default zero value to whatever value I want.
In this case, we can try the number five and hit enter.
Here we can see a print statement saying waiting for a service to become available, followed by our
request, which was made, which was the number five.
Then a response was received, which in this case the decision was odd.
We can see how this looked on the service server side.
Here we see we received a request which has number equal to five and we send back our response object,
which has a decision equal to odd.
Great.
We have our service server working as intended.
Now let's work on the client script which will make the request and can process the response.
So I'll go back to VS code.
I'll close the raw to status bar for now and create a new script called Service Client by.
I'll go ahead and copy the contents from our servers server as a baseline.
Then I will change everywhere It says server to client.
And I'll go ahead and delete most of the contents within this order, even check client class.
So all we have so far is our standard main function, which starts up our odd even check client node,
and I'll be sure to change that as well, which comes from this class above.
I'm going to set the script up so it sends a request, processes it, and then stops.
So I will not need to spend the node like we've been doing in all the previous lectures.
So for now, I'll go ahead and delete this spin call and just put in pass for now.
In our class, I will go ahead and create a new client variable and set it equal to the value of the
create client function.
This function takes in two arguments our service interface object and the service topic name.
These will be the same as it was in our server node.
I can also go ahead and initialize our request object, which in this case is done by calling the odd
even check service interface object and calling the request aspect of it.
Now I have an empty, odd even check request message which is ready to be filled with the data and sent
to the service server.
I will do all this in a function I will call send request which will take in the class self attribute
and I will also have it taken the number we want to include in the request.
In this function, the first thing I will do is load the number the user gives into the request.
So I can do this by setting self dot request dot number equal to the integer of the number.
I'm just calling the in function here as a safety net in case the user enters a number that is not an
integer.
Then we will have to wait for the service server to be ready to receive our request.
I can do this using the wait for service method of our client variable.
So you could put a time out here, but we're just going to leave this blank, which means you will continue
to wait until the service is available.
Then once the service server is available, we will send our service call.
We will do this by setting a future variable.
A feature object is a Ross to object which awaits for a Ross server node to reply.
This asynchronous call function takes in the request object.
Since we are using an asynchronous call, we will need to spin our node until a reply is received by
the future object.
We do this by using the ROS client libraries spin until future complete function which takes in the
node and the future variable as parameters.
Since this class is our node, we just put this self as the node argument since we are within it.
Then lastly, we can retrieve the result object from the future variable by calling the result method
of it.
Then we can close out this send request function by returning the result object.
Okay, great.
With that, we have all the functionality we need for our client node.
Now I can go back into our main function where I have the pass statement, and here I will prompt the
user for an integer that they want to check is either odd or even so, I'll create a variable called
user input and use Python's input function to ask them to enter an integer.
I'll then call the client nodes send request method we just finished working on it will return the result
object so I will create a rest variable and set it equal to it and we will use the user input as our
number argument for send request.
Then lastly, to process the result, I'm just going to print it to terminal by saying server returned
and then depending on the decision attribute of our raise variable which will have the result sent by
the server.
Great with that.
We have finished our client node.
We can go ahead and save the file, head over to our make list x file and add this script.
And then save our make list text file and rebuild the project.
All right.
I'll go ahead and close this and I'll head over to our terminal.
And we still have our service server node running.
I'll go ahead and clear this bottom screen.
Now I'll just double check to make sure this terminal is sourced to our setup file.
And then launch our newly created service client pie node.
So here we see.
We get prompted to enter an integer.
I'll just type in 11 in this case and we can hit enter and see.
We get a response from our server saying that the number 11 is odd.
So we'll rerun the client node again and enter six.
And we see that the server responds that six is an even number.
And so we can even see the decisions being processed in the server in this tab above.
All right.
With that, you have successfully implemented services by creating a service server and a service client
node.
And the next lecture, we will take this service functionality to the next level by implementing in
a project where we use image processing over ROS like we might on a robot with a camera.
Now, for now let's review what we learned.
In this lecture, we created our very own service interface and nodes.
We created a custom service file which has a request and response separated by three dashes.
Each has a data type followed by an attribute name.
Then we configured our package XML file to include our Ross idle dependencies and used member of group
to include it with the other Ross two interfaces on our machine.
We configured our make list text file by including the ROS idle default generators package and by specifying
our newly created interface files with ROS idle generate interfaces.
We utilize some terminal commands which allow us to list all available interfaces, lists, all available
service topics, and even interact with the service server.
We then coded our service functionality in Python by first learning how to import our custom service.
Then we created the server node by using the create service function and creating a callback which processes
the requested data and returns back a response.
Lastly, we created a client node using the create client function.
We initialize our service request message, filled it with data, then waited for the service server
to become available.
Once available, we utilize a feature object and the clients call async function to send the request.
We then use the spin until future complete function and afterwards could get back the results from the
future object which acquired the response from the server node.