In this laboratory lesson, we will create a service client in Ros two using C plus plus that use the
functionality offered by the service server developed in the previous laboratory lesson.
In practice we are going to create a C plus plus node that uses the service for the sum of two integers,
which we called Add Joins.
And so following what we have learned in the theoretical lessons, the client will send a request to
the service according to the message interface defined by the service and then will be notified with
a response message when the server completes its execution.
So let's create a new script inside the Arduino bot CP examples in the source folder.
And here let's create a new file called Simple Service Client Dot CP here.
Let's start by including the CP and the CP dot PHP, which we can use to create a new Ros two node.
So let's create a new class called Simple Service Client, which inherits from the RCL, CP.
So from the Node class.
And let's define this class.
Let's start by defining among the public attributes of this class, the constructor.
So the function that has the same name of the class that we called Simple Service client.
And here, in order to initialize also the base class, let's call the node constructor to which we
provide a name.
So let's call this node simple service client and also let's make the constructor so the simple service
client constructor to receive two parameters.
So to integers as input that we call A and B and these two numbers.
So these integers will be the one that will be added together.
So when we are going to create a new object of the simple service client class, also we need to pass
the two numbers so A and B that we want to send so that we want to request to the service server.
Let's continue by adding among the private variables of this class a new shared pointer of type rql
CPP client.
So this is a template class and we take a shared pointer from this class which we call client.
So let's include also the memory module from the standard C plus plus library.
And now, just as we did for the server class, the client class.
So as we can see here is a template class and receives among the angular parentheses the type of the
interface that it needs to use for the communication with the server.
So we define this interface in the Arduino board messages in the service folder and in the Add joints
interface.
And so let's also say that the client that we are going to create use this interface.
And so from the Arduino, what messages from the service it uses the Add joints interface.
And now we can proceed actually to initialize this variable within the constructor.
And as you might have, imagine, if for creating the service, we used the create service function
to create the client, we use the create client function that is also, in this case, a template function.
And also this function requires as input the type of the interface that it has to use for the communication
with the service.
And so this is in the Arduino board messages.
So in this service we are using the Add joints interface.
And then among the parentheses, it also receives the name of the service, which is the name by which
the server is recognized in roster.
And so we called this one add to its.
Now that we have our client, we can create a request message that we are going to send to the client.
So let's create a new variable that we called request.
And let's initiate this one with a shared pointer.
So this is a shared pointer that we can create with the function, make shared from the standard C plus
plus library.
And here we need to define the type of the interface.
So this is our request message that is defined in the Arduino board, message in the server folder,
in the Arduino interface.
And we want to create an instance of the request interface.
Now we can assign a value to the variable A.
So from the request message, let's assign a value to the variable A and let's set this one equal to
the variable A that we received as input of the constructor.
And let's do the same also for the variable B.
So request B is equal to the variable B that was received an input from the constructor.
Now, before sending these requests to the server, let's first verify that actually the server is running
and so it's available to receive new requests.
To do so, we can use the function, wait for service.
So on the client object, let's use the wait for service function.
And let's put this one within a while loop.
So while the wait for service function doesn't return true.
So while we have not found any service that corresponds to this name, let's wait more time.
And so let's import the Chrono Library of C plus plus and then let's use the namespace STD.
Chrono Literals.
And let's use this one in order for the client to wait for service one second before considering it
not available.
So here the client will wait for the service one second and if it's not available, it will print an
error message in the terminal.
So with the function rcl cp error, let's print a message.
So let's first get the logger with the name RCL, CP and then let's print the message that says service
not available.
Waiting more time.
So here it just says that it's going to wait again.
Let's also check actually that Ross is still running.
So let's check that RCL CP is still okay.
And if is not.
So if this is not, let's stop waiting for service.
So let's stop this function here with another error.
So rcl cp error.
Let's get logger with the name rcl, cp and let's print the message interrupted while waiting for service.
So this message is going to be printed if, for example, the service assurance is not yet available
and we interrupt the execution of the node so the client is not is not able to find the service.
And also Ross is not running anymore.
So we are going to execute.
So we are going to see this message in the terminal and in this case, let's terminate the execution
of the node with the return.
Otherwise, if Ross is still okay, we are going to continue waiting for the service to appear.
Alternatively, if we are out of the while loop, this means that we have found a service named Adjoints
in Ross.
True, and also that this service is ready to process any new request.
And so at this point we can send a new request to the service by using the client object.
And on this object, let's call the async send request.
And this function we need to pass the request message that we just created and in which we inserted
the A and B values.
And now we can also store the result of this function into a new variable that we called result.
And so that stores the output of the async send request function.
This function.
So the async send request sends the request to the service and immediately returns a result.
So this one that is a future variable without waiting for the server to finish its execution.
So actually we don't know where the service is done with its execution.
We can know, for example, when the service is done by adding a callback function.
So namely a function that is executed whenever the service finished is processing.
So its calculation and we can define this one still within the async send request function and we can
use the bind function.
So standard bind from the standard library and let's call this function response callback and we are
going to define this function still within the simple service client class.
So let's declare the response callback.
As a member of the simple Service client class.
Also, let's use the pointer.
This to indicate that we want to use this object, the current object for the implementation of the
response callback.
And also then let's declare the usage of the placeholders modules from which we take just the placeholder
number one that we use to indicate that the function response callback receives one input.
So just takes one input and now we can actually move on so we can see that there is an error because
actually we have not yet defined the response callback function which we can do here among the private
variables.
So among the private variables of the simple service client class.
So this return type is void and this function receives as input a future variable.
So this one is in the RCL CPP client class, which is a template class and which requires as input the
message interface that is used for the message exchange with the service.
So again, the add to interface that is in the Arduino board messages package.
And then let's take a short pointer.
So shared future and let's call this variable.
Future.
These future variables provide a mechanism for accessing the result of an asynchronous operation where
there are some threads that are waiting for the results of other threads.
So if this future variable is valid.
So let's check.
That this variable is valid.
In this case, let's print an informative message into the console.
So with the SQL CPP info stream, then let's use the Get logger to get the SQL CPP logger and let's
print the message service response.
And from the future variable, let's take its content.
So the result message.
So from the future variable, let's take its content.
And from this one we want to access to the variable sum.
So let's close this one.
And here actually we need to close this parentheses and here we don't need any parentheses.
Otherwise.
So here else if this function so if the result of the future variable is not valid.
Let's simply print an error message.
So rcl cp error and this error message.
Let's take the get logger and let's call it RCL.
CP And the message that we are going to print is simply service failure since we have not been able
to get the future variable.
So to read from the future variable the response.
And so the sum variable with this, the simple service client class is complete and now we can move
on to define the main function.
So the one that will be automatically executed when the node starts.
And here within this function let's initialize ros two with rcl cpp init to which we pass the argument
of the main.
And now we can create a new shared to an object of this simple service class.
So let's call this one node and let's use the make shared function, which is a template function to
create a new object of the simple service client class.
However, since with this instruction we are basically calling the constructor, so we are executing
this function Here we are executing the constructor of the Simple Service class.
We also need to pass two integers so the number A and B, which will be the two numbers that then will
be placed within the request message to send to the server.
We can make these two numbers to be summed up some parameters of the script itself.
So of the node, and namely, when we are going to launch the node, we are going to launch the node
by passing also these two numbers.
So for doing so, we can use the argument that are received by the Maine.
And so here for example, we can start checking that actually the number of arguments.
So argc is different from three and here we are using three because always the main function receives
at least one argument as input, which is the name of the node itself.
So apart from the name of the node, we also need the script to be started with two more additional
arguments, which are the two integers that we want to sum.
So if, for example, the script is started with a number of arguments that is different from the one
that we expect, let's print an error message.
So error, let's use the Xcp get logger function, let's get the logger for CPP and let's print the
message.
Wrong number of arguments.
And then let's also say that we expect the usage of this node to be simple service client and then A
and B, So we expect the user to start this node with simple service client followed by A and B, and
now in this case, let's return one.
That means we are returning an error and so we are aborting the execution of this script.
So alternatively.
So if we don't enter in this if statement, it means that the node has been started with the correct
number of arguments.
And so we can pass the first and the second of these argument directly to the constructor of the simple
service class.
So let's pass the first element, the first argument, and also the second one since by default, the
arguments of the main.
As you can see here, it's defined in an array of characters.
We need to cast it before passing it to the simple service client as it expects to be integers.
So let's use the function a two integer.
To convert the character.
So this one.
Two integers.
And then finally, so after the creation of the node, if, for example, we stop the execution of the
node with C, let's shut down the node with the shutdown function, let's save it.
And now with this, the simple service client script is complete, and so we can proceed to declare
it and install it within the cmakelists.txt file.
So here we can add a new executable so we can exactly copy what we did for the simple service server.
And let's just change the name of the executable in simple service client.
And the name of the script is the simple service client Dot CP.
So let's also change it here in the target dependencies and the dependencies that the simple service
client is going to need are the same as the server.
So the CP and the Arduino both messages.
And finally, let's declare.
So let's install the simple service client also.
So let's list it in the install statement.
For this node, we don't have to modify the package dot XML file since the simple service client didn't
introduce any new dependency.
So it is using the same dependencies as the server so we can directly proceed to see how this node works.
So let's open a new terminal and let's go into the workspace and let's start by building it.
So click on Build.
Once the build is successful, we can open a new window of the terminal.
And we can start by.
Sourcing the workspace.
So the file setup.
Bash And now we can start by running the service server node.
So Ros, to run.
And from the Arduino bot examples, let's start the simple service server node.
So this is the one that we created in the previous Cplusplus lesson.
And now once the server is up and running, we can also start the client.
So in a new terminal again, let's source the workspace and let's start the client with the Ros to run
and steal from the Arduino board example, let's start the simple service client.
And now to start this node correctly, as you might remember, we also need to provide two additional
arguments, which are the two numbers that we want to add together.
For example, let's sum five entry.
So let's press enter and in the terminal we can see that the client has correctly sent our request to
the server.
So we see the number five entry, the server elaborated and calculated the sum and then it was returned
to the client.
If, for example, we try to start the simple service client node with a wrong number of arguments,
let's say without any argument, we see that there is an error message in the console that tells us
that we expect an usage.
So like this, we expect to run the simple service client and then followed by two numbers, the two
numbers that will be added together.
Now if we try to stop the service server and we try again to start the client this time with a correct
number of arguments and we try to send the request, we can see that there is also an error message
printed continuously so repeatedly every second, more or less, that says that the service is not available.
And so the service client is still waiting for the service to come up.
And as soon as we start it, we can see that actually it received the two new numbers that we are adding
together and it returned correctly, the sum of these two numbers.