1
00:00:01,060 --> 00:00:04,770
In this lecture, we will create our very own Roth publisher node.

2
00:00:04,780 --> 00:00:10,630
We'll make a simple publisher that publishes a string that says Hello World, followed by a number which

3
00:00:10,630 --> 00:00:13,240
increments up every time we publish.

4
00:00:13,450 --> 00:00:18,700
Then in a future lecture, we'll create a subscriber to receive the messages we publish.

5
00:00:20,290 --> 00:00:23,440
For now, let's open up our Visual Studio code editor.

6
00:00:24,010 --> 00:00:25,630
Go over to file.

7
00:00:27,240 --> 00:00:32,670
Open folder and we will open up our Ras two Pi workspace folder.

8
00:00:34,440 --> 00:00:35,910
Go ahead and trust the workspace.

9
00:00:37,210 --> 00:00:41,230
And for now we're going to skip configuring our C make environment.

10
00:00:41,230 --> 00:00:43,930
So for now, just go ahead and cancel that and hit escape.

11
00:00:43,930 --> 00:00:51,170
And now we see all of our folders from our project workspace directory here in the left side panel.

12
00:00:51,190 --> 00:00:54,790
Now notice it's also generated a hidden VS code folder.

13
00:00:54,790 --> 00:01:00,490
This contains all the setting configurations for our Visual Studio Code editor and you can see it within

14
00:01:00,490 --> 00:01:07,660
the file Explorer by hitting Control H or by heading over to the three dashes and checking or unchecking

15
00:01:07,660 --> 00:01:08,800
show hidden file.

16
00:01:08,800 --> 00:01:10,840
So now we can't see that hidden file.

17
00:01:10,840 --> 00:01:16,200
So the first thing I can go ahead and do is open up the source folder, which takes us into our RAS

18
00:01:16,210 --> 00:01:18,730
two package and we can go into the scripts folder.

19
00:01:18,730 --> 00:01:19,840
So currently we don't have any.

20
00:01:19,840 --> 00:01:25,810
So I'll go ahead and right click hit new file and I will just create a new script called Publisher Spy.

21
00:01:26,410 --> 00:01:33,430
Just a pre face all RAR to Python functionality is documented in the RCL py API documentation.

22
00:01:33,430 --> 00:01:36,310
Here you can review specific functionality of things.

23
00:01:36,310 --> 00:01:41,470
We are going to be using in the RAS two Python library, including additional arguments and how they

24
00:01:41,470 --> 00:01:42,100
work.

25
00:01:44,530 --> 00:01:47,890
But for now, I'm just going to go through and show you how this functionality works first hand.

26
00:01:47,890 --> 00:01:52,060
But if you have additional questions, feel free to reference that documentation page.

27
00:01:53,060 --> 00:01:58,650
In order to use raw features in Python, we need to import the ROS client library python module.

28
00:01:58,670 --> 00:02:01,070
This is abbreviated as rcl py.

29
00:02:01,340 --> 00:02:07,130
Within the script I will create a standard python if name is equal to main call and within it I will

30
00:02:07,130 --> 00:02:09,230
just call a function called main.

31
00:02:09,390 --> 00:02:12,560
You'll see my reasoning for doing this later in the course.

32
00:02:15,070 --> 00:02:17,350
So let's create the main function above.

33
00:02:19,270 --> 00:02:19,680
All right.

34
00:02:19,690 --> 00:02:24,760
The first thing we're going to do in our main function is initialize our Ros RDS communications.

35
00:02:24,790 --> 00:02:29,950
We can do this by calling our ROS client library and using the init function.

36
00:02:30,220 --> 00:02:35,980
This has two optional arguments which can be put in command line arguments and a context name we won't

37
00:02:35,980 --> 00:02:36,640
use either.

38
00:02:36,640 --> 00:02:39,850
So we'll just leave this function as is with no parameters in it.

39
00:02:40,290 --> 00:02:45,730
OC We are configured to be able to use ROS functionality, so let's actually create our node.

40
00:02:45,880 --> 00:02:51,280
The ROS client library contains a node class with all the different ROS functionality to implement in

41
00:02:51,280 --> 00:02:52,080
our code.

42
00:02:52,090 --> 00:02:57,790
So what we can do is create our own class which inherits all the functionality of that existing ROS

43
00:02:57,790 --> 00:02:58,810
node class.

44
00:02:59,220 --> 00:03:02,590
I'll create the class above and call it Hello World Publisher.

45
00:03:02,860 --> 00:03:07,870
Now I need to pass it in the node class to inherit its functionality, so I will first import it in

46
00:03:07,870 --> 00:03:09,430
from the ROS client library.

47
00:03:09,430 --> 00:03:10,300
Like so.

48
00:03:12,980 --> 00:03:17,120
Now I can pass this node class into our Hello world publisher for it to inherit it.

49
00:03:17,940 --> 00:03:22,530
The first thing to do in any Python class object is to create our init function.

50
00:03:24,180 --> 00:03:26,950
And the first thing we will do is initialize the node.

51
00:03:26,970 --> 00:03:33,570
So we will use Python's super function to gain access to the init method from that node object we inherited

52
00:03:33,570 --> 00:03:35,070
from ROS client library.

53
00:03:35,890 --> 00:03:40,440
And just as a side note, by default, Vee's code will set the spaces to four.

54
00:03:40,450 --> 00:03:43,540
I'd like to prefer using tabs instead of spaces.

55
00:03:43,810 --> 00:03:48,940
So if I go ahead and highlight this, you can actually see individual dots which represent the spaces

56
00:03:48,940 --> 00:03:50,770
for which our code is organized.

57
00:03:50,770 --> 00:03:55,390
So if you want to change that, I'll just go ahead and hit shift tab and re tab that back in.

58
00:03:55,390 --> 00:03:59,950
And now instead of these spaces we are seeing the actual tab marks and I'll go ahead and do that for

59
00:03:59,950 --> 00:04:01,240
these lines as well.

60
00:04:02,990 --> 00:04:06,440
So this is totally personal preference, if you like, spaces versus tabs.

61
00:04:06,440 --> 00:04:10,820
But I figured it was worth noting for those of you who are new to Visual Studio Code.

62
00:04:11,300 --> 00:04:13,160
Now back to this node in IT object.

63
00:04:13,160 --> 00:04:17,030
So the node object can take in several different optional parameters and I can actually see that by

64
00:04:17,030 --> 00:04:20,270
going ahead and deleting these parentheses right now and recreating them.

65
00:04:20,270 --> 00:04:24,460
And here we see VS Code gives us a dialog window of all the optional parameters we can put in here.

66
00:04:24,470 --> 00:04:28,580
Now of course you could also check the SQL Pie Docs page for more information.

67
00:04:28,580 --> 00:04:33,170
However, the only required arguments is what we want the name of the node to be.

68
00:04:33,170 --> 00:04:34,760
In this case, let's name it.

69
00:04:34,790 --> 00:04:36,290
Hello World Pub Node.

70
00:04:36,530 --> 00:04:38,500
Now our node is initialized.

71
00:04:38,510 --> 00:04:40,010
Let's create our publisher.

72
00:04:40,220 --> 00:04:46,430
I will create a class member variable called pub and set it equal to the self dot create publisher function

73
00:04:46,430 --> 00:04:47,750
which we inherited.

74
00:04:47,750 --> 00:04:53,750
When we initialize the node above the create publisher Command takes in three required arguments.

75
00:04:53,750 --> 00:04:57,260
The first is the ROS message type we want for our publisher.

76
00:04:57,260 --> 00:05:02,540
Since we want to publish a hello world message, we can use the ROS string message type.

77
00:05:02,540 --> 00:05:06,020
We will learn more about ROS message types in future lectures.

78
00:05:06,020 --> 00:05:11,810
For now I will just import the string message from the standard messages ROS library and use it in our

79
00:05:11,810 --> 00:05:13,250
create publisher function.

80
00:05:14,390 --> 00:05:17,870
The second parameter is the topic name we want to publish over.

81
00:05:17,870 --> 00:05:20,180
I will just call it Hello World.

82
00:05:20,690 --> 00:05:26,750
Note that the topic nor node name can have spaces in them, which is why I use underscores to separate

83
00:05:26,750 --> 00:05:27,530
words.

84
00:05:28,380 --> 00:05:35,340
Now, the last argument for our publisher is the shows profile size cross stands for quality of Service.

85
00:05:35,590 --> 00:05:40,920
COS serves a similar purpose as the queue size did in Ross, one in which we are setting a queue depth

86
00:05:40,920 --> 00:05:42,600
to save old messages.

87
00:05:42,600 --> 00:05:47,760
That way, if our robot is on an unstable network connection between other raw systems, when we regain

88
00:05:47,760 --> 00:05:50,950
connection, we can get a backlog of the published messages.

89
00:05:50,970 --> 00:05:54,390
In this case, I will just set our publisher queue size to ten.

90
00:05:54,570 --> 00:05:57,320
With that, our publisher is actually created.

91
00:05:57,330 --> 00:06:02,040
Now we want to tell our node to keep publishing our Hello world message at a certain rate.

92
00:06:02,040 --> 00:06:07,140
This used to be done in Ross one using a rate object and a while loop to have your nodes keep completing

93
00:06:07,140 --> 00:06:12,930
the action within the while loop at the desired rate in Ross to a timer functionality was added to help

94
00:06:12,930 --> 00:06:17,610
simplify this so we can create a timer variable and set it equal to our nodes.

95
00:06:17,610 --> 00:06:18,930
Create timer function.

96
00:06:20,370 --> 00:06:25,590
This function takes in two parameters the rate of our timer in seconds and the callback function We

97
00:06:25,590 --> 00:06:30,900
want to run at that rate in this case, we're going to want to create a callback function to publish

98
00:06:30,900 --> 00:06:32,550
our Hello world message.

99
00:06:32,670 --> 00:06:37,140
So we will create a new function in our class called Publish Hello World.

100
00:06:37,530 --> 00:06:43,650
You can see I set the rate to 0.5, which means that every 0.5 seconds this function will run.

101
00:06:43,860 --> 00:06:45,990
So let's go ahead and create this function below.

102
00:06:49,490 --> 00:06:53,540
The first thing we need to do before we publish any data is to create the message object we're going

103
00:06:53,540 --> 00:06:54,320
to be using.

104
00:06:54,500 --> 00:06:59,360
In this case, we are using a string from the Standard Messages library so we can initialize it like

105
00:06:59,360 --> 00:07:04,010
so this string object only has one attribute which is called data.

106
00:07:04,160 --> 00:07:08,720
So all we need to do to load our data into this variable is to set the string message data attribute

107
00:07:08,720 --> 00:07:10,350
to the data we want to send.

108
00:07:10,370 --> 00:07:12,890
In this case, a string saying Hello world.

109
00:07:13,010 --> 00:07:19,160
Now that our message data is loaded, let's publish the message by using our pub variables publish function

110
00:07:19,160 --> 00:07:20,870
which takes in our message.

111
00:07:21,080 --> 00:07:21,650
Great.

112
00:07:21,650 --> 00:07:24,020
So let's quickly review what's going on in this code.

113
00:07:24,020 --> 00:07:30,950
So far we created a class called Hello World Publisher, which inherited the functionality of the node

114
00:07:30,950 --> 00:07:33,200
object from the ROS client library.

115
00:07:33,350 --> 00:07:39,950
We initialized our node, created a publisher which publishes string messages over the Hello world topic

116
00:07:40,100 --> 00:07:44,000
and then created a timer which will run our publish Hello world function.

117
00:07:44,000 --> 00:07:44,930
Within our publish.

118
00:07:44,930 --> 00:07:50,510
Hello world function we create a string message load our hello world string data into the message and

119
00:07:50,510 --> 00:07:53,630
then tell our publisher to publish this message.

120
00:07:53,930 --> 00:08:00,110
Now, one more thing I will add to this is a counter to count up every time we publish a message so

121
00:08:00,110 --> 00:08:02,900
we can see some variation in the data coming over this topic.

122
00:08:02,900 --> 00:08:06,680
So I will create a counter variable when we initialize our class.

123
00:08:07,010 --> 00:08:12,770
Then in our publish Hello world function, include it within our message data and add one after we publish

124
00:08:12,770 --> 00:08:13,610
the message.

125
00:08:16,430 --> 00:08:17,030
With that.

126
00:08:17,030 --> 00:08:18,860
I am now done with my class.

127
00:08:18,860 --> 00:08:22,430
So back in my main function I can create an instance of this class.

128
00:08:22,580 --> 00:08:26,930
I will just call it my pub then to make it look a little bit nicer.

129
00:08:26,930 --> 00:08:30,710
When we run this in terminal, let's print out that our publisher node is running.

130
00:08:31,430 --> 00:08:35,810
Now we are going to want this Python script to keep running in the terminal until we tell it to stop

131
00:08:35,810 --> 00:08:36,860
by hitting control.

132
00:08:36,860 --> 00:08:43,370
C So to stop our Python scripts from finishing right after we create our My Pub variable, I will use

133
00:08:43,370 --> 00:08:48,950
the ROS client library spin function, which we will run until there is a keyboard interrupt.

134
00:08:48,950 --> 00:08:52,280
So I will wrap it in a try except statement like so.

135
00:08:57,950 --> 00:09:02,510
Now, when there is a keyboard interrupt, I'm going to want to stop my node by calling the destroy

136
00:09:02,510 --> 00:09:03,560
node function.

137
00:09:05,370 --> 00:09:09,720
With that, I have finished my publisher script, so let's save it, which you can do with either the

138
00:09:09,720 --> 00:09:14,450
control se shortcut key or by heading over to file and save.

139
00:09:14,460 --> 00:09:18,870
And then we can go ahead and open up a terminal and then we'll change it to the directory which our

140
00:09:18,870 --> 00:09:24,330
script is located in and run the Python three command, followed by the name of our script, which is

141
00:09:24,330 --> 00:09:26,460
publisher Pi OC.

142
00:09:26,490 --> 00:09:28,980
We ran the command and got that the publisher node running.

143
00:09:28,980 --> 00:09:30,180
Print it to the screen.

144
00:09:30,180 --> 00:09:33,000
We can check this by opening a new terminal tab.

145
00:09:33,720 --> 00:09:36,840
And using the Ross to node list command.

146
00:09:37,110 --> 00:09:38,040
Here we see.

147
00:09:38,040 --> 00:09:43,500
Hello World Pub node is one of the nodes running and that's the name we defined when we called our init

148
00:09:43,500 --> 00:09:46,350
method from the node class we inherited.

149
00:09:47,070 --> 00:09:51,570
You can also check for topics by using the ROS two topic list command.

150
00:09:51,870 --> 00:09:57,090
And here we see our default ROS out and parameter events topics which you'll see by default when ROS

151
00:09:57,090 --> 00:09:57,690
is running.

152
00:09:57,690 --> 00:10:02,880
And our Hello world topic which we defined for our publisher here.

153
00:10:05,060 --> 00:10:10,100
Last but not least, we can see the data coming in over the topic by running the Ross two topic Echo

154
00:10:10,100 --> 00:10:14,360
command, followed by the name of the topic, which as we know is Hello World.

155
00:10:15,930 --> 00:10:21,540
And here we see the Hello World data coming in, as well as this number incrementing up with each time

156
00:10:21,540 --> 00:10:22,480
it prints out.

157
00:10:22,500 --> 00:10:28,140
So I'll go ahead and stop that with control C And to stop your publisher node, you can click on that

158
00:10:28,140 --> 00:10:30,660
terminal tab and hit Control C as well.

159
00:10:30,660 --> 00:10:34,020
And we see the terminating nodes and now none of our nodes are running.

160
00:10:34,020 --> 00:10:41,280
And if we run across to node list, we see that indeed our Hello world hub node has stopped.

161
00:10:42,190 --> 00:10:43,330
Congratulations With that.

162
00:10:43,330 --> 00:10:47,710
You have successfully created your very own Ras to publisher in Python.

163
00:10:48,840 --> 00:10:54,880
In this lecture, we learned how to use the ROS client Library Python API to create a publisher node.

164
00:10:54,900 --> 00:10:59,970
We imported the ROS client library, node class and string message types.

165
00:11:00,450 --> 00:11:03,690
We'll talk a bit more about message types later on in the course.

166
00:11:04,140 --> 00:11:09,480
Then we created our own class, which is based off of the ROS client libraries Node object.

167
00:11:09,570 --> 00:11:14,520
We then use the super init call to initialize our node with a node name.

168
00:11:14,730 --> 00:11:19,210
We then use the create publisher function, which takes in the message type, topic, name and queue

169
00:11:19,230 --> 00:11:19,820
size.

170
00:11:19,830 --> 00:11:25,320
And lastly, we utilize a create timer function to run a callback function at a particular rate.

171
00:11:25,830 --> 00:11:31,950
In this callback function we initialize our message object, which in this case was our string message.

172
00:11:32,010 --> 00:11:36,450
We then loaded the data attribute of it with the data we wanted to send.

173
00:11:36,900 --> 00:11:41,790
Then we call the publish function of our publisher variable, which takes in the message object and

174
00:11:41,790 --> 00:11:43,740
publishes it over Ros.

175
00:11:44,190 --> 00:11:49,890
Lastly, within our main function we initialize our ROS communications and use the spin function to

176
00:11:49,890 --> 00:11:51,000
keep the node running.

177
00:11:51,000 --> 00:11:57,330
And then if an exception occurred, we then destroyed our node to stop our ROS communications.
