第二章:驾驶员需求扭矩解析
大家好,我是老张。今天咱们聊聊VCU控制里最基础、也最容易被忽视的一环——驾驶员需求扭矩解析。
说白了,就是搞清楚「驾驶员到底想要车怎么走」。你踩油门、踩刹车、选模式、甚至什么都不做,VCU都得读懂你的意图。我在项目里见过太多因为信号处理不到位导致的顿挫、溜坡甚至安全故障。嗯,这一章咱们就把这些坑一个个填上。
核心知识点一览:
- 加速踏板信号处理(含冗余校验与故障诊断)
- 制动踏板信号处理(含制动优先逻辑)
- 驾驶模式选择(经济/运动/雪地等)
- 蠕行扭矩计算(起步与低速场景)
2.1 加速踏板信号处理
加速踏板,说白了就是驾驶员跟VCU对话的主要通道。你踩多深,VCU就该给多大扭矩。但这里有个关键问题——信号可靠性。
现在的加速踏板基本都是双路冗余设计,一路信号上升,另一路下降。我习惯叫它们APP1和APP2。正常情况下,APP1 + APP2 ≈ 5V(或某个固定值)。如果这个关系不成立,那信号就有问题。
我的经验:曾经有个项目,APP1和APP2的斜率比标定反了,结果踩到一半扭矩突然跳变。查了三天才发现是硬件焊接时把两路信号接反了。从那以后,我每次做标定都会先手动验证一下两路信号的对应关系。
信号处理流程大致如下:
- AD采样——获取原始电压值
- 有效性检查——电压是否在合理范围(通常0.5V~4.5V)
- 冗余校验——APP1与APP2是否满足预设关系
- 故障处理——如果校验失败,进入跛行模式或限制扭矩
- 归一化——将电压映射到0%~100%开度
代码实现上,我一般这样写:
/* 加速踏板信号处理 - 简化示例 */
float AppPercent_Calc(uint16_t app1_raw, uint16_t app2_raw)
{
float app1_percent, app2_percent, app_final;
/* 1. 原始值转百分比 */
app1_percent = (float)(app1_raw - APP1_MIN) / (APP1_MAX - APP1_MIN) * 100.0f;
app2_percent = (float)(app2_raw - APP2_MIN) / (APP2_MAX - APP2_MIN) * 100.0f;
/* 2. 范围检查 */
if((app1_percent < 0.0f) || (app1_percent > 100.0f) ||
(app2_percent < 0.0f) || (app2_percent > 100.0f))
{
/* 信号超限,报故障 */
SetFault(FAULT_APP_RANGE);
return 0.0f;
}
/* 3. 冗余校验:APP1 + APP2 应接近100% */
if(fabs(app1_percent + app2_percent - 100.0f) > APP_REDUNDANCY_THRESHOLD)
{
/* 冗余校验失败,报故障 */
SetFault(FAULT_APP_REDUNDANCY);
return 0.0f;
}
/* 4. 取两路平均值作为最终开度 */
app_final = (app1_percent + (100.0f - app2_percent)) / 2.0f;
/* 5. 防抖处理(一阶低通滤波) */
static float app_filtered = 0.0f;
app_filtered = APP_FILTER_COEFF * app_final + (1.0f - APP_FILTER_COEFF) * app_filtered;
return app_filtered;
}
注意:防抖系数不能设得太小,否则响应太慢。我一般取0.1~0.3之间,具体看硬件噪声水平。太灵敏的话,驾驶员会感觉车「神经质」——明明没动踏板,扭矩却在抖。
2.2 制动踏板信号处理
制动踏板处理,核心就一句话:制动优先。
什么意思?就是只要检测到制动踏板被踩下,不管加速踏板是什么状态,VCU都必须立即切断驱动扭矩。这是安全底线,没得商量。
制动踏板信号通常有两种形式:
- 开关量——踩下/松开,简单粗暴
- 模拟量——可以知道踩多深,用于能量回收协调
我个人更推荐模拟量方案。为什么?因为你可以根据制动深度来调节能量回收强度,而不是一刀切。我在一个项目里就吃过亏——用的开关量制动,结果每次轻踩刹车能量回收都全开,乘客晕得不行。
制动优先逻辑的伪代码:
/* 制动优先逻辑 */
if(BrakePedal_IsPressed()) /* 制动踏板被踩下 */
{
/* 立即清零驱动扭矩 */
DriverDemandTorque = 0;
/* 根据制动深度计算再生制动扭矩 */
if(BrakePedal_HasAnalogSignal())
{
float brake_depth = BrakePedal_GetDepth(); /* 0~100% */
RegenTorque = BrakeDepthToRegenMap(brake_depth);
}
else
{
/* 开关量制动,使用固定再生扭矩 */
RegenTorque = FIXED_REGEN_TORQUE;
}
}
else
{
/* 无制动,正常处理加速踏板 */
DriverDemandTorque = AppPercent_To_Torque(app_percent, drive_mode);
}
关键点:制动优先的响应时间必须小于100ms。我见过一些方案用CAN信号传递制动状态,延迟太大,紧急情况下根本来不及。建议用硬线信号,直接进VCU的IO口。
2.3 驾驶模式选择
驾驶模式,说白了就是给同样的踏板开度配上不同的扭矩响应曲线。
常见的模式有:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| 经济模式 | 踏板响应平缓,扭矩输出保守 | 城市通勤,追求续航 |
| 标准模式 | 线性响应,兼顾动力与能耗 | 日常驾驶 |
| 运动模式 | 踏板初段扭矩大,响应激进 | 超车、山路、追求驾驶乐趣 |
| 雪地模式 | 扭矩输出柔和,限制大扭矩 | 湿滑路面,防止打滑 |
模式切换时,我建议做扭矩平滑过渡。你想想看,如果驾驶员在高速上从经济模式切到运动模式,扭矩突然增大,车会猛地窜出去——这很危险。
我的做法是:模式切换后,目标扭矩按一定斜率逐渐逼近新模式下的扭矩值,过渡时间大约200~500ms。
/* 驾驶模式扭矩映射 - 简化示例 */
float DriveMode_MapTorque(float app_percent, DriveMode_t mode)
{
float torque_base;
switch(mode)
{
case MODE_ECO:
torque_base = app_percent * 0.7f; /* 经济模式,扭矩打7折 */
break;
case MODE_NORMAL:
torque_base = app_percent * 1.0f; /* 标准模式,1:1映射 */
break;
case MODE_SPORT:
torque_base = app_percent * 1.3f; /* 运动模式,扭矩放大30% */
break;
case MODE_SNOW:
torque_base = app_percent * 0.5f; /* 雪地模式,扭矩减半 */
break;
default:
torque_base = app_percent * 1.0f;
break;
}
/* 限制最大扭矩 */
torque_base = MIN(torque_base, GetMaxTorqueByMode(mode));
return torque_base;
}
避坑指南:我曾经遇到过一个问题——模式切换时扭矩没有做平滑处理,结果在雪地模式下切回标准模式,扭矩瞬间增大,车轮直接打滑。从那以后,我所有模式切换都加了斜坡函数,宁可慢一点,也不能让驾驶员吓一跳。
2.4 蠕行扭矩计算
蠕行,就是驾驶员不踩加速踏板、也不踩制动踏板时,车辆缓慢前进(或后退)的功能。说白了,就是模拟燃油车怠速的感觉。
蠕行扭矩的计算,核心取决于两个因素:
- 车速——车速越高,蠕行扭矩越小,最终在某个车速以上完全退出
- 坡度——上坡时需要更大的蠕行扭矩防止溜坡,下坡时可能不需要甚至需要负扭矩
我一般用查表法:
/* 蠕行扭矩查表 - 基于车速和坡度 */
float CreepTorque_Calc(float vehicle_speed, float road_grade)
{
/* 车速-蠕行扭矩表(示例数据) */
const float creep_map[5][2] = {
{0.0f, 50.0f}, /* 0km/h -> 50Nm */
{3.0f, 40.0f}, /* 3km/h -> 40Nm */
{5.0f, 25.0f}, /* 5km/h -> 25Nm */
{8.0f, 10.0f}, /* 8km/h -> 10Nm */
{10.0f, 0.0f} /* 10km/h -> 0Nm */
};
float torque_base = Interp1D(vehicle_speed, creep_map, 5);
/* 坡度补偿:每1%坡度增加5Nm */
float grade_compensation = road_grade * 5.0f;
float torque_final = torque_base + grade_compensation;
/* 限制蠕行扭矩范围 */
torque_final = CLAMP(torque_final, CREEP_TORQUE_MIN, CREEP_TORQUE_MAX);
return torque_final;
}
注意:蠕行扭矩不能太大,否则在平地上起步会感觉「窜」。我一般把最大蠕行扭矩限制在50~80Nm之间,具体看整车质量。另外,蠕行退出车速建议设在8~12km/h,太早退出的话,走走停停的工况会很别扭。
还有一个容易被忽略的点——蠕行与能量回收的衔接。当车速降到蠕行车速以下时,如果驾驶员还在滑行,VCU应该从能量回收平滑过渡到蠕行扭矩。否则你会感觉到一个明显的「拖拽感」突然消失,然后车又往前窜一下。嗯,这个过渡我一般用200ms左右的斜坡。
好了,这一章的内容就到这里。驾驶员需求扭矩解析,说白了就是「读懂人、读懂车、读懂路」。信号处理是基础,模式选择是策略,蠕行是细节。每一个环节都马虎不得。
如果你在实际项目中遇到什么奇怪的问题,欢迎来公众号找我聊聊。毕竟,做VCU的坑,我一个人踩不完,大家一起踩才热闹。