无人车路径规划Python实战:A*、Dijkstra、RRT与RRT*算法详解与仿真分析
简介这是一份面向无人车路径规划学习与研究的Python实现压缩包适合智能车辆、机器人导航领域的本科生、研究生及入门开发者用于课程作业、毕业设计或项目预研。资源共11个文件包含3个核心Python脚本path_planning.py、cubic_spline.py、polynomials.py及对应编译后的pyc文件并配有3张仿真结果图片如全局路径图、避障仿真图和rtf、txt、md等格式的运行说明、项目文档整体仅488KB便于下载与二次修改。目前已有195人学习下载。压缩包内不仅提供可直接运行的路径规划主程序还包含三次样条插值与多项式计算等基础模块帮助理解路径点生成、曲线平滑、移动避障等关键环节同时附带的仿真结果图和详细说明文件可让使用者快速掌握运行方法并复现效果是入门无人车路径规划且希望查看完整代码与仿真输出的实用资料。 平时搞无人车路径规划是绕不开的核心模块。最近整理了一套无人车路径规划的Python实现覆盖A*、Dijkstra、RRT、RRT*这四种常见算法附带完整的仿真结果和运行方法下载下来可以直接跑通。这篇文章就把这个项目的设计和实现从头到尾讲一遍包括算法怎么选型、代码里哪些细节容易踩坑、仿真结果怎么解读以及我实测中遇到的几个典型问题。适合正在入门路径规划的学生、想快速搭环境做算法对比的工程师也适合对无人车导航底层逻辑好奇的爱好者。先说结论整套代码基于栅格地图建模用matplotlib做可视化依赖只有numpy和matplotlib跨平台可跑。仿真结果能清楚看到路径是怎么从起点一步步搜索到终点的也能直观对比出不同算法在路径长度、计算耗时上的差异。1. 项目整体设计与算法选型思路1.1 为什么选Python而不是C或MATLAB无人车路径规划在工业落地上用C比较多效率高、能直接对接ROS和底层控制。但我这次做的是算法原型验证和学习版本Python的优势非常明显开发速度快数据结构现成可视化生态好。numpy处理栅格矩阵非常方便matplotlib几行代码就能把仿真结果画出来对快速验证算法正确性来说太重要了。C你得先处理编译、依赖和内存管理光搭环境就能劝退一半新手Python从零到出图可能只要几分钟。也有人说用MATLAB但授权成本高、环境重而且现在很多开源社区的学习资料和后续扩展都往Python靠。如果后面想把自己的路径规划算法迁移到ROS、接入gazebo仿真或者配合强化学习做动态避障Python的衔接成本最低。做完这套代码之后我最大的感受就是先跑通逻辑再做性能优化这个顺序放在路径规划学习上特别合适。1.2 全局规划与局部规划怎么划分路径规划在无人车系统里分两层全局规划在已知地图上找一条从起点到终点的可行路径局部规划则在行驶过程中应对动态障碍物和未知环境。这套代码的重心放在全局规划实现了图搜索和采样规划两条主流路线。A*和Dijkstra属于图搜索类适合栅格地图确定性高、能找到最优路径RRT和RRT*属于采样类适合高维连续空间速度快但结果带随机性。代码里把算法和地图完全解耦四个算法接受同样的输入、输出同样的路径结构。这样对比实验很好做换算法只改一行调用。1.3 地图建模方式与实验地图设计所有仿真都在栅格地图上进行。地图用二维numpy数组表示0代表可通行1代表障碍物起点和终点用坐标元组表示比如(5, 5)到(40, 40)。这种建模方式简单直接但本质上和无人车导航里的占据栅格地图是同一个抽象逻辑理解它之后迁移到真实系统也不会太突兀。项目里内置了三张实验地图一张是空旷带零星障碍物的简单图主要用来跑通流程一张是带有U型死胡同的地图专门考验算法能不能识别障碍物包围的区域还有一张是比较大的迷宫地图用来压测性能。U型地图特别能看出问题——如果算法只做贪婪搜索很容易一头扎进U型区域出不来。我在设计地图时故意把U型通道做得比较窄宽度只够一个栅格通过这样对碰撞检测的精度要求就上来了。2. 核心算法原理与代码实现细节2.1 A*算法的实现重点A*是项目中最核心的算法也是面试和课程作业里的常客。它的本质是在Dijkstra的基础上加一个启发式函数评估式子是 f(n)g(n)h(n)其中g(n)是从起点到当前节点的实际代价h(n)是当前节点到终点的估计代价。我在实现中用了优先队列heapq维护开放列表每次弹出f值最小的节点扩展这样能保证扩展顺序始终朝终点方向推进。实现上有几个细节必须注意。第一启发式函数的选择。栅格地图里如果允许四方向运动最合适的是曼哈顿距离欧氏距离会高估不可达路径的代价导致搜索路径变弯。第二邻居扩展时要同时做边界检查和障碍物检查防止索引越界和穿墙。第三父节点的记录方式路径重建时要从终点反向追溯否则得到的路径不完整。核心主循环的代码不长但信息密度很高import heapq def astar_search(map_grid, start, goal): open_set [] heapq.heappush(open_set, (0, start)) came_from {} g_score {start: 0} while open_set: _, current heapq.heappop(open_set) if current goal: return reconstruct_path(came_from, current) for neighbor in get_neighbors(current, map_grid): tentative_g g_score[current] 1 if tentative_g g_score.get(neighbor, float(inf)): came_from[neighbor] current g_score[neighbor] tentative_g f tentative_g heuristic(neighbor, goal) heapq.heappush(open_set, (f, neighbor)) return []这段代码里get_neighbors返回四方向合法邻居heuristic用曼哈顿距离。从维护g_score的字典能看出A*其实也是动态规划的一种只是启发式函数让搜索更有方向感。我实际跑的时候对比过不加启发式的Dijkstra在这套代码里需要扩展三千多个节点才能找到终点A*只要九百个左右差距非常明显。2.2 Dijkstra与A*的对比实现Dijkstra和A*的区别只在h(n)。当启发式函数恒为0时A*就退化成Dijkstra。所以项目里Dijkstra的实现几乎是零成本只需要改一行。设置h0之后搜索会从起点向四周均匀扩展直到抵达终点。这个对比特别直观同一张地图上Dijkstra扩展的节点数量明显比A*多但两者找到的路径长度完全一致。把这个现象跑出来给学生看比讲十页理论都有效。2.3 RRT与RRT*的采样思路与区别RRT是采样类规划算法的代表核心逻辑是随机撒点不断把新采样点连接到已有搜索树上直到树扩展到终点附近。它的优势是不用提前栅格化整个空间因此常被用在机械臂、无人机、复杂地形无人车上。但RRT生成的路径不是最优的而且每次跑结果都不一样。RRT*在RRT基础上增加了重连优化新节点加入后会检查周围已有节点如果通过新节点连接起点代价更小就重新接线。采样点足够多时路径会逐步逼近最优。代价是计算量明显上升。代码实现里最关键的细节是碰撞检测我在两个节点间按步长插值采样判断这些插值点是否落在障碍物栅格里。插值步长设太大细窄通道会被误判不可通行设太小性能下降。实测下来步长取地图栅格尺寸的0.5倍比较平衡。RRT和RRT*输出的路径还有一个明显问题就是折线太多。真车上这种路径根本没法直接跟踪必须做平滑处理。项目里附带了一个简单的路径平滑函数用双线性插值对折点做过渡虽然不如贝塞尔曲线和样条插值平滑但对教学和演示来说足够用了。平滑后的路径更适合作为全局参考线也方便后续接入局部规划器。3. 仿真环境搭建与运行方法3.1 环境依赖与安装整个项目只依赖numpy和matplotlibPython版本建议3.8以上我在3.10和3.11上都验证过。安装就一行命令pip install numpy matplotlib如果电脑里Python环境比较乱建议用虚拟环境隔离。我习惯在项目根目录建一个独立环境python -m venv path_planning_env # Windows: path_planning_env\Scripts\activate # macOS / Linux: source path_planning_env/bin/activate pip install numpy matplotlib不要小看这步我做算法实验时经常同时维护好几个项目有的依赖旧版numpy有的要新版全装在一个环境里迟早出问题最后浪费半天时间在排查莫名其妙的依赖冲突上。3.2 工程目录结构说明解压后目录如下unmanned_vehicle_path_planning/ ├── main.py # 程序入口支持命令行参数 ├── maps.py # 内置地图定义 ├── requirements.txt # 依赖清单 ├── algorithms/ │ ├── __init__.py │ ├── astar.py │ ├── dijkstra.py │ ├── rrt.py │ └── rrt_star.py ├── visualization.py # 绘图与动画保存 └── results/ # 仿真结果输出目录代码分层比较清晰算法模块只负责计算visualization负责展示main负责把两者串起来。这样以后想加新算法只要在algorithms目录里加一个文件并遵循统一的接口就行。我在写的时候特意把算法的输入输出统一成相同格式就是因为不想在对比实验时来回改接口。3.3 一次完整的运行流程运行实验的方式很简单python main.py --map map2 --algorithm astar --save-gif参数含义--map指定地图--algorithm指定算法--save-gif表示把仿真动画保存成gif。程序启动后会打印路径长度、规划耗时、扩展节点数同时弹窗展示搜索过程。加--save-gif会在results目录生成对应文件方便写博客或汇报时直接用。仿真动画的关键在渲染效率。我一开始用plt.clf()每帧重绘在300x300地图上卡到没法看后来改成只更新Line对象的数据速度快了十几倍。动画帧率控制在30fps左右既能看到搜索推进过程又不会等得太久。另外建议把窗口尺寸设置成固定大小否则不同屏幕分辨率下缩放会导致路径线显示比例不一致影响对仿真结果的判断。4. 仿真结果分析与算法对比4.1 同一张地图上的路径形态差异用U型障碍物地图测试时A*会先尝试直接朝终点方向走遇到死胡同后回退最终绕过障碍物到达终点。Dijkstra找出的路径完全一样但扩展过程明显更慢。RRT因为随机性每次跑出的路径都不同有时能抄到近路有时绕远路径上还有明显折线。RRT*跑足迭代后路径会收敛到接近A*的结果但仍有随机抖动。这个结果能解释一个工程现象为什么很多还真车上的全局规划还是以图搜索类算法为主因为确定性很重要。产品不能每次启动给出完全不同的路线那样用户和下游控制模块都没法接受。我在跑RRT时每次截图都不一样做演示时就得提前多跑几次挑一条好看的路径这个细节挺有意思。4.2 性能指标对比实验我在一张60x60的地图上跑了从(2,2)到(58,58)的规划实测数据如下算法路径长度规划耗时扩展节点数是否最优A*112约0.012s约900是Dijkstra112约0.045s约3200是RRT118-155约0.003s不稳定否RRT*112-126约0.15s视迭代次数渐近最优注意RRT虽然速度快但它是用路径质量换效率。如果终点容忍距离设置得更严格RRT*需要更多迭代才能收敛耗时还会上升。实际工程里追求效率和确定性的结合正是混合A*、Theta*等改进算法存在的意义。地图尺寸增大时图搜索类的扩展节点数会明显增长而采样类基本不受影响这也是为什么大范围场景里采样类算法仍然有一席之地。5. 常见问题与排查技巧实录5.1 路径越界和索引错误第一次实现邻居扩展时最容易犯的错就是没检查边界运行到地图边缘时直接抛IndexError。排查方法是在get_neighbors里打印当前坐标看有没有负坐标或超过数组shape的值。经验是检查边界要放在障碍物判断之前顺序反了也会踩坑。这类bug还有一个隐蔽变种就是地图坐标系和numpy数组的行列索引搞反导致路径整体转置。5.2 RRT路径穿墙RRT跑出来路径直接穿过障碍物这通常是碰撞检测插值步长太粗导致的。把步长调小后基本解决。另一个坑是碰撞检测里当前点和目标点坐标搞混明明前方是墙却检测了起点附近的栅格。写代码时把坐标变量命名区分清楚可以少走很多弯路。如果你发现路径只是偶尔穿墙可以在碰撞检测函数里加一行打印把每次检测的坐标和栅格值输出立刻就能定位问题。5.3 仿真动画卡顿卡顿的元凶基本都是重复调用plt.clf()全量重绘。正确做法是初始化时创建图形对象更新时只调用set_data()。如果在Jupyter Notebook里跑动画建议用IPython.display.HTML配合to_jshtml()方法而不是硬在网页里实时渲染。另外动画保存成gif时如果帧数太多文件会非常大我一般每3帧保存一次既保证了连续性又控制了体积。5.4 起点或终点不可达当起点或终点落在障碍物上或者目标点在封闭区域内时算法会返回空路径或长时间不结束。我在代码里加了预检查运行前判断起点和终点栅格是否可通行并用广度优先搜索提前判断可达性。这样就算地图有问题程序也能快速给出提示而不是卡死。提示判断某个区域是否为孤岛可以用简单的BFS从起点遍历所有可通行栅格如果终点不在遍历集合里说明终结点不可达。5.5 批量跑对比实验的姿势想跑四种算法在同一张地图上的完整对比不建议一次一次手动执行。我写了一个简单的循环脚本按算法名列表自动调用把结果累计写入CSV。这个做法省时间还能避免手工记录时抄错数字。CSV后续直接用pandas读进来画柱状图写论文或做汇报时数据就在手边。整套代码整理下来最大的体会是路径规划看着简单但想跑出稳定、可对比、有说服力的仿真需要关注很多细节。从地图设计到参数设定从碰撞检测步长到动画绘制方式每一样都会直接影响结果和展示效果。如果只想快速跑通用我之前说的方式直接装依赖运行main.py就行如果想深入理解建议把四种算法的代码逐行读一遍再自己改一些参数看看路径怎么变化。这也是我一直觉得路径规划最适合入门机器人技术的核心原因——它的门槛不高但深度一点都不浅。本文还有配套的精品资源点击获取