Vision · University · about 50 min
Three identical shapes, one job, and a task the depth sensor cannot begin.
[1 mark]Three identical balls differ only in colour. Why can the depth sensor not pick out the green one?
[1 mark]The survey finds three 6 cm balls. What does this print?
import math
F, R = 92.4, 3.0
seen = {"red": (100, 14), "green": (200, 28), "blue": (250, 9)}
for colour, (cx, width) in seen.items():
got = 2 * R * F / width, math.degrees(math.atan((cx - 160) / F))
print(colour, "%.0f cm at %.0f degrees" % got)red 40 cm at -33 degrees green 20 cm at 23 degrees blue 62 cm at 44 degrees
Range is 554.4 / width: 39.6, 19.8 and 61.6 cm. Bearings are atan((cx - 160) / 92.4): -33, 23 and 44 degrees.
[1 mark]Why turn to the green ball's bearing and servo on its apparent size, rather than work out its coordinates and drive there open loop?
[1 mark]Why must the survey be a separate phase before the approach?
[1 mark]The approach should stop 20 cm from a 6 cm ball. About how many pixels wide should it look, to 1 decimal place, with f = 92.4?
[1 mark]Which choices help the robot stop short of the ball without touching it?
Tick every answer that is true.
Survey all three balls and print red:, green: and blue:, the range in centimetres to each. Then drive to the green ball and stop within reach of it without touching it. position() is not allowed: the robot has to find it by looking.
from bugbot import * import math connect() F, R = 92.4, 3.0 TARGET = "green"
The hint students can ask for: Three balls, all 6 cm across, all the same size and shape to a depth sensor. Survey first: the camera runs one detector at a time, so set each colour in turn, give it a moment, and record the range and bearing of what you see. Print all three. Then set the detector back to the colour you were sent for and servo onto it as in U11.6, stopping about 20 cm short.
from bugbot import *
import math
connect()
F = 92.4
R = 3.0 # every ball is 6 cm across
STANDOFF = 22.0
WANT = 2 * R * F / STANDOFF
TARGET = "green"
def survey(colour):
"""Range and bearing of the largest blob of one colour, or None."""
set_cv("blob", colour)
wait(0.3)
seen = blobs()
if not seen:
return None
cx, cy, area, x0, y0, x1, y1, aspect = seen[0]
return 2 * R * F / (x1 - x0), math.degrees(math.atan((cx - 160) / F))
for colour in ("red", "green", "blue"):
got = survey(colour)
if got is None:
print(colour + ": not in view")
else:
print("%s: %.1f cm, bearing %.1f" % (colour, got[0], got[1]))
set_cv("blob", TARGET)
wait(0.2)
last = 1.0
for tick in range(700):
seen = blobs()
if not seen:
drive(0, 0, 25 * last)
wait(0.1)
continue
cx, cy, area, x0, y0, x1, y1, aspect = seen[0]
w = x1 - x0
err = cx - 160
last = 1.0 if err > 0 else -1.0
rot = max(-55, min(55, 0.35 * err))
if abs(err) < 6:
rot = 0
elif abs(rot) < 17:
rot = 17 * (1 if rot > 0 else -1)
gap = WANT - w
fwd = max(-40, min(45, 4.0 * gap))
if abs(gap) < 1.5:
fwd = 0
elif abs(fwd) < 18:
fwd = 18 * (1 if fwd > 0 else -1)
if abs(err) > 60:
fwd = 0
drive(fwd, 0, rot)
plot("cx", cx)
plot("width", w)
wait(0.1)
if fwd == 0 and rot == 0: # both errors inside their bands: arrived
break
stop()
wait(0.5)
print("arrived at the", TARGET, "ball")
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.