In this laboratory lesson, we will develop a simple service server in C plus plus that will provide
the functionality of calculating the sum of two integers.
Then we will also develop a client that will use this service within another Ros two node.
This will help us to understand how services works practically and how to use the Ros to command line
interface to interact with them.
Let's start by creating a new Cplusplus script inside the Arduino.
CPP examples.
So inside the source folder.
And let's call this script simple service.
Server dot cpp.
Here, as always, let's start by importing the CPP library.
And so let's include the CPP dot PHP.
And then from this library, let's use the node class to create a new Ros2 node.
So let's call this one simple service server that inherits from the CPP library and so from the node
class.
So let's define this class and among the public methods of this class, let's start as always by declaring
the constructor of this class.
So the function simple service server and here, as we did in the previous lesson.
Also, let's start by initializing the node class.
So the base class and we need to provide as input of the constructor the name of the node, let's call
it, for example, simple service server.
Now among the private variables of this class.
So here let's create a new object of type service.
So from RCL, CP, let's create a new service.
And this is a template class and we take a shared pointer to this class and let's call this variable
service.
Now let's also remember to include here include the memory library from C plus plus in order to be able
to use the shared pointer and now the service template class.
So this one here needs as input.
So among the angular parentheses, the name of the message interface.
So the one that contains the request and response message that should be used in order to communicate
with the service server.
To do this.
If you haven't followed me in the Python laboratory lessons.
We need to create a new message interface for the communication with the server that we are going to
create by convention.
And also as a general rule in Ros2, it is recommended that all the new message types, both those for
interaction with topics and those for the communication with services are placed in a different package
than the ones that contains instead the robots functionalities.
So if you haven't done so, let's open a new terminal and let's go to the Arduino Bot workspace and
then to the source folder.
And here let's create a new package.
So to package, create and let's use as a build type, amend CMake and let's call this package Arduino
bot messages as it will contain just message interface for the communication in Ros2.
I have already created this package in my workspace, so I'm not going to run this command again.
But anyway, you can see it created here.
So now you need to go back to your workspace and build it again with the command called build so that
the new package is recognized and is ready to use in Cplusplus.
So go back in Visual Studio code.
And now here we can define the new message interface that the service server must use for the communication
with the service server.
So within the Arduino bot messages still, if you haven't followed me in the Python lessons, you need
to create the serve folder.
That by convention is where we place all the message interface with the service servers.
And so here you need to create the add joints.sv file.
And inside this file we need to define the structure of the request message that is the one that the
client sends to the server.
And this one contains just two integers, two numbers that are the two numbers that we want the server
to send and then separated by three dashes.
We also need to declare the response message and this server will simply return another integer, which
is the sum of the two integers received as inputs or received in the request.
With this we have completed the definition of the add joints and so in order to use it, we need also
to declare it inside the cmakelists.txt so that the compiler is aware of the existence of this message
interface here in the previous lesson.
First of all, we declared the usage of the standard message library, which contains the definition
of the integer message.
Then we also define the usage of the Ros IDL Default Generators library.
That is the one in charge of compiling our SV files.
So in general our Ros to interface messages and make them available to the node.
So to the scripts both Cplusplus and Python.
Then also we used the instruction Ros generate interfaces in order to generate the interface for the
current project.
So for the current package that is the Arduino board messages and we declared the existence of the Arduino
dot SVG file within the SVG folder.
Next.
We need to also to modify the package dot XML file and here we need to add the dependency still from
the standard message library.
Also, we need to add a build dependency from the Ros IDL Default Generators library.
That is the one that we are going to use to build our messages.
Then we also need an execution dependency from the Ros IDL default runtime.
And finally, we also need to use this tag so the member of group in order to declare and so in order
to use the ros IDL interface packages.
And this is all we need in order to define and declare this interface.
So the Add joins interface that from now on we can use within our script.
So both within our Python and our C plus plus script.
But before doing so, so after you create this interface in the Arduino board messages in order for
it to be recognized by Roscoe, let's go back again in the workspace and let's build it with the command
called build.
Now the interface is compiled and we can go back to our simple service server here and we can start
using this interface.
So let's include and from the Arduino board messages here, if you don't have the autocompletion of
the text, you need to press Ctrl shift P and then look for Ros.
Update Cplusplus properties.
So this will scan again the workspace and will enable the Autocompletion for Ros two.
And so then from the Arduino bot messages, we have the Autocompletion now from the SR folder, let's
import the Add joints interface and now we can use this interface within the angular brackets.
So here inside the service to declare that the service server that we are going to use is using the
interface from the Arduino board messages from the service and that is called add to INS.
Now here in the body of the constructor of the Simple Service Server class, let's initialize the service
variable.
So this shared pointer and as we used the create publisher function to initialize our Ros to publisher
and the create subscription function to initialize our subscriber, we can use the Create service function.
So create service function to initialize our service server.
This is a template function that requires, again among the angular parentheses the type of the interface
used for the communication with the service server, which once again is this one is the one that we
declared in the Arduino board messages and that is called Add joins.
Inside the parentheses instead.
So here, as the input of the function, we need to pass the name to give to this service.
So the name by which this service will be recognized in Russia, for example, let's call it add two
ins.
Then also as input, we need to provide a callback function.
So namely a function that has to be executed by the service server every time it receives a new request.
So every time a new client requests the execution of the server.
And so the execution of this of the two integers to do so, we can use the bind function of the C plus
plus standard library and let's call the function service callback, which we are going to declare still
within the simple service server class.
So let's say that this service callback function will be a member of the simple service server class
and that we want to use the one declared in the current instance.
So in the current object.
And then also let's use the placeholder namespace.
So using from the standard library, the namespace STD placeholders.
And so from this namespace, let's use the placeholders one and two to indicate that this callback function.
So the service callback function will require two inputs.
So we require two variables as input.
That will be exactly the two messages contained in the interface with the server.
So the request and the response message.
To finish the constructor of this class, let's just print an informative message in the terminal.
So with the CP info and let's print the message.
Let's take the reference to the logger with the get logger function and let's print the message.
So service.
And then the name of the service that is at two ends is ready.
So that we can confirm that the service has been correctly instantiated.
Now, still here, among the private attributes of the simple service class, we can define the service
callback function.
So let's copy this one and let's define this function.
So it returns void.
So it returns no parameters.
And as this is a callback function, as we said previously, it requires a input the message interface
to be used for the communication.
And so for the data exchange with the service server, therefore it receives a shared pointer to a request
message.
So it receives a constant
shared pointer of type Arduino, both messages and then from the service from the Arduino interface
of.
So it receives a request message and let's call this variable request.
And then the second input of this, one of this function is still another constant pointer.
So another shared pointer.
And this time still from the Arduino bot messages.
Let's take from these services the add to into service and let's take the response and let's call this
one response.
As a first thing in this callback function, let's print another informative message in the terminal.
So with the rql cpp info stream function.
And here let's use the function Rcpp get logger.
And then let's print the message.
New request received followed by the two numbers.
So the two integers that were received in the request message.
So a that is in the request message.
And also let's print B and also this one is in the request message under the name of the variable B.
Then after this message, we can execute the actual logic of the server that basically consists of calculating
the sum of the two integers that were received as input.
So it calculates the sum between the variable A plus the variable B that are in the request message.
And let's store the content of this operation within the response message and within the sum variable.
So within the sum variable, let's store the sum of these two and let's finally print one more message
in the terminal.
Still, let's use the jet logger
and let's print the message returning some.
Followed by the sum.
So here, let's use the double quotes.
And now let's print.
The sum of the two numbers that is in the response message under the name of the variable sum.
This is all we need for the moment, for the definition of all the components of this simple service
server class.
And now we can move on to create the main function.
And let's return zero.
And here let's initialize the node with rcl.
CPP init.
Then let's create a new shared pointer.
So a new shared pointer to the simple service server class.
So let's create a new variable called Node and then let's use the function make shared from the standard
C plus plus library.
And we want this one to create a pointer.
So a shared pointer to an object of the simple service server class.
And so let's save this one within the node variable.
And now let's keep this node up and running with the CPP spin function.
So let's keep the node running.
And then if, for example, we terminate the execution of the node with control C, let's shut down
Ross with RCL cpp shut down function.
With this, we have completed also our simple service server node.
So before executing this node, let's modify also the file Cmakelists.txt in order to install it.
So in order to declare the missing dependencies and also to install the new executable, first, we
need to declare the dependency from the Arduino board messages library.
So Arduino board messages.
That is the package that contains the definition of the interface with the service.
Then we can add a new execute table so we can basically copy these two instructions and we can paste
it below.
And so let's call this new executable simple service server.
So let's copy this one.
The Executable.
So the script is also called Simple Service Server Dot CP.
And then let's also add the the target dependencies to this script that are the RCL, CP and the Arduino
board messages.
So let's copy this one.
Finally in the install section.
So here we also need to install this new node.
So the simple service server.
So let's list it below the other executable that we have already created so far.
Last but not least, since we used the Arduino bot messages in the new executable.
Now we need also to declare its usage in the package dot XML.
So here let's add a new dependency from the Arduino bot messages package.
Now everything is set and we can proceed to run our node.
So let's open a new terminal and let's go into the workspace and here let's build it.
So click on Build so that the new node is compiled and we have an executable that we can run.
Here.
We forgot in the main function.
Yes.
Here.
We forgot to pass the argument of the main to the cpp init.
So let's save and build again.
And also here we have another error because in the get logger we need to specify that we want the logger
for the CP.
So let's copy this one also here and here.
So whenever we use the get logger function.
So let's give it one more try.
And now the build is finally successful so we can start using our node.
So let's open a new terminal.
And here let's search the workspace.
So the file setup dot bash.
And now we can finally run our service server.
So, Ros to run.
And from the Arduino bot CP examples, let's start the simple service server node.
So let's press enter and as soon as we launch it, we have the confirmation that the server is ready.
So the service server is ready and we can also double check it.
If we open a new terminal and we launch the command Ros two service list.
Actually we can see that among other services that were automatically created by Ros2, there is a word
service, so the Add Chewins service.
Furthermore, if we source the workspace also in this terminal, we can get additional information about
the service and so about the type of the communication interface that the service Atkins is using.
And we can do so with the command Ros2 service type, followed by the name of the service that is the
Atkins.
So let's press enter and we can see that this service is using the interface, Atkins declared in the
Arduino bot messages.
Also from the terminal.
We can also send a request message to the service and so we can use the command rescue service call
this time and then followed by the name of the service which we want to call.
And this is the Add Chewins.
And this is followed then by the type of the message interface that we need to use in order to contact
with the server.
If we press tab twice, we can see that Ross two is able to automatically detect the type of the interface.
So let's type the interface and then if we use double quotes and press tab twice again, and then type
the letter A and tab again, Ros two is able to autocomplete the text.
And so here we have a prototype of the message.
So of the request message that we can send directly to the service server.
For example, let's ask the service server to calculate the sum between the number seven and five.
So let's press enter.
And as you can see, the request is sent to the service.
So here it is, informing us that it received a new request and the request contains the numbers seven
and five and also that it returned, it calculated correctly the sum and it is returning the correct
sum to the client that then is receiving correctly.
So here is the response that the client is receiving from the server.