You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -5,75 +5,246 @@ Another way to utilize the ultrasonic rangefinder is to use it to locate a nearb
5
5
6
6
.. admonition:: Try it out
7
7
8
-
Before reading more, brainstorm different ways to use the ultrasonic rangefinder to locate a nearby object.
8
+
What's the most effective way to locate an object? Try it out!
9
9
10
-
How?
11
-
~~~~
10
+
Turn and Detect
11
+
~~~~~~~~~~~~~~~
12
12
13
-
The easiest way to explain the intuition behind this process is sonar.
13
+
To first detect an object, the robot can slowly spin in a circle while continuously polling the rangefinder.
14
+
Then, when an object is detected, it can stop spinning, and head towards the object.
14
15
15
-
The robot will essentially spin in a circle and take a distance reading while it spins.
16
+
How can we tell when an object is detected? Imagine that the robot is in the center of an empty room, and a
17
+
random object is placed somewhere near the robot. The rangefinder would be giving large distance readings, until
18
+
it reaches the object, at which point the distance reading would drop. It's the *change* in distance readings that
19
+
hints that an object has been detected.
16
20
17
-
Then, when an object is detected to be within a certain distance, the robot will stop spinning and go towards the object.
21
+
How can we find the change in distance readings over each iteration of the loop? We can store the previous distance
22
+
reading in a variable, and compare it to the current distance reading. If this change is greater than some threshold,
23
+
then we can assume that an object has been detected.
18
24
19
-
This is a very simple way to locate an object, but it is also very effective (and will be especially helpful during your final project).
25
+
To code this, we can start by setting the drive motor speeds to spin in opposite directions to start spinning
26
+
the robot in place. Then, once the change in distance reading is greater than
27
+
the threshold, the robot can stop spinning and head towards the object.
20
28
21
-
The First Step
22
-
~~~~~~~~~~~~~~
29
+
In the following example code, we use a change threshold of 30 cm.
23
30
24
-
The first step is to spin the robot in a circle and stop when an object is detected.
31
+
.. tab-set::
25
32
26
-
To do this, utilize a while loop which instucts the robot to spin in a circle while the distance reading is greater than a certain value.
33
+
.. tab-item:: Python
27
34
28
-
In the following example code, our "distance threshold" is 20 cm.
35
+
.. code-block:: python
29
36
30
-
.. error::
37
+
changeThreshold =30# distance change in cm needed to trigger detection
31
38
32
-
TODO insert a video and code of a working example
39
+
# store initial value for current distance
40
+
currentDistance = rangefinder.distance()
33
41
34
-
The Second Step
35
-
~~~~~~~~~~~~~~~
42
+
# start spinning in place until an object is detected
43
+
drivetrain.set_speed(5, -5)
44
+
45
+
whileTrue: # doesn't actually repeat forever. loop will be broken if an object is detected
46
+
47
+
# update previous and current distance
48
+
previousDistance = currentDistance
49
+
currentDistance = rangefinder.distance()
50
+
51
+
# if sudden decrease in distance, then an object has been detected
52
+
if previousDistance - currentDistance > changeThreshold:
53
+
break# break out of the while loop
54
+
55
+
time.sleep(0.1)
56
+
57
+
# stop spinning drive motors
58
+
drivetrain.stop()
59
+
60
+
61
+
.. tab-item:: Blockly
62
+
63
+
.. image:: media/detection.png
64
+
:width:900
65
+
66
+
Improving Accuracy
67
+
~~~~~~~~~~~~~~~~~~
68
+
69
+
Do you see any issues with this solution?
70
+
71
+
When the rangefinder distance dips below the threshold, the implication isn't that the robot has found an object,
72
+
but rather that the robot has found its *edge*. So, the robot will aim for the edge of the object, rather than the center.
73
+
74
+
Instead, the robot should remember the heading it faces when detecting *both* edges. Then, the robot can aim for the center
75
+
between those edges, and thus the center of the object. We can store each edge angle in variables, naming them :code:`firstAngle`
76
+
and :code:`secondAngle`.
77
+
78
+
We're already quite familiar with turning until an edge is detected. Now, we'll need to detect *both* edges. However, it would be
79
+
quite unwieldy and error-prone to just copy the edge detection code, so let's make a function to generalize this. Note that the existing
80
+
code detects a sudden *decrease* in distance, but we want to handle sudden *increases* in distances too.
81
+
82
+
How can we support both behaviors in a single function? We can pass in a parameter to specify whether we want to detect an increase
83
+
or decrease in distance! We can call this parameter :code:`isIncrease` and pass in a boolean (true or false) value.
84
+
85
+
If :code:`increase` is :code:`True`, then we want to detect an increase in distance, which is when :code:`currentDistance - previousDistance > changeThreshold`.
86
+
87
+
If :code:`increase` is :code:`False`, then we want to detect a decrease in distance, which is when :code:`previousDistance - currentDistance > changeThreshold`.
88
+
89
+
For more flexibility, let's add a parameter for the change threshold.
90
+
91
+
Here's the function definition:
92
+
93
+
.. tab-set::
94
+
95
+
.. tab-item:: Python
96
+
97
+
.. code-block:: python
98
+
99
+
defturnUntilEdge(isIncrease, changeThreshold):
100
+
101
+
# store initial value for current distance
102
+
currentDistance = rangefinder.distance()
103
+
104
+
# start spinning in place until an object is detected
105
+
drivetrain.set_speed(5, -5)
106
+
107
+
whileTrue: # doesn't actually repeat forever. loop will be broken if an object is detected
108
+
109
+
# update previous and current distance
110
+
previousDistance = currentDistance
111
+
currentDistance = rangefinder.distance()
112
+
113
+
if isIncrease and currentDistance - previousDistance > changeThreshold:
114
+
# if sudden increase in distance, then an object has been detected
115
+
break
116
+
elifnot isIncrease and previousDistance - currentDistance > changeThreshold:
117
+
# if sudden decrease in distance, then an object has been detected
118
+
break
119
+
120
+
time.sleep(0.1)
121
+
122
+
# stop spinning drive motors
123
+
drivetrain.stop()
124
+
125
+
126
+
.. tab-item:: Blockly
127
+
128
+
.. image:: media/detectiondefinition.png
129
+
:width:900
130
+
131
+
Here's the equivalent function call to the turn and detection code in the previous section:
132
+
133
+
.. tab-set::
134
+
135
+
.. tab-item:: Python
136
+
137
+
.. code-block:: python
138
+
139
+
turnUntilEdge(False, 30)
140
+
141
+
.. tab-item:: Blockly
142
+
143
+
.. image:: media/detectioncall.png
144
+
:width:200
145
+
146
+
Now, it's time to write the full program to detect both edges and turn to the center.
147
+
148
+
Implementing Dual Edge Detection
149
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150
+
151
+
Let's walk through each step of the process in code.
152
+
153
+
First, the robot should spin in place until it detects the first edge, then stop. This is simply the function call we saw earlier.
154
+
155
+
.. tab-set::
156
+
157
+
.. tab-item:: Python
158
+
159
+
.. code-block:: python
160
+
161
+
turnUntilEdge(False, 30)
162
+
163
+
.. tab-item:: Blockly
164
+
165
+
.. image:: media/detectioncall.png
166
+
:width:200
167
+
168
+
Next, we want to record the robot's heading for this first edge, and store it to :code:`firstAngle`.
169
+
170
+
.. tab-set::
171
+
172
+
.. tab-item:: Python
173
+
174
+
.. code-block:: python
175
+
176
+
firstAngle = imu.get_yaw()
177
+
178
+
.. tab-item:: Blockly
179
+
180
+
.. image:: media/firstangle.png
181
+
:width:200
182
+
183
+
Then, the robot should spin in place again until it detects the second edge, which is when there is a sudden increase in distance.
184
+
185
+
.. tab-set::
186
+
187
+
.. tab-item:: Python
188
+
189
+
.. code-block:: python
190
+
191
+
turnUntilEdge(True, 30)
192
+
193
+
.. tab-item:: Blockly
194
+
195
+
.. image:: media/turntoedgetrue.png
196
+
:width:200
36
197
37
-
The second step is to go towards the object and stop when the object is within a certain distance.
198
+
Once the robot has detected the second edge, it should record its heading and store it to :code:`secondAngle`. Now, need to figure
199
+
out how much the robot needs to backtrack to aim for the center of the object. We can do this by finding the difference between
200
+
the two angles, and dividing by two. This is half the angle between the two edges, and if the robot backtracks by this amount,
201
+
it will be facing the center of the object. Let's store this in a variable called :code:`angleToTurn`.
38
202
39
-
To do this, integrate the code from the previous example and add a while loop which instructs the robot to move forward while the distance reading is greater than a certain value.
203
+
.. tab-set::
40
204
41
-
In the following example code, our "distance threshold" is 5 cm.
205
+
.. tab-item:: Python
42
206
43
-
.. error::
207
+
.. code-block:: python
44
208
45
-
TODO insert a video and code of a working example
209
+
secondAngle = imu.get_yaw()
210
+
angleToTurn = (firstAngle - secondAngle) /2
46
211
47
-
The Problem with this Method
48
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
212
+
.. tab-item:: Blockly
49
213
50
-
The problem with this method is that it is not very accurate.
214
+
.. image:: media/angletoturn.png
215
+
:width:400
51
216
52
-
The reason for this is that our robot is currently acting on the "edge" of the object that it sees.
217
+
Finally, the robot can turn this much to face the center of the object, and head towards it.
53
218
54
-
This means that the robot will not be able to accurately locate the center of the object.
219
+
Here's the full code. Note that half-second pauses are added to make the robot's actions more visible:
55
220
56
-
The Solution
57
-
~~~~~~~~~~~~
221
+
.. tab-set::
58
222
59
-
The solution to this problem is to use "flags" to keep track of the edges of an object.
223
+
.. tab-item:: Python
60
224
61
-
In this case, we can use a "first edge" flag and a "second edge" flag.
225
+
.. code-block:: python
62
226
63
-
The first edge flag will be set to true when the robot first detects a sudden decrease in distance measurements (i.e. the robot detects the first edge of an object)
227
+
# turn to first edge
228
+
turnUntilEdge(False, 30)
64
229
65
-
When the first edge is set to be true, the robot will take note of that angle, let's call it "firstAngle"
230
+
# store angle at first edge
231
+
firstAngle = imu.get_yaw()
66
232
67
-
The second edge flag will be set to true when the robot detects a sudden increase in distance measurements (i.e. the robot detects the second edge of an object)
233
+
time.sleep(0.5)
68
234
69
-
Now that the second edge is also set to be true, the robot can then take note of that angle, let's call it "secondAngle".
235
+
# turn to second edge
236
+
turnUntilEdge(True, 30)
70
237
71
-
We then know that the center of the object is at the angle halfway between firstAngle and secondAngle.
238
+
# store angle at second edge and calculate angle to turn
239
+
secondAngle = imu.get_yaw()
240
+
angleToTurn = (firstAngle - secondAngle) /2
72
241
73
-
To find that angle, we can take the average of firstAngle and secondAngle; and then save that angle as "centerAngle".
242
+
time.sleep(0.5)
74
243
75
-
This method will allow the robot to accurately locate the center of an object.
0 commit comments