Great.
We have a service server and we are even able to call it from the terminal.
Now let's create a Python service client so we can actually call this new service from your code directly.
And we will start with a non OOP example that you can use later as a template to test any service quite
quickly.
So here in this lesson we are going to see the mechanisms and the different steps to create a service
client.
Send a request and get the response.
And we're going to create a very simple script that then you can use to test any server.
For example, here you could see that we could call the service from the terminal.
But I told you that it's only going to work for very simple requests.
If you have a more complex request, you will need to write some code.
And so you can use what we do now as a template.
And then in the next video, we will integrate the service client inside an existing node that uses
object oriented programming.
So you can integrate service clients inside any node in your application.
All right let's get started.
So I'm going to just open any terminal.
Let's go to our Python package and let's create a new file add to ins client.
I'm going to name that one no oop.py.
And let's make it executable.
Okay.
So now let's go back to VS.
Code was already open here.
And let's open that one I'm going to use a template.
Yes I'm going to use a template.
But I'm going to modify this.
So here what I'm going to keep is this.
So we're going to import.
So we have the Python three interpreter line.
We're going to import CLP and import the node.
But then I'm going to remove the class okay.
I'm just going to do a simple script with a main function.
So here we're going to initialize Ros to communications.
Then we are going to create a node.
And let's give it a name add to its clients.
No oop.
And then we make the node spin.
Actually no I'm going to remove that line.
So the three lines we keep is the initialization of Rosetta communication.
We create a node.
And at the end we're going to shut it down.
Okay.
So the structure is a bit different than what we've done previously.
Now let's see how to create a client and then send a request.
So I'm going to create a client I'm going to store it in a client variable.
And I'm going to use the node okay that I've created.
So we still need the node I'm going to do node dot.
So in the node in the class you would do self.
But here I name it node.
So that's going to be node in my main function node dot create client okay.
And I need to give of course the service type and the service name.
So if I want to call this service I've created here I need to use the add to hints.
And I also need to use that exact same name.
So I'm going to import from example interfaces dot csv import add to int I provide it here add to int
and then let's make sure we use the same name add to int.
Great.
And that's it.
You just create a client like that.
So the client is not going to do anything.
Then you need to use it to send a request.
Now there is one thing we can do is to first wait for the service to be up.
Because if you try to send a request but the service is not up.
So basically the node containing the service is not running, then you're going to get an error.
So what we can do and that's a common structure we can do while not client wait for service.
So you have the wait for service method inside the client.
And we can give a timeout of one second for example.
And then do a print.
So node dot get logger.
And this time, well, instead of info, I'm going to use one.
Okay.
Because that's more like a warning message.
The server is not up and we can say waiting for server waiting for for example add to insert server.
So what's going to happen is this is going to wait for the service indefinitely.
But you can also provide a timeout.
So it's going to return after one second.
If the service is not found it's going to return false.
And so you put a not.
And so basically as long as the service is not found we say waiting for the server.
And then we keep waiting.
Then when the service is found we're going to go out of the loop because this is going to return true.
Okay.
We can already test this code just to make sure that we can create a client and we can find the service
server.
So I'm going to save that and I'm going to create a new executable here comma.
And then let's name it add to insert client.
No.
OOP.
So it starts to be quite long.
My pi pkg and then add to int client.
No.
OOP.
And that's the main function.
It's always the main function here.
The main.
So we call the main function.
Okay.
Let's save that.
All right.
So what's going to happen very simply is that we initialize rose to communications.
We create a node.
Then we create a client inside the node.
And we just wait for the service.
Let's build.
Let's go back to the Ros2 workspace Qualcomm build packages.
Select with my pi pkg E.g. and let's use Simulink install so we don't need to build again to modify
this code.
Okay.
And then I'm just gonna stop the terminals here, open new ones so everything is correctly sourced.
And let's start here.
The node we have just created Ros to run my pi pkg add to mint client.
No OOP.
Let's run that.
And you can see waiting for the server because the server is not up.
Now here I'm going to run Ros to run with my Pi pkg add to its server.
And you see add to server has been started.
And then you see we return here.
So what does it mean.
It means that it's currently working on the client side.
We create a client.
And then as long as the server is not up we are waiting for the server.
Now, look, if I start the service client again, it's going to return immediately because the service
server is already running.
Okay.
So this mechanism here is just in case.
It's like a safety.
So if you start both nodes around the same time, but if the client is up before the server then you
make sure that you wait for the server.
Okay.
Good.
So now we have created our client.
And at this point of the execution here, we know that the service server has been found.
So what we can do is we can create a request and send that request.
Let's create a request.
So we do request is equal to add to int dot request okay.
So it's basically like creating a message.
You create a request and then you do request dot a.
So y dot a.
Because if you remember in this interface we have a and B as the request and then some as the response.
Let's say three.
So let's give some number here.
Request dot b is equal to eight.
So the sum should be 11.
And then we are going to use this request with the client to send where to send the request.
How do we do this.
We are going to do client dot.
And then we have call and call async.
So call is going to be synchronous call.
But it's not recommended because you might end up in a deadlock situation.
Okay.
It's going to block the execution.
And then actually to get the response you need to have the node that's spinning.
But if you block here the node is not going to be spinning.
Well that's a bit more complex for you to understand right now.
But basically if you write call here just like that, you might have some issues and you may never get
the response.
So we are going to do a call async, which means that we are going to call.
So to send the request.
And then that's going to return.
And we need to do something else to get the response, and we send the request here.
Request.
So client dot call async with the request.
This is going to return a future.
Object.
Okay.
No need to really understand future objects in Python.
Just need to.
Know that it's a future.
So it's something that's going to return in the future.
And then what I'm going to do here is I'm going to make the node spin until the future is complete.
For that I can do CLP dot spin until future complete.
So you see we are now using the normal spin.
We are using a different spin.
And I put the node that's the one we've created here.
And I put the future that we have here.
All right.
So very basically put you send a request and then you just say spin the node until we receive a response.
And in this case the future is going to get the result.
And after that well we can do response is equal to future dot result.
And that's going to be the response of the service okay.
And let's do a log.
So we're going to use the node here node dot get logger with info.
And let's just print a plus B is equal to sum.
Actually I think I've done it here already.
Yes you can just get this okay.
So we don't need to rewrite.
Everything is one more parenthesis.
Okay.
So we just print the request a plus.
The request b is equal to the response dot sum.
And that's going to be pretty much it.
So let's do a quick recap.
First we initialize roster communication.
We create a node.
Then we create a client.
We wait for the service to be up.
We create a request.
We send that request.
We make the node spin until the future is complete, which means that we got the response from the server,
and then we just get the response using the future object.
And we can just print or do whatever we want with this response.
And finally we shut down Rosta communications and everything is going to be shut down.
So let's save that and let's go back here.
I don't need to build again because we've used the Simulink install.
So the server is running okay.
We haven't touched anything in the server.
So let's keep it that way and let's run that again.
And you see now we have here a log on the server side and a log on the client side, which means that
the communication was successfully done.
All right.
So now you have seen what are the different steps that you need to implement as a client.
So to send a request and get a response.
And this here this no OOP script I've written it like this because it's going to be quite useful for
you.
Let's say you have created a service server and the request is a bit complex.
So you have created the server, but you want to quickly test it and you cannot really do a ros2 service
call from the terminal because it's going to be a mess.
And it's hard to build the request from the terminal.
Well, you can just use that.
You use that, you create a client, you just change the interface, the name, and then you create
the request.
Well, you fill the request with whatever you need, okay.
And then basically it's the same thing.
This line is the same.
That line is the same, that line is the same.
And then you just well, you just print something else if you want, okay.
But basically you can use that as also a template for you to test any service server that you have created.
And not only that, but if you have written a service server in Python or in C plus.
Plus as you know that Ros is language agnostic, you can use this Python script here to test even a
C plus plus service server.