资讯动态

无人驾驶横向控制:Pure Pursuit与Stanley算法深度解析

发布时间:2026/10/5 1:15:20 来源:尧图企业网站定制
1. 横向控制在无人驾驶里到底解决什么问题我先说一个背景省的后面聊算法时大家脑补不出来画面。无人驾驶系统的软件架构通常被切成分层结构感知、融合、预测、决策规划、控制。前面几层往往最受关注比如激光雷达点云、目标检测、车道线识别、行为预测那套热闹且视觉冲击力强。但真正到了车辆执行层面就是个把“脑子里想好的路径”变成“前轮实际打过去的角度”的问题这一层叫车辆控制又分横向控制和纵向控制。纵向控制管油门和刹车解决的是“什么时候加速、什么时候减速、最终稳在目标车速上”。横向控制管方向盘解决的是“这条期望路径车怎么跟踪住、不偏离、不振荡”。做控制的朋友应该能体会规划层给出再漂亮的轨迹控制层跟不住或者跟出了蛇形整个自动驾驶表现得就像个新手司机体验非常差。更严重的是在狭窄工况、高速避障、倒车入库这些场景里横向跟踪误差一上去直接就是剐蹭甚至碰撞的风险。所以横向控制是无人驾驶车从L2辅助驾驶一路走到L4、L5绕不开的核心模块。今天聊的是横向控制里两个最经典、也是目前落地工程里最常见的几何类跟踪算法Pure Pursuit纯跟踪和 Stanley。这两个算法不依赖复杂的车辆动力模型也不要求你提前把整个动力学矩阵建出来它们都以“车辆运动学自行车模型”为底层假设只要知道轴距、当前速度和前轮转角指令就能把车沿路推着走。它们足够简洁、可调参项直观、便于嵌入式部署在无数真实项目和仿真环境里经历了大量验证。这两个算法我后来在实车和仿真里都反复调过。今天的文章我打算从横向控制的误差定义说起把两条算法的几何原理、数学模型、代码实现、参数整定逻辑和常见坑一次性讲透。内容不抬杠、不堆公式但该有的数学推导我也不会省毕竟控制这种事定性描述只能帮你理解八成剩下两成必须在式子里才能看着不掉坑。适合入门无人驾驶控制方向的工程师、准备做毕设或课题的硕博生以及想把横向控制模块整合进自己的无人车平台、或者在Simulink/Carla/ROS里做仿真实验的开发者。2. 先搞明白横向控制的目标和误差定义2.1 横向控制的输入输出长什么样在实际的控制器实现里横向控制的输入一般有这么几组参考路径通常来自规划模块是一条带有姿态信息的轨迹点序列每个点至少包含x、y坐标和航向角。当前车辆状态来自定位与惯性导航融合后的结果包括车辆后轴中心位置、横摆角、横摆角速度、纵向车速等。车辆参数比如轴距、转向机构传动比等。输出则是一个方向盘的转角指令或者下发给转向执行机构的弧度/角度值。这里有个非常关键的概念横向控制跟踪的参考路径到底以哪个点为基准。不同的算法基准不一样这直接决定公式的形式和控制效果。Pure Pursuit和Stanley虽然都基于自行车模型但Pure Pursuit本质上是基于“车辆后轴中心点”的跟踪而Stanley则是基于“车辆前轴中心点”的跟踪。这一点很多人学的时候容易忽略等到实车调试才发现同样的路径下两种算法的误差表现差异很大很多时候就是吃了这种基准理解的亏。2.2 横向跟踪误差分哪些在深入算法之前把误差的类型捋清楚非常必要。横向控制领域里有三种最常见的误差横向位置误差即车辆当前位置到参考路径上最近点的垂直距离通常记为e_lat或者cross_track_error这个误差是控制的核心目标之一。航向误差即车辆当前航向和参考路径上最近点期望航向之间的差值记为e_heading。曲率误差即参考路径在当前点的曲率和车辆实际行驶曲率之间的偏差可以理解成车辆是否“弯得够快”、是否“转的过猛”。三种误差里横向位置误差是控制主目标航向误差是保证车辆姿态正确的重要指标曲率误差其实由规划路径的连续性和前两个误差的控制效果共同决定。Pure Pursuit算法能直接压制横向位置误差但对于路径曲率突变的情况响应有限Stanley算法则同时对横向位置误差和航向误差施加反馈所以在急弯和切线段过渡的地方表现得更有张力。在工程上目标跟踪质量通常用横向误差的均值、最大绝对值和均方根误差来衡量。一个调校良好的横向控制器在低速园区场景下横向误差均值应该在5厘米以内高速快速路段也不应该超过25~30厘米。如果超过这个范围路径跟踪质量就会出现肉眼可感知的偏移。3. Pure Pursuit 纯跟踪算法拆解3.1 几何直觉就像追着一个前方目标点走Pure Pursuit的核心思想用一句话就能说清楚在当前车辆后轴中心位置沿着前方一定距离处选取参考路径上的一个目标点然后控制车辆前轮转角让车辆恰好沿着一小段圆弧“追”到这个目标点。这个思路像极了人走路时的预瞄行为。你往前走路的时候眼睛往往会盯着前方两三米的路径上某个点然后自然调整脚步方向让身体走出平滑的轨迹而不是低头一步步盯着脚下走。预瞄距离越长路线越平滑但容易抄近路预瞄距离太短则动作迅速但容易抖动。Pure Pursuit的前视距离就是这个算法里最核心、最需要调参的量。由此还带出了一个关键特性Pure Pursuit天然带有“前瞻性”。因为它追踪的是前方路径点而不是当前位置最近点所以即使参考路径上有一个小小的尖角或者突变只要预瞄点还没落到那个突变位置车辆的转角就不太会被扰动。这也是为什么在曲率比较连续的路径上Pure Pursuit开起来特别顺滑。3.2 数学模型推导下面把Pure Pursuit的数学框架推导一遍。为了避免公式符号混乱先约定几个变量ld预瞄点到车辆后轴中心的直线距离即前视距离。α车辆当前航向与预瞄点方向之间的夹角。δ前轮转角。L车辆轴距。R车辆转向圆弧的半径。控制目标是让车辆沿圆弧到达预瞄点。由平面几何关系车辆后轴中心、预瞄点与圆弧圆心构成等腰三角形其中腰的长度是R。结合正弦定理可以得到ld / sin(2α) R / sin(π/2 - α)化简这个式子。注意sin(2α) 2 sinα cosα而sin(π/2 - α) cosα所以ld / (2 sinα cosα) R / cosα两边同时约去一个cosα前提是α不为90度正常预瞄场景都不为90度得到ld / (2 sinα) R于是圆弧半径R ld / (2 sinα)。接下来由自行车模型的转向几何关系前轮转角δ与转弯半径R之间的关系是δ arctan(L / R)把上面的R替换进去最终得到纯跟踪控制律δ arctan(2 L sinα / ld)这就是Pure Pursuit的核心公式。注意这里面的α虽然叫航向角误差但实际上它隐含了预瞄点在车辆前方这一条件所以这也意味着假如预瞄点跑到车辆后方去了这个式子就不再适用需要在工程上做特殊处理防止奇异。这里值得多说一句从纯运动学的角度看只要α不为0且ld不为0前轮转角指令就可以让车辆沿圆弧收敛到预瞄点。但这个“收敛”是开环意义上的收敛它假设车辆严格按自行车模型运动并且不滑动。考虑到真实车辆的轮胎侧偏、路面附着、转向执行延迟等因素单靠这个几何关系其实无法保证系统稳定工程上还必须配合足够的控制频率和预测校正机制。3.3 前视距离怎么算最核心的经验公式前面说了Pure Pursuit里前视距离ld直接决定跟踪质量。ld太小车辆对路径变化太敏感容易出现蛇形摇摆ld太大车辆会“抄近路”转弯时明显切弯误差在弯道内会被放大。工程上最常用的处理方式是把ld做成纵向车速的线性函数ld k * v ld0这里的k称为预瞄时间或时间增益单位是秒ld0是基础预瞄距离单位是米。常见标定范围低速场景下k在1.0到2.0秒之间ld0在1.0到3.0米之间高速场景需要减小k值避免振荡。我自己实际踩过的经验是在5米长的轴距测试车上园区低速5~20km/h时候取k1.6、ld02.0效果不错但到了高速公路工况就必须降到k0.8、ld01.0附近否则车辆在换道曲线上会出现明显的反向回摆。还要留意一个问题预瞄点在参考路径上的选取到底是等间距选取还是按弧长等距选取。如果参考路径点的间距不均匀直接按最小欧氏距离找预瞄点会导致预瞄点跳动从而让转角指令出现毛刺。因此工程上通常先把参考路径点按固定弧长重采样一般采样间隔取0.1米到0.5米保证相邻两个路径点的距离远小于前视距离。这里给一个我用Python写的重采样参考代码也顺便把预瞄点搜索逻辑一起放出来。这个代码不是最优实现但足够直观、容易改成C。import numpy as np from scipy.interpolate import splprep, splev def resample_path(path_xy, interval0.2): # path_xy: (N, 2) 数组包含x,y坐标 x path_xy[:, 0] y path_xy[:, 1] # 用样条插值重采样保证等间距 tck, u splprep([x, y], s0) u_new np.linspace(0, 1, 10000) x_new, y_new splev(u_new, tck) # 计算累计弧长 diff np.diff(np.vstack([x_new, y_new]), axis0) seg_len np.hypot(diff[:, 0], diff[:, 1]) cum_len np.cumsum(seg_len) total_len cum_len[-1] n_points int(np.ceil(total_len / interval)) resampled np.zeros((n_points 1, 2)) resampled[0] [x_new[0], y_new[0]] target_dist interval j 0 for i in range(1, n_points 1): while cum_len[j] target_dist and j len(cum_len) - 1: j 1 # 线性插值 if j 0: resampled[i] [x_new[0], y_new[0]] else: excess target_dist - cum_len[j-1] ratio excess / (cum_len[j] - cum_len[j-1]) resampled[i] [x_new[j-1] ratio * (x_new[j] - x_new[j-1]), y_new[j-1] ratio * (y_new[j] - y_new[j-1])] target_dist interval return resampled重采样之后预瞄点的搜索只需要在路径上找第一个距离大于当前车辆的ld的点即可。考虑到路径点数量可能很大用线性搜索在实时系统里可能压力稍大更快的做法是维护一个“上一帧最近点索引”然后从那个索引附近开始向后搜索避免每次全路径扫描。def find_lookahead_point(current_pose, path_xy, ld, last_idx0): # current_pose: (x, y) 当前车辆后轴中心 x, y current_pose n len(path_xy) # 从上次索引开始搜索 for i in range(last_idx, n): dist np.hypot(path_xy[i, 0] - x, path_xy[i, 1] - y) if dist ld: return path_xy[i], i # 如果没找到说明离终点太近返回最后一个点 return path_xy[-1], n - 13.4 纯跟踪的代码实现与仿真直接给一个完整的控制器类实现包含了上文提到的核心公式和预瞄距离车速关联逻辑。为了容易测试我用的是Python实际项目里改成C非常容易也就是一个类的事。import math class PurePursuitController: def __init__(self, wheelbase2.5, k1.6, ld02.0, max_steer0.6): self.L wheelbase self.k k self.ld0 ld0 self.max_steer max_steer # 单位弧度 def get_lookahead_distance(self, velocity): # velocity 单位 m/s ld self.k * velocity self.ld0 return ld def compute_steer_cmd(self, current_pose, current_yaw, velocity, target_point): # current_pose: (x, y) 后轴中心坐标 x, y current_pose dx target_point[0] - x dy target_point[1] - y # 目标点在车体坐标系下的方向角 alpha math.atan2(dy, dx) - current_yaw # 把alpha归一化到[-pi, pi] alpha math.atan2(math.sin(alpha), math.cos(alpha)) ld self.get_lookahead_distance(velocity) if ld 1e-6: return 0.0 steer math.atan2(2 * self.L * math.sin(alpha), ld) # 限幅 steer max(-self.max_steer, min(self.max_steer, steer)) return steer这个实现里有个细节atan2和角度归一化。工程上很容易犯的错误是直接用dy / dx求角度差然后接着叠加上车辆航向角做差结果角度在±π边界处跳变转角指令瞬间跳变车就抖了。正确做法是先atan2(dy, dx)得到目标点方向角再减current_yaw然后用atan2(sin(α), cos(α))归一化到[-π, π]。这个细节对后续的横向控制稳定性影响很大。3.5 参数标定心得我在多款不同轴距的试验车辆上调过Pure Pursuit参数发现几个规律第一前视距离的上下限一定要钳制住。哪怕车速公式已经给了一个值实际执行时仍然建议增加一个最小值和最大值限制。比如最小ld不能小于4米太小了在石子路、起伏路面上响应容易过于激进最大ld不要超过30米太远了转弯时会严重提前转向弯道里内切严重。这个钳制范围跟车辆轴距强相关我一般按轴距的3到6倍来设定初值。第二方向盘的执行延迟会直接影响k值的选取。转向执行器响应慢的车如果k值取得太小控制器以为已经转向、实际上前轮还没打到位就会出现明显的相位滞后表现就是弯道里先外飘再拉回。遇到这种情况可以用纯延迟模型做一个Smith预估器或者直接把k加大一点给预瞄多留一些时间。调整的时候建议用仿真先测出来执行器时间常数再结合实际路试效果综合定。第三Pure Pursuit对路径点的密度不敏感这点是它的一个优点。因为预瞄点搜索只要最近点在前方路径点的疏密只影响预瞄点位置精度不直接进入转角公式。但是到路径终点时由于找不到足够远距离的预瞄点控制器会出现“目标点索引回退”的情况导致转角突变。解决办法是终点前做一个减速或者停车目标点的切换比如把最终目标点锁定在路径末端不动并让速度逐渐趋零。4. Stanley算法拆解4.1 和Pure Pursuit本质上的区别Stanley算法由斯坦福大学的Hoffmann等人提出最早是用在斯坦福自动驾驶赛车Stanley上的这也是它名字的由来。它在概念上和Pure Pursuit最大的不同是它不再通过一个前视目标点来生成圆弧轨迹而是直接把前轴中心位置投影到参考路径上然后用两个误差——航向误差和横向位置误差——构造一个非线性反馈控制律。把两种算法放到一个画面对比Pure Pursuit像是个“只管远方目标”的追踪者Stanley更像是个“盯着当前偏差”的修正者。Pure Pursuit在弯道中因为持续跟踪前方点转弯半径天然比较平滑Stanley则因为直接对横向误差做比例放大横向偏差收敛要快得多但控制量也更容易振荡。所以业界有个经验路径较为平滑、速度较高时用Pure Pursuit更舒服路径弯道密集、需要精确跟踪时Stanley往往表现更硬核。4.2 控制律推导Stanley算法的控制律由两项叠加而成δ ψ_e arctan(k * e / v)其中ψ_e 是航向误差定义为参考路径最近点的切向航向与车辆当前航向之差。e 是横向位置误差定义为前轴中心到参考路径最近点的垂直距离通常规定车辆在参考路径左侧时为正。k 是可调增益反应横向误差收敛的速率。v 是纵向车速。先说第一项ψ_e。它的作用是让车辆朝向与路径方向一致抵消航向偏差。如果车辆方向正确、只是平行偏移了一段距离那么ψ_e为零此时转向完全由第二项控制。这比Pure Pursuit要更“诚实”Pure Pursuit没有直接使用路径切向航向的信息只用预瞄点的方向角所以它在平行偏移状态下仍然会先转向预瞄点产生一段弧线逼近而Stanley则会直接线性地朝路径靠拢轨迹更接近“拉直线修正”而不是“弧线追踪”。第二项里有个关键行为特征横向误差e越大转角越接近±90度的极限值意味着车辆会以近乎垂直的方向切回路径随着误差变小转角收敛到零。这个非线性项本质上是一个带饱和特性的比例控制器饱和点由k的取值决定。注意到分母上有个车速v这一点非常有意思。车速越低同一横向误差产生的转角越大。这保证了低速时修正动作足够迅猛而高速时不会因为过大的横向误差导致转角饱和、车辆姿态失控。但这也带来一个不好的副作用车速趋近零时第二项趋近±π/2转角指令直接饱和到极限这在泊车和拥堵跟车场景中必须特别小心。通常工程上需要把低速段做保护比如v小于0.5m/s时直接用固定角度或者切换到其他算法。4.3 代码实现与仿真直接给Stanley算法的Python实现。这里我选择前轴中心作为跟踪基准点所以状态输入除了后轴中心的坐标还要根据当前航向角和轴距推算前轴中心位置。import math class StanleyController: def __init__(self, wheelbase2.5, k1.0, max_steer0.6): self.L wheelbase self.k k self.max_steer max_steer def compute_steer_cmd(self, current_pose, current_yaw, velocity, ref_point, ref_yaw): # current_pose: 后轴中心坐标 (x, y) # ref_point: 参考路径最近点坐标 (x, y) # ref_yaw: 参考路径最近点的切向航向角 x, y current_pose fx x self.L * math.cos(current_yaw) fy y self.L * math.sin(current_yaw) # 横向误差前轴中心到参考路径最近点的距离带符号 # 通过向量叉积判断正负 dx fx - ref_point[0] dy fy - ref_point[1] # 参考路径切向方向 tx math.cos(ref_yaw) ty math.sin(ref_yaw) # 叉积: tx*dy - ty*dx大于0表示车辆在路径左侧 cross tx * dy - ty * dx e cross # 横向误差单位米 # 航向误差 psi_e ref_yaw - current_yaw psi_e math.atan2(math.sin(psi_e), math.cos(psi_e)) # 非线性反馈项 v max(velocity, 0.1) # 防止除零 delta2 math.atan2(self.k * e, v) steer psi_e delta2 steer max(-self.max_steer, min(self.max_steer, steer)) return steer这里最容易被忽略的一个点是横向误差e的正负定义。很多初学者直接用最近点到前轴中心的欧氏距离来当作e结果发现车在路径两侧时控制效果完全相同完全无法收敛实际上就是因为符号丢失了。一定要通过向量叉积来判断车辆在参考路径的哪一侧这个符号信息决定了转角的修正方向。4.4 最近点搜索与航向插值Stanley算法必须找到“参考路径上离前轴中心最近的点”这就需要做最近点搜索。跟Pure Pursuit的预瞄点搜索不同最近点搜索应该是全局搜索或者局部维护一个固定窗口。因为车辆在急弯处可能暂时偏离参考路径很远如果搜索窗口过小可能找不到真正的最近点导致误差计算不连续。实际工程里一个高效的方案是维护上一帧的最近点索引然后从附近向两侧各扩张若干点做搜索每次扩张范围取决于路径点密度和车速。路径点密度为0.2米时我通常向两侧各搜索50到100个点基本覆盖20米范围足够普通工况下的最近点搜索。最近点找出来之后参考路径在该点的切向航向可以用相邻路径点做差分或者直接用当前点与下一个点连线方向。相邻点间距越小切向航向越准确。前面提到的重采样操作在Stanley算法里同样很重要因为如果路径点间距不均匀最近点对应的切向航向会出现类似“多边形折线”的跳变导致ψ_e项抖动。5. 两种算法的横向控制性能对比与选型依据5.1 做一个简单的车辆运动学仿真对比为了直观看清两个算法的差异我写了一个小仿真脚本模拟车辆以自行车模型行驶并跟踪一条包括直线、S弯和U形弯的参考路径。初始位置故意给了一个0.5米的横向偏移观察横向误差的收敛速度。仿真里我用的参数轴距2.5米车速恒定5m/sPure Pursuit的k1.6、ld02.0Stanley的k1.0。每条曲线都取横向误差绝对值。用这段代码可以很快地扫出一批曲线def simulate_path_tracking(path_xy, velocity, controller, dt0.05, steps5000, start_offset0.5): # 初始状态从起点前方偏移start_offset米开始 x path_xy[0, 0] start_offset y path_xy[0, 1] yaw math.atan2(path_xy[1,1]-path_xy[0,1], path_xy[1,0]-path_xy[0,0]) # ... 省略绘图细节只提核心循环 errors [] for _ in range(steps): # 找最近点/预瞄点 # 计算控制量 # 用自行车模型运动学递推状态 pass return errors光看仿真曲线的形态能总结出几条直观规律Stanley的横向误差衰减速度快了大约2~3倍在初始大偏移时尤其明显车辆会很快切入参考路径。Pure Pursuit在线路段上的跟踪更平滑横向误差曲线几乎没有高频振荡但初始误差的大幅收敛需要更长时间因为它是弧线逼近。在U形弯道中Pure Pursuit会明显切弯最大横向误差可以达到0.3米左右而Stanley则可以把误差控制在0.12米以内。在S弯连续变曲率路径上Pure Pursuit的预瞄特性减少了转向频率转向指令曲线更平滑Stanley则需要更频繁的转向修正执行器负担更高。这些差异在实际车辆上会进一步放大。因为真实车辆存在转向执行器延迟和轮胎侧偏特性Stanley那种“高增益硬反馈”更容易激发极限振荡所以做高速或者大型车辆时我一般更偏向用Pure Pursuit做基础跟踪再用Stanley做误差修正的双环结构。5.2 算法适用场景速查表场景推荐算法理由高速公路、城市快速路Pure Pursuit路径曲率小、连续预瞄特性让转向平滑高速侧向加速度小执行器友好园区低速、封闭场地Stanley低速下横向修正能力更强对路径边界的逼近精度高适合狭窄空间弯道密集的山路混合或Stanley增强纯跟踪切弯严重Stanley低速修正更直接但要注意增益别太大高速换道、避障Pure Pursuit增大前视换道轨迹曲率不大平滑度为第一优先级预瞄距离大更稳泊车、倒车入库自定义算法或MPC两个算法都不适合倒车Stanley低速段还会饱和泊车建议用几何规划MPC表格里比较关键的一条倒车工况下两个算法都不可直接使用。Pure Pursuit要求预瞄点在行驶方向前方倒车时这个前提不成立Stanley虽然有学者扩展了倒车版本但经典形式同样不适合倒车。有倒车需求的场景还是老实走路径规划MPC模型预测控制或者A* 后轮反馈控制那套方案。5.3 实车调参时的一些差异实车和仿真最大的差异有两个一是转向执行延迟二是车辆的转向传动比线性度。Pure Pursuit对转向延迟相对耐受因为预瞄点的存在转角指令本身带有一定“提前量”。但Stanley对延迟很敏感如果方向盘的执行延迟超过100ms弯道里的横向误差容易变成等幅振荡。遇到这种情况我在工程上通常采用两个处理办法要么增加Stanley的前向补偿在参考路径上取一个前方点做近似而非严格最近点要么降低增益k让修正动作更温和承受一部分稳态误差。转向传动比线性度则影响两个算法的转角指令到实际前轮转角之间的映射精度。如果转向系统在中间位置线性很好、在大角度附近开始出现饱和或非线性那么Stanley那种经常触发大转角的控制律会出现“指令跳变”Pure Pursuit因为控制律偏平滑对大角度工况的容忍度反而更好。因此对于大型工程机械那种大转角、多节铰接的转向系统很多人会优先考虑Pure Pursuit做底层基础控制再用额外反馈做误差修正。6. 工程机械无人驾驶场景下的特殊问题6.1 工程机械和乘用车在横向控制上的区别最近“工程机械无人驾驶”这个概念越来越热很多读者可能以为学会乘用车横向控制就能平移到挖掘机、装载机、矿卡上去实际上差异挺大的。工程机械有几个显著特点轴距长整车尺寸大部分矿卡的轴距超过7米前视距离即使按线性公式取值也很大Pure Pursuit的切弯现象会被几何放大。车速低装载机、挖掘机的作业速度常常在5km/h以下Stanley算法里的e/v项会膨胀到饱和状态必须做速度下限保护。转向方式特殊压路机、装载机很多是铰接式转向也就是前车架和后车架之间通过铰接油缸推拉形成折角而不是传统前轮转向。这导致自行车模型的假设需要修改等效“轴距”为铰接点到前/后车桥的距离转角指令变成了铰接角指令。6.2 铰接式工程机械怎么改造这两个算法先理清铰接式运动学的关键点。以装载机为例它的前车架和后车架通过一个竖直铰接销连接转向时前后车架绕铰接点相对转动。等效转向角就是前后车架中心线之间的夹角称为铰接角。这个铰接角跟普通前轮转角的关系可以类比前轮转角是前轮与车架中心线的夹角铰接角是前车架与后车架中心线的夹角。因此只要把自行车模型里的前轮转角δ替换成铰接角再把“轴距”改写成铰接点到前桥和后桥的等效距离两个算法的核心公式依然可用。但有一个非常重要的差异Pure Pursuit的几何推导是基于后轴中心的而铰接式车辆的“后轴中心”仍然可以定义在后车架后轴上这一点没变可是前轴中心在铰接转向时已经不再沿期望圆弧运动因为前车架会相对后车架偏转。所以在铰接式车辆上直接套用经典Stanley算法效果会差一些因为前轴中心轨迹受到铰接角变化的影响e的符号判断容易出现错误。工程上的折中方案是把Stanley的基准点从“前轴中心”改到“铰接点”然后用铰接角作为控制量。这样车辆等效模型变成后车架跟随铰接点铰接点跟踪参考路径前车架随动。实测下来这种“铰接点跟踪”的Stanley变体在低速装载机自动铲装作业中能保持5~10厘米的跟踪精度配合激光雷达停障和位姿调整环节已经能完成许多重复性作业。6.3 低速大负载场景下必须做的工程修整工程机械作业过程中还有个特殊性负载变化巨大且伴随重心的明显移动。装载机铲斗满载和空载时整车惯性参数差异非常大运动学类算法对此天然不敏感这也是为什么在工程机械低速场景里运动学控制算法仍然能撑起一片天。但如果要让车在复杂地面保持稳定还必须叠加以下工程修整首先是横向误差的滤波。工程机械作业时车架振动、颠簸远比乘用车严重横向位置误差信号如果直接进控制器高频噪声会被放大成方向盘或铰接油缸的抖动。一般需要对误差信号做一阶低通滤波或中值滤波截止频率设置在1到3Hz是比较合理的起点。其次是速率限制。执行器顶层通常有一个转角速率限制比如铰接式转向系统的油缸流量决定了铰接角的角速度上限。控制算法计算出的转角指令变化如果超过执行器最大速率就必须做限速处理否则会出现指令超前于实际执行的问题闭环上表现为持续的超调性振荡。这个限速可以用一阶惯性环节或者简单增量限制实现。最后还需要考虑地形不平导致的参考路径坐标系问题。路径规划通常是在大地坐标系里完成的但工程机械在坑洼田地中作业时车身俯仰和侧倾角度很大定位系统给出的数据如果不能正确转换到地面平面坐标系上横向误差e里会混入坡度引起的伪误差。很多团队在这块选择用IMURTK的融合定位把车体姿态对位置做补偿尽可能消除地形影响。7. 实操阶段常见的坑和排查技巧7.1 车辆跑蛇形到底是谁的问题横向控制项目里最常见的现象就是“蛇形行驶”车在直道上左右晃看着像喝了酒。遇到这种情况先别急着改算法按顺序排查先看误差来源。打开日志看看横向误差曲线是不是一个有规律的振荡。如果是正弦状且频率比较高大概率是前视距离或增益设置过小车辆反应过度活跃如果振荡频率低、周期长大概率是预瞄距离或增益过大导致车辆处于欠阻尼状态。我自己的经验是先用仿真扫一遍不同参数下的误差曲线把目光集中在振荡频率上基本能快速定位问题的方向。接着看执行器实际转角。很多团队只在仿真里验证算法不检查实车上的转向执行跟随性能。方向盘指令和实际转角之间往往有100~200ms延迟和一个稳态误差。如果执行器的跟随误差超过5%控制算法调得再精细也白搭。一定要先在空载工况下做一次转向执行器的阶跃响应测试把延迟时间、稳态误差、最大速率全部测出来再决定控制参数。再看定位数据质量。横向控制对定位质量极其敏感。RTK信号在没有遮挡的地方定位精度能到2厘米一旦到了高架桥下或者树荫里可能存在多路径效应、跳变点甚至定位丢失。定位跳变会在误差信号里引入尖峰直接被控制律放大成方向盘猛打一下。处理办法包括定位质量检查、跳变剔除、多传感器融合定位等。7.2 弯道出口外飘怎么解决弯道出口外飘是Pure Pursuit的高频问题。原因是弯道内车辆处于持续转向状态但当路径点开始向直线过渡时预瞄点还在弯道内部转角指令仍然带着一个往弯内的角度等到预瞄点进入直线段车辆已经积累了过大的侧向速度转弯半径一下拉不回来于是向外飘。表现为出弯后短时间横摆角速度过大、横向误差骤增。解决方向有几个适当缩小前视距离让预瞄点更快进入直线段但这里要小心诱发蛇形。在弯道出口附近人为给路径增加曲率平滑过渡让参考路径本身不存在突变。增加一个航向误差阻尼项也就是在Pure Pursuit控制律后面并联一个比例于航向误差的修正角度。这也是我在实际中最常用的简单增强效果立竿见影。最后一种做法的代码其实就是steer pure_pursuit_steer k_yaw * yaw_error这个k_yaw取值不能太大一般0.2~0.4之间太大了会把Pure Pursuit的预瞄平滑效果破坏掉。这个改造虽然不再是严格的Pure Pursuit但工程上很多人都在用这里讲清楚缘由希望能帮大家少走弯路。7.3 Stanley算法在起点处疯狂打方向怎么处理Stanley算法在起点处如果车辆初始横向误差很大转角指令很容易饱和到极限值车辆会对着参考路径“猛扎过去”前期轨迹非常激进而且还可能因为大转角导致的C.G.重心横向移动带来额外的方向扰动。这在自动驾驶最需要平顺起步的阶段非常不友好。一个经验做法是在误差较大时限制最大转角增量而不是直接限制最大转角值。也就是每帧转角指令的变化量不超过某个阈值。这样即使Stanley算法下达了一个极限转角命令执行器也只能以受限速率逼近目标车辆在起步时就会以一个相对平滑的弧线收敛到路径上而不是画一个尖锐的急转弯。另一个做法是给Stanley的增益k加一个随车速变化的调度表。低速起步时k取小一些让修正更柔和车跑起来以后k再逐步加大到正常值。这个调度在标定表里维护起来也很简单而且对整车操稳性的改善非常明显。8. 两种算法之外的一些扩展思考写到这里其实想多说一句Pure Pursuit和Stanley并不总是什么最优控制策略很多项目做到后期会转向MPC或者LQR这类基于模型的控制器。但作为运动学阶段的基石这两个算法依然在大量产品里扮演基础角色而且理解它们的几何直觉对后续学习更复杂的控制策略非常有帮助。在纯几何算法之上经常能看到三种增强方向一是把它们与动力学结合利用PID或LQR对误差做二次调节形成串级控制结构二是把它们与SLAM/路径规划打通利用前视偏差信息实时调整规划路径的参数形成规划控制联合优化三是把纯跟踪中的预瞄距离做成动态可变——比如根据参考路径的曲率预测自适应调整前视距离。第三个方向上我试验过一种思路在转弯前提前增大前视距离保证入弯平滑在弯心处减小前视距离提高跟踪精度出弯时再逐步恢复。实测效果比固定参数有显著提升代价只是多了一个曲率前馈模块代码量不大。工程项目的价值往往就藏在这类“小改动”里。两个算法本身不复杂复杂的是结合具体车型、场景、执行器特性后的调校和组合。很多人以为控制算法的终点是最小化某个误差指标但实际做下来你需要的往往是让车辆在安全性、舒适性、准确性之间找到可接受的平衡。这个平衡没有标准答案它高度依赖场景。这也是为什么我在文中反复强调要从误差定义、基准点选择、执行器特性这些看似底层的地方抓起而不是拿到一个公式就盲目上参数试跑。底层的东西搞清楚了参数怎么调、算法怎么改、出了问题朝哪个方向排查思路自然就顺了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑