1
00:00:00,510 --> 00:00:06,300
Raw services are aren't interface with a request response architecture which nodes can use to communicate

2
00:00:06,300 --> 00:00:07,140
with each other.

3
00:00:07,440 --> 00:00:09,530
Service nodes have two parts to them.

4
00:00:09,540 --> 00:00:15,480
You'll have a service client which makes a request and a service server which will process the request

5
00:00:15,480 --> 00:00:18,090
and then send a response back to the client.

6
00:00:18,480 --> 00:00:25,090
In this lecture we will implement our own simple ROS service, which give it an integer number.

7
00:00:25,110 --> 00:00:28,590
We'll return whether or not it is an odd or even number.

8
00:00:28,920 --> 00:00:33,660
To do this, we will create our very own custom ROS service interface.

9
00:00:34,800 --> 00:00:40,470
If we open up a terminal and run the Ross to Interface list command.

10
00:00:41,280 --> 00:00:43,500
We are given a list of interfaces.

11
00:00:43,620 --> 00:00:46,020
If we head over to the services section.

12
00:00:47,010 --> 00:00:53,610
We can see service interface types currently available to us if we run Ross to interface show.

13
00:00:53,850 --> 00:00:57,130
We can see the contents of these particular interfaces.

14
00:00:57,150 --> 00:01:01,740
In this case I will look at the standard services set bool interface.

15
00:01:02,670 --> 00:01:06,260
Here we can see two sections separated by three dashes.

16
00:01:06,270 --> 00:01:10,970
The section above is the request, which in this case is a boolean called data.

17
00:01:10,980 --> 00:01:15,240
Then we see some notes written about it, which are indicated by the pound symbol.

18
00:01:15,480 --> 00:01:21,990
The bottom section is the response, which contains a boolean called success and a string called Message.

19
00:01:21,990 --> 00:01:26,070
We are going to create our very own service interface type, which follows this format.

20
00:01:26,070 --> 00:01:30,480
So I'll go ahead and close my terminal and open up Visual Studio Code.

21
00:01:30,630 --> 00:01:35,760
Since we will be creating a service interface type, we will put it in a folder within our package called

22
00:01:35,770 --> 00:01:36,000
S.

23
00:01:36,660 --> 00:01:38,580
So I'll go ahead and create that now.

24
00:01:38,580 --> 00:01:44,040
Then I'll create a new file in this folder and call it odd even check CRV.

25
00:01:44,790 --> 00:01:49,710
Note that the naming convention for interface files in Ross is Upper Camel case.

26
00:01:50,040 --> 00:01:50,460
All right.

27
00:01:50,460 --> 00:01:57,180
For our odd even check service, I want the request to be an integer so I can use the int 64 message

28
00:01:57,180 --> 00:01:57,780
type here.

29
00:01:57,780 --> 00:02:02,610
And the right is a picture of available types for you to use when creating custom interfaces.

30
00:02:02,670 --> 00:02:07,680
You can find a detailed list of available types in the ROS two tutorials page on interfaces.

31
00:02:07,860 --> 00:02:10,700
All right, now I need to associate this type with a name.

32
00:02:10,710 --> 00:02:12,900
In this case, I will just call it number.

33
00:02:12,930 --> 00:02:17,610
Then I'll create our response, which I signify by using three dashes.

34
00:02:18,630 --> 00:02:25,200
Then we will want a response from the server once it decides if the number is odd or even so, I will

35
00:02:25,200 --> 00:02:28,350
use the string message type and call it decision.

36
00:02:28,620 --> 00:02:28,830
Right.

37
00:02:28,830 --> 00:02:33,030
With that, we have created our custom service file, so let's go ahead and save the file.

38
00:02:33,030 --> 00:02:38,370
And now we need to configure our package so it knows we have custom interface types so it can generate

39
00:02:38,370 --> 00:02:42,330
the code needed to use these custom interfaces within our Python code.

40
00:02:42,330 --> 00:02:47,800
So I'll go ahead and open our package XML file so we can add in some dependencies.

41
00:02:47,820 --> 00:02:52,530
I'll go ahead and put these new dependencies under the meant build tool dependent lines.

42
00:02:52,770 --> 00:02:58,350
These new dependencies will include a build dependency for Ross idle default generators.

43
00:02:58,470 --> 00:03:02,430
Here idle stands for interactive data language.

44
00:03:03,810 --> 00:03:10,860
Then we will need to include the exec dependency ROS idle default runtime so that the interactive data

45
00:03:10,860 --> 00:03:13,710
language code created can be used at node runtime.

46
00:03:15,870 --> 00:03:22,230
Then lastly, we will want to include our newly created interface with our group of other ROS to interfaces,

47
00:03:22,230 --> 00:03:27,990
so we will create a member of group tag which contains ROS idle interface packages.

48
00:03:34,440 --> 00:03:39,510
All right, that's it for the dependencies in our package XML file, so we can go ahead and save it

49
00:03:39,510 --> 00:03:43,320
and head over to our make list text file here.

50
00:03:43,320 --> 00:03:46,980
We will have to include the ROS idle default generators packet.

51
00:03:46,980 --> 00:03:52,830
Then we will have to tell our compiler exactly what new interface files we created that need to have

52
00:03:52,830 --> 00:03:54,840
idle code generated for it.

53
00:03:55,110 --> 00:04:01,770
We do this with the ROS idle generate interfaces function which takes in the name of our package which

54
00:04:01,770 --> 00:04:07,800
is stored in the project name variable, followed by the actual file locations within the package.

55
00:04:07,890 --> 00:04:13,800
In this case we will include the file that is in our CRV folder named Odd even check dot.

56
00:04:15,330 --> 00:04:15,690
Great.

57
00:04:15,690 --> 00:04:21,240
With that, we have set up our package to be able to use this new service interface we created.

58
00:04:21,270 --> 00:04:27,330
You can go ahead and save this file and we'll go ahead and recompile our workspace.

59
00:04:28,820 --> 00:04:29,120
All right.

60
00:04:29,120 --> 00:04:30,140
So that's gone ahead and compiled.

61
00:04:30,140 --> 00:04:33,940
And notice it's taken a bit longer than usual to compile our package.

62
00:04:33,950 --> 00:04:39,590
That's because our package had to generate all the idle code for our custom odd even check service file.

63
00:04:39,770 --> 00:04:44,840
So now I can go ahead and close this head over to terminal and I'll source it.

64
00:04:49,160 --> 00:04:55,460
And now if I run the Ross to Interface list command, we can see a new interface listed for our Utme

65
00:04:55,460 --> 00:04:58,320
rescue package called Odd even check.

66
00:04:58,340 --> 00:05:03,170
We can also use the RAS two interface show command on our service to see the code we just put within

67
00:05:03,170 --> 00:05:04,330
our RV file.

68
00:05:04,610 --> 00:05:04,930
OC.

69
00:05:05,000 --> 00:05:07,230
We created a custom service interface.

70
00:05:07,250 --> 00:05:09,920
Now let's create our python nodes to use it.

71
00:05:10,190 --> 00:05:16,490
The first node we will create will be the server node, which processes the request and sends the response.

72
00:05:16,670 --> 00:05:22,930
So I will create a new file in our scripts folder called service underscore server dot pie.

73
00:05:23,180 --> 00:05:28,820
As usual, I will set the script up to execute our Python three environment and include my ROS client

74
00:05:28,820 --> 00:05:30,080
library functionality.

75
00:05:32,000 --> 00:05:36,620
Then I will import my newly created service, which is called odd even check.

76
00:05:37,610 --> 00:05:42,560
Then to save some time I will copy the contents of our main function and if name equals two main section

77
00:05:42,560 --> 00:05:47,480
of my code from the publisher script we created earlier to initialize and spin our node.

78
00:05:51,280 --> 00:05:55,570
I will go ahead and change the variable names to be service node.

79
00:06:01,760 --> 00:06:06,560
And modify the print statement to say that my odd even check service server is running.

80
00:06:07,010 --> 00:06:11,420
Now let's go ahead and create this odd even check server class above.

81
00:06:11,630 --> 00:06:16,910
As usual, we will reference the node class from our client library and we'll initialize the node as

82
00:06:16,910 --> 00:06:19,070
odd even service server node.

83
00:06:23,820 --> 00:06:29,910
Then I will create a service variable to hold my service, which I can create using the create service

84
00:06:29,910 --> 00:06:30,570
function.

85
00:06:30,600 --> 00:06:32,600
This function takes in three arguments.

86
00:06:32,610 --> 00:06:36,690
The first is my custom service class, which in this case is odd.

87
00:06:36,690 --> 00:06:37,590
Even check.

88
00:06:39,130 --> 00:06:43,730
The second is the name of the service topic name which I will call odd even check.

89
00:06:43,750 --> 00:06:48,400
And the third argument is the name of the callback function that will get executed when a service request

90
00:06:48,400 --> 00:06:49,330
is received.

91
00:06:49,420 --> 00:06:52,630
I will call my callback function determine odd even.

92
00:06:54,010 --> 00:06:58,270
Now let's go ahead and create this determine odd even function below.

93
00:06:58,360 --> 00:07:03,490
This callback function will take in the self variable of our class, the request object of the service

94
00:07:03,490 --> 00:07:05,290
and the response object.

95
00:07:10,500 --> 00:07:15,390
The first thing I will do is create a print statement saying the request was received just so I'm aware

96
00:07:15,390 --> 00:07:19,650
of what is happening when we run this node in terminal, then to check if the number submitted in the

97
00:07:19,650 --> 00:07:26,190
request is odd or even I will use the remainder operator, which is the percent symbol to see what the

98
00:07:26,190 --> 00:07:29,170
remainder of the number is after I divide it by two.

99
00:07:29,190 --> 00:07:35,140
So I'll create an if statement to check if the remainder of the number attribute of the request is zero.

100
00:07:35,160 --> 00:07:39,150
If it is, then I will set the decision attribute of the response to the string.

101
00:07:39,150 --> 00:07:45,450
Even note that the attribute names of the request and response must match the attribute names we defined

102
00:07:45,450 --> 00:07:46,860
in the SRI file.

103
00:07:46,860 --> 00:07:50,670
So the request we have number and for the response we have decision.

104
00:07:50,670 --> 00:07:55,170
So that's why I am calling number here and decision here.

105
00:07:56,170 --> 00:08:00,700
Now if the remainder of the number sent by the request is instead one, then the number is odd.

106
00:08:00,700 --> 00:08:05,830
So I'll set the response position to odd then to make sure we don't get a weird input that does not

107
00:08:05,830 --> 00:08:07,430
meet either of these criteria.

108
00:08:07,450 --> 00:08:12,940
I will have an L statement which sets the response to error just so that you can visualize how this

109
00:08:12,940 --> 00:08:14,140
information is getting processed.

110
00:08:14,140 --> 00:08:15,400
As it goes through this callback.

111
00:08:15,400 --> 00:08:20,650
I'll create two print statements afterward which prints the request and response object.

112
00:08:21,900 --> 00:08:25,560
Then lastly, we will end the callback by returning the response object.

113
00:08:26,380 --> 00:08:31,050
Well, and I just realized I forgot to do one more thing, which was go into our make list text file

114
00:08:31,050 --> 00:08:36,570
and be sure to add this new script within our install directory where we're installing our individual

115
00:08:36,570 --> 00:08:37,230
scripts.

116
00:08:38,850 --> 00:08:39,570
Great with that.

117
00:08:39,570 --> 00:08:45,600
We have created our service server node so we can go ahead and save this file and I'll rebuild my workspace

118
00:08:45,600 --> 00:08:47,310
so we can test this new node.

119
00:08:52,910 --> 00:08:54,470
All right, so I'll open up my terminal.

120
00:08:54,800 --> 00:08:55,610
Clear the screen.

121
00:08:56,330 --> 00:09:00,470
And this terminal environment's already sourced, so I can just go ahead and run our service server

122
00:09:00,470 --> 00:09:03,520
node using the ROS to run command OC.

123
00:09:03,530 --> 00:09:06,650
We see the print statement saying that the odd even check server is running.

124
00:09:06,650 --> 00:09:12,890
Now I can open a new terminal tab and source our workspace and I can list the available services to

125
00:09:12,890 --> 00:09:14,930
make sure our node is running as intended.

126
00:09:14,930 --> 00:09:17,180
Using the RAR to service list Command.

127
00:09:17,920 --> 00:09:24,790
So here we see our odd even check service, which we defined here in our create service call.

128
00:09:25,960 --> 00:09:31,270
And here we have some other things attributed to the service server node, which are related to the

129
00:09:31,270 --> 00:09:33,010
parameters we talked about earlier.

130
00:09:33,160 --> 00:09:36,610
Now, it's also worth noting, since we're using Visual Studio Code in the ROS extension, if we hit

131
00:09:36,610 --> 00:09:39,160
the F one key, it brings up this command panel.

132
00:09:39,250 --> 00:09:44,140
We can type in ROS to see some of the ROS commands available to us in that extension.

133
00:09:44,170 --> 00:09:47,550
One of the most prominent ones are the show Status Command.

134
00:09:47,560 --> 00:09:51,940
So if I go ahead and click on that, it opens up this sidebar right here on the right.

135
00:09:51,940 --> 00:09:56,770
And so this is just helps us a little nice dashboard so we don't have to keep running these types of

136
00:09:56,770 --> 00:10:01,480
commands to see what nodes, topics and services are available to us.

137
00:10:01,480 --> 00:10:03,220
So here we see the same type of information.

138
00:10:03,220 --> 00:10:09,370
If we ran a ROS to node list, so we see the odd even service server node and we don't have any other

139
00:10:09,370 --> 00:10:14,440
topics since we're just running our service and we see our odd even checked service just like we did

140
00:10:14,440 --> 00:10:15,550
in terminal here.

141
00:10:15,970 --> 00:10:18,660
So that's just a little side note, just so that you're aware of it.

142
00:10:18,670 --> 00:10:22,240
It's a little handy feature to interact with my service server node.

143
00:10:22,240 --> 00:10:25,570
I can use the ROS to service call command.

144
00:10:25,570 --> 00:10:30,610
This command takes in the service topic name, which in this case is forward slash, not even check.

145
00:10:31,090 --> 00:10:35,080
Then we point it to the service interface file, which is within our package.

146
00:10:35,080 --> 00:10:40,300
So I can start typing Udemy and if I hit the tab key it'll auto complete the correct service message,

147
00:10:40,300 --> 00:10:41,500
which is our odd-even check.

148
00:10:42,100 --> 00:10:46,260
And then the last parameter will be to include the request arguments.

149
00:10:46,270 --> 00:10:49,210
In this case, my request only has one attribute named number.

150
00:10:49,210 --> 00:10:54,280
So if I start typing and um and then hit the tab key, it all completes to this format.

151
00:10:54,280 --> 00:10:58,990
Here I can simply edit the default zero value to whatever value I want.

152
00:10:58,990 --> 00:11:02,200
In this case, we can try the number five and hit enter.

153
00:11:02,850 --> 00:11:07,440
Here we can see a print statement saying waiting for a service to become available, followed by our

154
00:11:07,440 --> 00:11:10,780
request, which was made, which was the number five.

155
00:11:10,800 --> 00:11:15,210
Then a response was received, which in this case the decision was odd.

156
00:11:15,210 --> 00:11:18,210
We can see how this looked on the service server side.

157
00:11:18,210 --> 00:11:23,490
Here we see we received a request which has number equal to five and we send back our response object,

158
00:11:23,490 --> 00:11:26,070
which has a decision equal to odd.

159
00:11:26,490 --> 00:11:27,000
Great.

160
00:11:27,000 --> 00:11:29,910
We have our service server working as intended.

161
00:11:29,910 --> 00:11:35,040
Now let's work on the client script which will make the request and can process the response.

162
00:11:35,040 --> 00:11:36,930
So I'll go back to VS code.

163
00:11:37,050 --> 00:11:42,840
I'll close the raw to status bar for now and create a new script called Service Client by.

164
00:11:45,050 --> 00:11:49,220
I'll go ahead and copy the contents from our servers server as a baseline.

165
00:11:51,850 --> 00:11:55,450
Then I will change everywhere It says server to client.

166
00:12:06,390 --> 00:12:11,510
And I'll go ahead and delete most of the contents within this order, even check client class.

167
00:12:11,520 --> 00:12:17,370
So all we have so far is our standard main function, which starts up our odd even check client node,

168
00:12:17,370 --> 00:12:22,950
and I'll be sure to change that as well, which comes from this class above.

169
00:12:25,150 --> 00:12:29,590
I'm going to set the script up so it sends a request, processes it, and then stops.

170
00:12:29,590 --> 00:12:34,240
So I will not need to spend the node like we've been doing in all the previous lectures.

171
00:12:35,110 --> 00:12:40,300
So for now, I'll go ahead and delete this spin call and just put in pass for now.

172
00:12:40,660 --> 00:12:46,450
In our class, I will go ahead and create a new client variable and set it equal to the value of the

173
00:12:46,450 --> 00:12:47,740
create client function.

174
00:12:50,200 --> 00:12:55,900
This function takes in two arguments our service interface object and the service topic name.

175
00:12:56,050 --> 00:12:59,320
These will be the same as it was in our server node.

176
00:12:59,440 --> 00:13:04,660
I can also go ahead and initialize our request object, which in this case is done by calling the odd

177
00:13:04,660 --> 00:13:09,250
even check service interface object and calling the request aspect of it.

178
00:13:11,470 --> 00:13:16,870
Now I have an empty, odd even check request message which is ready to be filled with the data and sent

179
00:13:16,870 --> 00:13:18,340
to the service server.

180
00:13:18,820 --> 00:13:24,610
I will do all this in a function I will call send request which will take in the class self attribute

181
00:13:24,610 --> 00:13:28,420
and I will also have it taken the number we want to include in the request.

182
00:13:29,720 --> 00:13:35,260
In this function, the first thing I will do is load the number the user gives into the request.

183
00:13:35,270 --> 00:13:41,780
So I can do this by setting self dot request dot number equal to the integer of the number.

184
00:13:41,780 --> 00:13:46,280
I'm just calling the in function here as a safety net in case the user enters a number that is not an

185
00:13:46,280 --> 00:13:46,910
integer.

186
00:13:47,730 --> 00:13:52,530
Then we will have to wait for the service server to be ready to receive our request.

187
00:13:52,560 --> 00:13:56,400
I can do this using the wait for service method of our client variable.

188
00:13:57,430 --> 00:14:01,000
So you could put a time out here, but we're just going to leave this blank, which means you will continue

189
00:14:01,000 --> 00:14:03,340
to wait until the service is available.

190
00:14:03,430 --> 00:14:08,140
Then once the service server is available, we will send our service call.

191
00:14:08,170 --> 00:14:10,720
We will do this by setting a future variable.

192
00:14:10,900 --> 00:14:16,510
A feature object is a Ross to object which awaits for a Ross server node to reply.

193
00:14:16,540 --> 00:14:20,380
This asynchronous call function takes in the request object.

194
00:14:21,540 --> 00:14:26,460
Since we are using an asynchronous call, we will need to spin our node until a reply is received by

195
00:14:26,460 --> 00:14:27,720
the future object.

196
00:14:27,750 --> 00:14:33,270
We do this by using the ROS client libraries spin until future complete function which takes in the

197
00:14:33,270 --> 00:14:35,610
node and the future variable as parameters.

198
00:14:35,730 --> 00:14:41,250
Since this class is our node, we just put this self as the node argument since we are within it.

199
00:14:42,010 --> 00:14:46,930
Then lastly, we can retrieve the result object from the future variable by calling the result method

200
00:14:46,930 --> 00:14:47,350
of it.

201
00:14:49,970 --> 00:14:54,080
Then we can close out this send request function by returning the result object.

202
00:14:57,490 --> 00:14:57,910
Okay, great.

203
00:14:57,910 --> 00:15:01,060
With that, we have all the functionality we need for our client node.

204
00:15:01,090 --> 00:15:06,880
Now I can go back into our main function where I have the pass statement, and here I will prompt the

205
00:15:06,880 --> 00:15:12,340
user for an integer that they want to check is either odd or even so, I'll create a variable called

206
00:15:12,340 --> 00:15:16,900
user input and use Python's input function to ask them to enter an integer.

207
00:15:18,770 --> 00:15:24,710
I'll then call the client nodes send request method we just finished working on it will return the result

208
00:15:24,710 --> 00:15:31,250
object so I will create a rest variable and set it equal to it and we will use the user input as our

209
00:15:31,250 --> 00:15:33,560
number argument for send request.

210
00:15:34,430 --> 00:15:40,730
Then lastly, to process the result, I'm just going to print it to terminal by saying server returned

211
00:15:40,730 --> 00:15:45,500
and then depending on the decision attribute of our raise variable which will have the result sent by

212
00:15:45,500 --> 00:15:46,250
the server.

213
00:15:49,260 --> 00:15:50,190
Great with that.

214
00:15:50,190 --> 00:15:52,590
We have finished our client node.

215
00:15:53,100 --> 00:15:58,830
We can go ahead and save the file, head over to our make list x file and add this script.

216
00:16:06,160 --> 00:16:10,420
And then save our make list text file and rebuild the project.

217
00:16:13,870 --> 00:16:14,160
All right.

218
00:16:14,170 --> 00:16:17,080
I'll go ahead and close this and I'll head over to our terminal.

219
00:16:17,780 --> 00:16:20,480
And we still have our service server node running.

220
00:16:20,480 --> 00:16:22,490
I'll go ahead and clear this bottom screen.

221
00:16:23,580 --> 00:16:27,300
Now I'll just double check to make sure this terminal is sourced to our setup file.

222
00:16:29,400 --> 00:16:33,300
And then launch our newly created service client pie node.

223
00:16:37,110 --> 00:16:37,890
So here we see.

224
00:16:37,890 --> 00:16:39,550
We get prompted to enter an integer.

225
00:16:39,570 --> 00:16:43,800
I'll just type in 11 in this case and we can hit enter and see.

226
00:16:43,800 --> 00:16:47,550
We get a response from our server saying that the number 11 is odd.

227
00:16:47,790 --> 00:16:53,040
So we'll rerun the client node again and enter six.

228
00:16:53,700 --> 00:16:57,480
And we see that the server responds that six is an even number.

229
00:16:57,480 --> 00:17:02,160
And so we can even see the decisions being processed in the server in this tab above.

230
00:17:03,420 --> 00:17:03,960
All right.

231
00:17:03,960 --> 00:17:09,810
With that, you have successfully implemented services by creating a service server and a service client

232
00:17:09,810 --> 00:17:10,530
node.

233
00:17:10,560 --> 00:17:15,450
And the next lecture, we will take this service functionality to the next level by implementing in

234
00:17:15,450 --> 00:17:21,300
a project where we use image processing over ROS like we might on a robot with a camera.

235
00:17:21,480 --> 00:17:24,210
Now, for now let's review what we learned.

236
00:17:25,610 --> 00:17:30,010
In this lecture, we created our very own service interface and nodes.

237
00:17:30,020 --> 00:17:37,070
We created a custom service file which has a request and response separated by three dashes.

238
00:17:37,190 --> 00:17:40,250
Each has a data type followed by an attribute name.

239
00:17:40,550 --> 00:17:47,540
Then we configured our package XML file to include our Ross idle dependencies and used member of group

240
00:17:47,540 --> 00:17:51,110
to include it with the other Ross two interfaces on our machine.

241
00:17:51,690 --> 00:17:58,590
We configured our make list text file by including the ROS idle default generators package and by specifying

242
00:17:58,590 --> 00:18:03,570
our newly created interface files with ROS idle generate interfaces.

243
00:18:03,930 --> 00:18:09,450
We utilize some terminal commands which allow us to list all available interfaces, lists, all available

244
00:18:09,450 --> 00:18:13,170
service topics, and even interact with the service server.

245
00:18:13,960 --> 00:18:19,950
We then coded our service functionality in Python by first learning how to import our custom service.

246
00:18:20,020 --> 00:18:26,620
Then we created the server node by using the create service function and creating a callback which processes

247
00:18:26,620 --> 00:18:29,470
the requested data and returns back a response.

248
00:18:30,170 --> 00:18:34,250
Lastly, we created a client node using the create client function.

249
00:18:34,400 --> 00:18:39,410
We initialize our service request message, filled it with data, then waited for the service server

250
00:18:39,410 --> 00:18:40,550
to become available.

251
00:18:40,790 --> 00:18:46,100
Once available, we utilize a feature object and the clients call async function to send the request.

252
00:18:46,400 --> 00:18:51,110
We then use the spin until future complete function and afterwards could get back the results from the

253
00:18:51,110 --> 00:18:54,680
future object which acquired the response from the server node.
