简介:面向嵌入式初学者和电子竞赛选手的STM32智能小车寻迹避障方案,覆盖硬件原理图、C语言工程代码与调试说明,适合课程设计、毕业设计或科创项目快速起步。整套资源共181个文件,压缩包约2.05MB;主体为74个.c源文件和78个.h头文件,包含基于STM32标准外设库的定时器PWM、超声波测距、OLED显示、GPIO与中断等驱动模块,另有PDF原理图/说明文档及hex固件,方便直接烧录验证。已有2991人学习下载,在同类资料中具有较高参考价值。资源亮点在于不仅给出主控板原理图与硬件连接方法,还提供完整的Keil工程,读者可边读源码边调试,理解寻迹时灰度传感器如何判断黑线位置、避障时超声波如何计算距离并控制转向。通过实践可掌握电机PWM调速、外部中断响应、滤波及PID调节等嵌入式核心技能,从而独立完成一辆具备自主循迹与避障能力的智能小车。
1. 需求分析与方案选型:赛道工况下的主控抉择
做小车项目,十有八九的翻车点不在算法,而在你没想过电池电压掉到 6V 以下时电机还转不转、灰度传感器还准不准。这套基于 STM32F103C8T6 的智能小车方案,目标很直接:把寻迹和避障两件事做到像一个职业选手,而不是跑马灯式 if 判断。它面向的是课程设计要交实物、比赛要出成绩、或者刚从 51 平台想升级到 32 位平台的人。方案里除了完整代码,还有 PCB 原理图,能让你从画板、布线、焊板、调参四个环节少走弯路。你需要的是一个能闭眼照做、又知道为什么这样做的完整参考。
为什么不用 51?不是 51 做不了寻迹,而是寻迹加避障同时存在时,51 的定时器资源和中断优先级会变成瓶颈。STM32 两个高级定时器出 PWM,一个输入捕获收超声波回波,还能留一个串口打印调试信息。这套方案选型时就按"三路灰度传感器 + 超声波避障 + 双路直流电机"的固定搭配来设计,所有引脚分配、代码结构、原理图模块都围绕这个组合展开。
2. 硬件架构与原理图设计:电源树、电机驱动与传感器接口的工程实现
原理图不是一个"能跑就行"的连线图,它是整个系统可靠性的第一道闸门。我一般先画电源树,再画最小系统,最后才是电机驱动和传感器接口。顺序不能反,反了就会出现"原理图看着通,样板一上电就复位"的怪问题。
2.1 主控最小系统与引脚分配
STM32F103C8T6 最小系统包含四部分:8MHz 外部晶振加两个 20pF 负载电容、NRST 复位引脚上拉 10K 电阻并联 104 电容、BOOT0 下拉接地进入 Flash 启动模式、3.3V 电源引脚就近放 100nF 去耦电容。这部分是芯片运行的地基,晶振走线要靠近 MCU,尽量不走长线过孔,否则容易起振不稳或者辐射干扰传感器。
引脚分配是所有硬件设计的前置决策,我在这份方案里按功能域做分区,避免 PWM 输出和传感器输入挤在同一个 GPIO 端口导致信号串扰:
角色分配上,PA6、PA7 接左电机 PWM,PB0、PB1 接右电机 PWM,PB3、PB4、PB5 接三路灰度传感器数字输出,PA0、PA1 接超声波 Trig 和 Echo,PA2 接舵机信号线。串口 1 的 PA9、PA10 留作调试口,不接任何功能外设。这样分配的原因是:PWM 通道集中在定时器 TIM3 的通道 1/2 和 TIM4 的通道 3/4,灰度输入放在没有重映射争议的 PB 口,后续无论是用标准库还是 HAL 库写初始化代码,都不用处理 AFIO 重映射,减少一个隐藏配置点。
2.2 电源树设计:三路电压轨与电流预算
小车用两节 18650 锂电串联,标称 7.4V。这个电压不能直接进单片机,也不能直接给舵机,所以电源树需要分出三个电压轨:7.4V 直接给电机驱动模块的 VM 引脚,保证电机有足够的电压摆幅;7.4V 经过 LM2596 降压模块出 5V,给舵机和超声波模块供电;5V 再经过 AMS1117-3.3 出 3.3V,给 STM32 和灰度传感器。两级降压看起来啰嗦,但能避免舵机堵转瞬间的电压跌落直接拉垮主控供电。
电流预算是原理图里最容易被忽视的数字。两个 TT 马达空载电流各约 150mA,堵转电流能冲到 800mA 以上,舵机打角瞬间电流约 300mA,超声波模块约 15mA,STM32 整板不超过 50mA。合计峰值电流接近 2A,所以电池必须用容量 2000mAh 以上的动力型电芯,普通的干电池组在堵转瞬间电压会掉到 5V 以下,导致 LM2596 直接进入欠压保护,现象就是小车一上坡就复位。
电源地的处理是这套原理图的一个关键细节:电机驱动的地线、电池负极、逻辑地必须单点汇合,不能把电机的回流通路和灰度传感器的地线串在一起。我见过不少同学直接把所有 GND 画成一坨网络,结果电机一转,灰度传感器读到全黑全白乱跳,那不是硬件坏了,是地线被电机电流抬起了一个不稳定偏移。
2.3 电机驱动模块:驱动器选型与 PWM 通道匹配
电机驱动是原理图中电气特性最"重"的部分。常见的 L298N 模块压降接近 2V,7.4V 供电到电机两端只剩 5.4V,转速明显偏软,而且 L298N 的使能引脚必须接高电平才能输出,逻辑电平是 5V,STM32 的 3.3V 高电平虽然能兼容,但长期运行存在不确定性。所以我在这份方案里选了 TB6612FNG,它的导通内阻只有 0.5Ω 左右,同样 7.4V 供电下电机端电压损失小,而且可以直接用 3.3V 逻辑驱动。
TB6612 与 MCU 的接线方式很固定:VM 接电池正极,VCC 接 3.3V(要求 VCC 同时给逻辑和传感器供电的情况下,内部电平转换才稳定),GND 接电源地,AIN1、AIN2、PWMA 控制左电机,BIN1、BIN2、PWMB 控制右电机。STBY 引脚必须接 3.3V 拉高,否则驱动器所有输出为高阻态,电机完全不动。这是一个非常隐蔽的坑,原理图里如果漏画 STBY 的上拉,焊接完你会发现小车怎么推都不走。
原理图上的 PWM 通道要按"一个电机占用一个定时器"的思路分配,两个电机不要共用同一个定时器的不同通道。虽然理论上可行,但一旦你想在代码里用独立中断分别处理两个电机的调速,共用一个定时器意味着两个通道共用一个时基,调整范围会互相锁住,排查起来非常痛苦。
2.4 传感器接口电路:灰度与超声波的电气匹配
三路灰度传感器用 TCRT5000 反射式红外模块,模块上自带电位器调节阈值。原理图层的设计要点是:传感器输出信号线不用加任何阻抗匹配,直接进 MCU 的 GPIO,因为模块内部已经做了比较器整形,输出是 0/3.3V 的数字电平。关键在于调节电位的操作要在实际赛道上做,不是桌面上做——桌面反射率和磨砂地胶完全不一样。
超声波模块 HC-SR04 的电气匹配才是容易翻车的地方。它的 Trig 是输入引脚,3.3V 高电平足够触发;但 Echo 引脚是模块内部用 5V 逻辑输出的,直接接到 STM32 的 PA1 上,长时间运行有概率损坏引脚。方案里在 Echo 信号线上串联一个 1K 电阻,利用 MCU 输入引脚的钳位二极管做分压,把有效高电平拉到 3.3V 以内。这个电阻不能省,也不能用 10K,10K 会把波形边沿拉缓,超声波测距在近距离时回波宽度窄,边沿缓了会丢脉冲。
通常的做法是 Echo 串联 1K 之后,在 PA1 对地再并联一个 10K 下拉电阻,这样模块不输出时引脚电平是确定的,不会因为浮空误触发中断。HC-SR04 测距的最小盲区是 2cm,原理图布局时超声波探头面要超出车头 3cm 以上,否则绕行时车头先撞到障碍物,超声波还没测出距离。
3. 软件总体设计:寻迹与避障状态机的状态划分与控制律切换
代码不能上来就写,先画状态机。寻迹和避障同时存在时,如果写成顺序判断:先寻迹再测距,则遇到障碍时小车已经在执行转向控制,避障逻辑想改 PWM,寻迹逻辑也在改 PWM,两个控制律会在同一个周期里互相覆盖,表现就是小车左右猛摆然后冲出赛道。状态机把"当前唯一执行的控制律"锁死,是这套软件方案的核心。
3.1 系统状态定义与迁移条件
软件定义四个状态:IDLE、TRACKING、AVOIDING、BACK。上电后进入 IDLE,等待启动按键或者串口指令,避免上电瞬间灰度传感器误判造成小车直接冲出去。按下启动键后进入 TRACKING,此时执行寻迹差速控制。TRACKING 状态下超声波距离小于设定的避障阈值(默认 25cm),切换到 AVOIDING,执行原地左转避障动作。AVOIDING 持续一段时间后,如果灰度传感器重新压到黑线,切回 TRACKING 继续寻迹。
这里有一个容易漏掉的迁移:AVOIDING 状态下超声波距离又恢复正常了,但车头朝向和黑线还有角度,不能立刻切回 TRACKING,必须等灰度传感器确认压线。方案在 AVOIDING 退出条件里加了一个时间锁:进入 AVOIDING 至少 500ms 后才允许检查压线状态,防止小车刚转了个小角度就试图回线,结果在障碍物和黑线之间来回摆动。
3.2 三路灰度寻迹查表算法
三路灰度传感器一字排开,间距按赛道黑线宽度(约 18mm)的一半来布置,中间探头正对车头中心。传感器读回 3 个布尔值:左 L、中 C、右 R。正常压线状态只有五种:L=0,C=1,R=0 表示正中直行;L=0,C=1,R=1 表示略偏右,需向左微调;L=1,C=1,R=0 表示略偏左,需向右微调;L=0,C=0,R=1 表示严重偏右,需大角度左转;L=1,C=0,R=0 表示严重偏左,需大角度右转。
我把查表做成一个二维数组,而不是五个 if-else。数组索引就是三路灰度拼出的二进制值,例如 0b010 对应 2,数组元素是转向修正量 correction,范围从 -1000 到 +1000。负值表示左轮减速右轮加速,正值反之。用查表的好处是,后续你想把传感器从三路升级到五路,只需要扩展数组维度,不用重写控制逻辑。最关键的边界是 L=0,C=0,R=0,即全白丢线状态,这时候不执行任何转向修正,而是直行 200ms 后如果还没压线就停车,这个处理能避免小车在交叉路口或断线处原地打转。
3.3 超声波避障控制律:测距、滤波与绕行
超声波测距使用查询方式而不是中断方式。主循环里每 50ms 触发一次测距,Trig 引脚拉高 10us 以上,然后轮询等待 Echo 引脚上升沿和下降沿,用定时器计数值算出高电平时间,距离 = 高电平时间 × 0.034 / 2,单位厘米。
超声波数据偶尔会跳变,这是这个传感器天生的毛病——声波打到斜面或者软物体上,回波强度不够,Echo 可能提前结束。方案里对连续 3 次测距结果取中位数,排序后取中间值,这样比平均值更能抗单次野值。我一般会再叠加一个合理性检查:如果本次测距结果与上次相差超过 80cm,直接丢弃本次数据,用上一次的值。实际赛道上这个判断非常有效,能过滤掉大部分"下午三点阳光直射地面造成红外干扰"的玄学问题。
绕行动作分两段:先原地左转 90°,这个过程不依赖测距,靠定时器延时控制舵机和电机配合;转完之后前行一段距离,灰度传感器一旦重新压到黑线,就说明绕过了障碍物侧面,退出避障状态。如果前行 2 秒还没压线,把状态机强制迁移到 BACK,小车倒车回退 300ms 再继续尝试压线,这个后退动作能解决障碍物太宽导致的车头卡在侧面出不来问题。
3.4 舵机扫描策略与 PWM 占空比标定
避障决策需要知道障碍在左边还是右边,所以单纯测一个正前方距离不够用。方案让舵机每 500ms 扫描一次:先测正前方,然后左转 90° 测左边,再右转回正。舵机信号是 20ms 周期脉冲,占空比 0.5ms 到 2.5ms 对应 0° 到 180°。这个标定需要用示波器或者逻辑分析仪做一次,不要相信代码里"写 1.5ms 就是 90°"的说法,不同舵机的中间位置有偏差。
扫描结果用于选边:左边距离大于右边,避障绕行方向选左转,反之选右转。如果两边都小于 25cm,说明是死胡同,需要原地掉头 180°。舵机在扫描过程中,电机不做避障转向动作,否则车头动态摆动会让超声波的测距方向混乱,测出来的距离没有参考意义。
4. 核心代码实现:从寄存器配置到双功能闭环的调参细节
代码用标准外设库实现,这样在 Keil5 里的工程结构最简单,不需要 HAL 库的初始化耗时。整个工程划分成 main.c、motor.c、sensor.c、control.c 四个文件,main 只做调度,具体功能全部下沉到模块函数里,方便答辩时讲清楚分层。
4.1 定时器 PWM 初始化
电机的差速控制需要 4 路 PWM,用 TIM3 和 TIM4 各输出两路。初始化顺序有讲究:先配置 GPIO 复用模式,再配置定时器时基,最后使能 OC 输出,且要把初始占空比设为 0。反过来先使能输出再设占空比,上电瞬间电机就会猛转一下。
void Motor_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // PA6 PA7 左电机,PB0 PB1 右电机,全部复用推挽输出 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_Init(GPIOB, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = 999; // 16位自动重载值 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz / 72 = 1MHz TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 四个通道都配置成PWM1模式,输出极性高电平有效 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比必须为0 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC3Init(TIM4, &TIM_OCInitStructure); TIM_OC4Init(TIM4, &TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); TIM_Cmd(TIM4, ENABLE); }这段初始化的关键点在于预分频值 71 配合重载值 999,得到 PWM 频率是 1MHz / 1000 = 1kHz。这个频率是直流电机调速的甜点区:太低了电机能听到明显的"咔咔"声,太高了驱动模块的开关损耗变大。TIM_Pulse 初始化为 0 是防上电猛转的关键,配合主循环里启动前的延时,能保证电机在上电瞬间是完全静止的。
4.2 主循环状态调度
主循环不需要快速执行,50ms 一个周期足够,因为电机和舵机的机械响应都远慢于这个周期。把状态机迁移放在主循环开头,然后按当前状态执行对应控制函数。
while (1) { uint16_t dist = Ultrasonic_GetDistance(); uint8_t line = Line_GetStatus(); switch (car_state) { case STATE_TRACKING: if (dist < AVOID_THRESHOLD && line != 0b000) { car_state = STATE_AVOIDING; avoid_enter_tick = GetSysTick(); Servo_SetAngle(90); // 舵机回正,避免扫描角度干扰绕行 } else { Tracking_Control(line); // 查表修正差速 } break; case STATE_AVOIDING: Avoiding_Control(); // 左轮反转右轮正转,原地左转绕行 if (GetSysTick() - avoid_enter_tick > 500 && line == 0b010) { car_state = STATE_TRACKING; // 压线且时间锁解除,恢复寻迹 } break; default: break; } Delay(50); }避障状态里的时间锁是整套状态机的灵魂。没有这个 500ms,小车左转 30° 时灰度偶然压到黑线就会提前退出避障,结果车头还朝着障碍物方向就切回寻迹,下一轮测距又触发避障,形成"抖动绕行"的死循环。加上时间锁之后,AVOIDING 至少持续 500ms,保证车头转过足够角度再做压线判断。
4.3 寻迹修正函数与 PWM 限幅
查表修正的核心是把灰度状态映射成修正量,然后叠加到基础 PWM 上。基础 PWM 需要根据电池电压微调,如果电压从 7.4V 掉到 7.0V,基础值要往上加,否则速度会变慢。
static const int16_t Line_Correction[8] = { 0, // 000 全白,丢线状态,不修正 -1000, // 001 左二右一,严重右偏,向左急转 -600, // 010 中, 正中 -300, // 011 左中右, 微右偏 300, // 100 微左偏 600, // 101 左中右, 微左偏 1000, // 110 严重左偏 0 // 111 全黑,交叉线,直行 }; static void Tracking_Control(uint8_t line) { int16_t correction = Line_Correction[line]; int16_t left_pwm = BASE_PWM + correction; int16_t right_pwm = BASE_PWM - correction; if (left_pwm > PWM_MAX) left_pwm = PWM_MAX; if (left_pwm < PWM_MIN) left_pwm = PWM_MIN; if (right_pwm > PWM_MAX) right_pwm = PWM_MAX; if (right_pwm < PWM_MIN) right_pwm = PWM_MIN; Motor_SetLeft(left_pwm, MOTOR_FORWARD); Motor_SetRight(right_pwm, MOTOR_FORWARD); }查表数组的索引就是灰度传感器拼出的 3 位二进制数,比如左中右三路对黑线分别是 L=0 C=1 R=1,拼成 0b011 即十进制 3,查出来修正量 -300。注意数组里 111 全黑状态处理为直行,这是为了过十字交叉线时不误动作,但代价是如果三个传感器同时压黑线横向条纹,小车会冲出去。通常的做法是检测到 111 后只直行 150ms,然后强制切回正常寻迹逻辑。
4.4 超声波测距:查询模式下的定时器捕获
超声波用定时器 2 的输入捕获通道或者直接用 Delay 方式测宽也可以,但用查询 + 定时器计数值的方式精度更高。方案里让 TIM2 工作在计数模式,用 GetTick 获取系统时基来做超时保护。
uint16_t Ultrasonic_GetDistance(void) { uint32_t t_start, t_end; uint16_t distance; GPIO_SetBits(TRIG_GPIO, TRIG_PIN); // Trig 拉高 Delay_us(15); // 保持 15us GPIO_ResetBits(TRIG_GPIO, TRIG_PIN); // 拉低 while (GPIO_ReadInputDataBit(ECHO_GPIO, ECHO_PIN) == 0); // 等上升沿 t_start = TIM2->CNT; while (GPIO_ReadInputDataBit(ECHO_GPIO, ECHO_PIN) == 1); // 等下降沿 t_end = TIM2->CNT; distance = (t_end - t_start) * 0.034f / 2; if (distance > 400) distance = 400; // 超量程保护 return distance; }这段代码有两个必须注意的点。第一,等待 Echo 上升沿和下降沿的 while 循环要加超时保护,否则超声波的探头如果被异物挡住导致模块不工作,主循环会死在这个 while 上,整个小车失控。保护方式是初始化时设一个最大计数阈值,超过就直接返回 400cm 当作无障碍。第二,距离换算公式里的系数 0.034 是声速 340m/s 换成 cm/us 的结果,但实际声速随温度变化,如果要精确可以把系数改成 0.0343。课设场景下 0.034 够用,但答辩时导师问起这个常数来源要答得出来。
5. 常见问题排查与避坑指南:五个最易翻车的现场场景
小车项目最折磨人的不是写代码,是现场出了问题不知道从哪排查。一条条硬凑出来的经验,按"现象 → 原因 → 解决"的格式整理成清单,做方案时可以当检查表用。
5.1 现象:小车下地就跑飞,完全不走线
原因基本是灰度传感器的阈值调节方式错了。很多同学在桌面上调电位器,桌面反射率高,到磨砂地胶赛道上一测,所有探头的输出逻辑全反了。解决方法是每次换赛道环境都要重新校准:把探头贴在白底上旋转电位器到输出翻转的临界点,再往黑线的方向微调半圈,保证黑白两种表面有足够裕量。校准完不要急着跑,先用手推着小车沿黑线走一遍,串口打印三路传感器的原始值,确认状态序列 010-110-010 是平滑变化的。
5.2 现象:超声波测距偶尔跳变到 300cm 以上
这是 HC-SR04 的常见问题。声波碰到倾斜障碍物时反射面积变小,回波衰减严重,模块可能测到混叠的多径回波。整套方案不是改代码能根治的,正确做法是先确认超声波探头的朝向:必须正对小车前进方向,不要有任何下倾角,而且探头前方 3cm 内不能有挡板或支架。如果结构上没法避免,在代码中位数滤波的基础上加一个滑动窗口,取最近 5 次的中位数而不是 3 次,能把偶尔的野值彻底压掉,代价是响应变慢约 50ms,避障场景完全接受。
5.3 现象:电机驱动模块很烫,小车跑几分钟就复位
原因几乎都是电源余量不足。TB6612 的 VM 引脚直接接电池正极没错,但如果电池线用太细的杜邦线,电机启动瞬间线上压降能达到 0.5V 以上,驱动模块的欠压保护会误触发。解决方法是电机电源线换 22AWG 以上的硅胶线,而且从电池到驱动模块的路径上不要经过面包板,直接焊接。另一个常见原因是 PWM 频率太低导致驱动器工作在开关损耗较大的区间,把 PWM 频率从 1kHz 提到 10kHz 能显著降温,但要注意电机电感噪声会变大,需要给电机并联 104 电容。
5.4 现象:上电瞬间小车猛冲一下
这属于初始化顺序问题。要么是 GPIO 配置成推挽输出但默认电平是高,要么是定时器的 OC 使能和 TIM_Pulse 赋值顺序反了。解决方案已经写进 4.1 节的代码里:所有初始化函数执行完后,确保四个通道的 TIM_Pulse 都是 0,再统一使能定时器。另外在 main 函数开头要加一个 200ms 延时,等电源稳定后再操作 GPIO,这个细节能避开上电瞬间 3.3V 还没稳定时 GPIO 输出的随机电平。
5.5 现象:避障绕行不出去,原地转圈
原因是 AVOIDING 退出条件设计不完善。如果只判断"灰度压线",那小车绕行时会因为车头角度没转够,一直骑在线上,永远满足退出条件,但车头方向仍然对着障碍物,下一轮测距立刻又触发避障。解决方法是加 5.1 节提到的时间锁,同时调整绕行电机参数:左轮反转 PWM 值不要太大,原地旋转速度快会导致离心力让后轮打滑,反而转不过去。合适的策略是左轮 PWM 设为右轮的 30%,旋转角速度大约 90 度每秒,这样 500ms 时间锁加上压线判断,绕行轨迹是一个稳定的圆弧而不是急转。
6. 验收与答辩演示:功能测试清单、数据佐证与现场脚本
验收不能只在桌上跑两圈就完事,要按功能域拆开测,每个测试项都留下数据痕迹,答辩时直接展示日志而不是空口说"能跑"。
6.1 功能验收清单
按照寻迹、避障、电源三个维度组织测试表。寻迹测试覆盖直行、左弯、右弯、S 弯、十字交叉线五种轨迹,每项跑五次,记录通过次数和平均用时。避障测试分单障碍、连续双障碍、不对称摆放三种场景,记录是否成功绕行以及绕行用时。电源测试用万用表监测锂电池电压从 8.4V 放到 7.0V 的整个过程,确认最低工作电压下车速下降不超过 20%,否则说明基础 PWM 值需要随电压做补偿。
每项测试通过的标准要量化:寻迹直行偏差不超过 3cm,S 弯不压线不冲出;避障绕行后能回到原赛道延长线,偏离不超过 10cm。这些数字在答辩现场用卷尺一量就能证明。
6.2 答辩演示脚本
现场演示的顺序有讲究:先跑寻迹完整一圈,让观众建立"这车会按线走"的认知;然后加一个障碍物,重点展示"减速 → 测距 → 转向 → 压线恢复"的完整过程。演示前用串口把实时灰度状态和距离值打到屏幕上的工程窗口,这个画面比口头解释强十倍,能看到传感器读到 010 时小车直行、读到 001 时左轮加速。
6.3 导师追问准备与数据佐证
最可能被问到的问题是"如果你的超声波模块坏了,小车会怎样"和"为什么不用编码器做闭环"。前一个问题的正确答案是:代码里超声波超时返回 400cm,小车会直行,属于"故障降级"而非"失控撞墙";后一个问题要承认开环方案的局限,同时说明三个灰度传感器本身构成了一条负反馈回路,已经具备基本的纠偏能力,编码器闭环是这套平台预留的升级方向,不是缺陷。
从那以后我每次做小车类项目,都会强制自己先画一遍电源树和引脚分配表再动原理图,焊完板子先测电压再刷程序,这个习惯救过我太多次了,希望帮到你。
本文还有配套的精品资源,点击获取