WEBVTT

00:00.920 --> 00:08.060
In this laboratory lesson, we will implement our first Ros two node in C plus plus that will use the

00:08.060 --> 00:13.670
publisher subscriber communication protocol to publish a message within our Ros two topic.

00:14.800 --> 00:17.860
Let's start by opening Visual Studio code.

00:17.860 --> 00:21.090
And here let's open the robots workspace.

00:21.160 --> 00:24.160
So let's open a folder.

00:25.860 --> 00:29.490
And let's open the folder that we called Arduino Bot Workspace.

00:30.560 --> 00:36.890
Inside the workspace in the source folder, we already find the two packages we created in the previous

00:36.890 --> 00:42.680
lesson and so the Arduino Pi examples and the Arduino, but CP examples.

00:42.680 --> 00:50.270
So let's open the CP examples package where the Ros two package create command is already automatically

00:50.270 --> 00:53.210
created various folder and files.

00:53.210 --> 00:55.520
And this is the typical structure.

00:55.520 --> 01:01.040
So this is the typical convention that is used for each C plus plus package in Ros two.

01:01.800 --> 01:03.420
The include sub folder.

01:03.420 --> 01:07.740
So this one contains another sub folder that has the same name of the package.

01:07.740 --> 01:11.100
And so Arduino CP examples.

01:11.100 --> 01:18.750
And this will contain the definitions of function and classes in C plus plus instead, the source folder

01:18.750 --> 01:25.140
contains the C plus plus files that define the behavior of function and classes, which is where we

01:25.140 --> 01:28.230
will insert the logic of each Ros two node.

01:28.320 --> 01:38.640
So within this source folder, let's create a new file and let's call this one simple publisher dot

01:38.640 --> 01:40.530
CP here.

01:40.530 --> 01:44.880
Let's start by including the CP library.

01:44.880 --> 01:56.280
So let's include the CP, and from this one, let's take the CP CP.

01:57.160 --> 02:04.120
And this library will allow us to use all the functionalities of Ros two within our script so we can

02:04.120 --> 02:13.540
use it to create a new Ros two node by creating a new class called, for example, Simple Publisher

02:13.540 --> 02:22.000
that inherits from the node class that is defined in the CPP package.

02:22.000 --> 02:25.030
And so let's inherit from the node class.

02:27.600 --> 02:32.310
First among the public methods of the simple publisher class.

02:33.480 --> 02:34.590
Among the public one.

02:34.620 --> 02:37.710
Let's start by defining the constructor of the class.

02:37.710 --> 02:40.590
That is the function that has the same name of the class.

02:40.680 --> 02:42.450
So simple publisher.

02:42.450 --> 02:46.800
And that is automatically executed when we create a new object of this class.

02:46.950 --> 02:52.980
And so when initializing a new object of the simple publisher class, the first step that we want to

02:52.980 --> 02:56.100
do is to initialize the component of the base class.

02:56.100 --> 02:58.110
So of the node class.

02:58.350 --> 03:03.480
By executing the constructor of the node class, that is the base class.

03:03.600 --> 03:10.980
And let's assign it a name to our node that we call simple publisher.

03:11.340 --> 03:14.150
Then among the private attributes.

03:14.160 --> 03:21.450
So here, let's add some support variables here.

03:22.490 --> 03:24.880
Let's open and close the parentheses.

03:25.090 --> 03:28.870
And here among the private variables, let's add some support variables.

03:28.870 --> 03:36.310
So let's start by adding an unsigned int called counter.

03:36.310 --> 03:41.310
And this will count the number of messages that are published within the Ros2 topic.

03:41.320 --> 03:45.760
So let's initialize this 1 to 0 when we execute the constructor.

03:45.760 --> 03:50.710
So let's set the counter variable to zero.

03:51.420 --> 03:58.290
Now that we have initialized the Ros two Node class, let's create a new publisher object using the

03:58.290 --> 04:00.590
Create Publisher function.

04:00.600 --> 04:10.800
So here in the constructor let's use the Create publisher function that is defined in the node class

04:10.800 --> 04:12.390
from which we are inheriting.

04:12.750 --> 04:18.060
And let's save the content so the output of this function in a new private variable.

04:18.060 --> 04:27.240
So here let's declare a new private variable as an object of the CPP publisher class.

04:28.060 --> 04:31.420
And we need to indicate here the message type.

04:31.420 --> 04:35.450
So the type of interface to be used for the message exchange.

04:35.470 --> 04:42.610
In practice, we need to specify the type of message the publisher object will send through the topic.

04:42.760 --> 04:49.180
For example, let's assume that we want to send text messages, so we want to send strings and the string

04:49.180 --> 04:52.730
message type is defined in another rescue library.

04:52.750 --> 05:01.790
So let's include from the standard messages library from the messages that are defined in this library.

05:01.810 --> 05:06.310
Let's include the string dot Http.

05:08.190 --> 05:09.390
And let's use it.

05:09.390 --> 05:16.290
So here when we are declaring the publisher object among the angular parentheses of this template class,

05:16.320 --> 05:22.020
let's use the message type standard messages.

05:22.680 --> 05:28.680
And from the messages of this library, let's take the string message.

05:29.650 --> 05:39.250
And let's take a shared pointer to this class and let's call this shared pointer Pope.

05:39.460 --> 05:46.630
Now we can finally store the output of the create publisher function within the Pope.

05:46.660 --> 05:47.380
Shared pointer.

05:47.380 --> 05:54.430
So within the Pope variable and also inside the angle brackets of the Create publisher class, we still

05:54.430 --> 05:58.540
need to indicate the type of message that we want to publish in the topic.

05:58.540 --> 06:05.740
So still from the standard messages library, from the messages of this library, let's use the string.

06:05.740 --> 06:11.590
And then instead in the parentheses we need to set the name of the topic in which we want the messages

06:11.590 --> 06:12.750
to be published.

06:12.760 --> 06:15.520
So let's call this one for example chapter.

06:15.520 --> 06:21.370
And furthermore, we also need to indicate the size of the queue, namely the size of the message queue

06:21.370 --> 06:22.930
that works as a buffer.

06:22.930 --> 06:29.570
If the subscriber to this topic is not receiving and processing messages fast enough, let's set this

06:29.570 --> 06:31.010
one, for example, to ten.

06:32.380 --> 06:34.660
At this point of the node initialization.

06:34.660 --> 06:40.210
Let's create a new timer object using the create wall timer function.

06:40.210 --> 06:44.590
So create wall timer.

06:44.590 --> 06:50.260
And this is still a function that is available from the node class from which we are inheriting.

06:50.410 --> 06:58.210
And let's call this function and again, among the private variables of the simple publisher class.

06:58.210 --> 07:09.820
So here let's define a new shared pointer to a class of type RCL, CP timer base, and let's take a

07:09.820 --> 07:16.360
shared pointer to this class and let's call this one timer.

07:16.360 --> 07:18.520
And now we can use this object.

07:18.520 --> 07:24.910
So this variable timer we just created to store the output of the create world timer function.

07:25.480 --> 07:28.450
So timer equals to create world timer.

07:29.320 --> 07:36.400
This function allows us to define a Ros two timer whose task is to repeatedly execute a specific function

07:36.400 --> 07:37.960
at a certain frequency.

07:37.990 --> 07:42.010
So the create timer function takes as input.

07:42.010 --> 07:47.420
So here between the parentheses, the frequency at which we want to execute the function.

07:47.440 --> 07:51.880
For example, let's assume that we want to execute it with a frequency of one second.

07:52.000 --> 07:59.440
So first, let's start by including here, the Chrono Library.

08:00.130 --> 08:07.300
And this is a plain cplusplus library and let's use so using namespace.

08:09.550 --> 08:10.090
Chrono

08:12.370 --> 08:18.550
literals in order to use the definition of the one second.

08:18.550 --> 08:22.660
So in order to create a world timer that will expire each second.

08:23.350 --> 08:30.490
Then in order to create this timer function, we also need to pass as input the name of the function

08:30.490 --> 08:36.460
that we want to execute at regular time intervals so that we want to execute every time the timer expires.

08:36.730 --> 08:44.890
To do so, let's use the bind function from the standard Cplusplus library and we want to execute the

08:44.890 --> 08:46.810
timer callback function.

08:46.810 --> 08:53.650
So timer callback, which we are going to define inside the same class.

08:53.650 --> 08:56.620
So inside the simple publisher class.

08:56.620 --> 08:57.460
So.

08:58.350 --> 09:06.450
Let's use the simple publisher in order to declare that the timer callback will be defined in the simple

09:06.450 --> 09:07.370
publisher class.

09:07.380 --> 09:13.260
And then let's also use the this pointer to indicate that we want to use the version of this class that

09:13.260 --> 09:15.450
is defined in this current object.

09:16.120 --> 09:19.360
As last step for the constructor.

09:19.360 --> 09:28.750
So here let's also print an informative message in the terminal using the CP info function which is

09:28.750 --> 09:32.940
defined still in the CP library that we have already imported.

09:32.950 --> 09:39.610
So let's use the RCL CP info.

09:40.740 --> 09:50.310
And this function takes as input the logger scope which we can obtain with the get logger function which

09:50.310 --> 09:53.310
we have already inherits from the node class.

09:53.310 --> 09:55.560
And it also takes the message.

09:55.560 --> 09:58.770
So the text that we want to print in the terminal.

09:58.770 --> 10:09.120
And so for example, let's print the message publishing at one hertz and this will be the one that we

10:09.120 --> 10:11.760
are going to view to visualize in the terminal.

10:12.360 --> 10:18.780
With this, the constructor of the Simple Publisher class is complete and now we have to define the

10:18.780 --> 10:20.250
timer callback function.

10:20.250 --> 10:21.210
In fact, here.

10:21.240 --> 10:26.160
Visual Studio code is telling us that the timer callback function is not yet defined.

10:26.250 --> 10:30.030
So let's define this function here.

10:30.330 --> 10:36.300
Still, within the simple publisher class, and the goal of this function is to publish a new message

10:36.300 --> 10:40.200
within the chapter topic every time this function is executed.

10:40.230 --> 10:46.350
So first we create the message to be published in the topic, which is a string message.

10:47.400 --> 10:57.540
Let's call this variable message and let's create an instance of the string message that is defined

10:57.540 --> 10:59.730
in the Standard Messages library.

11:01.450 --> 11:14.410
And let's change the content of this message to Hello Ross to followed by the counter and then followed

11:14.410 --> 11:16.300
by the variable counter.

11:16.330 --> 11:18.550
So let's convert first.

11:21.220 --> 11:30.460
To string the counter and then also let's increase its value for the next execution of this function.

11:31.150 --> 11:36.730
Then we can use the publish function that is available in the publisher object.

11:36.730 --> 11:40.060
So let's take the put object.

11:40.060 --> 11:48.910
And on this let's execute the publish function in order to publish the message that we have just created.

11:49.660 --> 11:54.550
With this, the simple publisher class is complete and now we can move on.

11:54.550 --> 11:58.750
So at the end of the class definition to define the main function.

11:58.750 --> 12:02.680
So the one that is automatically executed when the script starts.

12:02.890 --> 12:06.130
So let's define the main function.

12:16.310 --> 12:20.390
And let's return zero if everything goes well.

12:20.390 --> 12:30.830
And here as a first step, we need to initialize the Ros two with the function init from the CPP library

12:30.830 --> 12:34.190
and also to this one we pass the argument of the main.

12:36.490 --> 12:41.470
Then we can also create a pointer to an object of the simple publisher class.

12:41.800 --> 12:53.800
So let's call this one node and let's use the function make shared to create a shared pointer of the

12:54.820 --> 12:57.220
simple publisher class.

12:58.330 --> 13:04.900
And then let's keep this node up and running, thus keeping the timer and the publisher active so that

13:04.900 --> 13:14.260
they can continuously send messages within the chapter topic using the Rql CPP spin function.

13:14.470 --> 13:18.310
And so here, let's pass the node.

13:18.910 --> 13:25.030
Finally, if we terminate the execution of the node with control C, we need to ensure that the simple

13:25.030 --> 13:32.680
publisher node is correctly destroyed by using the shut down function.

13:34.110 --> 13:38.140
Now this is all and we can proceed to execute this node.

13:38.160 --> 13:44.070
But first we need to instruct the compiler on how it should build our script and make it an executable

13:44.070 --> 13:44.970
in Ros two.

13:45.270 --> 13:52.800
To do this, we need to modify the file cmakelists.txt, which was automatically created within the

13:52.800 --> 13:54.990
Arduino CP examples package.

13:55.170 --> 14:01.770
First, to facilitate reading of this file, let's delete all the commented rows that were automatically

14:01.770 --> 14:02.370
added.

14:02.400 --> 14:04.590
So let's remove all of these.

14:09.960 --> 14:16.200
And you can think of this file as a sort of instruction sheet that tells the compiler how it should

14:16.200 --> 14:24.330
translate our cplusplus scripts into executable files first before building our script and making them

14:24.330 --> 14:25.210
executable.

14:25.230 --> 14:31.770
We need to declare the support packages that we use so the dependencies that we use to develop the functionalities

14:31.770 --> 14:32.760
of our node.

14:32.790 --> 14:42.720
And if you remember correctly, we used the CPP library, so let's use a new instruction, find package.

14:42.840 --> 14:47.610
And so let's declare the usage of the CPP package.

14:48.630 --> 14:50.550
And this is required.

14:50.640 --> 14:54.910
And also we used the definition of the standard messages library.

14:54.930 --> 15:02.970
So let's copy this instruction and let's change the name of the package to standard messages.

15:03.670 --> 15:10.330
And now we can proceed actually to instruct the compiler on how it should build and install our script

15:10.360 --> 15:12.010
with an Add.

15:14.570 --> 15:17.450
Executable instruction.

15:17.450 --> 15:27.500
So let's call our executable simple publisher and its source code is located in the source folder.

15:27.620 --> 15:35.570
And in this simple publisher dot CPP script, Then let's add the dependencies.

15:35.570 --> 15:42.200
Let's declare the dependencies to this executable with the almond target.

15:44.730 --> 15:45.770
Dependencies.

15:45.780 --> 15:50.220
So to the simple publisher executable.

15:50.460 --> 15:54.630
Let's add the dependencies from the CPP library.

15:54.960 --> 15:57.680
The standard messages.

15:57.690 --> 16:03.840
And finally, we can install this script with the instruction install.

16:03.960 --> 16:12.540
And so the target, the executable that we want to install is the one that is called Simple Publisher.

16:13.380 --> 16:16.740
And also we need to specify where we want to install it.

16:16.740 --> 16:23.760
So the destination will be the lib folder and then the subfolder.

16:23.760 --> 16:27.900
We want to install this one in the folder that has the same name of the package.

16:27.900 --> 16:30.840
So the Arduino CPP examples package.

16:30.840 --> 16:39.510
And this is contained in a useful variable of the CMake that is called Project name.

16:39.510 --> 16:45.490
So basically this variable will contain the name of the package that is Arduino, but CPP examples.

16:46.240 --> 16:52.150
Finally before building the workspace so we can save this file, we need also to declare the dependencies

16:52.150 --> 16:58.630
that we use so our xcp standard messages also in the package dot XML file.

16:58.630 --> 17:05.950
So this other file here that was also automatically created when we use the Ros2 package, create command.

17:06.400 --> 17:08.980
So here we need to add two dependencies.

17:09.580 --> 17:21.310
So with the tag depend, let's declare the dependencies from the CPP library and also from the standard

17:21.730 --> 17:22.870
messages library.

17:23.260 --> 17:29.200
Let's save this file and these are the only two libraries that we need in the simple publisher script

17:29.320 --> 17:31.660
so we can finally execute our node.

17:32.330 --> 17:35.300
And let's open a new Linux terminal.

17:35.720 --> 17:42.100
Let's go into the workspace and let's use the command called build.

17:42.590 --> 17:45.320
This will build the entire workspace again.

17:45.500 --> 17:51.890
Here we can see that there is an error since in the CMake list, this should be targets.

17:52.880 --> 17:54.770
Okay, let's save again.

17:56.390 --> 17:58.670
And let's build again our workspace.

18:00.810 --> 18:06.690
And this command will build the entire workspace again, including also the new Cplusplus node.

18:06.870 --> 18:10.950
Now that the build is successfully complete, we can split the terminal.

18:10.950 --> 18:14.820
So let's open a new window and here let's source the workspace.

18:14.820 --> 18:17.970
So the setup dot bash.

18:18.240 --> 18:26.040
And this way the Arduino CP example package is recognized in the environment and we can proceed to start

18:26.040 --> 18:34.950
the node with the command Ros run followed by the name of the package that is Arduino boot CP examples

18:34.950 --> 18:40.110
so we can press tab to use the Ros2 Autocompletion of the packages.

18:40.110 --> 18:46.980
And also if we press tab twice, we can see that Ros is automatically able to detect that in the Arduino

18:46.980 --> 18:47.130
board.

18:47.130 --> 18:51.300
CP Examples exists the simple publisher node.

18:51.630 --> 18:58.260
So let's run this simple publisher node, let's press enter and we can see that it appears the message

18:58.260 --> 19:01.570
publishing at one hertz in the terminal.

19:01.690 --> 19:09.580
So to verify that indeed the node is running and is publishing messages within the chatter topic, let's

19:09.580 --> 19:16.390
open another window of the terminal and let's take a look to the list of all the topics that are currently

19:16.390 --> 19:22.210
available in Ros two with the Command Ros two topic list.

19:22.210 --> 19:28.240
And as the name of this command suggests, it will show you all the topics that are currently available

19:28.240 --> 19:28.870
in Ros two.

19:29.020 --> 19:34.360
And among these we can see that the chatter topic, which is exactly the name you gave to our topic

19:34.360 --> 19:35.950
in the publisher node appears.

19:36.470 --> 19:42.890
For example, if we stop the execution of the publisher node and we launch again the command Ros2 topic

19:42.890 --> 19:46.460
list, we can see that the chapter topic is no longer available.

19:46.460 --> 19:50.630
Since the node that was publishing it is not longer running.

19:51.320 --> 19:58.220
And by relaunching the node and relaunching again, the command Ros2 topic list, the chapter topic

19:58.220 --> 19:59.480
is back there.

20:00.250 --> 20:09.850
We can also see which messages are now traveling in the topic using the command Ros2 topic Echo, followed

20:09.850 --> 20:12.900
by the name of the topic, which is chatter.

20:12.910 --> 20:19.840
So let's press enter and all the messages that are now published within this channel are printed in

20:19.840 --> 20:20.530
the console.

20:20.530 --> 20:23.590
And so we can see that each message contains the string.

20:23.620 --> 20:26.290
Hello Ros2 followed by a counter.

20:26.290 --> 20:31.360
So a number that increases at each new messages that we are publishing.

20:31.720 --> 20:38.080
So for example, if we stop the execution of the publisher, we can see that in the terminal there are

20:38.080 --> 20:43.540
no longer printed any new messages, since no one is publishing on this topic.

20:44.050 --> 20:48.370
And when we launch it again, the count restarts.

20:50.060 --> 20:57.020
There are two other Ros, two useful commands that provide additional information about a topic, and

20:57.020 --> 21:05.510
these are Ros two topic info followed by the name of the topic from which we want to get more information.

21:05.810 --> 21:12.140
So let's take the chatter topic and here we can see that the message type that is published in this

21:12.140 --> 21:15.050
topic is of type string as we have defined.

21:15.050 --> 21:19.190
And also there is only one node that is publishing in this topic.

21:19.340 --> 21:27.200
Also, if we use the flag variables, we also get more information about this topic.

21:27.200 --> 21:32.180
For example, we can see also the name of the node that is actually interacting with this topic.

21:32.180 --> 21:34.730
That is the simple publisher node.

21:35.520 --> 21:43.380
Finally, one last rose to comment that we are going to use in this lesson is the ros2 topic.

21:44.270 --> 21:48.290
Earth's still followed by the name of the topic that is chatter.

21:48.290 --> 21:50.030
So let's press enter.

21:50.030 --> 21:56.180
And this command analyzes the messages that are published in the topic and calculates the frequency

21:56.180 --> 21:57.410
of the publishing.

21:57.440 --> 22:01.490
In this case, as you can see that it calculates a frequency of one earth.

22:01.490 --> 22:08.090
So the rate, the average rate is one hertz, which is exactly the value that we have set for the timer

22:08.090 --> 22:09.590
in the simple publisher.

22:09.590 --> 22:13.460
So here we set a delay of one second in the timer.

22:13.460 --> 22:16.670
So basically we are publishing one message per second.
