从电赛F题复现到智能车系统设计:STM32与OpenMV的工程实践

📅 2026/8/27 4:48:04
从电赛F题复现到智能车系统设计:STM32与OpenMV的工程实践
1. 项目概述从“复现”到“精进”的暑期实践每年暑假对于电子、自动化、通信等相关专业的学生来说都是一个绝佳的“练级”窗口期。而全国大学生电子设计竞赛简称“电赛”的国赛题目无疑是这个窗口期里最具挑战性和含金量的“副本”。2022年夏天我带着几个学弟学妹没有选择去追逐最新的热点而是回过头来决定“简单实现”2021年的电赛国赛题目。这个决定背后其实有我们自己的考量新题固然吸引眼球但往往资料零散、思路未经验证容易陷入“开荒”的迷茫而上一年的赛题经过一年的沉淀网上有大量参赛队的开源方案、技术报告甚至“踩坑”实录这为我们提供了一个近乎完美的“高完成度学习样本”。我们的目标不是简单地“抄作业”而是通过亲手复现去逆向拆解优秀作品的设计思路理解每一个元器件选型、每一行代码逻辑、每一个调试技巧背后的“为什么”从而把别人的经验真正内化成自己的肌肉记忆。这个过程远比单纯做一个新项目更能夯实基础、锻炼系统性工程思维。如果你也正处在技术成长的平台期或者对电赛充满好奇但不知从何下手那么跟随我们一起复盘这次“旧题新做”的旅程或许能给你带来不少启发。2. 核心思路与方案选型为何选择2021年F题“智能送药小车”2021年电赛国赛题目共有七道涵盖了电源、测控、通信、仪器等多个方向。经过团队讨论我们最终选择了F题“智能送药小车”作为我们的实践对象。选择它主要基于以下几点考量首先它是一个典型的“系统集成”型题目。题目要求设计一辆小车能够在模拟医院病房的赛道上循迹行驶并准确识别病房编号将“药品”用砝码模拟送达指定病房最后返回出发区。这短短几句话的描述背后涉及了机械结构、运动控制、传感器融合、图像识别、路径规划等多个技术模块。对于学习者而言这样一个项目就像一台精密的仪器拆开它能让你同时接触到嵌入式开发、自动控制、机器视觉等多个领域的核心知识综合性极强。其次技术栈成熟且开源资源丰富。智能车是电赛的常客基于STM32或OpenMV的循迹、避障、识别方案经过多年迭代已经非常成熟。2021年赛后各大高校和开源社区涌现了大量关于这道题的详细解题报告、代码仓库和视频讲解。这意味着我们在实现过程中遇到的大部分技术问题都能找到参考可以把更多精力放在“理解”而非“从零创造”上学习效率更高。最后具有极高的可扩展性和趣味性。“送药小车”本身就是一个很好的应用场景原型。在实现基本功能后我们完全可以对其进行扩展比如增加无线通信实现上位机监控、加入语音播报提示、设计更高效的调度算法等。这让项目不至于停留在“复现”层面而是有了持续迭代和创新的空间能保持团队的学习热情。基于以上思路我们确定了项目的核心实现方案以STM32F4系列单片机作为主控制器负责小车的运动控制、传感器数据融合和任务调度使用OpenMV Cam H7作为视觉模块专门处理赛道循迹线和病房编号识别车体则选用结构稳固、易于改装的四轮麦克纳姆轮小车底盘。这个方案在性能、成本和开发难度上取得了较好的平衡是当时众多参赛队的主流选择之一。3. 系统设计与模块拆解要实现一辆合格的智能送药小车必须将其分解为若干个相对独立又协同工作的子系统。我们的设计主要分为五大模块主控与电源模块、视觉感知模块、运动执行模块、机械执行机构取放药机构以及决策与调度模块。3.1 主控与电源模块系统的“大脑”与“心脏”主控芯片我们选择了意法半导体的STM32F407ZGT6。这款芯片属于F4系列高性能微控制器拥有Cortex-M4内核主频高达168MHz并具备浮点运算单元FPU。这对于需要处理多路传感器数据、进行浮点运算如PID控制的应用来说至关重要。其丰富的片上资源多个定时器、USART、SPI、I2C、ADC也为我们连接各种外设提供了便利。注意虽然STM32F103“蓝桥杯”常用款成本更低但其主频和计算能力在处理图像串口数据、运行复杂控制算法时会显得捉襟见肘。F407在项目后期进行算法优化和功能扩展时能提供更充裕的性能余量避免因主控瓶颈导致整个系统卡顿。电源管理是保证系统稳定运行的基石。我们的小车系统包含多个电压需求不同的部件电机驱动模块如TB6612需要7.2V-12V的直流电压。STM32主控、OpenMV、舵机、传感器通常需要5V或3.3V电压。因此我们采用了一节2S锂电池7.4V作为总电源。通过一个大电流降压模块如LM2596可调模块将电池电压稳定至5V为大部分数字器件供电。STM32和部分传感器所需的3.3V则通过STM32开发板上自带的LDO低压差线性稳压器从5V转换得到。务必确保电源模块的输出电流能力足够特别是电机启动瞬间电流很大如果电源带载能力不足会导致电压瞬间跌落引起单片机复位小车“猝死”。3.2 视觉感知模块小车的“眼睛”视觉模块负责两大核心任务赛道循迹和数字识别。我们选用OpenMV Cam H7它内置了强大的图像处理库可以直接在摄像头模块上用Python脚本完成复杂的视觉算法并通过串口将结果如偏移量、识别到的数字发送给STM32主控极大减轻了主控的计算压力。1. 赛道循迹策略赛道路径通常由黑色电工胶带贴在白色KT板上构成。我们采用经典的灰度传感器摄像头辅助的方案。基础循迹在车头底部安装一排通常5个红外对管灰度传感器。它们返回的是数字量0或1代表白或黑响应速度快用于实现最基础的PID巡线控制保证小车能紧贴黑线行驶。复杂路径处理当遇到十字路口、直角弯、起止线等特殊元素时灰度传感器的信息就不够用了。这时需要OpenMV出场。我们在OpenMV上编写脚本实时拍摄车头前方的图像通过颜色阈值分割提取黑色轨迹线并计算其重心或角度。例如在十字路口OpenMV会识别到横向黑线并发送一个“到达路口”的指令给STM32STM32再根据任务要求决定直行、左转还是右转。2. 病房编号识别策略病房编号是打印在赛道路旁的数字卡片。我们采用模板匹配的方法进行识别。赛前我们用OpenMV拍摄所有可能出现的数字0-9样本制作成模板图片库。在行驶过程中OpenMV持续对特定区域ROI进行搜索与模板库进行匹配并返回匹配度最高的数字结果。为了提高识别率和速度我们做了以下优化图像预处理先对图像进行二值化、腐蚀、膨胀等操作去除噪点突出数字轮廓。ROI限制根据小车与数字卡的相对固定位置划定一个较小的搜索区域避免对全图进行无谓的搜索大幅提升处理帧率。多次验证不是识别到一次就采信而是连续识别到3次相同的数字才确认避免因光线抖动或图像模糊导致的误判。3.3 运动执行模块精准的“手脚”小车的运动由四个直流减速电机驱动每个电机由一个TB6612FNG双路电机驱动芯片控制。STM32通过定时器产生PWM波控制电机速度通过GPIO控制电机的方向。运动控制的核心是PID算法。我们为巡线控制设计了一个双环PID系统内环速度环每个电机都有一个独立的PID控制器用于让电机的实际转速精确跟随目标转速。这能抵消不同电机之间的细微差异保证小车走直线时不跑偏。编码器反馈的实际转速作为输入。外环位置环/方向环根据灰度传感器或OpenMV计算出的车体与黑线的横向偏差通过一个PID控制器计算出小车的目标转向角再将其分解为左右轮的速度差。例如偏差偏左则控制右轮加速、左轮减速使小车向右调整。PID参数的整定调整Kp Ki Kd三个系数是一个“玄学”但至关重要的过程。我们的经验是先P后I再D。先给一个较小的Ki和Kd比如0逐渐增大Kp直到小车出现明显的左右振荡然后加入一点Kd来抑制振荡最后加入Ki来消除静态误差小车始终无法对准黑线中心。整定最好在赛道上实时进行观察小车的响应。3.4 取放药机械机构设计最后的“临门一脚”题目要求小车能将一个圆柱形砝码模拟药瓶放入目标病房的圆环内。我们设计了一个简单可靠的舵机控制推杆式机构。结构在小车中部安装一个平台平台前端有一个挡板用于限位药瓶。平台下方安装一个9g微型舵机舵机摇臂连接一根轻质推杆。动作流程小车到达病房区域并精准停车后STM32控制一个电磁铁或继电器如果药瓶是铁质断电药瓶落在平台。舵机旋转一定角度推动推杆将药瓶向前推出使其落入地面的圆环。舵机回位小车驶离。关键点机构的可靠性需要反复测试。推杆的力度和行程要刚好能把药瓶推入环中又不能因力度过大导致药瓶弹出。小车停车的位置精度直接决定了投放的成功率这又回到了运动控制的精度问题。3.5 决策与调度软件框架如何让各个模块有序工作我们设计了一个基于有限状态机FSM的软件框架。将小车的整个任务流程划分为若干个状态每个状态执行特定的动作并根据传感器输入判断何时跳转到下一个状态。例如一个简化的状态机可以如下设计STATE_IDLE空闲状态等待启动命令。STATE_LINE_FOLLOWING循迹状态执行PID巡线同时OpenMV检测前方是否有路口或数字。STATE_CROSSROAD_PROCESS路口处理状态当OpenMV报告路口时进入。根据预设的任务地图决定直行、左转90度、右转90度或180度调头。执行完转向动作后返回循迹状态。STATE_NUMBER_RECOGNITION数字识别状态当接近病房时进入精细识别状态降低车速反复识别数字直至确认。STATE_DELIVERY投递状态停车执行机械臂投递动作。STATE_RETURN返回状态完成所有投递后规划返回起点的路径。在STM32的main函数中主要就是一个switch-case结构根据当前状态调用不同的处理函数。这种框架逻辑清晰易于调试和扩展。4. 核心环节实现与调试实录4.1 OpenMV与STM32的串口通信协议两者之间的数据交互是整个系统的信息纽带。我们自定义了一个简单高效的串口通信协议。数据帧格式帧头(0xAA) 数据类型(1字节) 数据长度(1字节) 数据内容(N字节) 校验和(1字节) 帧尾(0x55)数据类型用于区分是循迹数据如偏移量、数字识别结果、还是路口标志。校验和通常采用前面所有字节的累加和取低8位用于检验数据传输是否出错。在OpenMV端Pythonimport pyb uart pyb.UART(3, 115200) # 初始化串口3波特率115200 def send_data(data_type, data): frame_head b\xAA frame_tail b\x55 length len(data) checksum (data_type length sum(data)) 0xFF # 计算校验和 frame frame_head bytes([data_type, length]) bytes(data) bytes([checksum]) frame_tail uart.write(frame)在STM32端C语言// 串口中断服务函数中解析数据 void USART3_IRQHandler(void) { if(USART_GetITStatus(USART3, USART_IT_RXNE) ! RESET) { uint8_t rx_byte USART_ReceiveData(USART3); // 放入自定义的协议解析状态机中处理... parse_uart_frame(rx_byte); // 这个函数实现帧头、长度、校验等的判断 } }实操心得调试通信协议时一定要先用串口助手单独测试OpenMV发送的数据是否正确再用单片机接收。遇到乱码或丢数据首先检查波特率是否一致其次是电平是否匹配OpenMV是3.3V TTL电平需与STM32的串口电平一致最后再检查代码逻辑。给关键数据如识别到的数字添加一个简单的心跳包或定期发送可以在上位机上直观看到通信是否正常。4.2 麦克纳姆轮底盘的移动控制麦克纳姆轮的优势在于可以实现全向移动包括横向平移和原地旋转这给小车在狭窄病房区域的微调带来了极大便利。其运动学模型比普通差速轮复杂一些。对于一个常见的四轮麦克纳姆轮底盘轮子呈X形布局其运动分解公式如下假设小车前进方向为X向左为Y逆时针旋转为正速度向量[Vx, Vy, ω]分别代表X方向速度、Y方向速度、自转角速度。四个轮子的转速W1, W2, W3, W4可以通过一个运动学逆矩阵计算得到。在实际编程中我们通常会封装一个函数输入目标速度向量输出四个电机的PWM占空比。很多开源的四轮麦克纳姆轮底盘库已经实现了这个矩阵运算。我们的工作主要是测量并校准轮子的实际转速与PWM占空比的关系。因为即使同一型号的电机在不同电压、不同负载下其“PWM-转速”曲线也会有细微差异。不校准的结果就是当你发送平移指令时小车可能会一边走一边自己旋转。校准方法将小车悬空分别给每个电机一个固定的PWM值比如50%用编码器测量其稳定后的转速。记录多组数据拟合出每个电机的PWM-转速曲线近似线性。在控制函数中根据目标转速反向查找所需的PWM值并乘以一个校准系数。这个过程繁琐但必不可少是提升移动精度的关键。4.3 特殊赛道元素的处理逻辑2021年F题的赛道包含多种元素处理逻辑是算法的核心。1. 十字路口检测OpenMV识别到横向黑线宽度超过阈值且与纵向黑线连通。动作STM32收到“路口”指令后控制小车继续前进一小段距离让车体中心到达路口中心然后根据任务要求执行转向。转向时关闭循迹PID直接给左右轮设定不同的速度差实现差速转弯同时用陀螺仪MPU6050积分角度作为反馈实现精确的90度或180度转向。转完后再重新开启循迹。2. 起止线/病房区域检测起止线通常是两条较粗的黑线。OpenMV可以检测到两条平行黑线。灰度传感器阵列也会检测到一个特定的“1 1 1 1 1”全黑模式。动作检测到起止线后小车需要完全驶过该区域并停车。这里需要精细的距离控制可以通过编码器累计的脉冲数来计算行驶距离实现精准停车。3. 数字识别与确认流程当小车根据任务地图行驶到目标病房附近时进入“搜索”状态。降低车速OpenMV持续识别。一旦连续3帧识别到同一个数字且该数字与目标病房号匹配则触发“到达”状态准备停车投递。抗干扰如果识别到的数字一直变化或无法识别则让小车以极慢的速度向前蠕动一小段调整摄像头视野直到识别稳定。设置一个超时时间防止在错误位置无限等待。5. 调试血泪史常见问题与排查技巧这个项目90%的时间都花在了调试上。下面是我们遇到的一些典型问题及解决方法希望能帮你避开这些坑。5.1 小车巡线时“画龙”或跑飞现象小车无法稳定保持在黑线中心左右大幅度摇摆甚至直接冲出赛道。可能原因与排查PID参数不当这是最常见的原因。P值过大导致振荡过小则响应慢、纠偏无力。D值能抑制振荡但过大会引入高频噪声。I值能消除静差但过大会导致积分饱和引起控制滞后。解决方法采用“试凑法”在赛道上实时调整。先调P让小车有反应但不振荡再调D平滑运动最后调I消除稳态误差。记录下每次调整的参数和现象。传感器安装问题灰度传感器距离地面高度不一致或未对准黑线中心线。解决方法用尺子测量并确保所有传感器安装高度一致且中心连线与小车中轴线垂直。可以用一个测试程序实时打印所有传感器的值观察在黑线/白线上时读数是否清晰、稳定。电机响应不一致/轮胎打滑两个驱动轮的电机即使给相同PWM转速也可能不同或者轮胎摩擦力有差异。解决方法进行前述的电机单独校准。同时确保轮胎清洁没有灰尘影响摩擦。可以在软件中加入速度闭环控制用编码器反馈实时调整每个电机的PWM确保两轮实际速度一致。电池电压下降随着电池电量消耗电压降低电机在相同PWM下的转速会变慢破坏原有的控制平衡。解决方法使用稳压模块为控制部分供电确保单片机逻辑稳定。对于电机可以采用速度闭环来补偿电压变化的影响。5.2 OpenMV数字识别不稳定或误识别现象数字时而被识别时而识别成其他数字或者在非目标区域误触发。可能原因与排查光照影响这是视觉项目最大的敌人。不同时间、不同角度的光线会极大改变数字的颜色和对比度。解决方法尽量在光照均匀且稳定的环境下测试和比赛。如果条件不可控可以采用自适应阈值算法或者使用灰度图像边缘检测来代替纯颜色阈值分割这样对光照变化的鲁棒性更强。模板制作不标准模板图片的背景不干净或者数字的字体、大小与赛场上实际的有差异。解决方法模板图片一定要在与实际比赛环境光照相似的条件下拍摄。对模板图片进行严格的预处理二值化、裁剪到只剩数字并尝试制作多角度、多尺度的小模板库。ROI设置不合理搜索区域太大包含了干扰物或者太小小车稍微偏一点就拍不到数字。解决方法根据小车与数字卡的固定相对位置仔细调整ROI的坐标和大小。可以画一个矩形框在OpenMV的IDE预览图上直观调整。识别算法单一只依赖模板匹配在数字形变、遮挡时容易失败。解决方法可以结合特征点匹配或简单的神经网络分类模型OpenMV支持运行小型的TensorFlow Lite Micro模型。虽然复杂度增加但识别鲁棒性会大幅提升。5.3 通信丢包或数据错误现象STM32收不到OpenMV的数据或收到的数据偶尔乱码。可能原因与排查波特率不匹配双方串口初始化时设置的波特率不一致这是最低级的错误。解决方法仔细检查代码确保两边都是115200或其他约定值。电气连接问题杜邦线接触不良或者TX/RX接反了。解决方法用万用表通断档检查连接线。确保OpenMV的TX接STM32的RXOpenMV的RX接STM32的TX。未处理数据溢出如果STM32处理数据的速度跟不上接收的速度串口接收缓冲区Buffer会溢出导致数据丢失。解决方法在STM32串口中断中收到一字节就立刻存入一个自定义的环形缓冲区Ring Buffer主循环再从容地从缓冲区里解析数据。避免在中断中进行复杂的协议解析。电源噪声干扰电机启停时会产生很大的电流波动可能通过电源线或空间耦合干扰到串口电平导致误码。解决方法为控制部分STM32 OpenMV和电机驱动部分使用独立的电源或进行良好的滤波隔离。在信号线上加磁珠或小电容滤波。尽量使用屏蔽线或双绞线连接串口。5.4 机械机构执行不到位现象舵机推杆推不动药瓶或者推的力度/角度不对。可能原因与排查舵机扭矩不足9g微型舵机扭矩通常只有1.5kg·cm左右如果推杆阻力太大可能无法动作到位。解决方法选用扭矩更大的舵机如20kg·cm的金属齿轮舵机或者优化机械结构减少摩擦和阻力臂让推杆作用点离舵机转轴更近。供电不足舵机在动作瞬间需要较大电流如果电源线太细或电源带载能力不够会导致电压被拉低舵机无力甚至导致单片机复位。解决方法为舵机单独供电或使用大容量电容在舵机旁做储能缓冲。程序逻辑问题舵机动作和停车时序没配合好。比如舵机开始推的时候小车还未完全停稳。解决方法在状态机中明确时序先确保小车完全停稳并延时几百毫秒 - 释放药瓶 - 延时等待药瓶落稳 - 舵机动作推药 - 舵机回位 - 小车启动离开。每个动作后都加入适当的延时或状态确认。6. 项目总结与进阶思考完成这个“简单实现”的项目后回过头看收获远超预期。它不仅仅是一次代码和电路的复现更是一次完整的、从需求分析到系统集成、再到调试排错的工程实践。我们深刻体会到在嵌入式系统开发中稳定性和鲁棒性远比实现炫酷的功能更重要。一个能在实验室跑通10次的系统未必能在比赛现场稳定跑通3次。环境的光照、地面的平整度、电池的电量甚至现场观众的无线电设备都可能成为影响最终成绩的变量。如果想让这个小车变得更“智能”还有很多可以深入的方向引入SLAM与路径规划如果赛道不是简单的循迹线而是一个未知的室内环境可以尝试使用激光雷达或深度摄像头结合SLAM算法构建地图并规划全局最优路径。升级视觉系统使用性能更强的树莓派OpenCV或Jetson Nano运行更复杂的深度学习模型实现更精准的物体识别如识别不同颜色的“药品”和语义分割。多车协同如果场景扩展到多楼层、多病房可以设计多辆小车通过Wi-Fi或ZigBee通信由一个中央调度系统分配任务实现协同送药这涉及到多智能体系统的知识。人机交互与监控开发一个基于Qt或Web的上位机软件实时显示小车位置、电池状态、任务进度并能手动下发指令。这次暑期实践让我们明白电赛题目本身就是一个绝佳的“练功房”。它设定了一个明确的目标和一系列约束条件逼迫你在有限的时间和资源内去综合运用所学知识解决一个真实的工程问题。无论获奖与否这个过程对工程能力的锤炼都是实实在在的。建议后来者不必一味求新求难沉下心来把一道经典题目吃透、做稳其收获可能比泛泛地做十个项目都要大。当你能够从容应对各种突发bug并清晰地知道每一步操作背后的原理时你就已经完成了从学生到工程师的关键一步。