ARTICLE DETAIL

资讯详情

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

VCU蠕行控制模型搭建全流程:从需求到代码生成

VCU蠕行控制模型搭建全流程:从需求到代码生成 开篇先聊个有意思的事很多刚接触新能源整车控制的朋友第一次在台架上把“松刹车就走”这个动作调出来时都会觉得它理所当然。但你仔细想一下传统燃油车靠发动机怠速就能实现蠕行电车没有怠速工况电机不输出扭矩车就是静止的。所以“蠕行”这个功能本质上是VCU用软件模拟出一套“虚拟怠速”让车在D挡松开刹车时不踩油门也能以5-8km/h左右的速度缓慢前行同时在坡道上还能帮忙防溜。这篇博文我就从零开始完整搭建一个VCU蠕行控制模型覆盖需求定义、Simulink建模、仿真验证、代码生成落地全流程重点讲清楚扭矩仲裁、坡道补偿、防冲击处理这几个核心逻辑。内容适合刚开始接触VCU控制策略的工程师也适合做新能源汽车方向毕业设计、需要快速跑通一个完整功能模型的学生。模型基于MATLAB/Simulink R2022b以上版本搭建文末会说明模型文件的获取方式。1. 蠕行控制的需求拆解与整体策略设计1.1 为什么纯电车必须做蠕行控制先解决一个最基础的问题蠕行到底解决什么痛点从驾驶员视角看燃油车自动挡挂D挡松刹车车子自己会走这个习惯已经被市场教育了二十年。如果电车一松刹车就完全静止市区拥堵路况下脚要一直搭在油门上开起来非常累而且和油车驾驶习惯产生了巨大割裂用户会直接投诉“这个车不会走”。从系统视角看蠕行还有几个隐藏价值坡道辅助在坡道上松开刹车蠕行扭矩可以在一定坡度范围内阻止车辆后溜减少坡道起步时手忙脚乱的操作。低速精确控制停车场挪车、堵车跟车时蠕行为驾驶员提供一个非常低的车速基准精度远高于人脚控制油门。整车扭矩安全蠕行控制逻辑本身带转速闭环和扭矩限幅比驾驶员猛踩油门更平缓对减速器、电机都更友好。1.2 蠕行控制的功能边界很多初学着在设计蠕行策略时容易把功能范围想得太大结果模型越搭越复杂最后根本标定不动。我建议不管什么车型第一版蠕行模型严格锁住以下功能边界功能项设计目标备注前进蠕行D挡、松刹车、不踩油门车速稳定在7km/h左右核心功能倒车蠕行R挡同样逻辑车速限制更严通常5km/h左右和安全强相关坡道防溜坡度5%以上蠕行扭矩自动补偿驻坡不后溜扩展功能第一版可先预留接口驾驶员干预踩油门、踩刹车、换挡时蠕行扭矩平滑退出必须有否则闯动严重车速退出车速超过30km/h后蠕行功能完全退出防止高速误触发这个边界很重要它会直接影响Simulink模型里的逻辑分支设计。你如果不做功能边界定义就直接开建模型后面大概率会在各种稀奇古怪的工况里反复补丁越补越乱。1.3 蠕行控制的核心策略逻辑蠕行控制策略从控制逻辑上分三个层次状态判断层根据挡位、刹车、油门、车速判断当前是否应该进入蠕行。扭矩计算层根据工况计算蠕行目标扭矩核心是车速闭环坡度补偿边界限制。扭矩仲裁层将蠕行扭矩与驾驶员扭矩、制动防溜扭矩进行仲裁输出最终扭矩指令。稳态蠕行扭矩的计算公式可以用最简单的PID形式表达T_creep Kp * (V_ref - V_vehicle) Ki * ∫(V_ref - V_vehicle)dt其中V_ref是目标蠕行车速标定值通常5-8km/hV_vehicle是当前车速Kp和Ki是标定参数。实际工程中PID输出后还要做以下处理输出限幅蠕行扭矩最大值不超过整车扭矩安全限值通常取电机峰值扭矩的30%-50%对于200kW级别的电机大概250-400Nm。积分限幅防止长时间堵车低速蠕行时积分项持续累积我一般把积分项限在蠕行最大扭矩的20%以内。变化率限制蠕行扭矩从0到目标值的爬升速率建议限制在20-50Nm/s这个值直接影响起步的平顺感标定的时候需要反复调。2. Simulink建模前准备与信号接口设计2.1 软件环境与模型架构规划我用的版本是MATLAB R2022bSimulink版本跟着MATLAB走这里有个小建议尽量使用2021a之后的版本因为信号线和总线操作比老版本顺手很多特别是信号命名和接口管理。如果你的项目涉及代码生成需要安装Simulink Coder和Embedded Coder如果要做硬件在环或者快速原型还需要对应的实时目标包。新建模型后我习惯第一件事不是拖模块而是先在草稿纸上规划好模型的顶层架构。蠕行控制模型的顶层信号流建议按下面的顺序组织输入信号采集 → 信号有效性检查 → 驾驶意图识别 → 蠕行状态判断 → 蠕行扭矩计算 → 扭矩仲裁 → 扭矩限制 → 输出分层上我建议分成4层子系统层级子系统名称主要功能L1Input_Processing对传感器原始信号进行滤波、有效性检查、物理量转换L2Driving_Intention判断驾驶员意图蠕行/正常加速/制动/驻车L3Creep_Control核心控制状态机、PID计算、坡度补偿L4Torque_Arbitration各方扭矩仲裁、变化率限制、安全限幅建模时严格遵循这个分层不要图省事把逻辑全堆在一个子系统里不然后面查问题的时候你会想抽自己。2.2 输入输出信号定义与数据结构设计这步看着不起眼但绝对能决定你后期调试的效率。蠕行控制需要的输入输出信号我整理成了一张表信号名信号描述单位数据类型来源AccPedal_Pct加速踏板开度%uint8踏板传感器BrkPedal_Pct制动踏板开度%uint8踏板传感器GearLever_Pos挡位信号P/R/N/Denumuint8换挡器VehSpd_Kmh车速km/huint16轮速换算LongitAccel_mps2纵向加速度m/s²int16加速度传感器MotorSpd_Rpm电机转速rpmint16电机控制器MotorTrq_Fbk电机实际扭矩反馈Nmint16电机控制器VehMode整车模式正常/经济/运动enumuint8整车模式管理每一个信号都需要明确单位、数据类型和来源这个习惯能让你在Simulink里不用猜来猜去。如果整车项目有现成的CAN通讯矩阵直接把信号名对齐到DBC文件里的信号命名后面做代码生成和总线对接时会省非常多时间。我建议从项目一开始就用Bus对象来组织信号特别是L4仲裁层输入输出如果整成一堆散线信号一多你连线都会连到怀疑人生。在模型里通过Bus Creator把相关信号打包仲裁逻辑里通过Bus Selector取用这样线束清晰而且后续加信号只需要在Bus里添加。2.3 Simulink求解器与步长设置蠕行控制这种逻辑密集型的模型推荐配置如下求解器类型定步长求解器discrete离散固定步长0.01s10ms任务周期为什么不用变步长因为VCU控制逻辑最终是要生成C代码跑在单片机上的单片机是按固定周期调度的。变步长仿真在桌面阶段看着精确但生成代码以后完全没有意义而且逻辑模块状态机、计数器在变步长下容易产生时序问题。10ms是针对蠕行这种车辆级动力学控制非常成熟的经验值响应够快而且对MCU主频要求不高。如果你是做毕业设计不涉及代码生成直接用默认的变步长也可以但后面如果想做V2X或者HIL建议尽早切定步长。3. 蠕行控制模型的Simulink搭建全流程3.1 顶层模型框架搭建打开Simulink新建空白模型先把顶层IO信号入口建好。我的习惯是在顶层放以下这些Inport模块泾渭分明AccPedal_Raw原始踏板百分比信号BrkPedal_Raw原始制动踏板百分比信号GearLever_Pos挡位枚举信号VehSpd_Raw原始车速信号km/hLongitAccel_Raw原始纵向加速度信号MotorTrq_Fbk电机扭矩反馈然后放置Outport模块蠕行控制模型这层的核心输出就一个TrqReq_Final最终扭矩请求Nm再加上一个用于调试监控的Outport把蠕行状态机当前状态、蠕行目标扭矩、蠕行使能标志等信号引出来方便后面在仿真时用Scope或者数据检查器看波形。3.2 L1输入信号处理子系统双击进入Input_Processing子系统这层的主要工作有三个滤波、有效性检查、物理量转换。滤波这块对于踏板开度信号我一般用一阶低通滤波截止频率10Hz左右。实现方式很简单用Simulink自带的一阶传递函数模块1/(0.016s1)或者用离散滤波器模块Discrete Filter也可以在代码生成时用离散化版本。注意这个滤波只是为了让ADC采到的毛刺不那么扎眼不要把时间常数取太大否则踏板响应会明显变钝。物理量转换用Gain模块配合常数就行比如原始踏板信号如果来自ADC是0-1000的AD值就需要乘一个系数转成0-100%的物理开度。这里有一个我踩过很多次的坑转换系数一定要把数据类型的运算逻辑搞清楚。比如uint8类型转uint16类型Simulink会做饱和处理而不是取模你如果不清楚这一点在信号范围边界经常会看到莫名其妙的突变。有效性检查是很多新手容易忽略的点但在实际工程中信号超时、信号无效、传感器自检失败这些场景都会真实发生。我的做法是通过CAN信号状态字判断如果信号无效直接把蠕行使能锁定为0并且输出一个故障码。对于毕业设计或者教学场景这一步可以简化成“信号大于物理上限视为无效”。3.3 L2驾驶意图识别子系统驾驶意图识别层是整个模型逻辑最密集的地方我建议用Stateflow状态机来实现比纯Simulink逻辑块更加直观且生成代码质量也更高。Stateflow状态机包含以下状态IDLE挡位P/N不响应蠕行CREEP_ACTIVE蠕行激活车速跟随目标蠕行车速DRIVER_OVERRIDE驾驶员踩油门蠕行被驾驶员扭矩覆盖BRAKE_INTERVENTON刹车介入蠕行扭矩回0EXIT_PENDING退出过渡态扭矩斜坡降至0转移条件要遵循以下优先级逻辑刹车踩下开度大于5%→ 无条件进入BRAKE_INTERVENTON挡位不在D/R → 进入IDLE车速大于30km/h → 进入EXIT_PENDING驾驶员油门开度大于阈值 → 进入DRIVER_OVERRIDE以上条件都不满足且车速小于8km/h → 进入CREEP_ACTIVE这里需要特别注意转移条件的优先级顺序在Stateflow里转移顺序是自上而下判断的必须把刹车和安全条件放在最前面否则极端工况下会先进入蠕行再退出虽然最终结果可能一样但中间会有一次不应该的扭矩波动。3.4 L3蠕行控制核心子系统进入正题蠕行控制核心子系统是整个模型中我最想详细讲的。3.4.1 蠕行使能判断蠕行的使能条件建议做一个独立的逻辑模块。我在工程里的使能条件是这样设计的挡位处于D挡或者R挡刹车踏板开度小于5%松开刹车加速踏板开度小于3%不踩油门车速没超过退出阈值前进蠕行30km/h倒车蠕行15km/h整车无严重故障如果所有条件都满足输出使能标志为1否则为0。这里有个细节退出阈值建议带滞回。举例来说前进蠕行进入阈值为10km/h退出阈值为30km/h中间这20km/h的区间是蠕行的“工作区”这样做的好处是避免车子在阈值附近反复切入切出引起扭矩抖动。3.4.2 PID车速控制蠕行控制的核心是车速闭环。目标车速V_ref标定值7km/h实际车速从VehSpd信号接入。PID模块可以直接用Simulink自带的PID Controller模块配置如下控制器类型PI不需要微分项微分对车速噪声太敏感比例系数Kp45积分系数Ki3输出饱和上限300输出饱和下限0开启Anti-windup积分抗饱和很多人搭建时直接拖一个PID Controller就完事但我要强调三点容易被忽略的坑第一PID Controller模块默认的采样时间要和你模型的步长一致否则仿真结果和你预期会有很大差异。直接在PID模块参数里把Sample time设为0.01。第二Anti-windup一定要打开。蠕行过程中经常出现长时间堵车、车速为0的情况PI积分项会持续累积如果积分饱和了一旦前车起步你会看到车明显“闯动”一下其实就是积分项泄压。第三积分初始值设置为0并且每次蠕行使能为0时把积分项强制清零。在Simulink里可以给PID模块加一个外部reset信号把使能信号的取反接进去这样每次退出蠕行时都会清空积分状态。3.4.3 坡度补偿逻辑在坡道上纯靠PID闭环其实也能达到目标车速但坡度过大时PID输出会一直处于饱和状态响应慢且会溜车。所以工程上一般会加一个前馈补偿项T_comp m * g * sin(θ) * r / (η * i)其中m是整车质量g重力加速度θ是坡度角r是车轮半径η是传动效率i是减速比。实际工程里坡度角通过纵向加速度传感器估算θ ≈ arcsin(LongitAccel / 9.81)。考虑到加速度传感器噪声比较大一定要加低通滤波和斜率限制我一般会加一个截止频率1Hz的低通滤波器再加一个50ms的斜率限幅。补偿后的蠕行目标扭矩T_creep_target T_pid T_comp注意这里不是简单的叠加要带限幅。特别是在大坡道上如果补偿值过大会导致整车扭矩请求超过安全限值所以补偿后的总值也要过一层限幅。坡度补偿虽然是扩展功能但我强烈建议第一版就预留这个接口——你后面标定时一定会遇到坡道测试到时候再改模型结构比现在多花三倍时间。3.4.4 蠕行扭矩限幅与变化率限制蠕行扭矩输出后必须做两层限制第一层是幅值限制蠕行扭矩上限我设定了D挡前进蠕行250NmR挡倒车蠕行180Nm经济模式下再乘0.8的系数运动模式下乘1.1的系数第二层是变化率限制这个直接影响整车平顺性。我用的实现方式是Rate Limiter模块前进蠕行扭矩上升速率限制为30Nm/s下降速率限制为80Nm/s。这里上升慢下降快的意图是起步时扭矩缓缓介入让车柔和起步退出时尽快撤掉扭矩避免驾驶员踩油门时新旧扭矩叠加产生突兀感。3.5 L4扭矩仲裁与安全输出扭矩仲裁逻辑其实是整个VCU里最考验系统思维的地方因为蠕行扭矩不是唯一在请求扭矩的。输入仲裁模块的扭矩有三个来源驾驶员扭矩由加速踏板开度乘以电机外特性得到的扭矩请求这个是最高优先级需求合理性角度蠕行扭矩上述计算得到的蠕行目标扭矩制动请求一般是负扭矩或者直接置0这里简单处理为扭矩请求置0仲裁逻辑我建议这样设计if 制动有效: 仲裁扭矩 0 elif 驾驶员扭矩 蠕行扭矩: 仲裁扭矩 驾驶员扭矩 else: 仲裁扭矩 蠕行扭矩关键在于驾驶员扭矩大于蠕行扭矩时的切换要平滑。直接在两个值之间做阶跃切换的话切换瞬间扭矩跳变量可能达到上百Nm这在实际车辆上非常危险。所以仲裁后还必须加一道变化率限制我用了200Nm/s的速率限制这刚好让扭矩切换在1秒左右完成既保证响应速度又避免冲击。信号流上用Switch模块加一个判断逻辑即可注意Switch的判断条件要整成Boolean类型不要用double做判断条件否则生成代码时有隐患。最后是扭矩安全监控模块我建议在输出之前加一个简单的看门狗如果蠕行使能状态下车速为0且蠕行扭矩请求大于300Nm且持续超过5秒判定为异常并直接输出0。这个逻辑非常粗糙但做毕业设计和原型验证时能保命。真正的量产项目里这层是独立的扭矩安全监控模块TMC复杂程度是另一篇文章了。4. 仿真验证与典型工况测试4.1 测试工况搭建模型建完不仿真等于白建。我习惯把仿真场景分为以下四个典型工况测试用例输入条件预期结果平路D挡起步车速0挡位D无油门无刹车车速稳定在7km/h左右行驶中踩油门蠕行稳定后油门开度30%扭矩平滑过渡到驾驶员扭矩行驶中踩刹车蠕行稳定后刹车开度30%扭矩快速回0车速下降坡道松刹车坡度5%车速0挡位D车辆不下溜缓慢起步测试时我推荐用Signal Editor模块来搭建输入信号序列这是Simulink自带的可以在一个模块里编辑不同时刻的信号值比手动改常量方便得多。4.2 利用Simulink Test自动化测试如果模型要不断迭代手点仿真太累了建议用Simulink Test工具包写自动化测试脚本。我给你看一个最简的测试脚本模板%% 创建测试用例 tp sltest.testmanager.TestPoint(Creep_Test_Point); tc sltest.testmanager.TestCase(Creep_Test_Case); %% 设定仿真输入 tc.setInputSignal(AccPedal_Raw, timeseries([0 0], [0 10])); tc.setInputSignal(BrkPedal_Raw, timeseries([0 0], [0 10])); tc.setInputSignal(GearLever_Pos, timeseries([1 1], [0 10])); % 1D %% 运行仿真 result run(tc); %% 断言最终车速在6-8km/h之间 finalSpeed result.OutputSignal(end); assert(finalSpeed 6 finalSpeed 8, 蠕行车速超范围);写完脚本后每次改完模型一键跑全量回归测试哪个工况挂了直接看测试报告效率至少提升3倍。4.3 联合Carsim仿真验证如果你手里有Carsim强烈建议做联合仿真。Carsim提供高精度的整车动力学模型包括轮胎、悬架、坡度等比Simulink里自己搭的车辆纵向动力学模型真实得多。联合仿真的配置方法在Carsim里选好车型我一般用B级车或SUV模板设置输入为Simulink输出的扭矩请求设置输出为车速、纵向加速度等信号然后在Simulink的模型里用Carsim S-Function模块替换我前面的简单车辆模型。仿真步长建议两边都设成1ms不然会出数值不稳定问题。实测下来Carsim联合仿真对坡道测试尤其有价值。我自己搭的简单车辆模型坡道仿真结果和Carsim能差出10%-15%的起步时间因为Carsim考虑了滚动阻力和空气阻力的非线性还有一个簧载质量转移问题。4.4 常见问题与排查技巧我在开发这套模型时遇到的几个比较典型的坑直接列给大家问题一蠕行起步时扭矩震荡现象车速在0-3km/h区间时扭矩请求高频率波动车一闯一闯的。排查这个问题90%是PID参数过强加上车速信号在低速区噪声大。我的处理方案是把Kp从45降到30Ki从3降到2同时把车速信号做一次低通滤波截止频率2Hz。如果还有轻微震荡再在PID后面加一个Rate Limiter上升速率压到20Nm/s。问题二刹车后重新起步时蠕行扭矩响应慢现象刹车踩死再松开车要过1-2秒才有蠕行动作。排查这是典型的防抖动策略把蠕行进入条件误触发了。我在踩刹车平稳工况设计了一个计数器刹车踩死超过3秒才标记为“驻车状态”驻车状态解除时需要制动踏板先松开且车速保持0持续0.5秒。问题就出在“保持0持续0.5秒”这个判断在车辆还没完全停稳时没法满足。最后我改成了“制动踏板松开且车速小于3km/h即退出驻车状态”这个问题就解决了。问题三坡道起步溜车现象5%坡度上松开刹车车先后溜一段距离才开始前进。排查PID响应再快也赶不上重力加速度必须加前馈补偿。启用坡度补偿前馈后把补偿系数从0.8调到1.05也就是稍微过补偿一点溜车距离从原来的30cm降到3cm以内。5. 模型工程化落地与代码生成5.1 模型规范和代码生成准备如果你的目标是把模型从仿真级别做成可以烧录的控制代码那么建模规范从一开始就要注意。以下几条是我踩过坑后总结的硬性规范所有模块命名必须语义化不要用什么Gain1、Gain2这种默认名字代码生成后你会看不懂。数据字典统一管理新建一个sldd数据字典文件把标定参数全部放里面并用Simulink.Parameter定义勾选“存储类标定”这样生成的代码里这些参数是可以在线标定的。所有信号设置合理的Simulink信号对象或者用Bus对象统一管理避免自动生成的结构体嵌套乱得一塌糊涂。禁止使用Continuous模块全部用离散模块特别是积分器用Discrete-Time Integrator不要用连续积分器。单位系统统一Simulink模型里虽然有Unit功能但很多老工程师不用建议从开始就坚持在信号线上标注单位。配置代码生成时我最常用的是ERTEmbedded Real-Time Target系统目标文件勾选“只生成代码”代码风格选择“可读性优先”这样生成的C代码基本能看懂方便和你手写的底层代码对接。5.2 外部模式与在线标定代码生成后不管是刷到快速原型控制器还是台架VCU你都需要在线调参与监控。Simulink外部模式External Mode在这时候就非常实用。配置外部模式的方法是在应用配置里把接口选择成“外部模式”连接方式根据你的硬件来选。连接成功后Simulink模型就和实际运行的控制器建立了实时通信你直接在Simulink界面里改PID参数硬件上立刻生效效果实时显示在Scope里。不过注意一个现实整车上一般不会用Simulink外部模式做标定而是通过CCP/XCP协议配合INCA/CANape这类标定工具来标定。这是因为整车环境对通信安全要求高外部模式在抗干扰和安全性上都不达标。但在开发验证阶段外部模式确实效率极高。如果要用XCP标定最方便的做法是在Embedded Coder里配置XCP服务在模型里需要标定的参数全部定义为Simulink.Parameter且设置存储类代码生成后标定工具通过A2L文件识别变量就能在线修改了。5.3 CAN故障诊断接口的预留量产VCU模型一定会有诊断功能我这里建议在蠕行控制输出之前加一个故障标志位汇总至少覆盖以下情况车速信号无效踏板信号超时电机扭矩反馈信号不一致蠕行扭矩请求持续超过限值这个故障标志位预留一个Outport后续接上DTC诊断故障码管理模块就可以直接使用。CAN报文故障诊断我单独写的话又是几千字这里提醒大家“预留接口”这个习惯非常值得养成。模型下载与使用说明很多朋友会问模型在哪里下载。这个模型目前我整理了两个版本基础版免费包含完整的L1-L4层Simulink模型所有信号接口完整可以直接仿真运行适合学习流程、理解蠕行控制逻辑。模型文件为.slx格式支持R2022b以上版本打开。完整版付费在基础版基础上增加了Stateflow完整状态机包含正常的坡道防溜、驾驶员干预状态、Simulink Test自动化测试用例、标定脚本自动标定Kp/Ki参数、以及Carsim联合仿真配置说明。获取方式在CSDN/公众号搜索“车辆控制技术笔记”或者“VCU蠕行控制模型”能找到历史文章的下载链接。模型我每次迭代都会更新建议优先看最新版本旧版本可能会有已修复的bug。下载后建议按以下顺序研究先打开顶层模型对照本文第3章的架构梳理信号流打开Data Dictionary看标定参数的定义和初值运行自带的测试用例看Scope波形的变化规律尝试修改Kp/Ki参数观察蠕行车速和扭矩的变化最后再尝试做代码生成把模型变成C代码这套流程走一遍你对VCU蠕行控制的理解会比干看十篇论文都有用。最后聊几句个人经验这套模型从最开始的需求分析到最终整理成可以对外发布的版本我前后改了差不多三版。第一版纯粹按“仿真能做出来”为目标结果拿到车上一试坡道起步就溜车堵车跟车时扭矩忽大忽小驾驶体验非常差。后来静下来重新梳理了一遍需求边界和信号流设计把坡道补偿和驾驶员干预拆开处理才真正把这个问题吃透。平时有朋友问我“学VCU控制应该从哪开始”我的建议一直是别一上来就研究复杂的扭矩矢量控制、能量回收先把蠕行这种“看似简单但五脏俱全”的功能完整走一遍。一个蠕行控制模型涵盖了你做VCU策略开发会遇到的所有核心问题信号处理、状态机设计、闭环控制、扭矩仲裁、安全保护、代码生成。把这件事吃透再往其他功能扩展就有了稳固的框架。另外非常推荐大家在写模型的时候养成写注释的习惯不是那种“这里是PID”的废话注释而是把参数为什么取这个值、哪个工况下需要调整、当前这块逻辑曾经出现过什么问题都写在模块Description里。半年后回来翻模型你会感激当时的自己。
返回列表