And now let's integrate this service client inside a node that uses OOP.
That first example here was great to start working with service clients.
And you can use this exact code as a template whenever you want to quickly test a service server that
you have just written.
Now as you can see, if we want to add this inside a node that uses object oriented programming, well,
if I come back to the template, you see we make the node spin okay.
And in this script we have a spin until future complete.
So if we use that we are basically going to make a node spin while it is already spinning.
And that can lead to very weird behaviors.
So we are not going to use that.
And I'm going to show you how to solve that challenge right now.
So let's create a new file okay.
Let's go back to Ros2 workspace Source Python package.
And let's create a add.
to its client.
So this one is just going to be the add to its client.
Okay.
With the normal OOP node dot p y.
And let's make it executable.
Add to its client dot p y.
Okay let's take the template.
And let's go to the client.
And let's use this template this time.
And let's call it add to int client.
Okay.
And add to int client.
Let's remove those and remove the column here.
Okay.
So first things first before we even create the service client we need to import the interface.
And the interface is going to be the same okay.
From the server.
a sort from example interfaces dot csv import add to ints.
Okay, we have that interface.
And now what I'm going to do is I'm going to do the first step which is to create a service client.
I'm going to do that in the constructor self dot.
Let's name it client is equal to self create client with add to int and add two ints okay.
So that's the same thing.
Here we provide the type and the name.
Make sure it's the same.
But this time you see we use self because we are directly inside the node class.
So this is a node we can use self and we store that as an attribute of the class.
Then what I will do is I will create a method that we will use to call the service to send the request.
Let's name this call Add two ints, for example.
So call and then the name of the service self.
And let's say we are going to give a and b okay.
So to match the a and b in the request.
And in this method what I will do is well before I send the request, I will first make sure that you
see the service is up.
So I can just take that line here and use it right here.
And let's put the correct indentation.
And you see we need to replace stuff.
So it's not client it's self client.
That's the one we've created here.
And the node is not just node it's self all right.
But the code stays the same.
So we create the client here in the constructor.
And then in this method that we're going to call later we first wait for the service.
We make sure that it's up.
After that we can create a request.
So to create a request well we use the same code.
So I'm just going to take that code here and put it there.
Okay.
We create a request which is an add to insert request.
And we give some numbers request a and request dot b.
The next step is to send the request how to send the request.
We do self client call async with the request.
Okay so nothing new here.
That's the same thing we did.
And this is going to give us a future.
So we save it as a future.
And then this is the big difference.
We are not going to do a spin inside the spin.
We are not going to spin while we are spinning.
What I'm going to do is I'm going to do future dot add done callback.
You see we have add done callback and I will create a callback function that will be called when the
client receives the response, okay.
And that's going to work because the node is spinning.
So if the node is spinning, we can execute all of the callbacks for this node including that one.
So let's do callback call add to insert for example.
That's the callback for this method here.
What do we receive.
So we have self and then we receive future.
All right so you can register I'm just going to put.
So I'm going to put pass.
If you don't know pass.
It just means you don't want to do anything in a function.
So here just useful.
So we don't have an errors in VS code.
For now I'm going to do future dot add done callback and I'm going to provide self callback call add
to ints.
All right.
So here I wait for the service.
I create the request.
I send the request asynchronously.
And then I add a callback for when we get the response.
So when we get the response we go to this code.
And we can do response is equal to future dot result.
And then we can do uh, not print but self getlogger for example.info let's say got response.
It's going to be the same plus.
So let's cast as a string response dot sum okay.
We get the response object inside the response object we have the sum.
All right.
And now there's just one thing that's missing.
Because if we start this node well we're going to start the client.
But then no request is going to be sent because we don't call this function.
So what I'm going to do in the main I'm going to create the node.
So it's going to create the client.
And then I'm going to do node dot call add to ints.
I'm going to call this function right away with.
So let's say actually here I put three and eight.
But it's going to be A and B.
Those are the parameters that I get from the method here.
Let's say two and seven.
And so what's going to happen here when we create the node it's going to create the client then.
Well you could call that from anywhere.
But here we don't have other callbacks for now.
So I'm just calling it here.
So that's going to wait for the service.
Create a request, send a request and then register a callback so that when we get the response we can
get it in this callback method after that.
So we're going to execute this return here make the node spin.
So the node is spinning and can execute the callbacks.
That's why when we get the response from the server we can get to that part okay.
So the node needs to be spinning in order to receive the response.
And here well as I told you, if we had let's say a subscriber callback or if we had a timer callback,
we could decide at some point to call this one from one of those callbacks.
But because I don't have this here, I just call it here.
It's going to be the same.
Now let's save this and let's go back to the setup.py.
And let's add the last executable here, add to its client which is going to be my pi pkg dot add to
its client.
And that's the main function.
Great.
Let's go back here.
Let's go to the roster workspace and call call build.
So if I go back here I can find call build with the Python package and symlink install okay let's open
some terminals.
I'm going to start a server here.
So ros2 run my pi pkg with add to intz server Okay.
And then I'm going to start the client Ros to run my Pi PG with add two ints client.
So this time you see I can choose between client.
No OOP.
That's the previous script.
And that one is the one we have just written.
So I'm going to run the latest and you can see it's working.
We have the log on the server side and the log on the client side.
Now let's say we also want to.
So here you see in this no.
Where is it.
Here in this callback I only get access to the response okay.
If I wanted to print a plus B is equal to sum I could pass for example the request here.
So I could put request.
And then here I would need to do request is equal to request.
So then I can pass the request object also in the callback.
So we get access to what was the previous request.
And in this case that request corresponds to that name here.
And this is the object we've created.
I'm just going to save and see if we get an error here.
So let's start again.
And you see we have an error okay.
Because the future add on callback got an unexpected keyword argument because you've added an extra
argument here.
So you need to use the partial function from func tools okay.
That's something specific to Python.
You cannot really know that without having looked on the internet.
So I'm going to import well for example here from Func tools.
That's a Python module import partial.
And then when you do add on callback you need to do partial here partial of that okay.
So just remember that if you want to add extra arguments to a callback with add on callback for a future
object, you need to add the partial function here from func tools.
And let's just go back to new line here, because it takes a lot of space.
Now let's save and that should work okay it's working.
So now that it's working we can use the request here.
And let's just do the same thing we did before here.
Let's print that.
So let's take this log and let's print that instead.
It's going to be self okay.
So we print the full equation.
Let's save.
And now I'm gonna run again.
Let's see if it works.
And you see we have the two plus seven is equal to nine.
So in the callback we have the response.
But we can also pass the requests okay.
To know what was the request fields?
Great.
And the last thing we can do as a test is, well, we just call the function once, but let's call it
actually three times.
I'm going to use different numbers.
So one plus four and then maybe ten plus 20.
Okay let's save.
And let's see what happens if we call it three times.
Um let's run that here.
You can see that it's working.
Okay.
We can send as many requests as we want.
You can see it's going to process all three requests.
So it's going to process them one by one.
But you can see here it was very fast.
So it looks like it's at the same time.
And then for each request it's going to send back.
So the server is going to send back the response to the client.
All right.
So with one client you can send several requests as you want.
Great.
And you have successfully written a full Python service server and client.