WEBVTT

00:00.050 --> 00:03.140
This is the step two for this final project.

00:03.140 --> 00:09.470
And in this step we are going to spawn some turtles on the turtle sim window here.

00:09.470 --> 00:13.250
And actually the first step and the second step are completely independent.

00:13.280 --> 00:16.130
Okay, you could have done the first step second.

00:16.130 --> 00:18.560
And this step first okay.

00:18.590 --> 00:24.470
Because for now the well the turtle controller and the turtle spawner that we will create are not communicating

00:24.470 --> 00:25.250
with each other.

00:25.250 --> 00:26.870
That's going to be for the step number three.

00:26.870 --> 00:29.300
So I'm going to I'm going to stop that.

00:29.300 --> 00:35.810
I'm going to I'm going to start the turtle sim again okay.

00:35.840 --> 00:40.460
And let's first see what we want to do here.

00:40.940 --> 00:44.090
So we want to spawn some turtles okay.

00:44.120 --> 00:50.660
There's going to be a node called turtle spawner responsible for spawning a turtle every x amount of

00:50.660 --> 00:51.020
time.

00:51.020 --> 00:54.980
And then this master turtle will have to catch them one by one.

00:54.980 --> 00:58.730
This time if we look at the services Ros2 service list.

00:58.820 --> 01:01.160
So we've done that previously in this course.

01:01.170 --> 01:04.410
And you see we have a spawn service.

01:04.410 --> 01:13.380
So we're going to use this spawn service to service type with uh spawn.

01:14.910 --> 01:25.500
You see we have the type Ros2 service uh, not service interface show okay.

01:25.500 --> 01:32.850
And we see so what do we need to send as a request x coordinate y coordinate the theta.

01:32.850 --> 01:37.500
So the orientation and an optional name here we're going to use the name.

01:37.500 --> 01:39.240
And then what we receive the name.

01:39.240 --> 01:42.510
So if you didn't provide the name you receive the generated name.

01:42.510 --> 01:45.750
Or if you provided the name you receive the same thing.

01:45.750 --> 01:53.370
Let's just test it from the terminal Ros2 service call with spawn.

01:53.400 --> 01:57.990
And then the type is turtle sim service spawn.

01:58.530 --> 02:11.510
And what I'm going to provide x, let's say 3.4 y 4.5 and then theta.

02:11.690 --> 02:13.610
Well let's give.

02:13.610 --> 02:15.200
So that's going to be in radians.

02:15.230 --> 02:17.750
So for example in radians you have 3.14.

02:17.960 --> 02:18.950
That's pi.

02:19.130 --> 02:24.440
So the total should be not facing the right side but the left side okay.

02:24.470 --> 02:29.330
Because that's pi that's 180 degrees and name.

02:30.410 --> 02:32.180
And let's use quote like that.

02:32.210 --> 02:34.400
ABC for testing.

02:35.060 --> 02:41.270
And you see we have a new total with the x 3.4 y is 4.5.

02:41.300 --> 02:43.730
Theta is 3.14.

02:43.850 --> 02:45.980
So it's facing left.

02:46.610 --> 02:52.040
And you see we have the name ABC and we get the name ABC as the response.

02:52.070 --> 02:52.460
All right.

02:52.460 --> 02:55.190
So that's the service we need to use in our node.

02:55.220 --> 02:59.450
So it's a good thing to first try it and test it from the terminal if you can.

02:59.480 --> 03:03.290
Now let's uh well where will we create our node?

03:03.290 --> 03:05.030
We will need to create a new file.

03:05.060 --> 03:07.670
Let's go to our package.

03:08.510 --> 03:09.440
Turtle.

03:12.590 --> 03:12.980
Turtle.

03:12.980 --> 03:14.420
SIM, catch them all.

03:15.170 --> 03:17.750
Turtle SIM, catch them all again.

03:18.500 --> 03:22.370
And let's create a turtle

03:23.450 --> 03:26.720
spawner.py.

03:27.260 --> 03:27.950
Okay.

03:28.310 --> 03:30.950
Also let's make it executable.

03:31.790 --> 03:33.890
Turtle spawner.

03:33.920 --> 03:34.880
All right.

03:34.880 --> 03:37.820
And then we can open VSCode.

03:37.850 --> 03:40.130
I don't need that one anymore.

03:40.280 --> 03:41.150
Turtle spawner.

03:41.180 --> 03:48.890
Let's take the well the node OOP template from here.

03:49.880 --> 03:53.360
And it's going to go there.

03:54.830 --> 04:02.630
Turtle spawner node here as well.

04:02.640 --> 04:06.750
and let's name it Turtle Spawner.

04:08.340 --> 04:10.560
Okay, I don't need that.

04:10.560 --> 04:12.780
And as well.

04:12.810 --> 04:13.290
Okay.

04:13.320 --> 04:15.150
And so what do we want to do in this code.

04:15.150 --> 04:20.820
Well we are going to create a service client so we can interact with the service server.

04:20.820 --> 04:22.710
We have just seen the spawn service.

04:22.710 --> 04:26.730
And we are simply going to call this every x amount of time.

04:26.730 --> 04:29.070
So for example every second every two seconds.

04:29.070 --> 04:31.950
And so let's start by creating a service client.

04:31.950 --> 04:34.680
We will first import the interface.

04:34.680 --> 04:36.510
What was the interface.

04:36.930 --> 04:38.370
We go back here.

04:38.370 --> 04:41.850
It's turtle sim srv spawn.

04:42.120 --> 04:51.450
So from turtle sim turtle sim dot srv import spawn.

04:51.450 --> 04:56.700
And we've already added turtle sim to the package dot XML, so no need to do that again.

04:56.700 --> 05:07.960
And here I'm going to do self dot spawn client Is self create client spawn.

05:08.380 --> 05:10.120
What is the name?

05:10.150 --> 05:13.180
The exact name slash spawn.

05:14.260 --> 05:17.170
So I'm going to use that exact name here.

05:17.170 --> 05:26.680
And then well let's just create a function called spawn service for example.

05:27.970 --> 05:36.040
Um we're going to give it the turtle name and then x y and theta coordinates okay.

05:36.070 --> 05:38.170
That's what we need for the service.

05:38.170 --> 05:44.530
And before we think about the logic of when we're going to call this service, let's just write the

05:44.530 --> 05:48.010
code to call it and to get the response in a callback.

05:48.010 --> 05:54.940
So for that you could open one node where we've done it before, for example the add to ins client.

05:55.390 --> 05:56.290
Okay.

05:56.290 --> 05:59.470
And we're just gonna get inspiration from that.

05:59.470 --> 06:01.540
So first we can wait.

06:02.710 --> 06:14.210
Let's do a do a weight while not self dot spawn client wait for service with let's say one second that's

06:14.210 --> 06:17.750
going to be self logger.

06:18.410 --> 06:28.640
Actually self get logger one waiting for spawn service.

06:28.880 --> 06:36.020
When we know that the service has been found, then we can create a request.

06:36.650 --> 06:47.360
So let's create a request which is going to be a spawn dot request object request.

06:47.750 --> 06:57.170
In this request we have a text field which is going to be the x from the parameters here.

06:57.380 --> 07:05.310
Then we have request dot y and then we have request Dot theta.

07:07.260 --> 07:11.490
And then we have request dot name.

07:12.450 --> 07:12.780
Okay.

07:12.810 --> 07:15.240
So we actually here have name it.

07:16.140 --> 07:16.980
Turtle name.

07:17.310 --> 07:17.580
Okay.

07:17.610 --> 07:18.570
We create a request.

07:18.570 --> 07:24.270
And then we need to send the request to the service with call async.

07:24.270 --> 07:39.090
So we do we're going to save it as a future self dot spawn client dot call async and we send the request.

07:39.660 --> 07:42.300
After that we can register a callback.

07:42.570 --> 07:44.430
Let's create a callback first.

07:44.430 --> 07:50.100
So callback call spawn service for example.

07:51.360 --> 07:54.960
So we're going to receive a future.

07:54.960 --> 07:58.170
And we're going to pass the request as well.

07:58.200 --> 08:04.810
So then we can later we can check the information that we have for x, y and theta.

08:04.810 --> 08:06.310
And what do we do here?

08:06.310 --> 08:14.140
For now, what we just do response is equal to future dot result.

08:14.290 --> 08:20.140
And in this response we have one thing in this response we have you see a name.

08:20.140 --> 08:22.480
So we have name one thing to know.

08:22.480 --> 08:27.670
And that's something you can test on your own, is that if you try to spawn a turtle, for example,

08:27.670 --> 08:32.650
that has a name that already exists, then it's going to return a empty string.

08:32.680 --> 08:38.350
Okay, so if there is an error while creating the turtle while it's spawning, a new turtle is going

08:38.350 --> 08:39.610
to return an empty string.

08:39.610 --> 08:43.540
And that's how you can know that no turtle was spawned.

08:43.540 --> 08:46.060
If you get a name, then there is a new turtle.

08:46.060 --> 08:53.230
So we're just going to do an if response dot and we don't have any auto completion, maybe we can add

08:53.230 --> 08:54.130
response.

08:54.130 --> 08:59.050
It's going to be a spawn dot response okay.

08:59.080 --> 09:07.650
So this is optional but makes the code a bit better if response dot Instancename is an empty string.

09:07.740 --> 09:10.590
Actually is not an empty string.

09:11.160 --> 09:15.510
Then we are going to do self dot get logger.

09:15.510 --> 09:16.800
For now we just print.

09:17.490 --> 09:32.670
We can say new alive turtle and plus response dot name which is a string.

09:32.700 --> 09:42.090
Okay, so after we get the response from the server, we print the name of the turtle if it succeeded.

09:42.120 --> 09:42.480
All right.

09:42.480 --> 09:47.490
So now I need to do a future dot add done callback.

09:47.700 --> 09:50.070
And if you remember here.

09:50.070 --> 09:52.140
So I'm going to provide the callback.

09:52.140 --> 10:00.300
But if I want to also provide an extra argument I need to use the partial function from the func tools.

10:00.300 --> 10:08.070
So I'm going to do from func tools import partial.

10:08.670 --> 10:11.460
And I will do here.

10:11.490 --> 10:17.520
So the partial is just to check directly here.

10:17.550 --> 10:23.430
Partial and then self callback call spawn service.

10:23.430 --> 10:26.010
And then we need to put request.

10:26.040 --> 10:29.310
That's the field is equal to request.

10:29.610 --> 10:32.220
We don't use it now but we're going to use it later.

10:34.500 --> 10:34.830
All right.

10:34.830 --> 10:37.200
So this is well nothing special.

10:37.200 --> 10:38.820
This is something we've already done.

10:38.820 --> 10:43.590
And you can just basically kind of almost copy paste from the previous code that we've done.

10:43.590 --> 10:46.830
And then before we go further, let's actually test this code.

10:46.830 --> 10:52.380
So let's test that that function here called spawn service is correctly working.

10:52.380 --> 10:54.330
How can we make a quick test.

10:54.330 --> 10:58.350
Well you just here you see you create the node okay.

10:58.380 --> 10:59.490
You create the client.

10:59.520 --> 11:04.770
Then you can directly send a request and you're going to get the response when the node is spinning.

11:04.770 --> 11:11.050
So here we could do node dot call spawn service with.

11:11.080 --> 11:13.000
So we need to provide a name.

11:13.000 --> 11:18.100
Let's do test and then a coordinate x.

11:18.250 --> 11:26.590
Let's do 3.0 coordinate y 3.0 theta is going to be 0.0 okay.

11:26.590 --> 11:27.460
Let's save.

11:27.460 --> 11:31.090
And then we need to create an executable for that.

11:31.090 --> 11:35.980
So I'm adding a comma here the executable.

11:35.980 --> 11:39.760
Let's name it spawner or turtle spawner as you want.

11:39.760 --> 11:41.920
And it's going to be turtle sim.

11:43.180 --> 11:49.360
Catch them all dot turtle spawner.

11:50.290 --> 11:53.320
And we want to execute the main function.

11:53.320 --> 11:54.760
Let's save that.

11:54.760 --> 11:59.980
Make sure you saved all the files and let's build click on build.

11:59.980 --> 12:05.740
So even if we use Simulink install as you know already, we need to build again because we have a new

12:05.740 --> 12:16.820
You file so packages select turtle sim, catch them all and we can use SIM link install.

12:16.820 --> 12:19.760
That's going to apply to the existing files.

12:19.760 --> 12:22.220
So the ones that we are going to build right now.

12:23.300 --> 12:26.000
So what do we need to test this.

12:26.000 --> 12:28.760
We need to start the turtle sim.

12:28.760 --> 12:34.550
So Rosrun turtle sim and turtle sim node.

12:34.550 --> 12:41.090
In fact for every test we do, that's going to be the first thing anyway we need to launch for our application.

12:43.580 --> 12:58.130
And here I'm going to source the terminal because we have the new node Ros to run my no turtle sim catch

12:59.360 --> 13:00.650
them all.

13:00.920 --> 13:03.320
And this time it's going to be the spawner.

13:03.860 --> 13:05.480
Let's see what we get.

13:05.900 --> 13:11.850
And you see that we are spawning a new turtle here on the coordinate three, three and zero for the

13:11.850 --> 13:12.840
orientation.

13:12.840 --> 13:17.490
And we have a log new turtle test.

13:17.520 --> 13:19.200
So that's the name of the turtle.

13:19.200 --> 13:23.610
And you can see spawning turtle test here with x, y and theta.

13:23.610 --> 13:25.620
So it's correctly working.

13:27.510 --> 13:29.040
Now let's go back to the code.

13:29.340 --> 13:33.990
So you see it's best to try to test stuff as soon as you can.

13:34.140 --> 13:34.410
Okay.

13:34.440 --> 13:36.420
You add a small functionality and you test.

13:36.420 --> 13:39.300
That's going to be much easier for you to develop ros2 applications.

13:39.300 --> 13:42.240
And now the question is, well, we're not going to do this.

13:42.240 --> 13:43.470
I'm going to remove.

13:43.500 --> 13:45.780
We're not going to spawn turtles like that.

13:45.780 --> 13:50.340
We want to spawn a turtle every, let's say every two seconds.

13:50.340 --> 13:51.810
So how do we do this.

13:51.840 --> 13:56.910
Well, as I told you previously, in this course you can just call this and you can call the service

13:56.910 --> 13:58.980
from anywhere you want.

13:59.010 --> 13:59.250
Okay.

13:59.280 --> 14:01.110
It could be from any callback you want.

14:01.140 --> 14:03.030
So we can create a timer.

14:03.060 --> 14:08.080
And so I'm going to create a timer here self dot Spawn.

14:08.590 --> 14:16.000
Turtle timer is equal to self dot create timer.

14:16.030 --> 14:18.760
Let's say two seconds to start.

14:18.760 --> 14:22.570
And then what I'm going to do is I'm not going to call this directly.

14:22.570 --> 14:24.460
I'm going to create an intermediate function.

14:24.460 --> 14:25.480
You will see why.

14:25.510 --> 14:31.390
So spawn new turtle with self.

14:32.680 --> 14:37.960
And I'm going to put that here self dot spawn new turtle.

14:37.960 --> 14:43.660
So this method is going to be called every two seconds when the node is spinning.

14:43.660 --> 14:45.460
Now why do I do this.

14:45.460 --> 14:51.670
Because we need to call that with a different name every time and also with different coordinates.

14:51.670 --> 14:57.520
So in this function I'm going to compute different names and coordinates which I'm going to choose at

14:57.520 --> 14:58.120
random.

14:58.120 --> 15:01.510
And then I'm going to call that function here okay.

15:01.540 --> 15:03.400
So let's start with the name.

15:03.400 --> 15:05.740
We're going to choose a name and to choose a name.

15:05.740 --> 15:08.180
Well we need the name that's different every time.

15:08.180 --> 15:12.710
So we first need a string, let's say turtle, my turtle, whatever we want.

15:12.740 --> 15:15.080
And then we could just add one.

15:15.080 --> 15:17.480
So let's say turtle one, turtle two, turtle three.

15:17.510 --> 15:19.430
There's going to be easier to do.

15:19.430 --> 15:31.220
And I'm going to add here self dot turtle name prefix is equal to turtle by default okay.

15:31.250 --> 15:34.730
So later on we will add this as a parameter.

15:34.730 --> 15:37.010
So basically we're going to start the name with turtle.

15:37.040 --> 15:40.250
But I just create a attribute in the class for that.

15:40.250 --> 15:45.950
So self dot turtle name prefix.

15:46.370 --> 15:50.000
Plus I will need here a number okay.

15:50.030 --> 15:55.010
So I'm going to also create here a turtle counter.

15:56.060 --> 16:00.530
Let's initialize to well let's initialize to zero.

16:01.370 --> 16:05.510
And then the first thing we do is we just do plus one for example.

16:05.540 --> 16:10.980
So self dot turtle hotel counter plus equals one.

16:10.980 --> 16:15.030
So in this case it's going to start at one and then two and three etc..

16:15.030 --> 16:17.340
And I'm going to add this.

16:17.340 --> 16:24.210
So I need to cast it as a string because that's an integer self total counter okay.

16:24.240 --> 16:27.180
So every time we just create a different name.

16:27.180 --> 16:33.060
So you see here it's going to be turtle one and then turtle two, turtle three etc..

16:33.060 --> 16:34.590
So that's it for the name.

16:34.590 --> 16:38.250
Now we need an x and a y and a theta coordinate.

16:38.250 --> 16:40.740
And how are we going to choose that.

16:40.740 --> 16:43.530
Well I'm going to just choose a value at random.

16:43.530 --> 16:50.520
And for that we can include the Python module here import random.

16:50.520 --> 16:57.510
And then I can do random dot uniform between let's say 0.0.

16:57.510 --> 17:02.370
And then let's say that the max value is 11.0 okay.

17:02.400 --> 17:08.370
So that's going to simply return a random value a random float value between 0 and 11.

17:08.950 --> 17:16.150
Let's do the same for y random dot uniform 0.0 11.0.

17:16.150 --> 17:22.570
And then theta is going to be random dot uniform.

17:22.570 --> 17:26.380
So we don't really need to provide an orientation.

17:26.380 --> 17:31.300
Because the only thing that really matters in the end is the position of the target total.

17:31.300 --> 17:33.280
But let's just make things complete.

17:33.280 --> 17:35.200
And let's add also an orientation.

17:35.200 --> 17:39.490
So it's going to be between zero and basically two times pi.

17:39.520 --> 17:41.740
So we have a complete circle.

17:41.740 --> 17:43.450
So we have 360 degrees.

17:43.450 --> 17:46.000
And I'm just going to provide the exact value.

17:46.000 --> 17:50.770
So I will import the math module.

17:50.770 --> 17:55.660
And I will do two times math dot pi.

17:55.690 --> 17:56.230
All right.

17:56.230 --> 17:59.800
So with this I have a different name every time.

17:59.800 --> 18:02.590
And I have a random coordinates.

18:02.590 --> 18:12.200
And then I can do self dot call spawn service with the name first and then x y theta.

18:12.410 --> 18:12.830
All right.

18:12.830 --> 18:14.870
And that should be it for the code.

18:14.870 --> 18:19.610
So to recap quickly in the constructor where we create some variables.

18:19.610 --> 18:27.290
Here we create a service client and we create a timer that's going to call this method here every two

18:27.290 --> 18:27.800
seconds.

18:27.800 --> 18:33.410
So we create a different name every time we create random coordinates.

18:33.410 --> 18:36.110
And then we call the service.

18:36.110 --> 18:40.160
So we create the request we call asynchronously the service.

18:40.160 --> 18:44.390
We add a callback and we get the response in that callback.

18:44.390 --> 18:46.520
So we should be able to test that.

18:46.550 --> 18:47.750
Let's go back to the terminal.

18:47.750 --> 18:50.000
And we have already used Simulink install.

18:50.000 --> 18:54.410
So let's run the total sim here.

18:54.440 --> 18:59.750
Let's start the spawner and let's see what we get.

19:01.790 --> 19:02.030
Okay.

19:02.030 --> 19:08.300
You can see the first time we have an error because we are trying to create turtle one which already

19:08.300 --> 19:08.750
exists.

19:08.750 --> 19:10.200
So that's not really a problem here.

19:10.200 --> 19:11.340
And then turtle two.

19:11.370 --> 19:12.060
Turtle three.

19:12.060 --> 19:14.010
You can see we have a new log every time.

19:14.010 --> 19:16.260
And we have a new turtle on the screen.

19:16.470 --> 19:16.980
All right.

19:17.010 --> 19:19.320
Once every two seconds.

19:19.320 --> 19:24.720
That is basically here you can see generated with random coordinates.

19:24.720 --> 19:28.710
So it's correctly working and I can stop the turtle spawner.

19:29.010 --> 19:35.010
And so the thing you can see at the beginning we got an error because turtle one is the turtle here

19:35.040 --> 19:36.000
is called the well.

19:36.000 --> 19:40.830
It's the main the first turtle that I will call maybe the master turtle that's going to have to catch

19:40.830 --> 19:41.910
the other turtles.

19:41.910 --> 19:46.590
So you could decide if you want to just increase the counter.

19:46.590 --> 19:50.790
So not start at one here, but start at two.

19:50.820 --> 19:52.140
It doesn't really matter here.

19:52.170 --> 19:52.590
Okay.

19:52.620 --> 19:56.460
If we have the prefix turtle we're just going to skip the first one.

19:56.520 --> 19:57.690
It's not really a problem.

19:57.690 --> 20:01.830
And then you see we have turtle two, turtle three, turtle four etc..

20:01.860 --> 20:08.970
Now the next part of the challenge is how to actually control the main turtle so that we catch the different

20:09.000 --> 20:10.650
turtles that we have spawned.
