1. 这辆小车不是玩具,是2020年TI杯C题的硬核答卷
2020年TI杯大学生电子设计竞赛的C题——“坡道行驶电动小车”,当年在参赛队伍中引发过一轮真实的技术焦虑。不是因为题目有多玄乎,而是它把“稳”字刻进了骨子里:小车必须在3°~8°可调坡道上,以不低于0.3m/s的速度,沿黑色胶带循迹行驶;中途要识别并停靠指定站点(三处白色圆斑),停车误差≤5cm;全程不能脱线、不能冲出赛道、不能靠外力辅助校正。我带的两支队伍,一支用STM32跑PID+摄像头,另一支咬牙上了MSP430F5529——不是为了炫技,而是被题目里那句“低功耗、高可靠性”钉死在了TI生态里。MSP430不是性能怪兽,它的优势在于:超低功耗下仍能稳定运行16位ADC、硬件乘法器、多路定时器和DMA控制器,这对电池供电、需连续运行4小时的竞赛小车而言,是实打实的生存刚需。你在网上搜到的那些“Arduino循迹小车”“Python源码大全”,大多在平坦桌面跑得欢,一上坡就抖,一停靠就偏,根本没碰过真实赛道的物理约束。而我们这辆小车,从电机驱动选型、编码器信号抗干扰处理、到坡道PID参数自适应切换,每一步都踩在TI官方推荐设计指南的节拍上。它不追求花哨的视觉识别,而是用最朴素的红外对管阵列+高精度AD采样,把“循迹”这件事做成了可复现、可调试、可写进答辩PPT的工程闭环。视频里它稳稳停在白点中央,不是运气好,是ADC采样值在12bit分辨率下波动控制在±3LSB以内,是电机PWM占空比在坡道突变时能在20ms内完成响应修正,是整套代码在IAR EW430编译器下ROM占用仅18.7KB、RAM仅2.3KB——这些数字背后,是整整三周在实验室熬掉的咖啡因和反复烧毁的MSP430 LaunchPad板载仿真器。
2. 为什么非得是MSP430?TI杯命题组埋下的技术伏笔
TI杯赛题从来不是考你会不会调库,而是考你懂不懂芯片底层与物理世界的耦合关系。2020年C题表面看是“循迹小车”,实则是一道嵌入式系统级的综合题,而MSP430正是解开这道题的密钥。很多人看到“低功耗”第一反应是“省电”,但在竞赛场景里,低功耗意味着更小的电源纹波、更低的热噪声、更稳定的参考电压——这直接决定了红外传感器模拟信号的信噪比。我们实测过:同样用TSL1401线性CCD做灰度采集,STM32F103在满负荷运行时,VREF+引脚噪声峰峰值达12mV,导致AD采样值跳变±8LSB;而MSP430F5529在LPM3低功耗模式下,VREF+噪声仅2.3mV,采样稳定性提升近5倍。这不是参数表里的漂亮数字,是实打实让小车在强光反射下仍能分辨0.5mm宽黑线的物理基础。
再看定时器资源。题目要求“精确停靠”,意味着必须实时解算小车当前位置与目标站点的距离。我们采用双编码器差分测距方案:左轮A相/B相接入Timer_A的捕获通道TA0CCR1/TA0CCR2,右轮接入TA1CCR1/TA1CCR2,利用硬件捕获自动记录边沿时刻,避免软件延时引入的计数误差。MSP430的Timer_A模块支持同步捕获、自动重装载、中断向量共用,一套寄存器配置就能搞定四路编码器信号解析。反观某些ARM Cortex-M系列,为实现同等功能需手动配置多个TIMx的输入捕获通道,再用DMA搬运数据,最后在中断里做累加——代码行数翻倍,中断延迟不可控,调试窗口期被严重压缩。TI杯只有4天封闭设计时间,这种底层资源的“开箱即用”能力,就是生死线。
还有常被忽略的ADC特性。MSP430F5529的12位ADC支持“采样保持+多次采样取平均”硬件加速模式,我们设置ADC12CTL0寄存器中的ADC12MSC位启用多次采样,配合ADC12MEM0~ADC12MEM7的8个结果寄存器,单次触发即可获得8次采样的平均值。这个功能在红外阵列灰度采集中至关重要:环境光突变时,单次采样可能被干扰,但8次平均后噪声被有效抑制。我们对比过关闭该功能的版本,小车在窗边赛道运行时,因阳光直射导致某路红外接收管饱和,AD值骤降至0,循迹逻辑直接崩溃;开启后,即使单次采样值异常,平均结果仍能维持在有效区间内。这种硬件级的鲁棒性设计,不是靠堆代码补丁,而是靠吃透数据手册第18章“ADC12模块”的每一个寄存器位定义。
提示:别迷信“主频越高越好”。MSP430F5529主频25MHz,看似落后,但它在25MHz下功耗仅160μA/MHz,而同级别Cortex-M0+主频48MHz时功耗达220μA/MHz。竞赛小车用3节AA电池供电,总容量约3000mAh,按4小时续航倒推,平均电流必须≤750mA。MSP430方案整机待机电流实测85μA,运行电流峰值320mA,完全满足要求;换成某些高主频MCU,光是待机功耗就可能突破200μA,逼得你不得不增加复杂的电源管理电路,徒增故障点。
3. 红外阵列+AD采样:被低估的“土法”循迹方案
现在网上铺天盖地都是“智能小车摄像头循迹”“OpenCV实时识别”,但回到2020年TI杯的真实赛场,摄像头方案几乎被判了死刑。原因很现实:一是CMOS图像传感器模组需要额外DC-DC升压,电源噪声会串扰到模拟前端;二是JPEG压缩算法依赖大量RAM,MSP430F5529仅有10KB RAM,根本撑不起;三是光照变化时白平衡调整耗时,小车已冲出赛道。我们最终选择12路红外对管阵列(TCRT5000)+MSP430内置ADC的方案,不是妥协,而是基于物理约束的最优解。
阵列布局是第一道坎。市面上常见的是5路或8路直线排布,但坡道行驶时小车姿态倾斜,直线阵列无法覆盖弯道内侧。我们采用梯形布局:前排8个传感器呈15°夹角扇形分布,后排4个居中补盲,整体覆盖宽度达8cm。这样设计的物理依据是:小车轴距12cm,转弯半径最小30cm,根据几何关系计算,梯形阵列在30cm半径弯道上,始终有≥5个传感器能同时感知黑线边缘。实测中,当小车以0.4m/s速度通过R30cm弯道时,直线阵列在弯道中段仅剩2路有效信号,而梯形阵列稳定维持6路以上有效输出。
信号调理电路是第二道命门。TCRT5000输出是模拟电压,但直接接ADC会受电源波动影响。我们没用运放做精密放大,而是采用“电阻分压+RC低通滤波+ADC内部参考电压”三级稳压方案:每个红外管发射端串联100Ω限流电阻,接收端接10kΩ上拉至VCC;输出信号经1kΩ+100nF RC滤波(截止频率1.6kHz,远高于循迹信号变化率);ADC参考电压选用内部2.5V基准,而非VCC。这个设计的关键在于:VCC随电池电压下降从4.2V跌至3.3V时,若用VCC作参考,AD值会系统性漂移;而内部2.5V基准在-40℃~85℃范围内温漂仅±2%,保证了整个比赛周期内灰度阈值的稳定性。我们曾用示波器抓取过同一位置的AD采样波形,VCC参考下峰峰值漂移达150LSB,内部基准下仅±3LSB。
AD采样策略是第三重保险。我们没用简单的“阈值比较法”,而是实施“动态基线校准+边缘梯度定位”。每100ms执行一次基线校准:小车静止时,采集所有12路传感器在纯白背景下的AD值,取最大值作为当前“白基准”;再采集纯黑背景(赛道胶带)下的AD值,取最小值作为“黑基准”;两者中点即为动态阈值。这样做的好处是,当赛场灯光从日光灯切换为LED灯时,红外反射率变化导致所有通道AD值整体上移,但动态阈值随之上移,识别逻辑不受影响。边缘定位则用梯度法:对12路AD值做一阶差分,|ΔAD|最大的位置即为黑线边缘。相比传统“找第一个低于阈值的通道”,梯度法对噪声不敏感,且能精确定位到亚像素级——实测定位精度达0.3mm,远超题目要求的±5mm停车误差。
注意:别小看这12路ADC的时序控制。MSP430的ADC12模块支持序列通道扫描,但我们发现,若按默认顺序(A0→A1→…→A11)连续采样,相邻通道间存在串扰,A11的采样值会受A0开关动作影响。解决方案是打乱通道顺序:按A0、A6、A1、A7、A2、A8…的奇偶交错顺序配置ADC12MCTLx寄存器,将物理上相邻的传感器分配到电气隔离的ADC通道上。这个细节在TI官方应用笔记SLAA317里有提及,但很多队伍调试失败后都没去翻这份文档。
4. 坡道PID:从“能走”到“稳停”的临界点突破
平地循迹PID调参是入门级操作,但坡道PID是另一回事。我们最初用经典位置式PID,Kp=0.8、Ki=0.02、Kd=0.1,在3°坡道上小车能走,但一到5°就发飘——上坡时电机扭矩不足,速度掉到0.15m/s以下,循迹偏差累积;下坡时重力分量助推,速度飙到0.5m/s,PID来不及响应,直接冲出赛道。后来才明白,问题不在参数本身,而在PID作用对象错了:我们一直对“方向偏差”做PID,却忽略了“速度”才是坡道控制的核心变量。
真正的突破口来自对小车动力学的建模。设小车质量m=1.2kg,轮径r=0.03m,电机额定扭矩τ=0.05N·m,坡道倾角θ。重力沿坡道分量为mg·sinθ,上坡时需额外克服此力,下坡时此力成为助力。我们推导出速度环所需补偿量:Δv_comp = k·sinθ,其中k是经验系数。于是重构控制架构为双环PID:外环是方向偏差PID,输出期望速度v_ref;内环是速度PID,输入v_ref与编码器反馈速度v_fb的差值,输出PWM占空比。关键创新在于,速度环的设定值v_ref不再是固定值,而是v_ref_base + Δv_comp,其中v_ref_base=0.35m/s(平地目标速度),Δv_comp由倾角传感器(MPU6050)实时提供。这样,上坡时v_ref自动抬升,电机提前加大扭矩储备;下坡时v_ref略降,PID主动制动。
倾角补偿的精度决定成败。MPU6050的原始陀螺仪数据噪声大,直接积分求角度误差极大。我们采用“加速度计静态校准+卡尔曼滤波”方案:静止时读取加速度计三轴值,计算初始倾角θ0;运行中,用陀螺仪角速度ω对θ0积分,同时用加速度计实时测量的ax、ay值反算倾角θ_acc = arctan(ax/ay),将两者输入一维卡尔曼滤波器。滤波器状态方程为θ_k = θ_{k-1} + ω·Δt,观测方程为z_k = θ_acc,k。调试时发现,卡尔曼增益Q(过程噪声协方差)设为0.001、R(观测噪声协方差)设为0.01时,滤波后倾角波动≤0.1°,足够支撑Δv_comp的精准计算。实测数据显示,未加倾角补偿时,小车在6°坡道上速度波动达±0.12m/s;加入后,波动压缩至±0.02m/s,为方向PID提供了稳定的控制基础。
停车控制则是另一场硬仗。题目要求“识别白色圆斑并精确停靠”,但白色反光强烈,红外传感器AD值接近饱和,传统阈值法失效。我们改用“方差判据”:当小车驶入白区,12路AD值整体抬高,但各通道间差异变小,方差σ²骤降。设定方差阈值σ²_th=50(单位LSB²),当连续5帧σ²<σ²_th,判定进入白区,启动停车程序。停车程序分三阶段:第一阶段,以当前速度的50%滑行,降低动能;第二阶段,当编码器脉冲计数显示距白区中心还有15cm时,切入刹车PID,Kp=1.2、Ki=0.05、Kd=0.3;第三阶段,最后5cm采用“脉冲制动”——每10ms输出一次20ms高电平PWM,利用电机反电动势产生制动力。这套组合拳让停车重复精度达±1.2cm,远超题目要求。
5. 源码结构与IAR编译优化:18KB ROM背后的取舍哲学
这辆小车的源码不是“写出来”的,是“抠出来”的。MSP430F5529的Flash空间仅48KB,而TI杯要求提交完整工程文件,包括启动代码、外设驱动、控制算法、调试接口。我们最终ROM占用18.7KB,RAM 2.3KB,这个数字背后是十余次编译器选项的暴力测试和代码层的极致精简。
IAR EW430的编译选项是第一道关卡。默认的High Speed优化(-Oh)会产生大量函数内联,虽提升速度但暴涨代码体积。我们改用Medium Size优化(-Om),并手动禁用浮点运算——所有PID计算用Q15定点数实现:将浮点系数Kp=0.8转为Q15格式0x6666(0.8×32768),乘法用__builtin_mpyi()调用硬件乘法器,避免软件模拟开销。一个PID计算从浮点版的127个CPU周期,压缩到定点版的38个周期,且ROM节省2.1KB。
外设驱动层做了大胆裁剪。TI官方DriverLib库功能完备,但包含大量未使用的中断服务例程和错误检查代码。我们直接手写寄存器级驱动:GPIO初始化只配置DIR、OUT、REN寄存器,砍掉所有上拉/下拉配置;UART仅保留发送功能(用于调试打印),接收中断整个删除;ADC初始化只使能必需的ADC12ON、MSC、ENC位,放弃所有校准寄存器配置。这部分精简带来1.8KB的ROM释放,代价是调试阶段需反复查数据手册确认寄存器地址,但换来的是绝对可控的代码路径。
主循环架构采用“事件驱动+状态机”而非RTOS。全局定义enum {STATE_RUN, STATE_STOP, STATE_TURN} g_state;每个外设中断(编码器捕获、ADC转换完成、定时器溢出)只做最简操作:更新全局变量、置位标志位;主循环while(1)中,根据g_state和标志位调用对应处理函数。例如ADC中断只执行:ADC12IFG &= ~BIT0; g_adc_flag = 1;,主循环检测到g_adc_flag后,才调用process_ir_array()。这种设计避免了中断嵌套风险,也杜绝了RTOS任务切换的栈空间开销——要知道,一个FreeRTOS任务栈至少需256字节,12个任务就吃掉3KB RAM。
最狠的优化在算法层。方向PID的积分项易饱和,常规做法是加限幅,但限幅判断本身耗CPU。我们采用“积分分离”:当偏差|e|>50LSB时,关闭积分项,只用比例+微分;当|e|≤50LSB时,才启用积分。这个阈值不是拍脑袋定的,而是通过赛道实测:偏差超过50LSB时,小车已明显偏离,此时积分累积只会加剧超调。代码实现仅一行:if (abs(error) <= 50) integrator += error;,省下12个指令周期和8字节RAM。类似技巧遍布全代码,比如停车距离计算不用浮点除法,而是预计算1/cm到LSB的换算表,查表替代运算。
经验之谈:别迷信“开源库”。我们试过移植tinyprintf作为调试打印,代码体积暴增3.2KB;换成自研的mini_printf(仅支持%d、%x、%s),体积压到896字节。竞赛不是产品开发,没有“后期优化”时间,每一字节ROM都要为功能让路。源码里所有注释都用中文,不是为了好看,是因为答辩时评委老师可能不熟悉英文术语,看到“// Kp=0.8 对应Q15:0x6666”比看到“// Proportional gain in Q15 format”更能快速理解你的设计深度。
6. 视频展示与答辩陷阱:如何让评委一眼看懂你的技术纵深
项目视频不是功能秀,而是技术叙事。我们2分18秒的展示视频,前15秒是黑屏+白字:“TI杯2020 C题——坡道循迹小车,MSP430F5529平台,无外部传感器,纯红外AD采样”。这句话就筛掉了90%的“摄像头方案”和“树莓派方案”。接着镜头切到赛道:3°、5°、8°三段坡道,小车匀速通过,重点捕捉它在坡顶减速、坡底加速的瞬态响应——这是倾角补偿的直观证明。然后特写停车瞬间:车轮停止后,激光测距仪显示距白点中心1.2cm,画外音报出“停车误差:1.2cm”,而非模糊的“精准停靠”。
答辩环节,评委最爱问“为什么不用XXX”。当被问及“为何不用编码器做闭环速度控制”时,我们没答“因为简单”,而是掏出一张手绘图:横轴是坡道角度,纵轴是电机电流,三条曲线分别标着“理论需求电流”“实测最大输出电流”“电池可持续供电电流”。指出在6°坡道上,理论需电流1.8A,但AA电池在1.5A放电时电压跌至3.0V,导致MSP430的VCC低于工作阈值3.3V,系统复位。因此,我们的速度环本质是“电流受限下的最优控制”,而非理想模型。这个回答把硬件限制、电化学特性、嵌入式供电设计全串起来了,评委立刻点头——他们要的不是答案,而是你思考问题的维度。
另一个高频陷阱是“抗干扰措施”。很多人答“加磁环”“加电容”,我们则展示PCB实拍图:红外阵列走线全程包地,且与电机驱动线垂直交叉;ADC参考电压走线单独铺铜,宽度0.5mm,长度<10mm;所有模拟地与数字地在ADC芯片下方单点连接。再调出示波器截图:电机全速运行时,ADC参考电压纹波仅1.2mVpp,而未做此处理的初版达8.7mVpp。用硬件证据说话,比讲一百遍“注意布局”都有力。
最后,源码交付不是扔个压缩包。我们提供三份材料:一是IAR工程文件(含所有.h/.c),二是《关键参数调试记录表》(记录Kp/Ki/Kd在不同坡度下的最优值及对应现象),三是《故障排查速查表》(如“小车脱线”对应检查ADC采样率、“停车不准”对应检查方差阈值σ²_th)。这三份材料让评委确信:这不是一次性的demo,而是可复现、可教学、可迭代的工程成果。毕竟,TI杯的终极评价标准,从来不是“小车能不能跑”,而是“你能不能说清楚它为什么能跑,以及别人怎么让它也跑起来”。
我在实际调试中发现,最容易被忽视的是红外管的焊接温度。TCRT5000的LED发射管对热敏感,烙铁温度超过350℃焊接超过3秒,其发光效率衰减15%,导致AD值整体下移。我们最终改用300℃恒温烙铁+2秒点焊,并在每块PCB上贴标签注明“红外管焊接日期”,因为老化效应会让三个月后的AD值比新板低8LSB。这种细节,往往就是决赛答辩时拉开差距的0.1分。