Localisation · University · about 35 min
The three steps in a loop on a real mat, with tags as the measurement.
[1 mark]Put one tick of Monte Carlo localisation in order.
Number the lines 1 to 4 to put them in the right order.
Weigh every particle against the sensor readingMove every particle by the odometry, plus noiseReport the weighted mean as the estimateIf neff is low, resampleMove every particle by the odometry, plus noise Weigh every particle against the sensor reading If neff is low, resample Report the weighted mean as the estimate
Predict, correct, resample if needed, then report. Resampling before weighting would copy particles on stale weights.
[1 mark]What does this program print?
depth = [0.9, 0.3, 0.05] tag = [0.05, 0.3, 0.9] both = [a * b for a, b in zip(depth, tag)] total = sum(both) print([round(w / total, 2) for w in both]) added = [a + b for a, b in zip(depth, tag)] print([round(w, 2) for w in added])
[0.25, 0.5, 0.25] [0.95, 0.6, 0.95]
Multiplying gives 0.045, 0.09, 0.045, so the middle particle, which neither sensor rules out, wins with half the weight. Adding scores the outer particles higher even though one sensor all but rules each of them out.
[1 mark]The filter has a weight from the depth sensor and a weight from a tag seen by the camera for each particle. How should they be combined?
[1 mark]The cloud collapses onto the wrong answer. Which of these could cause it?
Tick every answer that is true.
[1 mark]The spread of the cloud stays large however long the robot stands still. What does the page recommend?
[1 mark]The filter tracks well for a minute and then loses the robot for good. What is the likely cause and fix?
[1 mark]What does MCL give the robot that dead reckoning does not?
Run the full filter while driving at least 50 cm. Plot spread, and print my y:, the robot's position on the mat as your filter has it. No position(). Drive straight, and expect the tag card to pull your answer a few centimetres ahead once the robot is near it.
from bugbot import * import math, random connect() DT, N, SIGMA = 0.1, 300, 3.5 particles = [random.uniform(0, 200) for i in range(N)]
The hint students can ask for: Particles spread over the mat, moved by the flow sensor and weighted by the depth reading against each particle's predicted distance to the far wall. Resample when the effective sample size falls below half. Print where the cloud has settled, in mat coordinates, not from the start.
from bugbot import *
import math
import random
connect()
DT = 0.1
N = 300
SIGMA = 3.5
particles = [random.uniform(0, 200) for i in range(N)]
weights = [1.0 / N] * N
def weigh(measured):
global weights
w = []
for y in particles:
d = (200 - y) - measured
w.append(math.exp(-d * d / (2 * SIGMA * SIGMA)) + 1e-12)
total = sum(w)
weights = [v / total for v in w]
def resample():
global particles, weights
step = 1.0 / N
r = random.uniform(0, step)
c = weights[0]
i = 0
fresh = []
for m in range(N):
u = r + m * step
while u > c and i < N - 1:
i += 1
c += weights[i]
fresh.append(particles[i] + random.gauss(0, 0.8))
particles = fresh
weights = [1.0 / N] * N
forward(60)
for tick in range(70):
v = flow()[1]
particles = [y + v * DT + random.gauss(0, 0.4) for y in particles]
weigh(distance())
neff = 1.0 / sum(w * w for w in weights)
if neff < N / 2:
resample()
mean = sum(w * y for w, y in zip(weights, particles))
spread = math.sqrt(sum(w * (y - mean) ** 2 for w, y in zip(weights, particles)))
plot("spread", spread)
if mean > 118:
stop()
wait(DT)
stop()
mean = sum(w * y for w, y in zip(weights, particles))
print("my y:", round(mean, 1))
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.