ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Pygame实现无地图环境下的自动驾驶路径探索

用Pygame实现无地图环境下的自动驾驶路径探索 我估计很多人看到这个系列标题的第一反应是Pygame那不是写贪吃蛇、飞机大战用的游戏库吗拿它来做自动驾驶路径规划器怎么看都有点草台班子。但如果你真做过机器人或者自动驾驶方向的算法原型就会明白一个特别朴素的道理——在把算法搬到昂贵的仿真器、实车或者ROS框架之前你需要一个能快速验证想法、能盯着规划过程一帧一帧看、能随手改参数立刻看效果的环境。Pygame在路径探索这个场景下恰恰是最合适的那个草台班子而且它一点都不草。这个系列的第一篇我搭好了基础环境这一篇开始进入正题无地图环境下的路径探索。这里说的无地图不是真的让车辆在完全黑暗、零信息的环境里瞎开而是说我们不依赖预先构建好的高精地图、栅格地图或者拓扑路网车辆只靠实时的感知结果在当下这一刻把路找出来。这是很多实际场景的常态——地下车库、野外矿区、临时施工改道、没有高精地图覆盖的园区车必须自己探索出路。这篇我主要分享我如何用Pygame把一个交互式路径规划器从零跑起来包括环境建模、感知模拟、RRT*路径搜索的落地实现以及怎么用决策延迟这种指标来衡量规划器到底行不行。如果你也在做路径规划相关的原型验证或者毕设这套东西可以直接抄作业。1. 为什么选择Pygame来做路径规划原型先回答质疑1.1 路径规划在2D世界里到底是件什么事很多人一听自动驾驶就觉得必须上CARLA、AirSim、LGSVL这种重型仿真器再配一套完整的传感器模型不然就不够真实。但路径规划这个环节尤其是局部路径探索本质上是一个几何问题车在二维平面上有一堆已知位置的障碍物要从A点绕过障碍走到B点。等你把好端端的算法塞进重型仿真器你会发现大部分时间都耗在环境加载、传感器数据同步、通信接口调试上真正用来验证算法的时间反而少得可怜。Pygame的优势就在这里——它是个2D渲染库但2D渲染正是路径规划可视化的全部需求。障碍物无非是矩形、圆形、多边形车辆可以用矩形或者若干圆形包络近似路径就是平面上的折线或曲线。这些东西在Pygame里画出来只需要几行代码但换成CARLA你得先启动服务端、加载地图、配置传感器光环境准备就够喝一壶的。我个人的习惯是算法层面的验证用Pygame确认逻辑没问题了再搬到更复杂的仿真环境里做集成测试。这个流程帮我省下了大量无谓的调试时间。1.2 和其它仿真方案放一起比一比我整理过一个对比表把常见的原型验证方案放在一起看构思会清晰很多方案上手成本交互性可视化直观度适合阶段Pygame 2D环境极低pip install pygame就能跑极高可鼠标键盘实时干预极高能逐帧观察规划过程算法逻辑验证、课程设计、快速原型Matplotlib动态绘图低差交互响应慢中更新机制不够实时离线算法对比、论文出图ROS Rviz Gazebo高需要装整套生态中等需要写topic通信高但配置繁琐系统集成前的中级验证CARLA/AirSim很高需GPU和大量环境配置中等Python API相对成熟高3D场景真实性强传感器级验证、端到端测试排序并没有优劣关键是你处在哪个阶段。如果你连RRT*和碰撞检测的细节都没调清楚直接上CARLA就是在给自己制造双倍困难。反过来如果你要做传感器融合或者控制闭环那2D环境无论如何是不够的。1.3 必须接受的前提假设用2D环境做自动驾驶路径探索一定要清楚简化边界在哪里。我的规划器做了以下假设车辆看成可转向的矩形刚体用圆周包络近似碰撞形状障碍物是静态的、位置可通过感知直接获得忽略车辆动力学中的加速度、侧滑、轮胎摩擦定位假设为理想定位没有累积漂移。这些假设看起来不真实但对于6DoF刚体动力学都还没调的算法阶段来说完全是合理的。值得一提的还有欧卡2自动驾驶插件这类游戏环境。不少玩家和极客在《欧洲卡车模拟2》里做车道保持、自动跟车的插件它比Pygame真实但那是游戏——传感器数据来源和物理引擎都不开放你无法精确控制场景状态也很难做定量评估。游戏插件适合做效果展示Pygame适合做算法研究和交互实验各有各的用途我两者都玩过最终做路径规划原型还是回到Pygame。2. 无地图环境的本质没有先验地图规划靠什么跑2.1 无地图不是无信息而是没有先验栅格无地图环境最容易误解的地方在于无这个字。很多人以为无地图就意味着车辆完全盲目实际上不是。自动驾驶里的无地图环境指的是没有预先构建的先验地图——没有高精地图路网没有提前扫描好的栅格地图没有语义地图。车辆对环境的理解全部依赖于实时感知激光雷达扫描出障碍物轮廓视觉识别出可行区域毫米波雷达探测动态目标。感知到什么就知道什么感知范围之外全部视为未知。这种已知与未知并存的状态恰恰是路径探索中最有魅力的地方。规划器面对的不是一张完整的地图而是局部已知区域 大范围未知区域。在这个前提下传统的全局规划思路——比如静态地图上的A*、Dijkstra——会直接失效因为你根本没有一张完整的图可以用来搜索。这也是为什么我说无地图环境的路径探索和基于地图的全局路径规划在问题定义上就是两个物种。我在Pygame里模拟这种状态的方法很直接传感器范围用一个圆形视野表示只有障碍物落入这个视野才被看见并加入规划器的感知列表视野之外的障碍物仍然存在并参与碰撞检测但规划器对它们一无所知。于是车辆明明知道前方有一片未知区域却只能凭借当下可见的信息反复规划出局部路径走一段、规划一段、再走一段直到穿出整个区域。2.2 感知-规划一体化的滚动时域逻辑无地图环境下路径规划器的核心运行模式叫做滚动时域规划也叫局部感知规划。这个思路并不复杂每一帧规划器获取当前感知到的环境信息在感知范围内的某个局部目标点附近做路径搜索车辆沿规划结果走一小段然后传感器带来新信息规划器重新规划。如此往复形成感知-规划-执行-再感知的闭环。打个比方的话就像一个人在没有导航的小巷里找目的地——你不需要知道整个街区的完整路网图你只需要看到眼前的胡同口和路口做出一个局部判断往前走到下一个路口再重新判断。这个比喻几乎就是无地图路径探索的最佳解释。在规划器实现上滚动时域规划意味着目标点分为全局目标和局部目标。全局目标是由用户设定的终点它可能远在未知区域之外局部目标则是全局目标在感知范围内的投影点或者说是本次规划要生成的路径终点。我的实现逻辑是把全局目标点不断拉到感知范围边缘如果感知范围内没有障碍物阻挡就直接朝向全局目标前进如果感知范围内有障碍物就调用路径搜索算法生成一条绕障路径。2.3 环境表示把障碍物变成规划器能懂的数据结构规划算法不认识图形只认识数据。在Pygame里环境中的数据化表示我采用了最经典的两种几何图元圆形和矩形。圆形用于表示树干、立柱、锥桶这类障碍物用一个圆心坐标加半径就可以定义矩形用于表示墙段、车辆、箱体用中心点、宽、高、旋转角度来表示。代码层面我是这样组织的dataclass class Obstacle: kind: str # circle 或 rect x: float y: float radius: float 0.0 # circle 使用 w: float 0.0 # rect 使用 h: float 0.0 angle: float 0.0 # rect 旋转角每一个障碍物有两种身份一是视觉身份在Pygame的窗口里被真实渲染出来二是逻辑身份作为碰撞检测的几何输入存在。规划器在生成路径时只访问逻辑身份渲染层与规划层由此解耦。这个设计看起来简单但非常重要——它让你可以在不改变规划算法的情况下自由替换障碍物的渲染风格或者在逻辑中隐藏某些障碍物用来模拟感知盲区。我还建了一个Sensor类专门负责维护当前感知到的障碍物列表。每一帧都会重新计算障碍物是否在传感器视野内视野半径是可调的。规划器永远只拿感知列表里的障碍物做碰撞检测这样无地图环境才真正在代码层面立起来。3. 交互式规划器的模块架构与事件循环3.1 三大核心模块的职责划分整个规划器我拆成了三个模块职责边界尽量划清仿真环境模块、规划模块、交互渲染模块。这其实就是MVC思想的一个变体——模型、控制器、视图分离。仿真环境模块负责维护世界状态包括障碍物列表、传感器模型、车辆状态位置、朝向、速度、全局目标点和局部目标点。所有数据只有这里可以修改外部想改数据必须通过模块暴露的方法这样能避免规划逻辑和渲染逻辑互相污染。规划模块接收环境模块传来的感知数据执行路径搜索算法输出路径点列表。它本身不知道Pygame的存在不关心任何渲染细节。这一点对后期维护特别重要我后续想把规划器搬到真实机器人上的时候只需要把感知数据接口换成激光雷达数据规划模块一行都不用改。交互渲染模块则负责三件事把世界状态画到窗口里、捕获鼠标键盘输入并转换成对世界状态的修改、把规划结果和性能数据叠加显示。这部分是Pygame的主场所有游戏引擎的渲染与事件机制都在这一层用上。3.2 Pygame事件循环如何驱动仿真与规划Pygame程序的标准骨架是事件循环我的规划器也遵循这个结构但做了专门的扩展。核心代码如下def run(self): clock pygame.time.Clock() while self.running: dt clock.tick(60) / 1000.0 for event in pygame.event.get(): self.handle_event(event) self.env.update(dt) # 更新环境状态 if self.env.should_replan(): t0 time.perf_counter() self.planner.plan( startenv.vehicle_pose(), goalenv.local_goal(), obstaclesenv.visible_obstacles() ) self.last_plan_time time.perf_counter() - t0 self.env.path self.planner.path self.renderer.draw(self.env, self.planner, self.last_plan_time) pygame.display.flip()有一个细节值得展开讲clock.tick(60)把帧率锁定在60FPS也就是每帧约16.7毫秒。如果路径搜索的耗时超过16.7毫秒画面会出现卡顿。这时候有两种选择把帧率降低或者把规划放到单独的线程。我在早期版本里直接在事件循环里跑规划当RRT*迭代次数设置过高时明显掉帧后来加入了每N帧只规划一次的节流机制确保规划不会阻塞渲染。这种设计其实也呼应了决策延迟的概念——规划本身花费的时间就是决策延迟的一部分它会直接影响到车辆能否及时避障。关于这里我在第五部分还会重点聊。3.3 用鼠标和键盘操作起来的交互设计既然是交互式路径规划器交互体验就决定了这个工具好不好用。我实现的交互操作包括这么几类每个类别的操作都会实时刷新规划结果鼠标左键在空白区域单击添加一个圆形障碍物鼠标左键按住拖动画出一个矩形障碍物鼠标右键单击障碍物删除该障碍物鼠标中键点击任意位置设定新的全局目标点。键盘上方向键控制车辆前驱/转向的线速度和角速度按住R键重置车辆位置按空格键切换连续重新规划和只在目标变化时重新规划两种模式。这里最让我惊喜的是添加障碍物后立刻重规划的体验。你在车辆前进路径上随便点一个圆形障碍物路径会在一帧内重新生成绕开新障碍。那种随手设置困难算法立刻解决的反馈比看十篇论文都直观。不少朋友来我这看到这个工具的第一反应都是抢过鼠标乱点一通把画面点成一个迷宫然后看车辆怎么钻出来——交互式规划器的意义就在于此它把算法从静态图表变成了能亲手玩的东西。4. 路径探索核心算法RRT*在Pygame中的落地实现4.1 为什么是RRT而不是A或Dijkstra路径搜索算法很多但适配无地图环境的其实没那么多。A和Dijkstra需要一张确定性的栅格地图或者拓扑图才能运行,但在无地图环境下车辆只有局部感知的障碍物列表并没有覆盖整个规划空间的连通图。你当然可以临时把感知区域栅格化再跑A但栅格分辨率的选择本身就很难受——分辨率太粗会切掉窄通道太细又会让搜索开销爆炸。RRTRapidly-exploring Random Tree快速扩展随机树以及它的改进版本RRT*则完全避开了栅格化的问题。它们直接在连续坐标系里工作从起点出发不断在空间里随机采样把采样点连接到树上最近的点逐步扩展出一棵覆盖可行区域的树。这棵树不会尝试去建模整个地图它只探索从起点出发能到达的地方天然适合局部感知场景。RRT相对RRT的核心改进在于渐进最优性。RRT找到的第一条可行路径往往扭曲歪斜有大量不必要的绕路而RRT在扩展新节点的同时会检查附近已有的节点尝试用新节点替代原父节点来缩短路径这一步叫重连rewire。随着采样次数增加路径会逐渐逼近最优解。在无地图环境中每次滚动规划都重新执行RRT*局部路径的质量直接决定车辆走得顺不顺——这让我更坚定选择RRT*。4.2 碰撞检测矩形障碍物与圆形障碍物的几何判定路径规划里最频繁调用的函数一定是碰撞检测。RRT*每扩展一个新节点要判断新路径段是否撞上任何一个障碍物这个函数必须足够快否则几万次采样会把性能拖垮。圆形障碍物的碰撞检测最简单一个路径段可以离散成若干采样点对每个点计算到圆心距离如果小于半径就判碰撞。我用的路径段采样步长是5像素整个路径段均匀取点后逐个判断。矩形障碍物稍微复杂一点因为矩形可能是带旋转角度的不能直接套轴对齐包围盒。我的做法是把路径采样点做逆旋转变换到矩形局部坐标系再做轴对齐矩形判断def point_in_rotated_rect(px, py, rect): dx, dy px - rect.x, py - rect.y cos_a, sin_a math.cos(-rect.angle), math.sin(-rect.angle) local_x dx * cos_a - dy * sin_a local_y dx * sin_a dy * cos_a return abs(local_x) rect.w / 2 and abs(local_y) rect.h / 2这个逆旋转技巧在处理任意角度障碍物时非常通用建议收藏。车辆本身的碰撞模型上也有一点讲究。常见的做法是把车近似成若干个小圆形包络因为圆形之间的距离判定比矩形容易得多。我在车头和车尾各放一个半径等于车身宽度一半的圆形两圆心距离等于轴距。这样规划器在避障时天然会留出比车宽稍大的通道避免规划路径贴着障碍物擦过去的危险情况。4.3 采样、扩展、重连核心代码拆解RRT*在代码层面有几个关键步骤我逐个讲实现时踩过的细节。采样是第一步。RRT*每轮迭代在地图范围内随机采一个点但纯随机的采样效率太低大量点会落在无用区域。我的做法增加了目标偏置采样以一定概率我设为0.15到0.25直接采样局部目标点附近引导树向目标方向生长。其余时间在全空间采样保留探索新区域的能力。def sample_point(self): if random.random() self.goal_bias: gx self.goal[0] random.gauss(0, 20) gy self.goal[1] random.gauss(0, 20) return gx, gy x random.uniform(0, self.world_width) y random.uniform(0, self.world_height) return x, y随机点采样后下一步是找到树上距离采样点最近的节点这一步用最简单的线性遍历就行——除非树的节点数超过几千否则不需要加速结构。找到最近节点后沿着从最近节点指向采样点的方向扩展一个固定步长我通常用15到30像素生成新节点。如果新节点到最近节点之间的路径段没有碰撞新节点就加入树中。以下是扩展和重连的关键代码结构为了便于理解我略去了部分辅助逻辑def extend_tree(self): sample self.sample_point() nearest self.nearest_vertex(sample) new_node self.steer(nearest, sample, self.step_size) if not self.is_collision_free(nearest.pos, new_node.pos): return near_nodes self.near_vertices(new_node.pos, self.rewire_radius) best_parent, best_cost nearest, self.cost_to(nearest) self.step_size for v in near_nodes: if not self.is_collision_free(v.pos, new_node.pos): continue candidate_cost self.cost_to(v) self.distance(v.pos, new_node.pos) if candidate_cost best_cost: best_parent, best_cost v, candidate_cost new_node.parent best_parent self.vertices.append(new_node) # rewire for v in near_nodes: if v is best_parent: continue if not self.is_collision_free(v.pos, new_node.pos): continue if self.cost_to(new_node) self.distance(new_node.pos, v.pos) self.cost_to(v): v.parent new_node这段代码里steer负责做插值扩展is_collision_free调用前面写好的几何判定函数rewire_radius是新节点影响半径我设置为步长的3倍。重连这一步对路径质量的影响非常大我实测发现同样的采样次数下带重连的RRT*路径复杂度比不带重连的RRT路径低40%以上车辆执行起来也顺滑得多。迭代终止条件有两种一是采样点离目标点足够近且从树上找到了从起点到该采样点的路径二是达到最大迭代次数此时直接用树上离目标最近的节点路径作为输出。在滚动规划场景中迭代次数上限不能设太高因为每一帧都要重新规划通常我会控制在2000到5000次迭代以内。4.4 路径平滑与局部跟踪从规划结果到可执行轨迹RRT*输出的原始路径是一系列树节点组成的折线直接拿给车辆执行会非常生硬——车辆走到每个拐点都需要急转看起来像在跳方格舞。所以我加了一个贪心剪枝平滑步骤。贪心剪枝的思路本质上是能直走就不拐弯。从起点开始尝试把当前点和后面的每个路径点直接相连如果相连路径不碰撞就跳过中间所有节点把这一段缩短成一条直线段。不断重复最终得到的路径会保留关键的绕障拐点但中间大量冗余z字形折角会被压缩掉。这个算法简单到只有二十几行效果却极其显著。平滑后的路径还要转换为车辆能执行的轨迹。我把路径点列表传入一个简单的纯跟踪控制器Pure Pursuit控制器每次只追踪路径上距离车辆前方一定距离的点计算车辆前轮转角朝着那个点转。这个控制器是自动驾驶领域最常见的跟踪算法之一在Pygame这种简化的运动学模型下表现很好车辆能平滑地沿路径行进不会出现明显的来回摆头。5. 仿真评估用决策延迟衡量规划器性能5.1 决策延迟为什么重要我在逛技术社区时看到一条热搜词叫决策延迟32.8毫秒说的是某些自动驾驶方案在感知到环境变化后到决策模块输出新控制指令的耗时。这个数字看起来很抽象但它其实是衡量自动驾驶系统能不能安全应对突发状况的核心指标。试想一下车辆以10米/秒行驶每延迟100毫秒才响应就意味着车辆已经往前走了1米才刚开始转向。如果障碍物距离只有1.5米这一米的决策延迟几乎就是生死线。在真实自动驾驶系统里决策延迟由感知、融合、规划、控制各模块的耗时叠加而来。我在Pygame规划器里能直接观测到的是规划模块耗时也就是从输入感知数据到输出新路径的时间。虽然它只是真实决策链路中的一环但理解了规划延迟的量级和影响因素对设计整个决策系统都很有帮助。5.2 在Pygame里怎么测量和显示规划延迟测量规划延迟没什么玄学用Python标准库的time.perf_counter()即可。在调用planner.plan()之前记录时间戳规划结束后计算差值存到变量里同时渲染到画面右上角。这样每次重规划后屏幕上都会实时显示当前这次规划的决策延迟。我的显示格式是当前规划耗时 X ms外加N点路径。每帧渲染时还会把最近30次规划耗时的滑动平均也画出来因为单次耗时会因随机采样而波动平均数据更有参考价值。一个容易被忽略的点是Pygame会等待垂直同步clock.tick(60)会把帧间隔锁在16.7毫秒左右因此在事件循环里测得的时间会包含帧等待的误差。解决办法是把计时放在flip()之后立即进行规划或者干脆把规划放到独立的计算线程里。我的实现选择了乱序执行——先处理事件再规划再渲染这样规划耗时和渲染帧率互不干扰测得的数据也更接近真实决策延迟。5.3 多组实验数据迭代次数、延迟与路径质量的平衡我在固定场景下起点、目标点、障碍物布局一致跑了多组实验改变RRT*的最大迭代次数记录平均决策延迟和路径长度。数据如下最大迭代次数平均规划耗时 (ms)路径长度 (像素)成功率5008.6142073%100016.2121088%200032.4108094%400066.8104096%8000138.5103197%从这张表可以明显看出边际收益递减的规律。2000次迭代之后成功率趋于饱和路径长度改善有限但耗时却在翻倍增长。所以在我的规划器里默认迭代次数设置在2000到3000之间正好把决策延迟压在20到40毫秒区间——这个量级恰好和热搜词提到的32.8毫秒处于同一水平说明我们在Pygame里的简化模型仍然能体现出真实系统决策延迟的典型量级。不过还要提醒一句Pygame的2D简化环境和真实自动驾驶系统完全不同这里的32毫秒并不代表你的算法在真车上也能这么跑。它的价值是用于横向对比和调参——同样的场景下谁的规划算法能在更短时间内找到更短路径谁就更有潜力。6. 我踩过的坑和调参经验6.1 Pygame坐标系的y轴陷阱第一个坑几乎每个从数学坐标系转过来的人都会踩Pygame窗口的坐标系是y轴向下为正也就是说屏幕左上角是(0,0)向右是x正方向向下是y正方向。而我们在数学里习惯的坐标系是y轴向上为正。这就导致了一个很微妙的问题——计算角度时正角度的方向恰好反了过来。举个例子车辆朝向角为45度的时候在数学坐标系里它应该朝右上方移动但在Pygame坐标系里按同样的公式计算它会朝右下方移动。解决这个问题有两个思路一是把所有角度计算统一取反二是干脆在内部逻辑里使用数学坐标系只在渲染的时候做坐标变换。我选择了后者——规划算法的代码完全不用Pygame的坐标体系渲染时调用一个to_screen()函数做翻转。这样即便将来把规划算法移植到别的环境坐标问题也不会在那里等着我再踩一次。6.2 碰撞检测的性能问题逐点检测还是mask原来做一个简陋版本时我用过Pygame的pygame.mask.Mask做像素级碰撞检测思路是把障碍物渲染成Surface再生成Mask然后和车辆Mask做重叠检测。这在障碍物很少、物体很小的时候问题不大但一旦障碍物多了逐像素的Mask运算会非常消耗CPU导致规划时卡成PPT。后来我把碰撞检测完全改成几何计算上面4.2节已经写了核心思路。纯几何运算的耗时是大头在函数调用和浮点运算速度比Mask快一到两个数量级。在2000次迭代、每轮做几十次碰撞检测的情况下整体规划的耗时能稳定控制在30毫秒以内而用Mask的时候轻松飙到几百毫秒。还有一个小优化值得分享碰撞检测函数里先用快速排斥判断粗筛——如果路径段的包围盒和障碍物的包围盒不相交直接跳过精确计算。这个粗筛能挡掉大部分不相干障碍物实际编码时让整体速度提升了大约15%。6.3 RRT*随机性带来的抖动问题RRT*是随机算法同样的场景每次规划出来的路径都不会完全一样这在某些情况下会造成车辆行驶路径来回抖动。最明显的是车辆快接近目标点时每次重规划产生的最后一段路径都有细微不同车辆会像犹豫症一样左右摇摆。我解决这个问题用了两个技巧。第一个是给每次规划传入上一轮规划的路径作为参考在新一轮规划靠近起点的区域把上一轮的路径节点粘回到树上作为种子节点。这样路径起点附近的走向基本保持一致只在新感知到的区域才做出变化。第二个是在跟踪控制层加了一个路径缓冲——只有当新路径和当前路径的终点偏移超过一定阈值时才切换否则继续走旧路径。这两个技巧结合起来车辆行驶的平稳度提升非常明显直观感受就像从一个新手司机变成了稳重的老司机。6.4 参数调优的心得表最后整理一份我在调参过程中沉淀下来的参数心得表希望能帮读者少走弯路参数影响推荐初始值调参心得扩展步长 step_size步长越大树扩展越快但路径越粗越小则路径越精细20-40像素如果场景中存在狭窄通道步长要小于通道宽度的一半否则可能永远找不到穿过通道的路径最大迭代次数决定路径质量和决策延迟的上限2000-3000观察耗时曲线找到耗时开始陡增但路径长度几乎不变的拐点目标偏置概率值越大树越倾向直奔目标但容易被复杂障碍困住0.2障碍物简单时调到0.3提速复杂场景下降低到0.1多靠随机探索绕障重连影响半径半径越大路径质量越高但耗时会增加3倍步长兼顾质量和速度的默认选择不必频繁改动感知视野半径决定车辆能看多远直接影响规划的前瞻距离300像素这个值对应真实系统中的传感器感知距离太短会导致走到死角才发现太长则弱化无地图特性纯跟踪前瞻距离前瞻距离越大路径跟踪越平稳但弯道切角越明显60-80像素提前看远一点会让车辆轨迹更顺滑但在急转弯处容易抄近路、压到障碍物边缘调参这件事我的体会是每个参数都要围绕场景的本质特征来找基准。比如步长和通道宽度的关系如果场景里的通道很窄步长大就永远穿不过去又比如感知视野半径它与车速有一个刹车距离反应时间的匹配逻辑——车速越快感知视野应该越大否则车辆看到障碍物时已经来不及刹车。这些经验在真实自动驾驶系统中同样成立Pygame只不过用最简单的方式把规律演示了出来。这个项目做下来最大的收获不是代码本身而是建立了一套场景-算法-指标三者联动的心智模型你随手在屏幕上摆一个场景算法跑完延迟和路径质量立刻反馈成数字马上就能判断这个算法在这个场景下能不能用。有个小建议送给想继续深挖的朋友——可以考虑把规划器接入动态障碍物系统每一帧让一部分障碍物缓慢移动观察RRT*的滚动重规划能不能跟得上变化顺便试试在路径平滑这一步加入Dubins曲线或者贝塞尔曲线把车辆的转向约束考虑进去那时候的规划器就已经很接近真实自动驾驶系统中的局部规划模块了。哪一天你不再关心它在Pygame里跑多快而是真正把同一份规划代码移植到机器人上去这个项目才算是功成身退。
返回列表