资讯动态

Stanley算法+CarSim/Simulink联仿:轨迹跟踪横向控制实战

发布时间:2026/10/20 9:09:24 来源:尧图企业网站定制
做车辆横纵向控制仿真的朋友大概率绕不开轨迹跟踪这个话题。我第一次正式把Stanley算法用在工程级项目里是在某园区低速自动驾驶的前期验证阶段当时团队在Pure Pursuit和Stanley之间来回纠结最后选了Stanley配合CarSim与Simulink联仿做了一套可改路径的快速验证平台效果出奇地稳横向偏差稳态基本压在厘米级。这篇文章我打算把整个项目的完整链路梳理一遍算法原理、CarSim与Simulink联仿的环境搭建、参考路径如何灵活切换、增益参数怎么标定、以及我踩过的几个大坑。无论你是刚接触轨迹跟踪的学生还是已经在联仿但总跑不稳的工程师这篇都应该对你有用。1. 为什么是Stanley三种常用跟踪算法的对比与选型1.1 从追点到循迹几何类算法的两个流派先梳理一下背景。轨迹跟踪算法粗分两类几何类算法和模型类算法。几何类不依赖复杂的车辆动力学模型直接用运动学关系算转角实现简单、实时性好非常适合快速验证。模型类以MPC为代表精度上限高但建模和调参成本也高。几何类里面用得最多的是Pure Pursuit和Stanley。Pure Pursuit的思路是在后轴前方找一个预瞄点然后算一个圆弧让车辆沿着这个弧线追过去本质上是在追逐一个不断更新的虚拟目标点。Stanley则完全不同它是把车辆前轴中心当作控制点同时考虑前轴中心离路径的横向偏差以及车辆航向与路径切线方向的角度偏差计算前轮转角更像老司机看着路沿修正方向的驾驶方式。这两种算法在低速下都能用但一上工况就有区别。Pure Pursuit的预瞄距离不好整预瞄太短容易振荡太长又会在弯道里切内线稳态横向偏差偏大。Stanley没有显式的预瞄距离它盯的是最近点所以稳态偏差通常更小尤其在中低速、曲率不是特别夸张的轨迹上优势非常明显。1.2 核心公式到底在算什么Stanley控制律的核心就是前轮转角公式写成离散仿真里常用的形式delta psi_e atan(k * e / v)psi_e车辆航向与参考路径最近点切线方向的偏差单位弧度带符号e前轴中心到最近路径点的横向偏差路径左侧为正、右侧为负单位米v纵向车速单位m/sk横向偏差增益单位1/s一般取0.5到5之间。公式第一项是航向修正保证车辆朝向和路径方向一致第二项是横向修正横向偏差越大补的转角越大。为什么横向项要除以车速v因为这个算法最早是按车辆以恒定速度行驶这个前提推导的除以v之后偏差修正对应的角速度或者说曲率需求才能与车速解耦。如果不除低速时一个大误差会把转角直接推向饱和车辆会非常夸张地左右甩头除以v之后速度越低转角修正越柔和高速时同样的偏差需要更小的转角也符合驾驶直觉。需要注意Stanley公式里的e是前轴中心的横向偏差不是后轴。这是它和Pure Pursuit最本质的区别。前轴是转向轴误差反映的是车辆当前正在压线的位置反馈更及时后轴中心偏差通常滞后半拍这也是Pure Pursuit在弯道里更容易切内线的原因。1.3 优缺点与适用边界用一张表把三种常见方案摆在一起方便选型时对照算法核心机理优点短板典型适用场景Pure Pursuit预瞄点圆弧跟踪实现简单对路径平滑度不敏感预瞄距离难调弯道稳态偏差大低速巡检、简单换道Stanley最近点航向/横向双反馈稳态精度高收敛快参数少对最近点搜索和路径曲率敏感园区低速、泊车、换道、S弯MPC预测模型滚动优化精度上限最高可加约束计算量大建模调参复杂高速工况、强约束场景我在实际项目里选Stanley是看中它参数少、物理意义清晰。整机只有k一个核心增益标定工作量和MPC完全不是一个量级非常适合做算法快速验证平台的第一版横向控制器。当然如果后面要上高速或者处理极限工况Stanley的轮胎侧偏假设会失效那就得考虑换MPC或者LQR了这是后话。2. 联仿框架搭建CarSim车体模型与Simulink控制器的接口配置写完选型说正事怎么把CarSim和Simulink接起来。这一节我按从零搭一套可复用的联仿平台的步骤讲照着做基本能一次跑通。2.1 CarSim侧准备模型选型与初始工况CarSim是一个高保真车辆动力学仿真软件整车模型里包含了悬架、轮胎、转向、制动等子系统拿来当被控对象比简化运动学模型可信得多。我习惯的配置是这样的车型选B级轿车或类似尺寸模型四轮独立悬架不是专门为了Stanley而是后续还要验证巡航控制车体参数得有一定代表性仿真工况选平地直线起步初始位置放在场地坐标系原点附近初始速度可以设为0也可以直接给目标车速路面摩擦系数设0.85干燥沥青暂时不引入湿滑干扰先把控制调稳。重要的一点CarSim里要先把输出通道配好。联仿时我们需要从CarSim拿四个量车辆X坐标、Y坐标、航向角Yaw、纵向车速Vx。在CarSim的Output页面里勾选对应的变量并把它们导出为Simulink能用的外部信号。这里最容易出问题的是单位CarSim导出的Vx默认可能是km/hYaw是弧度位置是米。单位不统一会让后面的控制器完全跑偏我在第五节会再展开讲。2.2 Simulink侧控制架构横向Stanley纵向PIDSimulink这边的整体架构分两条支路。一条是横向控制读入车辆状态x、y、yaw、vx在MATLAB Function里跑Stanley算法输出前轮转角。一条是纵向控制目标车速与当前车速做误差进PID输出驱动力矩或节气门开度。两条支路的输出最终都送进CarSim S-Function模块作为整车模型的输入。CarSim在Simulink里的接入有两种常见方式方式一用CarSim提供的S-Function模块适合信号数量不多的情况方式二把CarSim生成好的S-Function函数直接挂到Simulink模型里手动连接输入输出接口灵活性更高。实际工程里我推荐方式二因为后面要改路径、加状态观测器接口留得灵活一点省心得多。Simulink里还要注意在MATLAB Function块中引用路径变量。路径点建议放在模型工作区Model Workspace或者Base Workspace不要直接写在函数硬编码里这样切换路径时不用重新打开模型直接在脚本里改变量即可。2.3 信号映射一张表说清楚接哪根线联仿最容易糊涂的就是接口信号。我整理一下常用的映射关系方向CarSim变量名示例Simulink信号单位与说明输出 - 控制器Xopath_current_x车辆X坐标m输出 - 控制器Yopath_current_y车辆Y坐标m输出 - 控制器Yawvehicle_yaw航向角rad输出 - 控制器Vxvehicle_vx纵向车速m/s注意原始可能是km/h控制器 - 输入Steer_L1/Steer_R1front_wheel_angle前轮转角rad控制器 - 输入My_Total_Drivedrive_torque驱动扭矩Nm特别提醒前轮转角这条CarSim里的Steer输入有两类口径一类是方向盘转角一类是前轮转角。Stanley算出的是前轮转角如果CarSim那边要求方向盘转角必须先乘转向传动比通常14到16之间。这个换算关系不对看到的现象就是控制器输出很小车却疯狂转向或者反过来。我自己的做法是在Simulink里定义常量R_steer 15然后delta_wheel delta * R_steer。这样调度脚本里改一个常量就行。2.4 仿真步长与运行顺序统一步长别给变步长联仿里一个不起眼但致命的细节是步长。CarSim的动力学求解默认是固定步长小步长比如0.001秒Simulink如果用的是变步长求解器两者之间的数据交换会出现时间戳错位表现就是控制信号忽大忽小甚至仿真中途发散。解决办法很简单Simulink求解器选固定步长步长和CarSim保持一致先用0.001秒跑稳之后再试0.002秒省时间。运行顺序也有讲究。正确流程是先在CarSim界面里点击Send to Simulink生成并注册S-Function然后在Simulink中打开模型、加载路径数据、点Run。第一次如果报错找不到S-Function大概率是动态库路径没加到MATLAB的路径里手动addpath一下就好。3. 自定义参考路径的两种做法内置路径替换与外部轨迹导入可改路径是这个项目标题里的关键词也是我当时做这个平台的核心诉求。下面两种方案我都试过直接说结论外部轨迹导入更灵活CarSim内置路径适合做最终验证。3.1 方案一CarSim内置道路替换CarSim自带路谱编辑工具可以定义道路中心线坐标点列、车道宽度、附着系数等。你要是想快速验证车辆在固定测试场地上跑一圈直接在CarSim里画路径最省事因为道路几何和车辆定位都在同一坐标系里天然对齐不会出现坐标转换问题。但这个方案有个明显的短板CarSim里的路径是静态的每次改路径都要重新进CarSim界面、重新生成道路文件、重新Send to Simulink非常不利于批量测试。而且CarSim的道路文件对点的密度有限制我试着导入过一条很密的蛇形路径结果CarSim在相邻点之间做了平滑插值曲率被抹掉一些和原始想验证的轨迹对不上。所以我的建议是CarSim内置路径只用在最终验收阶段开发迭代期还是用外部轨迹。3.2 方案二Simulink里维护路径表推荐我的做法是路径数据以数组形式放在工作区Simulink里的MATLAB Function块通过参数引用这套数组。路径格式非常简单path_xN行1列每个路径点的X坐标path_yN行1列每个路径点的Y坐标path_yawN行1列每个路径点的切线航向可以在生成时算好。车辆在每一控制周期拿到当前x、y、yaw后先在路径表里找最近点然后根据最近点的切线方向算出psi_e再算横向偏差e最后代入Stanley公式。切换路径的时候我只需要在脚本里重新执行一个路径生成函数比如生成双移线、圆环、snake路径更新工作区变量Simulink里直接再次Run就行。如果做批量测试套一层for循环每轮改路径、跑仿真、记录结果半小时就能扫完十几条轨迹非常爽。3.3 最近点搜索与航向提取核心代码与效率优化这一段是控制器的核心代码不复杂但很容易写错。我在MATLAB Function块里的Stanley实现大致如下function delta stanley_ctrl(x, y, yaw, vx, path_x, path_y, path_yaw, k) % 最近点搜索线性扫描 d2_min inf; idx 1; for i 1:length(path_x) d2 (x - path_x(i))^2 (y - path_y(i))^2; if d2 d2_min d2_min d2; idx i; end end % 横向偏差向量 e (车辆位置 - 最近点) 在路径法向的投影带符号 dx x - path_x(idx); dy y - path_y(idx); e -sin(path_yaw(idx)) * dx cos(path_yaw(idx)) * dy; % 航向偏差归一化到 [-pi, pi] psi_e path_yaw(idx) - yaw; psi_e atan2(sin(psi_e), cos(psi_e)); % Stanley 控制律vx 下限保护 delta psi_e atan(k * e / max(vx, 0.5)); % 前轮转角限幅 delta max(min(delta, 0.5), -0.5);每次控制周期线性扫描全路径在路径点几千个以内完全够用一个周期顶多几百次循环Simulink跑起来没有压力。如果路径点非常密几万个点线性扫描就会吃掉不少CPU工程上可以改用稀疏粗搜局部精搜先每隔几十个点找一次最近点得到大概位置再在附近的小窗口内重新精确搜索。实测下来可以把搜索耗时降到原来的十分之一左右而且不会漏掉真正的最近点。3.4 生成路径的工具函数双移线、圆环、蛇形为了做到可改路径我在项目里封装了一个路径生成脚本。核心思路是任何路径都用一个函数接口生成function [path_x, path_y, path_yaw] gen_path_double_lane() % 双移线路径常用于模拟换道工况 n 2000; s linspace(0, 150, n); y_ref 3.5 / 2 * (1 - tanh(2 * (s - 60) / 10)); % 平滑过渡 % ... 还可以继续定义 y_ref生成平滑换道 path_x s; path_y y_ref; path_yaw atan2(gradient(path_y), gradient(path_x));双移线是最常用的验证路径因为它覆盖了直线段和连续曲率变化段能同时考验稳态精度和动态响应。圆环路径用于测试稳态转向能力蛇形路径用于测试连续变曲率下的稳定性。每个生成函数的输出都是三个等长数组Simulink侧接口完全一致切换路径零成本。这里要特别强调一点路径生成后最好做一次平滑和重采样。如果直接用原始插值点可能会出现切线方向剧烈跳变导致psi_e瞬间变化很大控制器跟着抖。我的做法是生成后用smoothdata或者自己写一个滑动平均把path_yaw平滑一遍周期性地抽样保证相邻路径点之间的距离不超过0.2米。路径点太稀比如间距一米以上会让最近点偏差在拐弯处产生台阶感横摆角估算也不准这个坑我在实际联仿里踩过后面会再提。4. 增益参数标定与不同车速下的表现算法和联仿环境就绪接下来是最花时间的环节参数标定。Stanley唯一的横向增益k看似简单实际上有很明显的速度依赖性。4.1 单个增益k为什么也要仔细调k的物理意义是横向偏差修正的权重。k越大横向偏差产生的转角修正越强车辆回到路径上的速度越快但过大的k会让修正力矩过猛车辆在路径两侧来回振荡转向角频繁换向不仅看起来不自然还容易让轮胎模型进入非线性区。k太小则收敛太慢车辆会拖着一条长长的渐进线慢慢靠回路径在弯道处表现为明显的切弯误差。我调参的次序是先把车速固定在20km/h从k1开始做阶跃测试观察横向偏差是否能在几秒内收敛到厘米级并且不振荡。如果收敛太慢就加大k如果开始振荡就减小k。这个手动试凑的过程大概半小时就能找到基线。需要注意每次只改一个变量最好横纵向分开调纵向PID把车速稳住之前不要去纠结横向偏差曲线上的毛刺因为速度波动会直接污染横向控制器判断。4.2 公式里的v带来的速度依赖Stanley公式里除以v这项让同一个k在不同车速下表现不一样。低速时横向项atan(k*e/v)在同样e下会给出更大转角高速时同样的偏差对应的转角会变小。换句话说同一个k不可能在所有车速下都最优。实际标定时我按速度区间分段取k然后在仿真里用一组固定工况对比。这是我某一次标定记录的数据车速从10到40km/h目标车速(km/h)k标定值(1/s)稳态横向偏差(cm)收敛时间(s)转向角峰值(deg)102.51.81.24.3202.02.51.53.6301.63.11.83.1401.24.22.22.8从表里能看出来车速越高最优k越小稳态横向偏差也会略大一些。这是因为高速工况下同样的前轮转角会产生更大的横摆角速度车辆对转向更敏感必须降低反馈增益去换取稳定。如果你的项目需要全速度域工作建议做一个车速查表插值的增益调度而不是死守一个k。4.3 限幅与抗饱和Stanley的atan项天然把横向修正限制在正负90度以内但在低速极端偏差下整个括号可能逼近饱和导致输出转角长时间处于上限车辆出现画龙式的大幅摆动。我在工程实现里加了两层保护第一层是控制量限幅前轮转角限制在正负30度也就是正负0.5弧度左右和实车转向机构的能力对齐第二层是偏差限幅当横向偏差超过一定阈值比如5米时不直接把原始e代入atan而是对e做软饱和处理用饱和函数e_clamped e_max * tanh(e / e_max)。这样处理比硬限幅平滑得多车辆远离路径时不会一上来就打死方向而是先缓和对齐渐进靠拢。4.4 改路径之后的复标定路径形状变化之后即使车速一样k也需要微调。圆环路径下车辆长期处于稳态转向状态我观察到的主要是稳态横向偏差偏大这是最近点切线方向和车辆航向之间存在小角度估计误差导致的需要适当增大psi_e的权重也就是在公式里给psi_e加一个系数a比如a1到1.5之间或者直接提高k。双移线路径下问题更多表现为动态滞后换道中段会出现横向偏差峰值这个需要略微减小k让车别追得太急同时也检查纵向PID是否在换道过程中把车速稳住。蛇形路径连续变曲率最容易暴露最近点搜索的跳变问题我建议在路径拐弯处把点加密保证相邻点距离不超过0.1米不然航向估算会有锯齿。5. 实测效果与踩坑清单从发散到收敛最后这部分我把联仿过程中踩过的坑按现象-原因-修复的方式记录下来再给一组最终效果数据。说实话Stanley本身不复杂项目里绝大多数时间都耗在这些看似不起眼的集成问题上。5.1 第一个坑单位没对齐控制器直接反向工作现象是车速表显示60但进入Stanley公式后车辆明显左右摆动、收敛极慢。查了半天发现CarSim导出Vx的默认单位是km/h我在MATLAB Function里当成m/s用了。60km/h被当成60m/s相当于真实车速被放大了3.6倍atan(k*e/v)分母偏大横向修正被大幅削弱控制器反应迟钝。修改方式是在导入Simulink前除以3.6或者在CarSim输出配置里直接把Vx单位设为m/s。这个坑非常隐蔽因为数值层面不报错只有曲线不对劲。5.2 第二个坑最近点跳变导致符号翻转路径是闭环圆时车辆跑到圆底部附近最近点搜索偶尔会在相邻两个路径点之间来回跳。横向偏差e的符号会跟着翻转控制器每隔几帧就收到一个相反方向的误差转向角高频抖动。查下来发现根本原因是路径点太稀圆环路径两端的点的间距达到了0.5米以上车辆在两个点之间的位置被归到不同最近点上。修复方法我前面提过路径重采样保证相邻点间距在0.1米以内。同时可以给最近点搜索加一个小技巧把上一时刻找到的最近点索引作为本轮搜索的起点只在小邻域内搜索这样即使路径点不完全均匀也不会出现大跨度跳变。这个带初值的局部搜索我强烈建议加上它同时还能提升搜索效率。5.3 第三个坑步长不一致信号出现毛刺Simulink默认是变步长求解器CarSim输出端是固定步长两者数据交换时时间戳对不上横向偏差曲线上会出现周期性的毛刺。正常情况下Simulink的采样时间都是连续但CarSim S-Function模块在变步长模式下会把输入输出插值到自己的时间轴上来回插值就有误差。解法是Simulink里也选固定步长求解器并且把步长设为和CarSim一致。我用0.001秒仿真速度虽然慢一点但曲线干净多了排查其他问题时也更容易定位。跑批量测试时再考虑放大到0.002秒。5.4 第四个坑初始位置离路径太远起步猛打方向联仿启动时如果车辆初始位置和参考路径起点偏差过大比如超过5米Stanley会输出很大的转角车辆立刻猛打方向看起来像失控。虽然限幅把它压在30度但起步阶段的大转角仍然会让车走出一条很奇怪的弧线再到路径上。我在项目里加了一个启动策略当横向偏差超过2米时不直接切Stanley而是先让车辆直线行驶或者用一个较小的比例转角让车辆慢慢靠近路径等偏差降到2米以内再切换完整Stanley控制。也可以直接对横向偏差做软饱和前面提到的e_clamped就是干这个的。实测下来起步阶段平稳很多曲线不会出现第一帧就打到饱和的丑陋跳变。5.5 最终效果一条典型的双移线测试数据用标定完的参数跑一条双移线车速20km/hk2.0得到的结果大概是这样的直线段横向偏差稳态在正负2厘米以内转向角几乎为零换道段曲率变化最大处横向偏差峰值约6到8厘米转向角峰值约3.5度无振荡回到直线段横向偏差在1秒内收敛回2厘米以内。转向角曲线整体平滑没有高频抖动的毛刺说明最近点搜索和单位换算都处理干净了。同一套平台我把路径换成半径30米的圆环稳态横向偏差大约3厘米方向盘转角维持在合理范围内换成蛇形路径连续过弯的横向偏差峰值能控制在10厘米以内。这个精度对于低速园区和换道验证场景来说足够用了也基本符合效果极佳的说法。5.6 一点个人体会如果让我复盘这个项目最核心的一条心得是Stanley算法的代码只占整个联仿平台很小的一部分真正花时间的永远在状态信号对不对、单位一致不一致、路径点够不够密、步长统一不统一这些集成细节上。控制律本身是死的算法落地是活的。项目里我一共迭代了三版路径生成工具最后沉淀成一键加载路径、批量跑仿真、自动记录横向偏差和转向角曲线的脚本后续再换算法比如上LQR也只是换掉MATLAB Function内部的十几行代码外围框架完全不用动。所以在动手做联仿之前与其急着写Stanley不如先把数据流梳理清楚。数据对了算法哪怕朴素一点出来的效果都会很稳。

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

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

免费获取报价 →
↑