Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a452213

Browse files
Chipe1norvig
authored andcommitted
Added Monte Carlo localization (aimacode#602)
1 parent 92c98f9 commit a452213

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

probability.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,3 +649,69 @@ def particle_filtering(e, N, HMM):
649649
s = weighted_sample_with_replacement(N, s, w)
650650

651651
return s
652+
653+
# _________________________________________________________________________
654+
## TODO: Implement continous map for MonteCarlo similar to Fig25.10 from the book
655+
656+
class MCLmap:
657+
"""Map which provides probability distributions and sensor readings.
658+
Consists of discrete cells which are either an obstacle or empty"""
659+
def __init__(self, m):
660+
self.m = m
661+
self.nrows = len(m)
662+
self.ncols = len(m[0])
663+
# list of empty spaces in the map
664+
self.empty = [[i, j] for i in range(self.nrows) for j in range(self.ncols) if not m[i][j]]
665+
666+
def sample(self):
667+
"""Returns a random kinematic state possible in the map"""
668+
pos = random.choice(self.empty)
669+
# 0N 1E 2S 3W
670+
orient = random.choice(range(4))
671+
kin_state = pos + [orient]
672+
return kin_state
673+
674+
def ray_cast(self, sensor_num, kin_state):
675+
"""Returns distace to nearest obstacle or map boundary in the direction of sensor"""
676+
pos = kin_state[:2]
677+
orient = kin_state[2]
678+
# sensor layout when orientation is 0 (towards North)
679+
# 0
680+
# 3R1
681+
# 2
682+
delta = [(sensor_num%2 == 0)*(sensor_num - 1), (sensor_num%2 == 1)*(2 - sensor_num)]
683+
# sensor direction changes based on orientation
684+
for _ in range(orient):
685+
delta = [delta[1], -delta[0]]
686+
range_count = 0
687+
while (0 <= pos[0] < self.nrows) and (0 <= pos[1] < self.nrows) and (not self.m[pos[0]][pos[1]]):
688+
pos = vector_add(pos, delta)
689+
range_count += 1
690+
return range_count
691+
692+
693+
def monte_carlo_localization(a, z, N, P_motion_sample, P_sensor, m, S=None):
694+
"""Monte Carlo localization algorithm from Fig 25.9"""
695+
696+
def ray_cast(sensor_num, kin_state, m):
697+
return m.ray_cast(sensor_num, kin_state)
698+
699+
M = len(z)
700+
W = [0]*N
701+
S_ = [0]*N
702+
W_ = [0]*N
703+
v = a['v']
704+
w = a['w']
705+
706+
if S is None:
707+
S = [m.sample() for _ in range(N)]
708+
709+
for i in range(N):
710+
S_[i] = P_motion_sample(S[i], v, w)
711+
W_[i] = 1
712+
for j in range(M):
713+
z_ = ray_cast(j, S_[i], m)
714+
W_[i] = W_[i] * P_sensor(z[j], z_)
715+
716+
S = weighted_sample_with_replacement(N, S_, W_)
717+
return S

tests/test_probability.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,68 @@ def test_particle_filtering():
168168
# XXX 'A' and 'B' are really arbitrary names, but I'm letting it stand for now
169169

170170

171+
def test_monte_carlo_localization():
172+
## TODO: Add tests for random motion/inaccurate sensors
173+
random.seed('aima-python')
174+
m = MCLmap([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0],
175+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
176+
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0],
177+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
178+
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0],
179+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
180+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
181+
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0],
182+
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
183+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
184+
[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0]])
185+
186+
def P_motion_sample(kin_state, v, w):
187+
"""Sample from possible kinematic states.
188+
Returns from a single element distribution (no uncertainity in motion)"""
189+
pos = kin_state[:2]
190+
orient = kin_state[2]
191+
192+
# for simplicity the robot first rotates and then moves
193+
orient = (orient + w)%4
194+
for _ in range(orient):
195+
v = [v[1], -v[0]]
196+
pos = list(vector_add(pos, v))
197+
return pos + [orient]
198+
199+
def P_sensor(x, y):
200+
"""Conditional probability for sensor reading"""
201+
# Need not be exact probability. Can use a scaled value.
202+
if x == y:
203+
return 0.8
204+
elif abs(x - y) <= 2:
205+
return 0.05
206+
else:
207+
return 0
208+
209+
from utils import print_table
210+
a = {'v': [0, 0], 'w': 0}
211+
z = [2, 4, 1, 6]
212+
S = monte_carlo_localization(a, z, 1000, P_motion_sample, P_sensor, m)
213+
grid = [[0]*17 for _ in range(11)]
214+
for x, y, _ in S:
215+
if 0 <= x < 11 and 0 <= y < 17:
216+
grid[x][y] += 1
217+
print("GRID:")
218+
print_table(grid)
219+
220+
a = {'v': [0, 1], 'w': 0}
221+
z = [2, 3, 5, 7]
222+
S = monte_carlo_localization(a, z, 1000, P_motion_sample, P_sensor, m, S)
223+
grid = [[0]*17 for _ in range(11)]
224+
for x, y, _ in S:
225+
if 0 <= x < 11 and 0 <= y < 17:
226+
grid[x][y] += 1
227+
print("GRID:")
228+
print_table(grid)
229+
230+
assert grid[6][7] > 700
231+
232+
171233
# The following should probably go in .ipynb:
172234

173235
"""

0 commit comments

Comments
 (0)