@@ -70,27 +70,12 @@ def get_neighbors(self, state):
70
70
71
71
for i , j in self ._neighbours :
72
72
try :
73
- if state .x + i > 0 and state .y + j > 0 :
73
+ if state .x + i >= 0 and state .y + j >= 0 :
74
74
state_list .append (self .map [state .y + j ][state .x + i ])
75
75
except IndexError :
76
76
pass
77
77
return state_list
78
78
79
-
80
- # def set_cost(self, region, cost, modify=None):
81
-
82
- # xmin = max(0, region[0])
83
- # xmax = min(self.col, region[1])
84
- # ymin = max(0, region[2])
85
- # ymax = min(self.row, region[3])
86
-
87
- # self.costmap[ymin:ymax, xmin:xmax] = cost
88
-
89
- # if modify is not None:
90
- # for x in range(xmin, xmax):
91
- # for y in range(ymin, ymax):
92
- # modify.modify_cost(self.map[y][x])
93
-
94
79
_root2 = np .sqrt (2 )
95
80
96
81
def cost (self , state1 , state2 ):
@@ -127,11 +112,12 @@ def show_h(self):
127
112
# - replace equality tests with math.isclose() which is faster than np.isclose()
128
113
# - add an offset to inequality tests, X > Y becomes X > Y + tol
129
114
class Dstar :
130
- def __init__ (self , map ):
115
+ def __init__ (self , map , tol = 1e-6 ):
131
116
self .map = map
132
117
# self.open_list = set()
133
118
self .open_list = []
134
119
self .nexpand = 0
120
+ self .tol = tol
135
121
136
122
def process_state (self , verbose = False ):
137
123
if verbose :
@@ -150,25 +136,27 @@ def process_state(self, verbose=False):
150
136
if verbose :
151
137
print (f"EXPAND { x } , { k_old :.1f} " )
152
138
153
- if x .h > k_old + 1e-6 :
139
+ if x .h > k_old + self . tol :
154
140
# RAISE state
155
141
if verbose :
156
142
print (' raise' )
157
143
for y in self .map .get_neighbors (x ):
158
- if y .t is not Tag .NEW and y .h <= k_old and x .h > y .h + self .map .cost (x , y ) + 1e-6 :
144
+ if (y .t is not Tag .NEW and
145
+ y .h <= k_old - self .tol and
146
+ x .h > y .h + self .map .cost (x , y ) + self .tol ):
159
147
if verbose :
160
148
print (f" { x } cost from { x .h :.1f} to { y .h + self .map .cost (x , y ):.1f} ; parent from { x .parent } to { y } " )
161
149
x .parent = y
162
150
x .h = y .h + self .map .cost (x , y )
163
151
164
- if math .isclose (x .h , k_old , rel_tol = 0 , abs_tol = 1e-6 ):
152
+ if math .isclose (x .h , k_old , rel_tol = 0 , abs_tol = self . tol ):
165
153
# normal state
166
154
if verbose :
167
155
print (' normal' )
168
156
for y in self .map .get_neighbors (x ):
169
157
if y .t is Tag .NEW \
170
- or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = 1e-6 )) \
171
- or (y .parent != x and y .h > x .h + self .map .cost (x , y ) + 1e-6 ):
158
+ or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = self . tol )) \
159
+ or (y .parent != x and y .h > x .h + self .map .cost (x , y ) + self . tol ):
172
160
if verbose :
173
161
print (f" reparent { y } from { y .parent } to { x } " )
174
162
y .parent = x
@@ -178,19 +166,19 @@ def process_state(self, verbose=False):
178
166
if verbose :
179
167
print (' raise/lower' )
180
168
for y in self .map .get_neighbors (x ):
181
- if y .t is Tag .NEW or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = 1e-6 )):
169
+ if y .t is Tag .NEW or (y .parent == x and not math .isclose (y .h , x .h + self .map .cost (x , y ), rel_tol = 0 , abs_tol = self . tol )):
182
170
if verbose :
183
171
print (f" { y } cost from { y .h :.1f} to { y .h + self .map .cost (x , y ):.1f} ; parent from { y .parent } to { x } ; add to frontier" )
184
172
y .parent = x
185
173
self .insert (y , x .h + self .map .cost (x , y ))
186
174
else :
187
- if y .parent != x and y .h > x .h + self .map .cost (x , y ) + 1e-6 and x .t is Tag .CLOSED :
175
+ if y .parent != x and y .h > x .h + self .map .cost (x , y ) + self . tol and x .t is Tag .CLOSED :
188
176
self .insert (x , x .h )
189
177
if verbose :
190
178
print (f" { x } , { x .h :.1f} add to frontier" )
191
179
else :
192
- if y .parent != x and x .h > y .h + self .map .cost (y , x ) + 1e-6 \
193
- and y .t is Tag .CLOSED and y .h > k_old + 1e-6 :
180
+ if y .parent != x and x .h > y .h + self .map .cost (y , x ) + self . tol \
181
+ and y .t is Tag .CLOSED and y .h > k_old + self . tol :
194
182
self .insert (y , y .h )
195
183
if verbose :
196
184
print (f" { y } , { y .h :.1f} add to frontier" )
@@ -212,28 +200,32 @@ def insert(self, state, h_new):
212
200
state .k = h_new
213
201
214
202
elif state .t is Tag .OPEN :
215
- # k_new = min(state.k, h_new)
216
- # if state.k == k_new:
217
- # # k hasn't changed, leave vertex in frontier
218
- # return
219
- # else:
220
- # state.k = k_new
221
- # # remove the item from the open list
222
- # # print('node already in open list, remove it first')
223
- # #TODO use bisect on old state.k to find the entry
224
- # for i, item in enumerate(self.open_list):
225
- # if item[1] is state:
226
- # del self.open_list[i]
227
- # break
228
-
229
- state .k = min (state .k , h_new )
230
- # remove the item from the open list
231
- # print('node already in open list, remove it first')
232
- #TODO use bisect on old state.k to find the entry
233
- for i , item in enumerate (self .open_list ):
234
- if item [1 ] is state :
235
- del self .open_list [i ]
236
- break
203
+ k_new = min (state .k , h_new )
204
+ if state .k == k_new :
205
+ # k hasn't changed, and vertex already in frontier
206
+ # just update h and be done
207
+ state .h = h_new
208
+ return
209
+ else :
210
+ # k has changed, we need to remove the vertex from the list
211
+ # and re-insert it
212
+ state .k = k_new
213
+
214
+ # scan the list to find vertex, then remove it
215
+ # this is quite slow
216
+ for i , item in enumerate (self .open_list ):
217
+ if item [1 ] is state :
218
+ del self .open_list [i ]
219
+ break
220
+
221
+ # state.k = min(state.k, h_new)
222
+ # # remove the item from the open list
223
+ # # print('node already in open list, remove it first')
224
+ # #TODO use bisect on old state.k to find the entry
225
+ # for i, item in enumerate(self.open_list):
226
+ # if item[1] is state:
227
+ # del self.open_list[i]
228
+ # break
237
229
238
230
elif state .t is Tag .CLOSED :
239
231
state .k = min (state .h , h_new )
@@ -244,50 +236,33 @@ def insert(self, state, h_new):
244
236
# self.open_list.add(state)
245
237
heapq .heappush (self .open_list , (state .k , state ))
246
238
247
- # def remove(self, state):
248
- # if state.t is Tag.OPEN:
249
- # state.t = Tag.CLOSED
250
- # else:
251
- # state.t = Tag.CLOSED
252
- # print('removing non open state')
253
- # self.open_list.remove(state)
254
-
255
239
def modify_cost (self , x , newcost ):
256
240
self .map .costmap [x .y , x .x ] = newcost
257
241
if x .t is Tag .CLOSED :
258
242
self .insert (x , x .parent .h + self .map .cost (x , x .parent ))
259
- # return self.get_kmin()
260
243
if len (self .open_list ) == 0 :
261
244
return - 1
262
245
else :
263
246
# lowest priority item is always at index 0 according to docs
264
247
return self .open_list [0 ][0 ]
265
248
266
- # def modify(self, state):
267
- # self.modify_cost(state)
268
- # while True:
269
- # k_min = self.process_state()
270
- # if k_min == -1 or k_min >= state.h:
271
- # break
272
-
273
- # def showparents(self):
274
- # return
275
- # for y in range(self.map.row):
276
- # if y == 0:
277
- # print(" ", end='')
278
- # for x in range(self.map.col):
279
- # print(f" {x} ", end='')
280
- # print()
281
- # print(f"{y}: ", end='')
282
- # for x in range(self.map.col):
283
- # x = self.map.map[y][x]
284
- # par = x.parent
285
- # if par is None:
286
- # print(' G ', end='')
287
- # else:
288
- # print(f"({par.x},{par.y}) ", end='')
289
- # print()
290
- # print()
249
+ def showparents (self ):
250
+ for y in range (self .map .row - 1 , - 1 , - 1 ):
251
+ if y == self .map .row - 1 :
252
+ print (" " , end = '' )
253
+ for x in range (self .map .col ):
254
+ print (f" { x } " , end = '' )
255
+ print ()
256
+ print (f"{ y } : " , end = '' )
257
+ for x in range (self .map .col ):
258
+ x = self .map .map [y ][x ]
259
+ par = x .parent
260
+ if par is None :
261
+ print (' G ' , end = '' )
262
+ else :
263
+ print (f"({ par .x } ,{ par .y } ) " , end = '' )
264
+ print ()
265
+ print ()
291
266
class DstarPlanner (PlannerBase ):
292
267
r"""
293
268
D* path planner
@@ -322,7 +297,7 @@ def __init__(self, occ_grid=None,
322
297
self .costmap = np .where (self .occgrid .grid > 0 , np .inf , 1 )
323
298
self .map = Map (self .costmap .shape [0 ], self .costmap .shape [1 ])
324
299
self .map .costmap = self .costmap
325
- self .dstar = Dstar (self .map )
300
+ self .dstar = Dstar (self .map ) #, tol=0)
326
301
327
302
328
303
def plan (self , goal , animate = False , progress = True ):
@@ -356,6 +331,9 @@ def plan(self, goal, animate=False, progress=True):
356
331
print (self .dstar .ninsert , self .dstar .nin )
357
332
358
333
334
+ @property
335
+ def nexpand (self ):
336
+ return self .dstar .nexpand
359
337
360
338
def query (self , start , sensor = None , animate = False , verbose = False ):
361
339
self .start = start
@@ -385,16 +363,18 @@ def query(self, start, sensor=None, animate=False, verbose=False):
385
363
val = self .dstar .modify_cost (X , newcost )
386
364
# propagate the changes to plan
387
365
print ('propagate' )
366
+ # self.dstar.showparents()
388
367
while val != - 1 and val < tmp .h :
389
368
val = self .dstar .process_state (verbose = verbose )
390
369
# print('open set', len(self.dstar.open_list))
370
+ # self.dstar.showparents()
391
371
392
372
tmp = tmp .parent
393
373
# print('move to ', tmp)
394
374
395
375
status = namedtuple ('DstarStatus' , ['cost' ,])
396
376
397
- return np .array (path ). T , status (cost )
377
+ return np .array (path ), status (cost )
398
378
399
379
# # Just feed self._h into plot function from parent as p
400
380
@@ -439,7 +419,7 @@ def sensorfunc(pos):
439
419
changes = []
440
420
for x in range (3 , 6 ):
441
421
for y in range (0 , 4 ):
442
- changes .append ((x , y , 5 ))
422
+ changes .append ((x , y , 100 ))
443
423
return changes
444
424
445
425
path2 , status2 = ds .query (start = start , sensor = sensorfunc , verbose = False )
0 commit comments