In this laboratory lesson, we will create a simple Python action server that calculates the Fibonacci
sequence.
By implementing these actions, we will have a practical example of how to use the Ros two actions and
then we will use this as a template for implementing a more complex application in the upcoming lesson
of the course.
If you are only interested in the C plus plus development, then you can skip to the next lesson in
which we are going to implement the same action server in C plus plus.
In this lesson, we want to use the two actions to implement a node that calculates the Fibonacci sequence.
In mathematics, the Fibonacci sequence, also known as Golden sequence, is a sequence of integers
numbers where each number is the sum of the two preceding ones, except for the first two numbers,
which are by definition zero and one.
The length of the Fibonacci sequence is defined as the order.
For example, the first two numbers of this sequence indicate the order, one of this sequence.
Then the order two of the sequence is represented by the other number one, which is the sum of the
two preceding numbers.
And then the order three of this sequence is represented by the number two and so on.
The sequence continues indefinitely.
Diction server we are going to implement in this lesson will receive the order of the Fibonacci sequence
as a goal and will return the entire Fibonacci sequence up to the requested order as an output referred
to as the result of the action.
So let's add this node that contains the action server in the Arduino bot Pi examples package.
So here in the Arduino Pi example sub folder, let's create a new file called Simple Action Server dot
pi.
As usual, let's start by importing the Pi library and then still from this library.
So from the Pi, from the node modules, let's import the node class and let's use it to define a new
node.
So let's define a new class called Simple Action Server.
And this one inherits from the Node class.
And then let's start by defining the constructor of this class.
So the init function that is a member of this class and within the constructor, the first thing that
we do is to call the constructor of the base class.
So of the node class.
So let's call the init function of the base class to which we pass the name of the node that we call
simple Action server.
Now to create an action server inside this node, let's import from the SQL Pi Library and this time
from the action module, let's import the definition of the Action server class.
And now let's create this class to instantiate a new object.
So here in the constructor, let's create a new variable called Action Server.
As an instance of the Action server class.
And this class is responsible for creating and managing the communication of an action server.
The constructor of this class takes as input the Ross to node.
So the implementation of the node class, which is the current object.
And so the simple action server.
This is our implementation and we access to this one with the self variable.
So we refer to the simple action server with the variable self.
It also takes as input the communication interface that has to be used for the communication with the
action.
And so the interface which specifies how the goal, the feedback and the response messages for the communication
with the action are done.
So let's start by defining this interface.
And once again, as this is a Ros two interface, we can define it within the Arduino Bot messages package.
And so here in this package, as we defined the interface with a service in the SRV folder to define
the interface with an action, we need to create a new folder called Action.
And this folder let's create a new file called Fibonacci Dot Action.
And here we need to indicate how the goal result and feedback messages are done.
So let's start with the goal message.
And this is composed by a single integer that indicates the order of the Fibonacci sequence that we
want the server to calculate.
So this is an integer and is called order.
Next, let's use three dashes and then let's also define the result message.
And so the result message should contain a list of integer, this time representing the full Fibonacci
sequence that was calculated by the server.
So let's use an array of integers and let's call this one sequence.
And finally, still, by using three dashes, let's also define the feedback message.
And so the message that the server will send periodically whenever we add a new element to the sequence.
And also this one is an array, so an array of integers and let's call this one partial sequence.
So let's save this interface.
And now let's make sure that this interface is installed and also it's usable by other node by modifying
once again the file Cmakelists.txt.
Now still in the Ros generate interfaces instruction.
We can also define the interface with an action.
And so let's define the interface that we declared in the action folder and that is called Fibonacci
dot action.
Let's save this file.
And finally in the package dot XML.
So here of the Arduino bot messages, let's also add a dependency.
So here let's add a dependency from the action messages.
And now we can finally save also this file and we can move on.
And so we can build our workspace so that the new interface, the Fibonacci action interface is compiled
and we can start using it within our simple action server.
So let's open a new terminal.
Let's go to the workspace and let's build it.
Now we can finally start using our interface.
So here from the Arduino bot messages and from the action folder, let's import the Fibonacci interface.
And now let's use this one to initialize the action server object.
So here in the constructor of the action server object, let's say that this action server is going
to use the Fibonacci interface.
And also let's assign a name to the action server.
Let's call this one for example, Fibonacci, and this is the name that other Ros two nodes can use
in order to send goals to the action server.
And so in order to calculate the Fibonacci sequence, finally for the constructor, we also have to
define the name of the function that this server will execute whenever a new goal message is received,
which is the function that contains the logic for the calculation of the Fibonacci sequence itself.
We call this the call callback function.
So let's use the goal callback function and we are going to define this function still within the simple
action server.
So as a member of the Simple Action server class, with this we have instantiated and initialized a
new action server that is called Fibonacci, which uses a message interface called Fibonacci that is
defined in the Arduino board messages package.
Next.
Still in the constructor, let's print an informative message.
So with the get logger function, let's print an informative message that says Starting the server.
And now let's go on and also define the callback function.
So the goal callback function as a member of the simple action server class.
As this function will be executed.
Whenever a client sends a new goal to an action server, it receives the goal message as an input.
So the one that we defined in the Fibonacci action interface.
And so let's call this variable goal Endl.
So when this function is called, let's start by printing an informative message.
So still with the get logger function.
Let's print an informative message.
And this message says received call request with order.
And then let's print the order that was just received.
And so basically we can display the order by accessing the goal handle.
And from this one, let's access to the request and then to the order.
Next, let's create a new feedback message that will be sent periodically to the client, informing
it about the progress of the Fibonacci sequence calculation.
So let's call this one feedback message, and this is from the Fibonacci interface, an instance of
the feedback message feedback.
Okay.
And we can already initialize it with the first two numbers that always make up a Fibonacci sequence.
So let's access to the feedback message and to the partial sequence and let's initialize the sequence
with the numbers zero and one that always are present within the Fibonacci sequence.
And now we can implement the actual logic for the Fibonacci sequence calculation.
So let's create a for loop that goes from one.
So let's create a new variable E in range.
And so this goes from one until the requested order.
So the goal Endl request order.
So this for loop goes from one to the requested order of the Fibonacci sequence.
And then at each iteration of this loop, let's add a new element to the partial sequence.
So to the feedback message, to the partial sequence, which is an array.
Let's append a new element, and this new element is given by the sum with the last element that is
present in the partial sequence.
So let's take again the partial sequence.
Here and let's access to the last element.
So to the element, to the position I and let's add to this one the element at the previous position.
So the second last one position.
So still to the partial sequence, let's access to the element I minus one at each iteration.
Let's also print an informative message in the terminal.
So with the get logger function, let's print an informative message with the current feedback.
So feedback.
And then let's print the partial sequence.
So let's format this string in order to print the feedback message partial sequence.
So in order to print the Fibonacci sequence that we have calculated up to this moment, so up to this
loop iteration.
Then by using the goal and object, we can send this feedback message also to the client, informing
it about the progress of the server.
To do so, let's use the function, publish feedback of the goal and object.
And to this one we pass the feedback message.
Finally to simulate that the action server is performing as low and resource intensive operation.
So an operation that takes some time to complete.
Let's add a slip to the loop.
And so this will pause the execution of the script for a second.
So at each iteration of this loop, let's pause the execution for one second.
To do so, let's import the Python time library.
And now from this library.
So from the time library, let's use the slip function to make this script slip for one second and then
it will continue with the execution of the for loop once the loop is finished.
So the action server will have calculated all the numbers in the Fibonacci sequence and also will have
sent a feedback message for each of the elements that it has calculated.
And so now we can conclude the action and return a result message to the client.
So let's use the goal and goal variable and let's set this one to succeed.
And then let's also create a new result message as an instance of the Fibonacci interface.
And so of the result message that we declared in this interface.
And now so this is the result variable.
And now let's set to the result variable to the sequence.
Let's set basically the full Fibonacci sequence and so we can set this one equal to the feedback message,
partial sequence.
Since up to this point, the partial sequence already contains all the elements that makes up the Fibonacci
sequence up to the requested order so we can set this one.
The sequence of the result equal to the last partial sequence that is in the feedback message.
And so let's return exactly this result message to the client which requested the execution of these
actions.
With this the simple action server node.
So this class is completed and now we can define the main function.
And this calls the function main that we can define here.
So let's define the function main.
And now within this function, let's start by initializing ros2 with rcl pi init.
Then let's create a new instance of the simple action server.
So let's call this variable simple action server as an instance of the simple action server and let's
keep this node up and running.
So let's keep the action server up and running ready to receive new goals.
So let's use the Pi spin function to spin the simple action server.
And as usual, when we press control C, let's make the shutdown of this node so simple Action server.
Let's destroy the node, destroy the node and also let's make the Pi shut down.
So let's call this shutdown of this node.
As usual, in order to compile and install this script, we need to add it into the setup.py file.
So here we need to add a new line in the console script.
So in the entry points so we can copy the one for the simple service client and let's call this one.
So the new executable Simple action server and its source code is still in the Arduino, but by examples
this time is in the simple action server.
And still from this script we want to execute the main function.
Now we can save also this file and we just need to compile our workspace again so that the new node
becomes an executable.
So let's open a new terminal, go to the workspace and let's build it with the command.
Click on Build.
Once the build is succeeded, we can open a new window of the terminal and finally we can start our
action server.
So let's source the file setup dot bash so that the Arduino Pi example package is recognized.
And now from this package, so from the Arduino Pi examples.
So if we press tab twice now we can see that there is the simple action server available.
So let's start this one, the simple action server, let's press enter and we get the confirmation that
the action server is running from the terminal so we can see that the simple action server is saying
starting the server and also we can actually double check it by opening a new terminal.
And here we can use the command Ros2 action list.
So let's press enter.
And since we have started only one node, so the one that creates and starts the Fibonacci action server,
this is also the only action server that is currently available in Ros two.
So this one if we search the workspace also in this new terminal.
So let's source the file setup dot bash.
We can have additional information about this action server using the command Ros2 action info followed
by the name of the action, which is the Fibonacci, followed by the minus D flag in order to show also
the message interface.
So the type of the interface that this action is using.
So let's press enter and currently we can see that for this action server there is only one node that
is interacting with it.
So here that is the simple action server node that actually creates this action server.
And also we can see that this action server is using the interface Fibonacci as declared in the Arduino
board messages.
At this moment we can see that there are no clients, so actually there is nobody that is interested
in the functionalities of this server and we can send a new goal to this server.
So to the Fibonacci server in order to see how it works, to send a goal to an action server, we can
use the command Ros2 action and then send goal followed by the name of the action, which is the Fibonacci,
the action server.
Then if we press tab twice we can see that the Ros two autocompletion is able to detect that we need
an interface of type Arduino board messages Fibonacci.
So let's use this interface to send a new goal to the action server.
Then let's use double quote.
And then let's set the order.
So let's press tab.
And so this has inserted an empty prototype of the goal message that we are going to send to the Fibonacci
action server.
So, for example, let's set the order to ten.
So we are asking the action server to calculate the Fibonacci sequence up to the order ten.
Let's also use the flag minus F in order to print the feedback messages that the server will send in
this same terminal.
So minus F stands for feedback.
So let's press enter and as soon as we send this goal, we can see how the action server informs us
that it has received a new goal and also that it starts processing the Fibonacci sequence element by
element up to the order ten for each number.
Also, we can see that for each new element that the server is adding to the sequence.
It also sending a feedback message that informs us about the progress of the goal.
And finally, once the desired order is reached, the action server also returns a result message.
So this one here with default.
So the complete sequence up to the desired order.
So up to the order ten.