WEBVTT

00:00.050 --> 00:00.470
Great.

00:00.470 --> 00:04.610
We have a service server and we are even able to call it from the terminal.

00:04.640 --> 00:11.060
Now let's create a Python service client so we can actually call this new service from your code directly.

00:11.060 --> 00:17.900
And we will start with a non OOP example that you can use later as a template to test any service quite

00:17.900 --> 00:18.530
quickly.

00:18.530 --> 00:23.870
So here in this lesson we are going to see the mechanisms and the different steps to create a service

00:23.870 --> 00:24.560
client.

00:24.560 --> 00:26.570
Send a request and get the response.

00:26.570 --> 00:32.540
And we're going to create a very simple script that then you can use to test any server.

00:32.540 --> 00:36.590
For example, here you could see that we could call the service from the terminal.

00:36.590 --> 00:41.210
But I told you that it's only going to work for very simple requests.

00:41.210 --> 00:44.210
If you have a more complex request, you will need to write some code.

00:44.210 --> 00:47.030
And so you can use what we do now as a template.

00:47.030 --> 00:54.200
And then in the next video, we will integrate the service client inside an existing node that uses

00:54.230 --> 00:55.970
object oriented programming.

00:55.970 --> 00:59.870
So you can integrate service clients inside any node in your application.

00:59.900 --> 01:01.490
All right let's get started.

01:01.490 --> 01:04.660
So I'm going to just open any terminal.

01:04.660 --> 01:15.400
Let's go to our Python package and let's create a new file add to ins client.

01:15.400 --> 01:19.630
I'm going to name that one no oop.py.

01:19.630 --> 01:22.300
And let's make it executable.

01:24.850 --> 01:25.480
Okay.

01:25.480 --> 01:27.010
So now let's go back to VS.

01:27.010 --> 01:29.410
Code was already open here.

01:29.620 --> 01:34.390
And let's open that one I'm going to use a template.

01:34.450 --> 01:35.740
Yes I'm going to use a template.

01:35.740 --> 01:37.390
But I'm going to modify this.

01:37.390 --> 01:41.860
So here what I'm going to keep is this.

01:41.860 --> 01:42.910
So we're going to import.

01:42.910 --> 01:45.310
So we have the Python three interpreter line.

01:45.340 --> 01:48.460
We're going to import CLP and import the node.

01:48.460 --> 01:50.590
But then I'm going to remove the class okay.

01:50.620 --> 01:54.130
I'm just going to do a simple script with a main function.

01:54.130 --> 01:57.430
So here we're going to initialize Ros to communications.

01:57.460 --> 02:00.490
Then we are going to create a node.

02:00.490 --> 02:05.430
And let's give it a name add to its clients.

02:05.460 --> 02:07.080
No oop.

02:07.170 --> 02:08.640
And then we make the node spin.

02:08.670 --> 02:10.980
Actually no I'm going to remove that line.

02:10.980 --> 02:15.600
So the three lines we keep is the initialization of Rosetta communication.

02:15.600 --> 02:16.770
We create a node.

02:16.770 --> 02:19.020
And at the end we're going to shut it down.

02:19.050 --> 02:19.470
Okay.

02:19.500 --> 02:22.800
So the structure is a bit different than what we've done previously.

02:22.830 --> 02:27.090
Now let's see how to create a client and then send a request.

02:27.090 --> 02:31.980
So I'm going to create a client I'm going to store it in a client variable.

02:31.980 --> 02:36.150
And I'm going to use the node okay that I've created.

02:36.150 --> 02:39.810
So we still need the node I'm going to do node dot.

02:39.810 --> 02:42.300
So in the node in the class you would do self.

02:42.300 --> 02:44.250
But here I name it node.

02:44.250 --> 02:51.150
So that's going to be node in my main function node dot create client okay.

02:51.150 --> 02:56.070
And I need to give of course the service type and the service name.

02:56.070 --> 03:02.160
So if I want to call this service I've created here I need to use the add to hints.

03:02.160 --> 03:05.780
And I also need to use that exact same name.

03:05.780 --> 03:17.990
So I'm going to import from example interfaces dot csv import add to int I provide it here add to int

03:17.990 --> 03:23.960
and then let's make sure we use the same name add to int.

03:24.020 --> 03:24.590
Great.

03:24.590 --> 03:25.250
And that's it.

03:25.250 --> 03:26.870
You just create a client like that.

03:26.870 --> 03:28.490
So the client is not going to do anything.

03:28.490 --> 03:31.670
Then you need to use it to send a request.

03:31.700 --> 03:36.650
Now there is one thing we can do is to first wait for the service to be up.

03:36.650 --> 03:40.280
Because if you try to send a request but the service is not up.

03:40.280 --> 03:46.100
So basically the node containing the service is not running, then you're going to get an error.

03:46.100 --> 03:53.120
So what we can do and that's a common structure we can do while not client wait for service.

03:53.120 --> 03:55.880
So you have the wait for service method inside the client.

03:55.880 --> 04:00.920
And we can give a timeout of one second for example.

04:00.980 --> 04:03.050
And then do a print.

04:03.050 --> 04:06.150
So node dot get logger.

04:06.480 --> 04:11.910
And this time, well, instead of info, I'm going to use one.

04:11.940 --> 04:12.180
Okay.

04:12.210 --> 04:15.000
Because that's more like a warning message.

04:15.000 --> 04:26.430
The server is not up and we can say waiting for server waiting for for example add to insert server.

04:26.970 --> 04:31.710
So what's going to happen is this is going to wait for the service indefinitely.

04:31.710 --> 04:33.360
But you can also provide a timeout.

04:33.360 --> 04:36.120
So it's going to return after one second.

04:36.120 --> 04:39.060
If the service is not found it's going to return false.

04:39.060 --> 04:40.380
And so you put a not.

04:40.410 --> 04:45.870
And so basically as long as the service is not found we say waiting for the server.

04:45.870 --> 04:47.460
And then we keep waiting.

04:47.460 --> 04:52.950
Then when the service is found we're going to go out of the loop because this is going to return true.

04:52.980 --> 04:53.520
Okay.

04:53.520 --> 05:01.680
We can already test this code just to make sure that we can create a client and we can find the service

05:01.680 --> 05:02.370
server.

05:02.370 --> 05:09.410
So I'm going to save that and I'm going to create a new executable here comma.

05:09.410 --> 05:13.640
And then let's name it add to insert client.

05:13.670 --> 05:14.390
No.

05:14.780 --> 05:15.440
OOP.

05:15.470 --> 05:17.180
So it starts to be quite long.

05:17.450 --> 05:26.390
My pi pkg and then add to int client.

05:27.080 --> 05:27.950
No.

05:27.980 --> 05:28.610
OOP.

05:29.330 --> 05:31.250
And that's the main function.

05:31.280 --> 05:32.900
It's always the main function here.

05:34.520 --> 05:35.480
The main.

05:35.480 --> 05:36.890
So we call the main function.

05:37.220 --> 05:38.120
Okay.

05:38.150 --> 05:40.460
Let's save that.

05:40.670 --> 05:41.180
All right.

05:41.180 --> 05:46.040
So what's going to happen very simply is that we initialize rose to communications.

05:46.040 --> 05:47.570
We create a node.

05:47.570 --> 05:49.760
Then we create a client inside the node.

05:49.760 --> 05:51.950
And we just wait for the service.

05:51.950 --> 05:54.020
Let's build.

05:55.670 --> 06:02.780
Let's go back to the Ros2 workspace Qualcomm build packages.

06:02.810 --> 06:10.480
Select with my pi pkg E.g. and let's use Simulink install so we don't need to build again to modify

06:10.480 --> 06:11.380
this code.

06:12.760 --> 06:13.540
Okay.

06:13.540 --> 06:23.470
And then I'm just gonna stop the terminals here, open new ones so everything is correctly sourced.

06:23.890 --> 06:25.750
And let's start here.

06:25.750 --> 06:34.360
The node we have just created Ros to run my pi pkg add to mint client.

06:34.390 --> 06:35.380
No OOP.

06:35.560 --> 06:36.760
Let's run that.

06:36.910 --> 06:43.120
And you can see waiting for the server because the server is not up.

06:43.150 --> 06:52.270
Now here I'm going to run Ros to run with my Pi pkg add to its server.

06:52.270 --> 06:56.560
And you see add to server has been started.

06:56.560 --> 06:58.300
And then you see we return here.

06:58.300 --> 06:59.410
So what does it mean.

06:59.410 --> 07:02.500
It means that it's currently working on the client side.

07:02.500 --> 07:03.790
We create a client.

07:03.790 --> 07:08.250
And then as long as the server is not up we are waiting for the server.

07:08.280 --> 07:16.680
Now, look, if I start the service client again, it's going to return immediately because the service

07:16.680 --> 07:18.810
server is already running.

07:18.840 --> 07:19.230
Okay.

07:19.260 --> 07:22.980
So this mechanism here is just in case.

07:22.980 --> 07:24.180
It's like a safety.

07:24.180 --> 07:30.180
So if you start both nodes around the same time, but if the client is up before the server then you

07:30.180 --> 07:32.100
make sure that you wait for the server.

07:32.130 --> 07:32.460
Okay.

07:32.460 --> 07:32.730
Good.

07:32.730 --> 07:34.410
So now we have created our client.

07:34.410 --> 07:40.530
And at this point of the execution here, we know that the service server has been found.

07:40.530 --> 07:46.050
So what we can do is we can create a request and send that request.

07:46.080 --> 07:47.910
Let's create a request.

07:47.910 --> 07:54.900
So we do request is equal to add to int dot request okay.

07:54.900 --> 07:57.300
So it's basically like creating a message.

07:57.300 --> 08:01.680
You create a request and then you do request dot a.

08:02.070 --> 08:03.420
So y dot a.

08:03.450 --> 08:10.850
Because if you remember in this interface we have a and B as the request and then some as the response.

08:11.480 --> 08:12.650
Let's say three.

08:12.650 --> 08:14.210
So let's give some number here.

08:14.240 --> 08:17.930
Request dot b is equal to eight.

08:17.960 --> 08:19.790
So the sum should be 11.

08:19.790 --> 08:26.690
And then we are going to use this request with the client to send where to send the request.

08:26.720 --> 08:28.160
How do we do this.

08:28.160 --> 08:30.410
We are going to do client dot.

08:30.410 --> 08:33.380
And then we have call and call async.

08:33.380 --> 08:36.290
So call is going to be synchronous call.

08:36.290 --> 08:40.910
But it's not recommended because you might end up in a deadlock situation.

08:40.940 --> 08:41.150
Okay.

08:41.180 --> 08:43.310
It's going to block the execution.

08:43.310 --> 08:47.810
And then actually to get the response you need to have the node that's spinning.

08:47.810 --> 08:50.060
But if you block here the node is not going to be spinning.

08:50.060 --> 08:53.360
Well that's a bit more complex for you to understand right now.

08:53.360 --> 08:59.510
But basically if you write call here just like that, you might have some issues and you may never get

08:59.510 --> 09:00.170
the response.

09:00.170 --> 09:04.940
So we are going to do a call async, which means that we are going to call.

09:04.940 --> 09:06.290
So to send the request.

09:06.290 --> 09:07.880
And then that's going to return.

09:07.880 --> 09:13.130
And we need to do something else to get the response, and we send the request here.

09:13.760 --> 09:14.750
Request.

09:15.830 --> 09:18.860
So client dot call async with the request.

09:18.890 --> 09:22.190
This is going to return a future.

09:22.220 --> 09:23.150
Object.

09:23.570 --> 09:24.110
Okay.

09:24.140 --> 09:28.820
No need to really understand future objects in Python.

09:28.820 --> 09:29.570
Just need to.

09:29.600 --> 09:30.740
Know that it's a future.

09:30.740 --> 09:33.800
So it's something that's going to return in the future.

09:33.830 --> 09:40.550
And then what I'm going to do here is I'm going to make the node spin until the future is complete.

09:40.550 --> 09:47.510
For that I can do CLP dot spin until future complete.

09:47.510 --> 09:49.970
So you see we are now using the normal spin.

09:49.970 --> 09:51.920
We are using a different spin.

09:51.920 --> 09:55.610
And I put the node that's the one we've created here.

09:55.610 --> 09:59.330
And I put the future that we have here.

09:59.360 --> 09:59.690
All right.

09:59.720 --> 10:08.090
So very basically put you send a request and then you just say spin the node until we receive a response.

10:08.090 --> 10:11.930
And in this case the future is going to get the result.

10:11.930 --> 10:20.630
And after that well we can do response is equal to future dot result.

10:20.960 --> 10:23.990
And that's going to be the response of the service okay.

10:23.990 --> 10:26.570
And let's do a log.

10:26.570 --> 10:35.390
So we're going to use the node here node dot get logger with info.

10:35.390 --> 10:39.410
And let's just print a plus B is equal to sum.

10:39.710 --> 10:42.050
Actually I think I've done it here already.

10:42.290 --> 10:46.670
Yes you can just get this okay.

10:46.700 --> 10:47.810
So we don't need to rewrite.

10:47.810 --> 10:51.140
Everything is one more parenthesis.

10:54.650 --> 10:54.980
Okay.

10:54.980 --> 10:57.410
So we just print the request a plus.

10:57.410 --> 11:02.360
The request b is equal to the response dot sum.

11:02.360 --> 11:04.370
And that's going to be pretty much it.

11:04.370 --> 11:06.590
So let's do a quick recap.

11:06.590 --> 11:08.720
First we initialize roster communication.

11:08.720 --> 11:09.740
We create a node.

11:09.740 --> 11:10.790
Then we create a client.

11:10.790 --> 11:13.180
We wait for the service to be up.

11:13.210 --> 11:14.770
We create a request.

11:14.800 --> 11:16.780
We send that request.

11:16.810 --> 11:22.510
We make the node spin until the future is complete, which means that we got the response from the server,

11:22.510 --> 11:25.420
and then we just get the response using the future object.

11:25.420 --> 11:29.080
And we can just print or do whatever we want with this response.

11:29.080 --> 11:33.610
And finally we shut down Rosta communications and everything is going to be shut down.

11:33.610 --> 11:37.000
So let's save that and let's go back here.

11:37.000 --> 11:40.540
I don't need to build again because we've used the Simulink install.

11:40.660 --> 11:43.240
So the server is running okay.

11:43.270 --> 11:44.830
We haven't touched anything in the server.

11:44.830 --> 11:48.190
So let's keep it that way and let's run that again.

11:49.210 --> 11:55.420
And you see now we have here a log on the server side and a log on the client side, which means that

11:55.420 --> 11:57.970
the communication was successfully done.

11:58.000 --> 11:58.480
All right.

11:58.510 --> 12:04.120
So now you have seen what are the different steps that you need to implement as a client.

12:04.120 --> 12:06.490
So to send a request and get a response.

12:06.490 --> 12:12.550
And this here this no OOP script I've written it like this because it's going to be quite useful for

12:12.550 --> 12:12.910
you.

12:12.940 --> 12:18.970
Let's say you have created a service server and the request is a bit complex.

12:18.970 --> 12:25.150
So you have created the server, but you want to quickly test it and you cannot really do a ros2 service

12:25.150 --> 12:27.820
call from the terminal because it's going to be a mess.

12:27.820 --> 12:31.030
And it's hard to build the request from the terminal.

12:31.030 --> 12:32.860
Well, you can just use that.

12:32.890 --> 12:37.540
You use that, you create a client, you just change the interface, the name, and then you create

12:37.540 --> 12:38.290
the request.

12:38.320 --> 12:41.620
Well, you fill the request with whatever you need, okay.

12:41.650 --> 12:43.570
And then basically it's the same thing.

12:43.570 --> 12:44.890
This line is the same.

12:44.890 --> 12:47.140
That line is the same, that line is the same.

12:47.140 --> 12:51.730
And then you just well, you just print something else if you want, okay.

12:51.760 --> 12:59.020
But basically you can use that as also a template for you to test any service server that you have created.

12:59.020 --> 13:03.940
And not only that, but if you have written a service server in Python or in C plus.

13:03.940 --> 13:11.740
Plus as you know that Ros is language agnostic, you can use this Python script here to test even a

13:11.740 --> 13:13.630
C plus plus service server.
