WEBVTT

00:00.260 --> 00:07.520
In this laboratory lesson, we will develop a simple Python service server that will provide the functionality

00:07.520 --> 00:10.430
of calculating the sum of two integers.

00:10.640 --> 00:17.210
Then we will also develop a client that will use this service within another Ros two node.

00:17.780 --> 00:25.130
This will help us to understand how services work from a practical perspective and how to use the command

00:25.130 --> 00:27.860
line interface to interact with them.

00:28.220 --> 00:34.190
If you are only interested in the C plus plus development, then you can directly move to the next lesson

00:34.190 --> 00:40.190
where we will implement a service server that offers the same functionalities of summing two numbers

00:40.190 --> 00:41.780
but in C plus plus.

00:42.520 --> 00:48.850
Let's start by opening Visual Studio code and by creating a new Python script within the Arduino Pi

00:48.850 --> 00:53.710
example package and within the Arduino Pi Examples app folder.

00:53.860 --> 01:01.390
And let's call this one simple service server dot pi.

01:01.930 --> 01:09.740
As usual, let's begin by importing the Pi library, which allows us to use all the tools of the two

01:09.820 --> 01:11.080
in the Python script.

01:11.440 --> 01:17.920
So let's import rcl pi and let's also import.

01:17.920 --> 01:26.560
So from RCL pi and from the node module, let's import the node class.

01:26.560 --> 01:29.860
And now we can use the node class to create a new class.

01:29.860 --> 01:40.780
So to create a new node, let's call this one simple service server that inherits from the node class

01:40.990 --> 01:41.560
here.

01:41.560 --> 01:44.840
Let's start by defining the constructor of the class.

01:44.840 --> 01:52.880
So let's define the init function that is a member of the Simple Service server class.

01:53.120 --> 01:57.020
And then we also need to call the constructor of the base class.

01:57.020 --> 02:02.810
So basically with the super function, let's call the init.

02:04.010 --> 02:06.080
Init function.

02:06.080 --> 02:09.800
So the constructor of the base class of the node class.

02:09.800 --> 02:12.230
And let's provide a name to the node.

02:12.230 --> 02:19.400
So for example, let's call it a simple service, a server.

02:20.300 --> 02:24.650
Next, let's create a new variable so a new member of the class.

02:24.860 --> 02:28.490
And let's call this one service.

02:29.840 --> 02:37.070
Just as we used the Create publisher function to create a publisher object and the create subscription

02:37.070 --> 02:39.410
function to create a subscriber object.

02:39.440 --> 02:49.490
Similarly, to create a service server, we use the create service function that we inherited from the

02:49.490 --> 02:50.480
node class.

02:51.170 --> 02:57.650
This function requires the message interface to be provided as input for the communication with the

02:57.650 --> 02:58.760
service server.

02:58.760 --> 03:05.570
And so the interface that specifies how the request and response messages are done for interacting with

03:05.570 --> 03:06.860
the service server.

03:07.250 --> 03:14.120
To do this, we need to create a new message interface for the communication with this new service server.

03:14.420 --> 03:22.280
As a convention and as a general rule in Ros2, it is advisable to place all the new message types so

03:22.280 --> 03:28.580
all the user defined message types in a different package from the ones in which we have developed the

03:28.580 --> 03:29.880
robots functionalities.

03:30.500 --> 03:36.710
So let's open our new terminal and here let's go to the workspace and to the source folder.

03:36.710 --> 03:38.720
And here let's create a new package.

03:38.720 --> 03:51.560
So Ros, to package create, let's use as build type, amend, see make, and let's call this new package

03:51.560 --> 03:53.210
that will just contain messages.

03:53.210 --> 03:58.610
So Ros to interfaces, Arduino bot messages.

03:58.610 --> 04:00.560
And so let's press enter.

04:00.590 --> 04:08.420
Now let's go back to the workspace and let's build it so that the new package is recognized.

04:08.690 --> 04:15.260
Now back in Visual Studio code, we can define an interface for the communication with the service server

04:15.380 --> 04:20.290
within the newly created Arduino bot messages for convention.

04:20.300 --> 04:26.450
The messages that define the interface for the communication with the service are placed within the

04:26.570 --> 04:28.020
serve folder.

04:28.070 --> 04:32.250
So let's create this folder that is called serve.

04:32.610 --> 04:41.310
And within this one, let's create a new file that is called Add to insert Serve.

04:43.300 --> 04:47.500
In this file, we need to define the structure of the request message.

04:47.500 --> 04:50.530
That is the one that has to be sent to the server.

04:50.680 --> 04:59.200
So the request message and this request message will consists of the two integers for which we want

04:59.200 --> 05:00.850
the server to calculate the sum.

05:01.210 --> 05:10.330
So these are two integers that we call A and B, And then we also need to define the structure of the

05:10.330 --> 05:11.380
response message.

05:11.380 --> 05:16.720
That is the one that is returned by the server when it has completed its calculation.

05:16.720 --> 05:26.560
So we can use three dashes to separate the response message from the request one and the server will

05:26.560 --> 05:33.280
simply return an integer that will contain the sum of the two integers that it received as input.

05:33.370 --> 05:35.560
So let's call this one sum.

05:37.060 --> 05:43.570
With this, we have completed the definition of the ad joints interface and now we can proceed to declare

05:43.570 --> 05:51.250
its existence to the compiler so that it can correctly build and compile this message so that other

05:51.250 --> 05:53.770
Ros two nodes and packages can use it.

05:54.010 --> 05:56.730
So let's open the file CMake list.

05:56.740 --> 06:08.380
And here let's add the dependency from the library standard messages and also let's add another find

06:08.380 --> 06:15.270
package instruction and here to compile and generate all the necessary file for using the new message,

06:15.280 --> 06:19.210
let's declare the usage of the Ros Idle.

06:21.880 --> 06:22.810
Default.

06:25.260 --> 06:26.850
Generators library.

06:27.060 --> 06:32.530
And then let's also add here before the build testing a new Ros.

06:33.190 --> 06:40.260
Idle generate interfaces instruction.

06:40.260 --> 06:46.140
And so here we say that we are generating an interface for the package Arduino bot messages.

06:46.260 --> 06:57.390
So let's use the variable project name and then let's declare the name of the service that we are using.

06:57.390 --> 07:04.180
So among the double quotes, let's declare that we have a new service within the service folder and

07:04.180 --> 07:08.570
this called Add to dot Serve.

07:09.710 --> 07:15.680
Now we are only missing to declare the dependencies of the Arduino bot messages package also in the

07:15.680 --> 07:17.390
package dot XML file.

07:17.720 --> 07:25.250
So here, let's add a dependency from the standard messages library.

07:25.460 --> 07:28.730
Then let's also add another build dependency.

07:28.880 --> 07:37.880
So here a build dependency from the Ros IDL default

07:39.980 --> 07:41.240
generators.

07:42.230 --> 07:45.350
Also declare another execution dependency.

07:45.380 --> 07:54.590
So execution dependency from the Ros IDL default runtime.

07:56.330 --> 08:04.840
And then for the generation of the service interface messages, we also need the tag member of group.

08:04.880 --> 08:14.300
And here we need to insert the ros IDL interface packages.

08:14.630 --> 08:17.470
So let's save this file.

08:17.480 --> 08:23.510
And now we can proceed to build our workspace so that the new message interface with the service.

08:23.510 --> 08:30.890
So the add to interface is recognized and we can start using it within the simple service server.

08:31.130 --> 08:32.870
So let's open a new terminal.

08:33.140 --> 08:37.070
Let's go into the workspace and let's build it.

08:40.420 --> 08:46.090
This has compiled the workspace and so it has generated also the interface with the service.

08:46.240 --> 08:53.410
And now we can go back to the simple service server here and still within the Create service function,

08:53.410 --> 08:59.050
we need to insert the interface so the message type that the service needs to use.

08:59.050 --> 09:00.520
So let's import it.

09:00.550 --> 09:12.310
So from the Arduino board messages from the services, let's import the add to insert interface.

09:13.320 --> 09:18.750
And then now let's use this interface within the create service function.

09:18.750 --> 09:25.440
So here to declare that the type of the service object that needs to be initialized should be the request

09:25.440 --> 09:30.600
and response message interface as defined in the Add joins interface.

09:31.050 --> 09:37.680
Still in the create service function, we also need to assign a name to the service, the name by which

09:37.680 --> 09:41.220
the service will be recognized in the Ros environment.

09:41.370 --> 09:47.220
For example, let's call it add two ins.

09:48.520 --> 09:55.390
Then we also need to provide a callback function, namely a function that will be executed by the service

09:55.390 --> 09:59.050
server whenever a new message request is received.

09:59.050 --> 10:06.970
So whenever a client requests the server to calculate the sum of two integers and let's call this function

10:07.990 --> 10:17.320
service callback that still we are going to define as a member of the simple service server class.

10:18.180 --> 10:22.440
To conclude the constructor of this class, let's also print a message in the terminal.

10:22.440 --> 10:28.260
So a log message using the get logger function.

10:28.410 --> 10:39.420
And then let's print an informative message that says service at the joints is ready.

10:39.900 --> 10:47.640
And now still the constructor is done, but still inside the simple service server we are missing to

10:47.640 --> 10:50.580
declare the service callback function.

10:50.580 --> 10:52.740
So let's declare this function.

10:54.490 --> 10:58.960
And let's declare it as a member of the simple service server.

10:59.770 --> 11:06.190
And as this is a callback function, it receives as input the message interface that is used for the

11:06.190 --> 11:09.550
communication and the data exchange with the server.

11:09.580 --> 11:16.630
Therefore, it receives the request and the response message for the communication with the client.

11:16.630 --> 11:22.840
So the request that was the one received from the client and the response, that is the one that we

11:22.840 --> 11:25.570
are going to return to provide to the client.

11:26.390 --> 11:30.570
First in this function, let's log an informative message in the terminal.

11:30.590 --> 11:45.020
So still with the get logger function, let's print an informative message that says new message received.

11:45.020 --> 11:50.630
And then let's print the two numbers, the two integers that we received in the request message.

11:50.630 --> 11:58.760
And so the variable A and then the variable B, So let's print both of them.

12:00.050 --> 12:03.350
And these are contained in the request message.

12:04.070 --> 12:10.640
So in the request message, let's access to the variable A and to the variable B.

12:11.150 --> 12:17.630
Now actually we can perform the logic of this service, which in this case is just to calculate the

12:17.630 --> 12:21.620
sum of the two integers that are received in the request message.

12:21.620 --> 12:30.980
And so let's calculate the sum between the variable A and the variable B, and let's store their value.

12:30.980 --> 12:34.010
So the value of the sum in the response message.

12:34.010 --> 12:41.660
So in the sum variable, so in the variable that we called sum in the response message at the end of

12:41.660 --> 12:45.560
this calculation, let's also print another informative message in the terminal.

12:51.060 --> 12:56.400
And this message says returning some.

12:56.760 --> 13:04.470
And then the value of the sum that is basically the one that we stored in the response message.

13:05.310 --> 13:10.620
Finally, to conclude this function, let's also return the response variable.

13:10.620 --> 13:16.680
So let's return the response message to the client that requested the execution of the service.

13:17.680 --> 13:22.500
This covers the definition of all the components of the simple service server.

13:22.510 --> 13:27.640
And now we can move on to define the main function, which is the one that is automatically executed

13:27.640 --> 13:29.140
when the node starts.

13:35.790 --> 13:38.250
So here, let's execute the main function.

13:38.670 --> 13:40.800
And now let's define.

13:43.180 --> 13:44.260
The main function.

13:44.260 --> 13:50.320
And let's start by initializing Ros with the function init.

13:50.350 --> 13:54.220
Then let's create a new instance of the simple service server class.

13:59.770 --> 14:01.990
And then let's keep this node up and running.

14:01.990 --> 14:11.020
So with the rcl py, let's use the spin function to keep the simple service server up and running.

14:11.200 --> 14:16.630
And finally, if we terminate the execution of the node with control Z, let's destroy the node.

14:16.960 --> 14:18.970
So simple service server.

14:21.440 --> 14:23.390
Destroy the node.

14:24.050 --> 14:26.630
And also, in this case, let's shut down Ros.

14:26.630 --> 14:27.960
So RCMP.

14:29.960 --> 14:30.920
Shut down.

14:31.960 --> 14:34.190
Here is our pie.

14:34.480 --> 14:35.440
Perfect.

14:35.590 --> 14:42.040
With this, the simple Service survey is completed, and now we can proceed to install it by modifying

14:42.040 --> 14:48.040
the file Setup.py, where we have already installed the simple publisher, subscriber and parameter

14:48.190 --> 14:53.290
so we can copy this line and we can paste it below and the new node.

14:53.290 --> 14:58.540
So the new executable will be the simple service server.

14:59.080 --> 15:04.090
And also it is in the simple service server script.

15:04.090 --> 15:08.920
As a final step since we used the Arduino bot Messages library.

15:08.920 --> 15:15.730
So since we used this library within the Arduino Pi example package, we need also to declare the usage

15:15.730 --> 15:16.660
of this library.

15:16.660 --> 15:20.230
And so we need to do this in the package dot XML.

15:20.260 --> 15:22.660
We need to add an execution dependency.

15:23.020 --> 15:29.200
So execution dependency from the Arduino bot messages.

15:29.200 --> 15:31.900
And now we can proceed to run the node.

15:31.900 --> 15:36.580
So let's open a new terminal and let's go to the workspace.

15:36.730 --> 15:43.000
And here let's first build our workspace so that the new node is installed.

15:43.720 --> 15:49.600
And now we can open a new window of the terminal, and here we can actually source the workspace.

15:50.080 --> 15:55.300
So if I set up Bash and we can run our service server node.

15:55.630 --> 16:00.370
So let's make this bigger with the command Ros to run.

16:00.400 --> 16:08.330
And from the Arduino Pi examples, let's start the simple service server node.

16:08.350 --> 16:10.540
So let's press enter.

16:10.630 --> 16:16.450
And as we do so, we can confirm that actually the node and so the server is running from the output

16:16.450 --> 16:17.200
of the terminal.

16:17.200 --> 16:20.900
So we can see that the service chewins is ready.

16:20.920 --> 16:30.190
We can also double check this if we open a new terminal and we use the command Ros two service list,

16:30.220 --> 16:37.480
we can see that actually the service Atkins is there, which is the name that we assigned to our script.

16:37.870 --> 16:41.260
Furthermore, if also in this terminal, we source the workspace.

16:41.680 --> 16:45.000
So let's source the workspace.

16:45.010 --> 16:48.580
We can also get additional information about this service.

16:48.580 --> 16:50.230
So about the communication.

16:50.230 --> 16:59.590
So the interface that it is using with the command Ros2 service type followed by the name of the service

16:59.590 --> 17:02.320
that is the Add Chewins.

17:02.320 --> 17:04.210
So let's press enter.

17:04.210 --> 17:11.890
And as we can see here, it tells us that it is using the interface the that is declared in the Arduino

17:11.890 --> 17:13.180
board messages.

17:14.050 --> 17:15.850
Now still from the terminal.

17:15.850 --> 17:21.430
We can also send our request to this service server by sending our request message.

17:21.430 --> 17:29.950
And we do this with the command rescue service call, followed by the name of the service that still

17:29.950 --> 17:34.450
is the Adkins, followed by the type of the request message.

17:34.450 --> 17:38.860
And so this is the one that belongs to the Adkins interface.

17:38.860 --> 17:43.990
So if we press tab twice, we can see that it is automatically detected.

17:44.350 --> 17:48.910
So let's insert a message of this type and then if we press tab twice.

17:48.910 --> 17:55.180
So let's insert the double quotes and let's insert the letter A and then let's press tab.

17:55.180 --> 18:00.400
We can see that it also enters an empty prototype of the request message.

18:00.400 --> 18:03.970
So the autocompletion of Ross in this is very useful.

18:04.390 --> 18:09.820
For example, let's ask the server to calculate the sum between seven.

18:10.820 --> 18:12.510
And the number five.

18:12.530 --> 18:14.300
So let's press enter.

18:14.300 --> 18:21.410
And as we can see, as soon as we do that, the server tells us that it received a new request and also

18:21.410 --> 18:23.480
it tells us that it is returning there.

18:23.780 --> 18:27.440
So 12 and also in the terminal in which we called.

18:27.440 --> 18:30.510
So we asked for the execution of this server.

18:30.530 --> 18:34.730
We see that we have the sum that was returned by the server.
