换挡策略与扭矩需求

本页除了介绍按转速判据自动换挡的方法,还提供一个不依赖 CARLA 的离线原型: src/ground/gear_shift_policy。它接受一条纵向速度剖面,输出挡位序列、每帧扭矩需求与四条断言结论, 可在没有仿真器、没有 GPU 的机器上直接复现。

这一页解决什么问题

车辆纵向的「该用几挡、要多少扭矩」通常是靠标定表与经验,难以复核。把两件事讲清楚就能复核:

  1. 换挡时机:由发动机转速决定,升挡线与降挡线之间留迟滞带,再加最短保持时间;
  2. 扭矩需求:按纵向力平衡反推,与发动机外特性比对,超了就说明这条剖面在这台车上做不到。

自主实现:gear_shift_policy

换挡判据

rpm(v, g)   = v · ratio_g · final · 60 / (2π · r)
升挡:rpm > upshift_rpm 且 g < 4
降挡:rpm < downshift_rpm 且 g > 1
限制:距上次换挡时间 ≥ min_dwell

默认传动比 3.55 / 2.10 / 1.40 / 1.00、主减速比 4.10、车轮半径 0.31 m,于是各挡的换挡车速为:

挡位 升挡车速(2600 rpm) 降挡车速(1500 rpm)
1 → 2 5.799 m/s 3.346 m/s
2 → 3 9.803 m/s 5.656 m/s
3 → 4 14.705 m/s 8.483 m/s
4 → — 20.586 m/s 11.877 m/s

两条线之间的距离(约 2.45 m/s)就是迟滞带。

扭矩需求

F   = m·a + ½ρ·Cd·A·v² + m·g·Crr          # 纵向力平衡
Tw  = F · r                               # 车轮扭矩
Te  = Tw / (ratio_g · final · η)          # 发动机扭矩,负值截到 0
判定:Te ≤ max_torque(rpm)

max_torque(rpm) 用简化外特性:峰值转速以下近似平台(0.60→1.00 线性),峰值以上抛物线衰减,两端留 35% 底。

四条断言

断言 判据
挡位覆盖 至少用到 4 个挡
换挡平顺 相邻换挡间隔 ≥ min_dwell,且 2×min_dwell(至少 1 s)窗口内无 A→B→A
转速区间 全程转速 ∈ [0.5×怠速, 红线]
扭矩上限 每帧扭矩需求 ≤ max_torque(rpm)

参数

参数 默认 含义
policy/upshift_rpm 2600.0 升挡转速线
policy/downshift_rpm 1500.0 降挡转速线
policy/min_dwell 0.50 换挡后最短保持时间 s
policy/idle_rpm / policy/redline_rpm 800.0 / 6500.0 怠速与红线
profile/accel / profile/max_speed / profile/hold_seconds / profile/decel 1.00 / 30.00 / 2.00 / 2.00 速度剖面四要素
engine/peak_torque / engine/peak_rpm 220.0 / 4200.0 发动机外特性
gearbox/final_drive / gearbox/efficiency 4.10 / 0.92 主减速比与效率
gearbox/ratio_1..4 3.55 / 2.10 / 1.40 / 1.00 各挡传动比
vehicle/mass / vehicle/wheel_radius 1500.0 / 0.31 质量与车轮半径
sim/step / rate/publish_hz 0.05 / 10.0 步长与频率

话题

话题 类型 内容
/gear/current std_msgs/Int32 末帧挡位
/gear/report std_msgs/String 完整文字报告
/gear/curve std_msgs/String 挡位条带 + 扭矩柱
/gear/shift std_msgs/String 换挡事件表

运行

roslaunch gear_shift_policy main.launch

默认剖面的真实输出(1.0 m/s² 加速到 30 m/s、保持 2 s、2.0 m/s² 减速):

帧数:941,时长:47.00 s,最高车速 30.00 m/s,最高转速 3789 rpm
换挡 6 次:
  t=5.80 s  1 -> 2  (5.80 m/s,2600 -> 1538 rpm)
  t=9.85 s  2 -> 3  (9.85 m/s,2612 -> 1742 rpm)
  t=14.75 s  3 -> 4  (14.75 m/s,2608 -> 1863 rpm)
  t=41.10 s  4 -> 3  (11.80 m/s,1490 -> 2086 rpm)
  t=42.80 s  3 -> 2  (8.40 m/s,1485 -> 2228 rpm)
  t=44.20 s  2 -> 1  (5.60 m/s,1485 -> 2511 rpm)
断言:4 通过 / 0 失败(共 4 条)
结论:PASSED

四个反例(每条断言都能单独翻红)

命令 结果
max_speed:=5.0 [FAIL] 挡位覆盖 用到的挡位 [1],另一侧只跑 9.5 s
redline_rpm:=2000 [FAIL] 转速区间 越界 631 帧(实测最高 3789)
accel:=3.0 [FAIL] 扭矩上限 超限 162 帧(峰值需求 419.2 N·m)
upshift_rpm:=1600 downshift_rpm:=1500 换挡 26 次、[FAIL] 换挡平顺 ……1.0 s 内来回换挡 20 次

另有两条「改了但依然合规」的对照组:upshift_rpm:=4000(升挡更晚,最高转速 3996)与 min_dwell:=2.5(换挡更保守,最短保持 2.50 s),两者都是 4 通过 / 0 失败。

离线回归测试

cd <仓库根目录>
python3 tests/test_gear_shift_policy_local.py

只用 Python 标准库,不需要 ROS、不需要 CARLA、不需要显示器;pytest 下也会真失败(不是假绿)。

与已有模块的关系

模块 算什么 与本页的分工
扭转控制 速度指令 → 转角 / 轮速 只做运动学换算
速度曲线规划 加速/匀速/减速怎么排 输出速度剖面,本页接它的剖面
刹车距离核算 从看见到停住要几米 只算制动侧
转向执行器滞后 转向执行器的滞后与回正 管横向执行器
本页 该用几挡、需要多少扭矩、够不够 把动力可行性变成四条断言

常见问题

Q:为什么用转速判据而不是车速判据? A:同样车速下不同挡位的转速差好几倍;转速判据能自动适配主减速比与轮胎半径的变化。

Q:为什么减速段扭矩是 0? A:减速由制动器承担,发动机倒拖时模型把负扭矩截到 0,避免把制动功算成发动机功。

Q:Melodic 上出现 UnicodeEncodeError? A:Python 2.7 的 rosgraph 对非 ASCII unicode 会调 str();节点内 _log() 已统一转 byte str。


使用大模型辅助代码编写、测试编写与文档整理,提交内容由本人负责。

闭环执行(默认模式)

上面一节是开环算法:车速剖面由参数给定,反推需要多少扭矩。从 1.0.0 起节点 默认改成闭环,把「执行」这一环也模拟进去:

目标车速 ──► 比例控制器 ──► 油门/刹车 ──► 扭矩请求
                                            │
                          发动机外特性限制 ◄─┘
                                │
                     牵引力 − 阻力 − 制动力
                                │
                            车速积分 ──► 转速 ──► 换挡决策 ──┐
                                ▲                            │
                                └────────────────────────────┘

换挡因此不再是「事后统计」,而是实时影响加速度:四挡扭矩不足就加速慢, 车速跟不上目标,跟踪误差变大。默认工况下:

  • 帧数 941,时长 47.00 s,行驶 734.59 m,最高车速 29.99 m/s
  • 首次升挡在 t = 6.25 s(5.80 m/s),比开环晚 0.45 s —— 就是滞后
  • 跟踪误差 最大 0.90 m/s、平均 0.57 m/s,最差点出现在减速末尾 (目标 0.20 m/s、实到 1.10 m/s,因为刹车还有惯性)
  • 结论 PASSED

四条断言换成:挡位覆盖 / 换挡平顺 / 跟踪误差 / 转速区间。

把红线压到 2000 rpm 可以看到闭环的另一种失败:

roslaunch gear_shift_policy main.launch redline_rpm:=2000
  [FAIL] 转速区间 越界 631 帧(怠速 800,红线 2000,实测最高 3788)
结论:FAILED

想回到开环对比:roslaunch gear_shift_policy main.launch closed_loop:=false。