WEBVTT

00:00.230 --> 00:07.880
In this laboratory lesson, we will create a service client in Ros two using C plus plus that use the

00:07.880 --> 00:13.250
functionality offered by the service server developed in the previous laboratory lesson.

00:13.430 --> 00:19.760
In practice we are going to create a C plus plus node that uses the service for the sum of two integers,

00:19.760 --> 00:21.860
which we called Add Joins.

00:21.870 --> 00:28.130
And so following what we have learned in the theoretical lessons, the client will send a request to

00:28.130 --> 00:34.610
the service according to the message interface defined by the service and then will be notified with

00:34.610 --> 00:38.690
a response message when the server completes its execution.

00:38.960 --> 00:45.890
So let's create a new script inside the Arduino bot CP examples in the source folder.

00:45.890 --> 00:54.980
And here let's create a new file called Simple Service Client Dot CP here.

00:54.980 --> 01:07.010
Let's start by including the CP and the CP dot PHP, which we can use to create a new Ros two node.

01:07.340 --> 01:19.430
So let's create a new class called Simple Service Client, which inherits from the RCL, CP.

01:20.300 --> 01:22.190
So from the Node class.

01:23.000 --> 01:25.640
And let's define this class.

01:26.030 --> 01:32.660
Let's start by defining among the public attributes of this class, the constructor.

01:32.660 --> 01:38.000
So the function that has the same name of the class that we called Simple Service client.

01:38.570 --> 01:46.100
And here, in order to initialize also the base class, let's call the node constructor to which we

01:46.100 --> 01:47.030
provide a name.

01:47.030 --> 01:56.300
So let's call this node simple service client and also let's make the constructor so the simple service

01:56.300 --> 01:59.660
client constructor to receive two parameters.

01:59.660 --> 02:06.450
So to integers as input that we call A and B and these two numbers.

02:06.450 --> 02:10.740
So these integers will be the one that will be added together.

02:10.740 --> 02:17.100
So when we are going to create a new object of the simple service client class, also we need to pass

02:17.100 --> 02:23.730
the two numbers so A and B that we want to send so that we want to request to the service server.

02:24.160 --> 02:34.270
Let's continue by adding among the private variables of this class a new shared pointer of type rql

02:34.300 --> 02:37.400
CPP client.

02:37.900 --> 02:46.710
So this is a template class and we take a shared pointer from this class which we call client.

02:46.780 --> 02:55.420
So let's include also the memory module from the standard C plus plus library.

02:55.750 --> 03:00.790
And now, just as we did for the server class, the client class.

03:00.790 --> 03:07.030
So as we can see here is a template class and receives among the angular parentheses the type of the

03:07.030 --> 03:10.870
interface that it needs to use for the communication with the server.

03:11.020 --> 03:21.950
So we define this interface in the Arduino board messages in the service folder and in the Add joints

03:21.970 --> 03:23.170
interface.

03:23.440 --> 03:30.370
And so let's also say that the client that we are going to create use this interface.

03:30.380 --> 03:37.430
And so from the Arduino, what messages from the service it uses the Add joints interface.

03:37.670 --> 03:43.340
And now we can proceed actually to initialize this variable within the constructor.

03:43.700 --> 03:49.700
And as you might have, imagine, if for creating the service, we used the create service function

03:49.700 --> 03:59.150
to create the client, we use the create client function that is also, in this case, a template function.

03:59.150 --> 04:05.780
And also this function requires as input the type of the interface that it has to use for the communication

04:05.780 --> 04:06.950
with the service.

04:07.130 --> 04:11.030
And so this is in the Arduino board messages.

04:11.390 --> 04:15.980
So in this service we are using the Add joints interface.

04:16.100 --> 04:22.460
And then among the parentheses, it also receives the name of the service, which is the name by which

04:22.460 --> 04:25.070
the server is recognized in roster.

04:25.340 --> 04:30.170
And so we called this one add to its.

04:30.990 --> 04:36.930
Now that we have our client, we can create a request message that we are going to send to the client.

04:37.470 --> 04:44.070
So let's create a new variable that we called request.

04:44.370 --> 04:47.970
And let's initiate this one with a shared pointer.

04:48.300 --> 04:55.980
So this is a shared pointer that we can create with the function, make shared from the standard C plus

04:55.980 --> 04:57.000
plus library.

04:57.510 --> 05:01.140
And here we need to define the type of the interface.

05:01.140 --> 05:08.400
So this is our request message that is defined in the Arduino board, message in the server folder,

05:08.400 --> 05:10.380
in the Arduino interface.

05:10.380 --> 05:14.490
And we want to create an instance of the request interface.

05:14.790 --> 05:18.270
Now we can assign a value to the variable A.

05:18.450 --> 05:25.590
So from the request message, let's assign a value to the variable A and let's set this one equal to

05:25.590 --> 05:29.330
the variable A that we received as input of the constructor.

05:29.340 --> 05:31.900
And let's do the same also for the variable B.

05:32.260 --> 05:40.600
So request B is equal to the variable B that was received an input from the constructor.

05:41.450 --> 05:47.480
Now, before sending these requests to the server, let's first verify that actually the server is running

05:47.480 --> 05:50.450
and so it's available to receive new requests.

05:50.870 --> 05:54.630
To do so, we can use the function, wait for service.

05:54.650 --> 06:00.500
So on the client object, let's use the wait for service function.

06:00.950 --> 06:04.130
And let's put this one within a while loop.

06:04.130 --> 06:09.170
So while the wait for service function doesn't return true.

06:09.200 --> 06:16.550
So while we have not found any service that corresponds to this name, let's wait more time.

06:16.550 --> 06:30.080
And so let's import the Chrono Library of C plus plus and then let's use the namespace STD.

06:32.550 --> 06:34.890
Chrono Literals.

06:36.000 --> 06:43.650
And let's use this one in order for the client to wait for service one second before considering it

06:43.680 --> 06:45.000
not available.

06:45.300 --> 06:50.910
So here the client will wait for the service one second and if it's not available, it will print an

06:50.910 --> 06:52.350
error message in the terminal.

06:52.500 --> 06:59.730
So with the function rcl cp error, let's print a message.

07:00.150 --> 07:12.690
So let's first get the logger with the name RCL, CP and then let's print the message that says service

07:13.260 --> 07:16.380
not available.

07:18.630 --> 07:21.390
Waiting more time.

07:21.720 --> 07:26.220
So here it just says that it's going to wait again.

07:26.250 --> 07:31.040
Let's also check actually that Ross is still running.

07:31.050 --> 07:36.370
So let's check that RCL CP is still okay.

07:36.520 --> 07:38.350
And if is not.

07:38.590 --> 07:42.760
So if this is not, let's stop waiting for service.

07:42.760 --> 07:46.630
So let's stop this function here with another error.

07:46.630 --> 07:50.620
So rcl cp error.

07:53.950 --> 08:10.270
Let's get logger with the name rcl, cp and let's print the message interrupted while waiting for service.

08:10.270 --> 08:16.990
So this message is going to be printed if, for example, the service assurance is not yet available

08:16.990 --> 08:23.980
and we interrupt the execution of the node so the client is not is not able to find the service.

08:23.980 --> 08:26.770
And also Ross is not running anymore.

08:26.770 --> 08:28.750
So we are going to execute.

08:28.750 --> 08:34.000
So we are going to see this message in the terminal and in this case, let's terminate the execution

08:34.000 --> 08:36.700
of the node with the return.

08:37.120 --> 08:43.630
Otherwise, if Ross is still okay, we are going to continue waiting for the service to appear.

08:44.080 --> 08:51.160
Alternatively, if we are out of the while loop, this means that we have found a service named Adjoints

08:51.160 --> 08:51.640
in Ross.

08:51.640 --> 08:56.170
True, and also that this service is ready to process any new request.

08:56.170 --> 09:02.650
And so at this point we can send a new request to the service by using the client object.

09:02.740 --> 09:08.050
And on this object, let's call the async send request.

09:08.620 --> 09:15.010
And this function we need to pass the request message that we just created and in which we inserted

09:15.010 --> 09:17.800
the A and B values.

09:18.040 --> 09:26.170
And now we can also store the result of this function into a new variable that we called result.

09:26.170 --> 09:30.970
And so that stores the output of the async send request function.

09:31.920 --> 09:32.820
This function.

09:32.820 --> 09:40.260
So the async send request sends the request to the service and immediately returns a result.

09:40.260 --> 09:46.740
So this one that is a future variable without waiting for the server to finish its execution.

09:46.740 --> 09:51.060
So actually we don't know where the service is done with its execution.

09:51.060 --> 09:55.980
We can know, for example, when the service is done by adding a callback function.

09:55.980 --> 10:02.040
So namely a function that is executed whenever the service finished is processing.

10:02.040 --> 10:11.460
So its calculation and we can define this one still within the async send request function and we can

10:11.460 --> 10:12.900
use the bind function.

10:12.900 --> 10:22.530
So standard bind from the standard library and let's call this function response callback and we are

10:22.530 --> 10:27.150
going to define this function still within the simple service client class.

10:27.720 --> 10:30.780
So let's declare the response callback.

10:31.550 --> 10:34.550
As a member of the simple Service client class.

10:34.670 --> 10:36.890
Also, let's use the pointer.

10:37.550 --> 10:43.250
This to indicate that we want to use this object, the current object for the implementation of the

10:43.250 --> 10:44.320
response callback.

10:44.330 --> 10:54.890
And also then let's declare the usage of the placeholders modules from which we take just the placeholder

10:54.890 --> 11:01.340
number one that we use to indicate that the function response callback receives one input.

11:01.340 --> 11:08.540
So just takes one input and now we can actually move on so we can see that there is an error because

11:08.570 --> 11:16.100
actually we have not yet defined the response callback function which we can do here among the private

11:16.100 --> 11:16.940
variables.

11:17.480 --> 11:21.440
So among the private variables of the simple service client class.

11:21.440 --> 11:29.300
So this return type is void and this function receives as input a future variable.

11:29.300 --> 11:38.550
So this one is in the RCL CPP client class, which is a template class and which requires as input the

11:38.550 --> 11:43.490
message interface that is used for the message exchange with the service.

11:43.500 --> 11:49.500
So again, the add to interface that is in the Arduino board messages package.

11:50.040 --> 11:52.080
And then let's take a short pointer.

11:52.740 --> 11:58.020
So shared future and let's call this variable.

11:59.600 --> 12:00.350
Future.

12:01.040 --> 12:08.570
These future variables provide a mechanism for accessing the result of an asynchronous operation where

12:08.570 --> 12:12.620
there are some threads that are waiting for the results of other threads.

12:12.740 --> 12:18.260
So if this future variable is valid.

12:19.130 --> 12:20.600
So let's check.

12:22.310 --> 12:25.160
That this variable is valid.

12:25.550 --> 12:29.830
In this case, let's print an informative message into the console.

12:29.840 --> 12:45.530
So with the SQL CPP info stream, then let's use the Get logger to get the SQL CPP logger and let's

12:45.530 --> 12:51.620
print the message service response.

12:51.980 --> 12:55.190
And from the future variable, let's take its content.

12:55.190 --> 12:56.990
So the result message.

12:57.470 --> 13:04.370
So from the future variable, let's take its content.

13:04.370 --> 13:08.150
And from this one we want to access to the variable sum.

13:10.010 --> 13:11.900
So let's close this one.

13:11.900 --> 13:18.800
And here actually we need to close this parentheses and here we don't need any parentheses.

13:19.660 --> 13:20.590
Otherwise.

13:20.590 --> 13:28.990
So here else if this function so if the result of the future variable is not valid.

13:29.020 --> 13:31.300
Let's simply print an error message.

13:31.300 --> 13:36.880
So rcl cp error and this error message.

13:37.030 --> 13:44.880
Let's take the get logger and let's call it RCL.

13:44.890 --> 13:54.880
CP And the message that we are going to print is simply service failure since we have not been able

13:55.090 --> 13:57.100
to get the future variable.

13:57.100 --> 14:00.760
So to read from the future variable the response.

14:00.760 --> 14:08.740
And so the sum variable with this, the simple service client class is complete and now we can move

14:08.740 --> 14:10.420
on to define the main function.

14:10.420 --> 14:14.710
So the one that will be automatically executed when the node starts.

14:27.520 --> 14:36.580
And here within this function let's initialize ros two with rcl cpp init to which we pass the argument

14:36.580 --> 14:37.420
of the main.

14:41.900 --> 14:47.770
And now we can create a new shared to an object of this simple service class.

14:47.780 --> 14:57.770
So let's call this one node and let's use the make shared function, which is a template function to

14:57.770 --> 15:02.030
create a new object of the simple service client class.

15:03.350 --> 15:10.190
However, since with this instruction we are basically calling the constructor, so we are executing

15:10.190 --> 15:14.990
this function Here we are executing the constructor of the Simple Service class.

15:15.020 --> 15:21.650
We also need to pass two integers so the number A and B, which will be the two numbers that then will

15:21.650 --> 15:25.220
be placed within the request message to send to the server.

15:25.880 --> 15:31.340
We can make these two numbers to be summed up some parameters of the script itself.

15:31.340 --> 15:36.710
So of the node, and namely, when we are going to launch the node, we are going to launch the node

15:36.740 --> 15:39.750
by passing also these two numbers.

15:39.770 --> 15:45.170
So for doing so, we can use the argument that are received by the Maine.

15:45.350 --> 15:51.020
And so here for example, we can start checking that actually the number of arguments.

15:51.020 --> 16:00.590
So argc is different from three and here we are using three because always the main function receives

16:00.590 --> 16:04.670
at least one argument as input, which is the name of the node itself.

16:04.670 --> 16:10.280
So apart from the name of the node, we also need the script to be started with two more additional

16:10.280 --> 16:13.490
arguments, which are the two integers that we want to sum.

16:13.970 --> 16:19.490
So if, for example, the script is started with a number of arguments that is different from the one

16:19.490 --> 16:22.400
that we expect, let's print an error message.

16:22.910 --> 16:38.540
So error, let's use the Xcp get logger function, let's get the logger for CPP and let's print the

16:38.540 --> 16:39.320
message.

16:41.010 --> 16:46.590
Wrong number of arguments.

16:46.590 --> 16:57.240
And then let's also say that we expect the usage of this node to be simple service client and then A

16:57.240 --> 17:05.940
and B, So we expect the user to start this node with simple service client followed by A and B, and

17:05.940 --> 17:09.000
now in this case, let's return one.

17:09.000 --> 17:14.550
That means we are returning an error and so we are aborting the execution of this script.

17:15.870 --> 17:17.100
So alternatively.

17:17.100 --> 17:23.160
So if we don't enter in this if statement, it means that the node has been started with the correct

17:23.160 --> 17:24.570
number of arguments.

17:24.570 --> 17:31.380
And so we can pass the first and the second of these argument directly to the constructor of the simple

17:31.380 --> 17:32.420
service class.

17:32.430 --> 17:43.260
So let's pass the first element, the first argument, and also the second one since by default, the

17:43.260 --> 17:44.700
arguments of the main.

17:44.940 --> 17:49.620
As you can see here, it's defined in an array of characters.

17:49.650 --> 17:56.280
We need to cast it before passing it to the simple service client as it expects to be integers.

17:56.280 --> 18:01.260
So let's use the function a two integer.

18:04.690 --> 18:06.820
To convert the character.

18:06.820 --> 18:08.950
So this one.

18:10.230 --> 18:11.370
Two integers.

18:13.250 --> 18:19.310
And then finally, so after the creation of the node, if, for example, we stop the execution of the

18:19.310 --> 18:27.110
node with C, let's shut down the node with the shutdown function, let's save it.

18:28.680 --> 18:34.470
And now with this, the simple service client script is complete, and so we can proceed to declare

18:34.470 --> 18:39.810
it and install it within the cmakelists.txt file.

18:39.840 --> 18:48.450
So here we can add a new executable so we can exactly copy what we did for the simple service server.

18:48.600 --> 18:54.240
And let's just change the name of the executable in simple service client.

18:54.570 --> 18:58.650
And the name of the script is the simple service client Dot CP.

18:59.310 --> 19:06.180
So let's also change it here in the target dependencies and the dependencies that the simple service

19:06.180 --> 19:08.820
client is going to need are the same as the server.

19:08.820 --> 19:12.720
So the CP and the Arduino both messages.

19:12.720 --> 19:14.940
And finally, let's declare.

19:14.940 --> 19:18.780
So let's install the simple service client also.

19:18.780 --> 19:21.870
So let's list it in the install statement.

19:22.800 --> 19:28.990
For this node, we don't have to modify the package dot XML file since the simple service client didn't

19:28.990 --> 19:30.820
introduce any new dependency.

19:30.820 --> 19:37.690
So it is using the same dependencies as the server so we can directly proceed to see how this node works.

19:38.200 --> 19:44.320
So let's open a new terminal and let's go into the workspace and let's start by building it.

19:44.320 --> 19:47.140
So click on Build.

19:51.310 --> 19:55.750
Once the build is successful, we can open a new window of the terminal.

19:56.720 --> 19:58.250
And we can start by.

20:00.700 --> 20:02.220
Sourcing the workspace.

20:02.260 --> 20:03.520
So the file setup.

20:03.730 --> 20:08.740
Bash And now we can start by running the service server node.

20:08.830 --> 20:11.950
So Ros, to run.

20:12.220 --> 20:19.120
And from the Arduino bot examples, let's start the simple service server node.

20:19.120 --> 20:23.440
So this is the one that we created in the previous Cplusplus lesson.

20:23.440 --> 20:28.030
And now once the server is up and running, we can also start the client.

20:28.030 --> 20:36.640
So in a new terminal again, let's source the workspace and let's start the client with the Ros to run

20:36.790 --> 20:44.830
and steal from the Arduino board example, let's start the simple service client.

20:44.830 --> 20:50.770
And now to start this node correctly, as you might remember, we also need to provide two additional

20:50.770 --> 20:54.180
arguments, which are the two numbers that we want to add together.

20:54.190 --> 20:57.310
For example, let's sum five entry.

20:57.490 --> 21:03.650
So let's press enter and in the terminal we can see that the client has correctly sent our request to

21:03.650 --> 21:04.250
the server.

21:04.250 --> 21:10.130
So we see the number five entry, the server elaborated and calculated the sum and then it was returned

21:10.130 --> 21:11.300
to the client.

21:11.720 --> 21:18.680
If, for example, we try to start the simple service client node with a wrong number of arguments,

21:18.680 --> 21:24.770
let's say without any argument, we see that there is an error message in the console that tells us

21:24.770 --> 21:26.720
that we expect an usage.

21:26.720 --> 21:32.570
So like this, we expect to run the simple service client and then followed by two numbers, the two

21:32.570 --> 21:34.700
numbers that will be added together.

21:35.180 --> 21:43.850
Now if we try to stop the service server and we try again to start the client this time with a correct

21:43.880 --> 21:49.610
number of arguments and we try to send the request, we can see that there is also an error message

21:49.610 --> 21:56.480
printed continuously so repeatedly every second, more or less, that says that the service is not available.

21:56.480 --> 22:01.660
And so the service client is still waiting for the service to come up.

22:01.660 --> 22:09.580
And as soon as we start it, we can see that actually it received the two new numbers that we are adding

22:09.610 --> 22:13.810
together and it returned correctly, the sum of these two numbers.
