Skip to content

Commit 0fc7694

Browse files
authored
Adding NDT mapping script and doc (AtsushiSakai#867)
* Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc * Adding ndt mapping script and doc
1 parent 49dd1a9 commit 0fc7694

File tree

12 files changed

+372
-83
lines changed

12 files changed

+372
-83
lines changed

Localization/extended_kalman_filter/extended_kalman_filter.py

+3-25
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
"""
88
import sys
99
import pathlib
10+
1011
sys.path.append(str(pathlib.Path(__file__).parent.parent.parent))
1112

1213
import math
1314
import matplotlib.pyplot as plt
1415
import numpy as np
1516

16-
from utils.angle import rot_mat_2d
17+
from utils.plot import plot_covariance_ellipse
1718

1819
# Covariance for EKF simulation
1920
Q = np.diag([
@@ -135,29 +136,6 @@ def ekf_estimation(xEst, PEst, z, u):
135136
return xEst, PEst
136137

137138

138-
def plot_covariance_ellipse(xEst, PEst): # pragma: no cover
139-
Pxy = PEst[0:2, 0:2]
140-
eigval, eigvec = np.linalg.eig(Pxy)
141-
142-
if eigval[0] >= eigval[1]:
143-
bigind = 0
144-
smallind = 1
145-
else:
146-
bigind = 1
147-
smallind = 0
148-
149-
t = np.arange(0, 2 * math.pi + 0.1, 0.1)
150-
a = math.sqrt(eigval[bigind])
151-
b = math.sqrt(eigval[smallind])
152-
x = [a * math.cos(it) for it in t]
153-
y = [b * math.sin(it) for it in t]
154-
angle = math.atan2(eigvec[1, bigind], eigvec[0, bigind])
155-
fx = rot_mat_2d(angle) @ (np.array([x, y]))
156-
px = np.array(fx[0, :] + xEst[0, 0]).flatten()
157-
py = np.array(fx[1, :] + xEst[1, 0]).flatten()
158-
plt.plot(px, py, "--r")
159-
160-
161139
def main():
162140
print(__file__ + " start!!")
163141

@@ -202,7 +180,7 @@ def main():
202180
hxDR[1, :].flatten(), "-k")
203181
plt.plot(hxEst[0, :].flatten(),
204182
hxEst[1, :].flatten(), "-r")
205-
plot_covariance_ellipse(xEst, PEst)
183+
plot_covariance_ellipse(xEst[0, 0], xEst[1, 0], PEst)
206184
plt.axis("equal")
207185
plt.grid(True)
208186
plt.pause(0.001)

Mapping/grid_map_lib/grid_map_lib.py

+85-40
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,42 @@
55
author: Atsushi Sakai
66
77
"""
8-
8+
from functools import total_ordering
99
import matplotlib.pyplot as plt
1010
import numpy as np
1111

1212

13+
@total_ordering
14+
class FloatGrid:
15+
16+
def __init__(self, init_val=0.0):
17+
self.data = init_val
18+
19+
def get_float_data(self):
20+
return self.data
21+
22+
def __eq__(self, other):
23+
if not isinstance(other, FloatGrid):
24+
return NotImplemented
25+
return self.get_float_data() == other.get_float_data()
26+
27+
def __lt__(self, other):
28+
if not isinstance(other, FloatGrid):
29+
return NotImplemented
30+
return self.get_float_data() < other.get_float_data()
31+
32+
1333
class GridMap:
1434
"""
1535
GridMap class
1636
"""
1737

1838
def __init__(self, width, height, resolution,
19-
center_x, center_y, init_val=0.0):
39+
center_x, center_y, init_val=FloatGrid(0.0)):
2040
"""__init__
2141
2242
:param width: number of grid for width
23-
:param height: number of grid for heigt
43+
:param height: number of grid for height
2444
:param resolution: grid resolution [m]
2545
:param center_x: center x position [m]
2646
:param center_y: center y position [m]
@@ -35,8 +55,9 @@ def __init__(self, width, height, resolution,
3555
self.left_lower_x = self.center_x - self.width / 2.0 * self.resolution
3656
self.left_lower_y = self.center_y - self.height / 2.0 * self.resolution
3757

38-
self.ndata = self.width * self.height
39-
self.data = [init_val] * self.ndata
58+
self.n_data = self.width * self.height
59+
self.data = [init_val] * self.n_data
60+
self.data_type = type(init_val)
4061

4162
def get_value_from_xy_index(self, x_ind, y_ind):
4263
"""get_value_from_xy_index
@@ -49,7 +70,7 @@ def get_value_from_xy_index(self, x_ind, y_ind):
4970

5071
grid_ind = self.calc_grid_index_from_xy_index(x_ind, y_ind)
5172

52-
if 0 <= grid_ind < self.ndata:
73+
if 0 <= grid_ind < self.n_data:
5374
return self.data[grid_ind]
5475
else:
5576
return None
@@ -101,7 +122,7 @@ def set_value_from_xy_index(self, x_ind, y_ind, val):
101122

102123
grid_ind = int(y_ind * self.width + x_ind)
103124

104-
if 0 <= grid_ind < self.ndata:
125+
if 0 <= grid_ind < self.n_data and isinstance(val, self.data_type):
105126
self.data[grid_ind] = val
106127
return True # OK
107128
else:
@@ -138,6 +159,27 @@ def calc_grid_index_from_xy_index(self, x_ind, y_ind):
138159
grid_ind = int(y_ind * self.width + x_ind)
139160
return grid_ind
140161

162+
def calc_xy_index_from_grid_index(self, grid_ind):
163+
y_ind, x_ind = divmod(grid_ind, self.width)
164+
return x_ind, y_ind
165+
166+
def calc_grid_index_from_xy_pos(self, x_pos, y_pos):
167+
"""get_xy_index_from_xy_pos
168+
169+
:param x_pos: x position [m]
170+
:param y_pos: y position [m]
171+
"""
172+
x_ind = self.calc_xy_index_from_position(
173+
x_pos, self.left_lower_x, self.width)
174+
y_ind = self.calc_xy_index_from_position(
175+
y_pos, self.left_lower_y, self.height)
176+
177+
return self.calc_grid_index_from_xy_index(x_ind, y_ind)
178+
179+
def calc_grid_central_xy_position_from_grid_index(self, grid_ind):
180+
x_ind, y_ind = self.calc_xy_index_from_grid_index(grid_ind)
181+
return self.calc_grid_central_xy_position_from_xy_index(x_ind, y_ind)
182+
141183
def calc_grid_central_xy_position_from_xy_index(self, x_ind, y_ind):
142184
x_pos = self.calc_grid_central_xy_position_from_index(
143185
x_ind, self.left_lower_x)
@@ -156,39 +198,40 @@ def calc_xy_index_from_position(self, pos, lower_pos, max_index):
156198
else:
157199
return None
158200

159-
def check_occupied_from_xy_index(self, xind, yind, occupied_val=1.0):
201+
def check_occupied_from_xy_index(self, x_ind, y_ind, occupied_val):
160202

161-
val = self.get_value_from_xy_index(xind, yind)
203+
val = self.get_value_from_xy_index(x_ind, y_ind)
162204

163205
if val is None or val >= occupied_val:
164206
return True
165207
else:
166208
return False
167209

168-
def expand_grid(self):
169-
xinds, yinds = [], []
210+
def expand_grid(self, occupied_val=FloatGrid(1.0)):
211+
x_inds, y_inds, values = [], [], []
170212

171213
for ix in range(self.width):
172214
for iy in range(self.height):
173-
if self.check_occupied_from_xy_index(ix, iy):
174-
xinds.append(ix)
175-
yinds.append(iy)
176-
177-
for (ix, iy) in zip(xinds, yinds):
178-
self.set_value_from_xy_index(ix + 1, iy, val=1.0)
179-
self.set_value_from_xy_index(ix, iy + 1, val=1.0)
180-
self.set_value_from_xy_index(ix + 1, iy + 1, val=1.0)
181-
self.set_value_from_xy_index(ix - 1, iy, val=1.0)
182-
self.set_value_from_xy_index(ix, iy - 1, val=1.0)
183-
self.set_value_from_xy_index(ix - 1, iy - 1, val=1.0)
215+
if self.check_occupied_from_xy_index(ix, iy, occupied_val):
216+
x_inds.append(ix)
217+
y_inds.append(iy)
218+
values.append(self.get_value_from_xy_index(ix, iy))
219+
220+
for (ix, iy, value) in zip(x_inds, y_inds, values):
221+
self.set_value_from_xy_index(ix + 1, iy, val=value)
222+
self.set_value_from_xy_index(ix, iy + 1, val=value)
223+
self.set_value_from_xy_index(ix + 1, iy + 1, val=value)
224+
self.set_value_from_xy_index(ix - 1, iy, val=value)
225+
self.set_value_from_xy_index(ix, iy - 1, val=value)
226+
self.set_value_from_xy_index(ix - 1, iy - 1, val=value)
184227

185228
@staticmethod
186229
def check_inside_polygon(iox, ioy, x, y):
187230

188-
npoint = len(x) - 1
231+
n_point = len(x) - 1
189232
inside = False
190-
for i1 in range(npoint):
191-
i2 = (i1 + 1) % (npoint + 1)
233+
for i1 in range(n_point):
234+
i2 = (i1 + 1) % (n_point + 1)
192235

193236
if x[i1] >= x[i2]:
194237
min_x, max_x = x[i2], x[i1]
@@ -211,52 +254,54 @@ def print_grid_map_info(self):
211254
print("center_y:", self.center_y)
212255
print("left_lower_x:", self.left_lower_x)
213256
print("left_lower_y:", self.left_lower_y)
214-
print("ndata:", self.ndata)
257+
print("n_data:", self.n_data)
215258

216259
def plot_grid_map(self, ax=None):
217-
218-
grid_data = np.reshape(np.array(self.data), (self.height, self.width))
260+
float_data_array = np.array([d.get_float_data() for d in self.data])
261+
grid_data = np.reshape(float_data_array, (self.height, self.width))
219262
if not ax:
220263
fig, ax = plt.subplots()
221264
heat_map = ax.pcolor(grid_data, cmap="Blues", vmin=0.0, vmax=1.0)
222265
plt.axis("equal")
223-
# plt.show()
224266

225267
return heat_map
226268

227269

228-
def test_polygon_set():
270+
def polygon_set_demo():
229271
ox = [0.0, 4.35, 20.0, 50.0, 100.0, 130.0, 40.0]
230272
oy = [0.0, -4.15, -20.0, 0.0, 30.0, 60.0, 80.0]
231273

232274
grid_map = GridMap(600, 290, 0.7, 60.0, 30.5)
233275

234-
grid_map.set_value_from_polygon(ox, oy, 1.0, inside=False)
276+
grid_map.set_value_from_polygon(ox, oy, FloatGrid(1.0), inside=False)
235277

236278
grid_map.plot_grid_map()
237279

238280
plt.axis("equal")
239281
plt.grid(True)
240282

241283

242-
def test_position_set():
284+
def position_set_demo():
243285
grid_map = GridMap(100, 120, 0.5, 10.0, -0.5)
244286

245-
grid_map.set_value_from_xy_pos(10.1, -1.1, 1.0)
246-
grid_map.set_value_from_xy_pos(10.1, -0.1, 1.0)
247-
grid_map.set_value_from_xy_pos(10.1, 1.1, 1.0)
248-
grid_map.set_value_from_xy_pos(11.1, 0.1, 1.0)
249-
grid_map.set_value_from_xy_pos(10.1, 0.1, 1.0)
250-
grid_map.set_value_from_xy_pos(9.1, 0.1, 1.0)
287+
grid_map.set_value_from_xy_pos(10.1, -1.1, FloatGrid(1.0))
288+
grid_map.set_value_from_xy_pos(10.1, -0.1, FloatGrid(1.0))
289+
grid_map.set_value_from_xy_pos(10.1, 1.1, FloatGrid(1.0))
290+
grid_map.set_value_from_xy_pos(11.1, 0.1, FloatGrid(1.0))
291+
grid_map.set_value_from_xy_pos(10.1, 0.1, FloatGrid(1.0))
292+
grid_map.set_value_from_xy_pos(9.1, 0.1, FloatGrid(1.0))
251293

252294
grid_map.plot_grid_map()
253295

296+
plt.axis("equal")
297+
plt.grid(True)
298+
254299

255300
def main():
256301
print("start!!")
257302

258-
test_position_set()
259-
test_polygon_set()
303+
position_set_demo()
304+
polygon_set_demo()
260305

261306
plt.show()
262307

0 commit comments

Comments
 (0)