Mapping · University · about 35 min
Eight beams, a known pose, and a map that fills in while the robot drives.
[1 mark]What does this program print?
W = 40 row, col = 3, 7 i = row * W + col print(i) print(divmod(1234, W))
127 (30, 34)
Cell (row 3, col 7) is at 3 x 40 + 7 = 127 in the flat list, and index 1234 is 1234 = 30 x 40 + 34, so row 30, col 34.
[1 mark]The robot drives at 30 cm/s and the mapper uses the pose from 150 ms after the scan was taken. How far, in cm, is every wall smeared?
[1 mark]Every wall in a map comes out shifted and some land off the edge of the grid, but their shapes are right. What is the most likely bug?
[1 mark]Put the steps of integrating one tick of scans into the grid in order.
Number the lines 1 to 5 to put them in the right order.
If the range is a real return, add L_OCC at the hit cellAdd L_FREE once to each cell in the setStep along the beam in half cells to one cell short of the range, collecting the cells in a setFor each beam, work out th = radians(heading + beam angle)Fetch the pose and add the start positionFetch the pose and add the start position For each beam, work out th = radians(heading + beam angle) Step along the beam in half cells to one cell short of the range, collecting the cells in a set Add L_FREE once to each cell in the set If the range is a real return, add L_OCC at the hit cell
The pose comes first, since every cell depends on it. Then each beam is two statements: free along it, occupied at the end if something was hit. The set is there because half-cell steps land in most cells twice, and one beam is one piece of evidence.
[1 mark]The plot of the known fraction has gone flat while the robot keeps driving in the same direction. What does that tell you?
[1 mark]Why is it normal to require several occupied cells in a row before believing a wall is there?
The robot starts at (100, 40). Drive at least 40 cm up the mat, integrating every scan into a log odds grid. Plot known, then print known:, the fraction of the grid your map has an opinion about, and wall y:, where your map puts the near face of the wall.
from bugbot import * import math connect() CELL, W = 5.0, 40 L_OCC, L_FREE, L_MAX, FAR = 0.85, -0.4, 8.0, 170.0 START_X, START_Y = 100.0, 40.0 grid = [0.0] * (W * W)
The hint students can ask for: The robot starts at (100, 40) on the mat. Each tick, take the pose, turn every scan() pair into a world direction, and run the inverse sensor model along it. Plot how much of the grid is known as you go, then read the wall's position off the finished map rather than off a reading.
from bugbot import *
import math
connect()
CELL, W = 5.0, 40
L_OCC, L_FREE, L_MAX = 0.85, -0.4, 8.0
FAR = 170.0 # past this the beam has run out of mat, not found a wall
START_X, START_Y = 100.0, 40.0
grid = [0.0] * (W * W)
def bump(x, y, amount):
c, r = int(x / CELL), int(y / CELL)
if 0 <= c < W and 0 <= r < W:
i = r * W + c
grid[i] = max(-L_MAX, min(L_MAX, grid[i] + amount))
def integrate():
px, py = position()
x, y = START_X + px, START_Y + py # position() is from the start, so put it on the mat
h = heading()
for a, d in scan():
th = math.radians(h + a)
sx, sy = math.sin(th), math.cos(th)
free = set() # each cell the beam crosses, once
r = 0.0
while r < min(d, FAR) - CELL:
free.add((int((x + r * sx) / CELL), int((y + r * sy) / CELL)))
r += CELL / 2
for c, row in free:
bump(c * CELL, row * CELL, L_FREE)
if d < FAR:
bump(x + d * sx, y + d * sy, L_OCC)
def known_fraction():
return sum(1 for v in grid if abs(v) > 1.0) / float(W * W)
forward(55)
for tick in range(85):
integrate()
plot("known", known_fraction())
if position()[1] > 60:
stop()
wait(0.1)
stop()
integrate()
print("known:", round(known_fraction(), 3))
# the near face of the wall is the lowest row that has occupied cells in it
face = None
for r in range(W):
if any(grid[r * W + c] > 1.0 for c in range(8, 32)):
face = r
break
print("wall y:", round(face * CELL + CELL / 2, 1))
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.