2. 全局路径规划
任务目标
在二维栅格地图上实现A*寻路算法,给定起点与终点坐标,输出从起点到终点的最短路径点序列(含起点与终点)。地图中障碍物以栅格值标记,路径规划需绕开障碍物。
实现方案
采用Python实现,使用优先队列(heapq)管理开放集,曼哈顿距离作为启发函数(四方向移动)。地图以二维列表表示,0为可通行,1为障碍。核心逻辑包括:节点代价记录、邻居扩展、路径回溯。代码自包含,不依赖第三方库。
关键完整代码
import heapq
def astar(grid, start, goal):
"""A*算法主函数
grid: 二维列表,0可通行,1障碍
start: (row, col) 起点
goal: (row, col) 终点
返回: 路径点列表[(r,c),...];无路径返回None
"""
rows, cols = len(grid), len(grid[0])
# 合法性检查
if not (0 <= start[0] < rows and 0 <= start[1] < cols) or \
not (0 <= goal[0] < rows and 0 <= goal[1] < cols):
return None
if grid[start[0]][start[1]] == 1 or grid[goal[0]][goal[1]] == 1:
return None
# 四方向移动
dirs = [(-1,0),(1,0),(0,-1),(0,1)]
# g_cost: 起点到该节点的实际代价
g_cost = {start: 0}
# parent: 记录路径回溯
parent = {start: None}
def heuristic(a, b):
"""曼哈顿距离"""
return abs(a[0]-b[0]) + abs(a[1]-b[1])
# 优先队列元素: (f_cost, g_cost, node)
open_heap = [(heuristic(start, goal), 0, start)]
closed_set = set()
while open_heap:
_, current_g, current = heapq.heappop(open_heap)
if current == goal:
# 回溯路径
path = []
node = current
while node is not None:
path.append(node)
node = parent[node]
path.reverse()
return path
if current in closed_set:
continue
closed_set.add(current)
for dr, dc in dirs:
nr, nc = current[0]+dr, current[1]+dc
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0:
neighbor = (nr, nc)
tentative_g = current_g + 1
if neighbor not in g_cost or tentative_g < g_cost[neighbor]:
g_cost[neighbor] = tentative_g
parent[neighbor] = current
f_cost = tentative_g + heuristic(neighbor, goal)
heapq.heappush(open_heap, (f_cost, tentative_g, neighbor))
return None # 无可行路径
# ========== 最小验证示例 ==========
if __name__ == "__main__":
# 5x5栅格地图,1为障碍
grid_map = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0]
]
start = (0, 0)
goal = (4, 4)
result = astar(grid_map, start, goal)
if result:
print("路径点序列:")
for p in result:
print(p)
else:
print("未找到可行路径")
运行与验证
运行方式:将上述代码保存为 astar_demo.py,在命令行执行 python astar_demo.py。
预期输出:由于地图中存在障碍,A*会绕开障碍物,输出路径点序列。根据代码逻辑可唯一推出以下路径(从起点到终点):
(0, 0) -> (1, 0) -> (2, 0) -> (2, 1) -> (2, 2) -> (3, 2) -> (3, 3) -> (3, 4) -> (4, 4)
验证方法:运行程序后,观察输出是否包含上述9个路径点且顺序一致。可手动修改 grid_map 中的障碍位置或起点终点坐标,验证算法能正确绕障或返回 None(当起点或终点被障碍包围时)。
常见问题
- 路径非最短:检查启发函数是否满足一致性(曼哈顿距离在四方向移动下满足),若使用欧氏距离可能导致次优路径。
- 死循环或内存溢出:确认
closed_set正确跳过已访问节点,且邻居坐标边界检查完整。 - 起点等于终点:代码会直接返回包含单个点的路径,符合预期。