简介:面向全国大学生智能汽车竞赛十九届折线电磁组,这份PDF方案分享覆盖从车模选型到控制调试的完整流程,适合参赛队员和指导教师在备赛各阶段参考。内容围绕折线形电磁赛道展开,涵盖F/G车模选型、编码器、电磁运放、TOF测距、陀螺仪等配件清单,以及各模块与STC32母板的接线要点;对电磁支架、蓝牙、干簧管、OLED等外设也给出了使用说明。控制部分重点讲解电磁信号采集、均值滤波与归一化处理,并引入差比和算法计算偏差,配合PID实现直线和弯道循迹;针对直角弯道、苯环和障碍物等新元素,方案还给出了基于电感值突变判断转向、基于四电感总和识别苯环入口等具体检测与处理思路。资源共1个PDF文件,大小约1.49MB,内容图文结合、结构清晰,可作为备赛参考文档直接打印或对照阅读。目前已有5502人学习下载,对准备折线电磁组比赛具有较强的实用价值。
1. 折线电磁组难点:比速度更难的是转角信息丢失
第十九届全国大学生智能车竞赛的折线电磁组,看似是传统电磁循迹的延续,实际却是对信息维度的一次砍削。普通电磁组跑的是平滑弧线,电感差分值连续变化,PID 只要盯住偏差就能闭环;折线组则不同,赛道中出现的是直角弯、钝角折线、以及折线前后那段让人头疼的“伪直道”。在这里,电磁信号会在一两个控制周期内从满幅跳变到接近零,或者反过来从零跳变到满幅。如果沿用直线赛道那套“偏差=误差”的思路,车会在折点前急打方向、在折点后疯狂摆头,最终要么切内线压路肩,要么直接冲出赛道。
这个方案的出发点不是“怎么把折线跑直”,而是“怎么在折点前识别出这是一个折线,并在折点处用重构的方式补出路径”。整套系统围绕三个问题展开:传感器排布怎么覆盖折线两侧的场强突变、动态阈值怎么区分直角与钝角、以及路径拟合怎么在信号断层时维持输出连续。适合正在备赛的电磁组队员,也适合想从“跑通”进阶到“跑稳”的调试者。下面按信号链从物理布局讲到最后一级参数整定,每一层都给出可以直接抄的配置和代码。
2. 横竖电感排布与扫线视角:折线检测的物理根基
2.1 为什么八字电感在折线组不够用
常见电磁方案采用水平八字电感,两个电感关于车模中轴线对称,夹角 60 到 90 度。这个布局在平滑弯道里表现很好,因为左右电感感受到的场强差与曲率近似线性,差分值可以直接作为转向偏差。但折线赛道有一个致命问题:折线的拐点处,导线方向发生突变,磁力线在拐角附近高度扭曲,水平电感的感应电压不仅幅度变化剧烈,相位关系也乱了。结果是,明明车头还没到折点,差分值已经提前饱和;等车头真正压到折线上时,电感输出反而回中,给控制器的感觉就像“赛道突然消失了”。
我一般会在折线组上放弃纯八字布局,改成“横纵结合”的排布:一对水平电感负责直道和缓弯的循迹,一对垂直电感负责感知折线前方的场强陡变。垂直电感的轴线与地面垂直,它感应的是磁力线的水平分量;在折点前方,导线方向急剧改变,水平分量会出现明显的局部极值。这个极值出现的时间比水平电感饱和要早 20 到 30 厘米,正好给控制器留出反应窗口。
2.2 五电感排布的具体坐标与角度
这里给一套经过实车验证的排布参数,车模以常见 B 车模为参考,前轮轮距约 20 厘米,电感安装杆位于前轮轴线前方 10 厘米处。所有电感使用 10mH 工字电感,谐振电容配 6.8nF,谐振频率约 19kHz,与比赛信号源频率一致。
表格:折线电磁组五电感布局
| 编号 | 位置 | 离地高度 | 安装角度 | 用途 |
|---|---|---|---|---|
| L1 | 车头左前,距中轴 8cm | 12mm | 水平,与中轴夹角 45 度 | 左半场循迹 |
| L2 | 车头右前,距中轴 8cm | 12mm | 水平,与中轴夹角 -45 度 | 右半场循迹 |
| L3 | 车头正前,中轴上 | 8mm | 垂直,轴线垂直于地面 | 前方场强陡变感知 |
| L4 | 车头左前,距中轴 4cm | 10mm | 垂直,轴线垂直于地面 | 左折线预判 |
| L5 | 车头右前,距中轴 4cm | 10mm | 垂直,轴线垂直于地面 | 右折线预判 |
这套布局的核心思想是:水平电感负责“我在赛道的哪个位置”,垂直电感负责“前方有没有折线”。L3 的安装高度比 L1/L2 低,是因为垂直电感离地越近,对导线拐角处的磁力线畸变越敏感;但也不能太低,否则车模震动带来的高度抖动会直接变成噪声。L4/L5 放在中轴两侧 4cm 处,是为了在直角弯处能区分“左折”还是“右折”——如果只有 L3 一根垂直电感,只能知道“有折线”,不知道“往哪折”。
2.2.1 信号采集的归一化处理
原始电感信号经过运放放大后,送入单片机 ADC,典型值是 0 到 4095(12 位 ADC)。但不同电感的灵敏度存在离散性,同一个电感在不同温湿度下输出也会漂移,所以必须做归一化。常见做法是采集一组最大值和最小值,用下面公式换算:
float normalize(uint16_t raw, uint16_t min_val, uint16_t max_val) { float val = (float)(raw - min_val) / (float)(max_val - min_val); if (val < 0.0f) val = 0.0f; if (val > 1.0f) val = 1.0f; return val; }归一化后的值稳定在 0 到 1 之间,这样后续的动态阈值、方向解算都不必关心绝对幅值。需要注意,最大最小值不能只开机采一次,因为赛道供电电压波动和电机启动瞬间的压降都会让信号整体缩放。我一般会在车模上电后跑一段直道,持续 500ms 采集每个电感的峰值,存入数组;如果后续发现某个值超过历史峰值 1.2 倍,就平滑更新它。归一化是整个方案的底层,它不直接解决折线问题,但能让后面所有阈值参数与场地脱钩。
3. 动态阈值与双峰判据:折线误差修复的核心算法
3.1 固定阈值在折线前的失效模式
很多队伍一开始会用一个固定经验值来判断折线是否来临,比如“垂直电感大于 0.6 就认为是折线”。这个值在小场地、信号强时能用,但到了正式比赛场地,现场灯光、地面金属支架、甚至旁边赛道的漏磁都会改变信号基线。更麻烦的是,直道上的垂直电感并非输出零,它也会感应到一定幅值的信号;在接近直角弯时,水平电感的串扰让垂直电感提前升高,固定阈值会把“缓弯”误判成“折线”。
动态阈值的思路是:不要把阈值设成一个绝对值,而是设成相对当前信号水平的比值。具体做法是维护一个慢速滑动的信号均值,代表“当前环境下的基线水平”,然后阈值取基线的 1.5 到 2.5 倍。这个倍数的选择取决于赛道元素复杂度,跑道越复杂,倍数越高,防止频繁误触发。
3.2 双峰判定流程与代码实现
折线(尤其是直角折线)的垂直电感信号特征非常明显:它在折点前会形成一个主峰,随后迅速回落,然后紧跟着一个较小的次峰。主峰对应车头接近拐角时的场强集中,次峰对应车头驶过拐角后、导线在另一侧的场强残留。这个“双峰”特征在普通的弧线弯道里不会出现,因为弧线弯道的导线方向渐变,场强不会骤升骤降。因此,用双峰检测作为折线的判据,比单阈值可靠得多。
typedef struct { float val; uint8_t is_peak; float peak_val; float trough_val; } PeakState; uint8_t detect_double_peak(float sensor_value, PeakState *state) { // 动态基线: 一阶低通, alpha=0.1 static float baseline = 0.5f; baseline = baseline * 0.9f + sensor_value * 0.1f; // 上升沿捕捉主峰 if (sensor_value > baseline * 2.0f && !state->is_peak) { state->is_peak = 1; state->peak_val = sensor_value; state->trough_val = sensor_value; } // 峰值后跟踪谷值: 主峰下降超过40%判定进入谷区 if (state->is_peak && sensor_value < state->peak_val * 0.6f) { if (sensor_value < state->trough_val) state->trough_val = sensor_value; // 谷后再次上升超过基线2倍, 判定次峰出现 if (sensor_value > baseline * 2.0f && sensor_value > state->trough_val * 1.3f) { state->is_peak = 0; return 1; // 双峰确认, 当前判断为折线 } } // 若主峰后超过 15ms 未出现谷回升, 判定为虚假峰 if (state->is_peak && sensor_value < baseline * 1.2f) { state->is_peak = 0; } return 0; }这段代码的逻辑需要跟硬件行为对应起来看。状态机维护一个 is_peak 标志,配合 baseline 动态基线。当传感器值超过基线两倍时,认为进入主峰上升沿;当数值从峰值跌落到 60% 以下,说明正在经过拐角盲区;之后若再次升到基线两倍,则确认这是次峰而非噪声。两个峰之间必须存在一个明显的谷,这是区分直角折线和普通大弯的关键——普通弯道不会有这么深的回落。最后一条防抖逻辑很重要,因为车辆震动可能导致电感瞬间掉落,这种假信号不应该触发折线状态。
3.3 误差重构:从“检测到折线”到“知道偏差多少”
检测到折线只是第一步,控制器最终需要的是一个可用的方向偏差值。在折线检测触发时,水平电感的差分值已经不可信,此时不能再用它算转向。我的处理方式是:触发时刻锁定垂直电感 L4/L5 的差值方向(左折还是右折),然后按照预设的“折线偏差曲线”重构误差,这个曲线的形状由速度决定——速度越快,前馈量越大,同时方差越大。
表达式说明:在折线区,方向偏差E不再由传感器实时计算,而是由下面公式给出:
E = E_base + K_v * v + K_d * D
其中E_base是折线类型对应的基础偏差值(左直角、右直角、钝角分别标定),v是当前车速,K_v是速度补偿系数,D是车头距折点的估计距离,K_d是距离衰减系数。这个公式的本质是:既然传感器在折点处已经“失灵”,那就用前馈模型顶上去,等车头驶过拐角、水平电感恢复正常后,再平滑切换回实时循迹。
4. 直角弯道的线构造与路径拟合:折线组的专项处理
4.1 离线赛道特征库:把“线”存成参数
不同于传统电磁组每次循环都依赖实时传感器,折线电磁组有一个得天独厚的条件:赛道元素序列是固定的。规则允许赛前已知赛道形状(只是不知道具体摆放),因此可以离线建立一个特征库,把每个折线段的入弯方向、角度、出弯方向、前后直道长度都存成参数表。比赛时,车模通过累计里程和垂直电感触发的次数,推断自己当前位于特征库中的哪一段。
这种方式类似“走马观碑”的记忆式跑法,但不完全是死记硬背。特征库的作用不是告诉车模“到第几个弯了打多少度”,而是提供一组先验的 PID 参数和误差重构曲线。比如同一个直角弯,入弯速度不同,最优打角时机就不同;特征库让这套参数可以在赛前针对每个弯单独整定,而不是全场共用一组。
表格:折线特征库条目示例
| 特征ID | 元素类型 | 角度 | 入弯直道长度 | 出弯直道长度 | K_v | 基础偏差 | 备注 |
|---|---|---|---|---|---|---|---|
| 01 | 左直角 | 90° | 120 cm | 80 cm | 0.15 | 0.42 | 入弯前有 3m 直道可加速 |
| 02 | 右直角 | 90° | 60 cm | 150 cm | 0.10 | -0.38 | 入弯前紧接 S 弯,速度偏低 |
| 03 | 钝角折线 | 135° | 200 cm | 200 cm | 0.18 | 0.30 | 可全速通过,需早打角 |
| 04 | 锐角折线 | 60° | 40 cm | 100 cm | 0.05 | 0.55 | 近似的 U 形弯,需急减速 |
4.2 在线折线匹配与状态切换
在线运行时的状态机分为四态:直道循迹、折线预判、折线重构、出弯恢复。特征库不参与每一帧的计算,只在状态切换的瞬间被查询一次,这是为了减少查表开销。
typedef enum { LANE_FOLLOW, // 直道/缓弯循迹 CORNER_PRE, // 已检测到折线但还未到拐点 CORNER_BUILD, // 正在重构路径, 以模型输出为准 CORNER_RECOVER // 出弯, 逐步切回传感器 } CornerState; void corner_state_machine(float *err, uint8_t corner_dir, uint16_t elapsed_ms) { static CornerState state = LANE_FOLLOW; static float model_err = 0.0f; switch (state) { case LANE_FOLLOW: // 双峰检测触发, 进入预判态 if (double_peak_flag) { state = CORNER_PRE; model_err = (*err) * 0.5f; } break; case CORNER_PRE: // 垂直电感超过峰值60%时进入重构态 model_err = get_model_error(corner_dir, elapsed_ms); if (vertical_sensor < peak_val * 0.4f) { state = CORNER_BUILD; rebuild_start_ms = elapsed_ms; } break; case CORNER_BUILD: model_err = get_model_error(corner_dir, elapsed_ms - rebuild_start_ms); if (elapsed_ms - rebuild_start_ms > 80) { state = CORNER_RECOVER; } break; case CORNER_RECOVER: // 线性插值, 300ms 内从模型输出过渡到传感器输出 float ratio = (float)(elapsed_ms - rebuild_ms) / 300.0f; if (ratio > 1.0f) ratio = 1.0f; *err = model_err * (1.0f - ratio) + sensor_err * ratio; if (ratio >= 1.0f) state = LANE_FOLLOW; return; } *err = model_err; }代码里的关键是 CORNER_RECOVER 态的线性插值。很多队伍在折线处理上栽跟头,就是因为重构状态结束时误差突变,转向舵机猛抽一下。300ms 的过渡时间不是拍脑袋定的——它取决于当前车速和舵机响应带宽。车速 2m/s 时,300ms 对应 60cm 的行进距离,足够车头完全驶出拐角影响区;如果车速更高,这个时间要相应缩短,否则出弯后传感器已经恢复,模型还在拖后腿。get_model_error内部做的就是上一章提到的E = E_base + K_v * v + K_d * D计算,只是根据特征库条目给不同的系数。
4.3 折线入弯的减速策略:起跑线在哪
直角折线入弯前必须减速,否则横摆角速度跟不上转向需求。但减速的时机如果在检测到折线之后才开始,就太晚了——从垂直电感触发到拐点只有 20 到 30cm,2m/s 速度下只有 100 到 150ms,电机响应不过来。所以减速要跟特征库绑定:车模每次经过一个直道起点时,就把里程计清零,当累计里程接近特征库中预报的折线位置时,提前 50ms 开始执行减速 PID 的目标速度切换。
减速曲线我用梯形速度规划:先以最大减速度把车速拉到入弯速度,保持这个速度通过拐角,出弯后再以最大加速度恢复。最大减速度受轮胎抓地力限制,一般取 1.5 到 2.0 m/s²,超过这个值车模会侧滑;入弯速度则根据弯角大小查表,90 度直角入弯速度建议控制在 1.2 到 1.5m/s,钝角可以到 2.0m/s 以上。
5. 参数整定顺序与阶跃观察法:稳定过折线的三个关键参数
5.1 先调电感高度,再调阈值倍率
到手一个新场地,不要急着调 PID,先做静态标定。把车模断电,手动推到赛道上不同位置,记录每个电感的归一化输出。重点关注直角拐点前 30cm、20cm、10cm 处的垂直电感值变化率。如果 L3 的值在拐点前 20cm 处才突然升高,说明它离地太远或前方遮挡过多,需要降低安装高度或前移位置。这个静态标定花 40 分钟,能省下后面一整天的动态调参时间。
接下来调动态阈值的倍率。现场放一个桩桶作为参照,车模以慢速(0.8m/s)反复通过折线段,观察串口打印的垂直电感实时值和 baseline 估计值。理想情况是:直道上垂直电感与基线的比值稳定在 0.8 到 1.2 之间,折线前 25cm 处比值跳到 2.0,拐角正中回落到 1.0 以下,出弯后再冲到 1.8 左右。如果直道上的比值波动已经超过 1.5,说明基线低通系数太小,跟随太慢,把 alpha 从 0.1 调到 0.15;如果折线处的峰值达不到 2.0,则说明电感方向角不对,垂直电感没对准磁力线的水平分量方向。
5.2 阶跃响应法确认重构时机
路径重构的起停时机是最难调的,因为差了 10ms 体感就完全不同。我用的方法是给舵机一个人为的阶跃指令,观察实际转角响应的延迟时间。具体操作:在直道上让车模以 1m/s 匀速跑,程序里每 500ms 向舵机发一次 30% 占空比的阶跃方向指令,用编码器反推车模实际横摆角速度,测出从指令发出到横摆角速度上升至 63% 的时间。这个延迟时间记为 T,那么 CORNER_BUILD 态的保持时间就取 2T 到 3T,CORNER_RECOVER 态的插值时间取 5T 到 8T。
这个数字比例来自一个简单逻辑:重构态必须覆盖整个传感器失效区间,而传感器失效区间的长度等于“拐角物理长度 / 车速”;舵机响应慢的话,同样的物理区间需要更长的重构时间。如果车模过折线时表现为“过分转向”,说明重构态的模型偏差过大,把 K_d 调小;如果表现为“转向不足”,则是重构开始得太晚,把 CORNER_PRE 态的触发阈值从 0.6 倍峰值下调到 0.5 倍。
5.3 验证清单:三类信号曲线
调参结束后做最终的确认测试,把车模架在台架上(后轮悬空),跑一遍完整折线赛道的虚拟信号序列,同时用串口绘制三条曲线:水平差分值、垂直电感值、重构后的误差值。三条曲线应该呈现这样的关系:垂直电感出现双峰的同时,水平差分值跌入无效区;重构误差在垂直电感双峰期间保持平滑,没有阶跃;水平差分值恢复正常后,重构误差与传感器误差的差值小于 0.05。若差距过大,检查特征库中的基础偏差是否标定正确。
最后的提醒:折线电磁组的调试瓶颈不在单片机算力,而在人对信号的感知速度。把归一化、动态阈值、双峰判据、误差重构、特征库串成一条可以逐级观测的信号链,每一级都用串口绘图确认,任何异常都能定位到具体环节。赛场上真正跑出优势的,不是把每个弯都吃满,而是让每个折线前的 30 厘米都被充分利用。
本文还有配套的精品资源,点击获取