路径规划器的实现
1. 伪代码
function A*(start, goal)
//初始化已经探索过的节点为空
closedSet := {}
// 初始化未探索的节点,开始时仅包含起点
openSet := {start}
//cameFrom是一个字典,键是当前节点,值是当前节点的父节点
cameFrom := the empty map
// gScore为一个字典,存放该点的gsocre,起点为0,其余点初始化为无穷
gScore := map with default value of Infinity
gScore[start] := 0
// fScore为一个字典,存放该点的fsocre F = G + H,
//因此起点为起点到终点的直线距离,其余点初始化为无穷
fScore := map with default value of Infinity
fScore[start] := heuristic_cost_estimate(start, goal)
while openSet is not empty
//取出F值最小的节点设为当前点
current := the node in openSet having the lowest fScore[] value //当前点为目标点,跳出循环返回路径,并通过camefrom来生成路径(逆序)
if current = goal
return reconstruct_path(cameFrom, current)
//将该点从待探索集中移除,放入已探索集
openSet.Remove(current)
closedSet.Add(current)
//遍历当前节点的所有邻居节点(需要在未探索集中)
for each neighbor of current
if neighbor in closedSet
continue
//Discover a new node
if not neighbor in openSet:
self.openSet.add(neighbor)
//计算tentative_gScore作为新路径的gScore
//tentative_gScore可以理解为假设移动到临接点之后点gscore
tentative_gScore := gScore[current] + dist_between(current, neighbor)
//类似冒泡排序,首先存一个最小耗散的点(初始时可能是任意的,然后如果发现比它小的就替换掉,否则使用原来的路径)
//新gScore>=原gScore,则按照原路径(移动后好散增加了)
if tentative_gScore >= gScore[neighbor]
continue
// 否则选择gScore较小的新路径,并更新G值与F值。同时更新节点的父子关系。
cameFrom[neighbor] := current
gScore[neighbor] := tentative_gScore
fScore[neighbor] := gScore[neighbor] + heuristic_cost_estimate(neighbor, goal)
return failure
//从caomeFrom中从goal点追溯到start点,取得路径节点。
2. 基于函数实现
这里直接引用 jluiz20/udacity_python_a_start_route_planner的实现
import math
def shortest_path(M,start,goal):
print("shortest path called, Start", start, "Goal", goal)
#the set already explored
closedSet = set()
#only the start node is known
openSet = {start}
#the dictionary with the parent with the best way until the node
cameFrom = dict()
#cost of getting from the start to the node
gScore = dict()
gScore[start] = 0
fScore = dict()
#the straight line distance between start and goal
fScore[start] = distance(M.intersections[start], M.intersections[goal])
while openSet:
current = node_lowest_value(openSet, fScore)
# If reached the goal, YEAH!
if current == goal:
print("Goal Reached!")
return reconstruct_path(cameFrom, current)
openSet.remove(current) #remove from open
closedSet.add(current) #mark as processed
for neighbor in M.roads[current]:
if neighbor in closedSet:
continue
#add the neighbor to the frontier
openSet.add(neighbor)
#The distance from start to a neighbor
tentative_gScore = gScore[current] + distance(M.intersections[current], M.intersections[neighbor])
if neighbor in gScore:
if tentative_gScore >= gScore[neighbor]:
continue # This is not a better path.
# This path is the best until now. Record it!
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
fScore[neighbor] = gScore[neighbor] + distance(M.intersections[neighbor], M.intersections[goal])
return
def reconstruct_path(cameFrom, current):
total_path = list()
total_path.insert(0,current)
while current in cameFrom:
current = cameFrom[current]
total_path.insert(0 , current)
return total_path
def node_lowest_value(openSet, fScore):
lowest_node = 35767 #large number
lowest_value = float('inf')
for node in fScore:
if fScore[node] < lowest_value:
if node in openSet:
lowest_node = node
lowest_value = fScore[node]
return lowest_node
def distance(p1,p2):
distance = math.sqrt( ((p1[0]-p2[0])**2)+((p1[1]-p2[1])**2) )
return distance
3. 基于类的实现
class PathPlanner():
"""Construct a PathPlanner Object"""
def __init__(self, M, start=None, goal=None):
""" """
self.map = M
self.start= start
self.goal = goal
self.closedSet = self.create_closedSet() if goal != None and start != None else None
self.openSet = self.create_openSet() if goal != None and start != None else None
self.cameFrom = self.create_cameFrom() if goal != None and start != None else None
self.gScore = self.create_gScore() if goal != None and start != None else None
self.fScore = self.create_fScore() if goal != None and start != None else None
self.path = self.run_search() if self.map and self.start != None and self.goal != None else None
def create_closedSet(self):
return set()
def create_openSet(self):
if self.start != None:
return {self.start}
raise(ValueError, "Must create start node before creating an open set. Try running PathPlanner.set_start(start_node)")
def create_cameFrom(self):
return dict()
def create_gScore(self):
gScore = dict().fromkeys(self.map.intersections,float('inf'))
gScore[self.start] = 0
return gScore
def create_fScore(self):
fScore=dict().fromkeys(self.map.intersections,float('inf'))
fScore[self.start] = self.distance(self.map.intersections[self.start],self.map.intersections[self.goal])
return fScore
def _reset(self):
self.closedSet = None
self.openSet = None
self.cameFrom = None
self.gScore = None
self.fScore = None
self.path = self.run_search() if self.map and self.start and self.goal else None
def get_path(self):
""" Reconstructs path after search """
if self.path:
return self.path
else :
self.run_search()
return self.path
def set_map(self, M):
self._reset(self)
self.start = None
self.goal = None
self.map = M
def set_start(self, start):
self._reset(self)
self.start = start
def set_goal(self, goal):
self._reset(self)
self.goal = goal
def get_current_node(self):
lowest_node = 9999
lowest_value = float('inf')
for node in self.openSet:
if node in self.fScore and self.fScore[node] < lowest_value:
lowest_node = node
lowest_value = self.fScore[node]
return lowest_node
def get_neighbors(self, node):
return self.map.roads[node]
def get_gScore(self, node):
return self.gScore[node]
def get_tenative_gScore(self, current, neighbor):
return self.get_gScore(current) + self.distance(self.map.intersections[current], self.map.intersections[neighbor])
def is_open_empty(self):
return len(self.openSet)==0
def distance(self, node_1, node_2):
distance = math.sqrt( ((node_1[0]-node_2[0])**2)+((node_1[1]-node_2[1])**2) )
return distance
def heuristic_cost_estimate(self, node):
return self.distance(self.map.intersections[node], self.map.intersections[self.goal])
def calculate_fscore(self, node):
return self.get_gScore(node) + self.heuristic_cost_estimate(node)
def record_best_path_to(self, current, neighbor):
self.cameFrom[neighbor] = current
self.gScore[neighbor] = self.get_tenative_gScore(current,neighbor)
self.fScore[neighbor] = self.calculate_fscore(current)
def reconstruct_path(self, current):
""" Reconstructs path after search """
total_path = [current]
while current in self.cameFrom.keys():
current = self.cameFrom[current]
total_path.append(current)
return total_path
def run_search(self):
""" """
if self.map == None:
raise(ValueError, "Must create map before running search. Try running PathPlanner.set_map(start_node)")
if self.goal == None:
raise(ValueError, "Must create goal node before running search. Try running PathPlanner.set_goal(start_node)")
if self.start == None:
raise(ValueError, "Must create start node before running search. Try running PathPlanner.set_start(start_node)")
self.closedSet = self.closedSet if self.closedSet != None else self.create_closedSet()
self.openSet = self.openSet if self.openSet != None else self.create_openSet()
self.cameFrom = self.cameFrom if self.cameFrom != None else self.create_cameFrom()
self.gScore = self.gScore if self.gScore != None else self.create_gScore()
self.fScore = self.fScore if self.fScore != None else self.create_fScore()
while not self.is_open_empty():
current = self.get_current_node()
if current == self.goal:
self.path = [x for x in reversed(self.reconstruct_path(current))]
return self.path
else:
self.openSet.remove(current)
self.closedSet.add(current)
for neighbor in self.get_neighbors(current):
if neighbor in self.closedSet:
continue # Ignore the neighbor which is already evaluated.
if not neighbor in self.openSet: # Discover a new node
self.openSet.add(neighbor)
# The distance from start to a neighbor
#the "dist_between" function may vary as per the solution requirements.
if self.get_tenative_gScore(current, neighbor) >= self.get_gScore(neighbor):
continue # This is not a better path.
# This path is the best until now. Record it!
self.record_best_path_to(current, neighbor)
print("No Path Found")
self.path = None
return False
if __name__ == '__main__':
planner = PathPlanner(map_40, 5, 34)
path = planner.path