基于STM32与OpenMV的医院智能送药小车:多传感器融合与状态机设计详解

发布时间:2026/8/29 19:25:36
基于STM32与OpenMV的医院智能送药小车:多传感器融合与状态机设计详解 1. 项目缘起与核心目标从“送药”需求到“智能”实现去年备赛的时候我们团队不眠者①队在选题上纠结了很久。当时看到“智能送药小车”这个题目第一反应是这不就是个循迹避障的小车吗市面上开源方案一大堆拿个现成的底盘STM32加几个传感器再套个OpenMV做视觉好像就能交差。但真正深入下去和指导老师、医院的后勤人员聊过之后才发现事情远没这么简单。一个真正能在医院走廊、病房门口这种复杂半结构化环境里可靠运行的“送药”小车它面临的挑战是立体且苛刻的。它不能只是个“玩具车”它需要具备在动态人流中安全导航、准确识别并操作目标比如病房门牌、药品架格口、与医院信息系统进行稳定数据交互以及在电量告急时自主决策的能力。所以我们给自己定的核心目标非常明确打造一个高可靠性、强任务适应性、具备完整数据链路的医院室内智能配送原型系统。“智能”二字对我们而言意味着它必须能“理解”环境、“规划”路径、“执行”任务并“反馈”状态而不仅仅是“移动”。这个目标直接决定了我们整个技术栈的选型和系统架构的设计思路。一等奖和推国赛的结果算是对这个思路的一种肯定。今天把整个项目的设计方案和核心代码开源出来也是希望能给后来者提供一个更贴近真实应用场景的参考框架而不仅仅是另一个循迹小车的Demo。2. 系统顶层设计模块化与高内聚低耦合在动手写第一行代码之前我们花了大量时间在系统架构设计上。一个常见的误区是拿到题目就直奔开发板开始逐个调试传感器和电机。这很容易导致后期各模块间耦合过紧牵一发而动全身调试和维护变成噩梦。我们的设计哲学是功能模块化通信标准化决策中心化。整个系统我们划分为五大核心模块主控决策模块STM32F407作为整个小车的大脑负责任务调度、路径规划基于上层指令或简单局部策略、运动控制PID计算、与服务器通信以及协调所有其他模块。选择F4系列是看中了其充足的RAM、Flash以及更强大的浮点运算能力为复杂的控制算法和通信协议解析留出余量。环境感知模块这是一个复合模块包括OpenMV Cam H7负责前向视觉任务主要是走廊循迹我们采用了抗干扰更强的双线识别而非单线、病房门牌号识别OCR、以及前方障碍物动态行人、静态杂物的检测。多路超声波传感器布置在车体左、右、前、前斜侧用于弥补视觉盲区进行近距离、高可靠性的障碍物测距尤其是在视觉受光照影响或对透明、反光物体失效时。编码器安装在两个驱动轮上用于实现精确的里程计计算是实现精准位置控制和闭环运动的基础。运动执行模块由两个带编码器的直流减速电机构成差速驱动底盘和舵机组成。舵机用于控制一个简单的机械臂或抽屉机构完成“递送”动作。电机驱动器选用的是经典的TB6612稳定且易用。人机交互与状态指示模块包括一块OLED显示屏用于实时显示小车状态如当前任务、电量、速度、故障码、一个蜂鸣器用于提示音、以及若干LED状态灯。别小看这个模块在调试和演示时它能提供极其宝贵的信息。通信与云端交互模块这是让小车从“自动”走向“智能”的关键。我们设计了双链路通信Wi-Fi (ESP8266)负责与部署在本地或云端的任务服务器进行长连接通信接收送药任务目标病房号、药品信息上报当前位置、状态运行中、等待、故障和任务完成情况。HC-05蓝牙模块作为调试和紧急干预的备用通道可以通过手机APP实时查看传感器数据、手动发送控制指令这在调试初期和演示现场应对突发情况时救过我们好几次。这些模块之间通过清晰的接口进行通信。UART串口成为最主要的桥梁STM32主控通过UART1与OpenMV通信获取视觉处理结果通过UART2连接Wi-Fi模块通过UART3连接蓝牙模块。而超声波传感器使用IO口触发和中断捕获编码器使用定时器的编码器模式电机和舵机使用PWM控制。这种设计使得每个模块都可以独立开发、测试和替换比如把OpenMV换成性能更强的树莓派摄像头只需要修改对应的通信解析函数即可主控逻辑几乎不变。3. 核心算法与策略实现细节有了好的架构血肉就是算法和策略。这里分享几个我们踩过坑才理顺的核心点。3.1 基于视觉与多传感器融合的鲁棒循迹与避障单纯依赖OpenMV的单线循迹在光照变化、地面反光或者线路轻微破损时极易翻车。我们的策略是双线识别与中线提取让OpenMV识别引导线的左右边缘然后计算中心线。这样即使某一边的线不清晰也能根据另一边和已知的赛道宽度估算出中线容错性大大提升。OpenMV的find_blobs函数结合颜色阈值过滤可以较好地完成这个任务但阈值需要根据现场光线进行自适应或提前校准。PID控制参数整定这是让小车跑得“稳”和“直”的关键。我们采用了两级PID角度PID外环输入是期望中线与图像中心线的横向偏差像素差输出是期望的转向角速度或直接是差速值。这个PID负责纠正方向。速度PID内环输入是期望速度由任务阶段决定如直道加速、弯道减速与编码器反馈的实际速度输出是PWM占空比。这个PID负责维持稳定速度。整定顺序一定是先内环速度再外环角度。内环调稳了外环才好调。我们最后在赛道上反复测试记录下不同偏差下的响应曲线才找到一组在直道和弯道都表现不错的参数。一个经验是弯道时适当降低速度环的P值可以防止过冲。多传感器融合避障这是安全底线。我们设计了一个简单的“安全区域”模型。前方超声波和OpenMV的障碍物检测作为最高优先级输入。一旦检测到障碍物进入危险距离比如30cm立即触发减速或停止。左右超声波用于在通过狭窄区域如门框时防止刮蹭。策略核心是“谁报警听谁的”并且视觉和超声波互为冗余。例如对于玻璃门超声波可能失效但OpenMV能看到对于深色物体或强光下的障碍OpenMV可能失效但超声波能检测到。代码实现上我们为每个方向设置了一个安全距离阈值在主循环中实时查询所有传感器数据任何一项触发就立即覆盖当前的循迹PID输出转为避障行为如绕行或停车等待。3.2 病房门牌识别与精确定位策略送到指定病房门口是核心任务。我们放弃了需要大量训练数据和复杂模型的通用目标检测针对医院门牌通常是规则的数字标牌的特点采用了更轻量可靠的方案区域搜索与提取当小车根据路径规划或简单的前进路口转向逻辑到达目标病房所在走廊区域后控制舵机抬起OpenMV使其镜头以一定角度朝向病房门牌可能出现的侧上方区域。OpenMV程序先通过颜色过滤例如识别白色标牌区域或特定颜色的数字找到可能的候选区域ROI。OCR数字识别对提取出的ROI进行二值化、降噪后使用OpenMV内置的tesseractOCR引擎需预先训练一个针对数字的小字体库效果远好于通用库进行数字识别。为了提高准确性我们会连续识别多帧比如5帧采用“投票法”或取中位数来确定最终识别的数字。验证与动作执行将识别结果通过串口发送给STM32。STM32将其与当前任务目标病房号进行比对。如果匹配则控制小车执行精确定位微调如侧向移动对准门牌中心然后触发递送机构动作。如果不匹配则记录日志并通过Wi-Fi上报“定位异常”由服务器决定下一步指令如继续前进寻找下一个门牌或重新确认位置。3.3 基于状态机的任务调度与异常处理小车的运行逻辑不能是线性的“执行步骤1然后步骤2……”必须能够应对各种中断和异常。我们为STM32主控设计了一个清晰的状态机State Machine这是整个系统稳定运行的“逻辑骨架”。核心状态包括IDLE待命、RECEIVING_TASK接收任务、NAVIGATING导航中、IDENTIFYING_DOOR识别门牌、DELIVERING递送中、AVOIDING避障中、CHARGING充电中、FAULT故障。 状态之间的转换由事件触发例如收到服务器任务 - 进入NAVIGATING识别到障碍物 - 进入AVOIDING到达目标区域 - 进入IDENTIFYING_DOOR。异常处理是这里的重中之重。我们为每个可能发生的异常定义了处理策略通信超时与服务器Wi-Fi连接丢失超过10秒尝试重连。重连失败则进入FAULT状态通过蓝牙上报并尝试原地安全停车。传感器失效某个超声波传感器持续返回异常值如超出量程则在状态机中标记该传感器不可用避障策略自动降级如仅依赖其他传感器和视觉同时上报故障。路径阻塞在AVOIDING状态超过一定时间如30秒仍无法通过判定为路径长期阻塞退出避障状态上报“路径阻塞”并请求新的路径指令或进入等待。低电量电压检测电路发现电量低于阈值立即终止当前非紧急任务通过Wi-Fi上报“低电量请求充电”并自动导航如果已知位置或原地等待指引至充电桩。状态机的实现使得代码逻辑非常清晰调试时可以通过OLED屏实时查看当前状态快速定位问题所在。所有状态转换和异常事件都记录在循环缓冲区中可以通过调试接口导出用于事后分析。4. 硬件选型、电路设计与机械结构要点硬件是算法的载体不合理的硬件设计会让软件的努力事倍功半。4.1 主控与核心传感器选型考量STM32F407 vs F103这是第一个关键决策。F103资源紧张在同时处理多路串口数据、运行浮点PID运算、维护Wi-Fi长连接并管理复杂状态机时容易出现卡顿或内存不足。F407的168MHz主频、192KB RAM和1MB Flash提供了充裕的空间。更重要的是其硬件FPU对于需要大量浮点运算的PID控制我们使用了位置式PID涉及浮点运算和滤波算法性能提升是数量级的。OpenMV Cam H7选择H7版本是因为其更强的处理能力480MHz双核可以在运行我们定制的双线循迹、颜色跟踪和数字识别算法时仍能保持较高的帧率15-20fps确保控制的实时性。它的MicroPython开发环境也加快了原型开发速度。电机与编码器我们选择了带AB相增量式编码器的直流减速电机。编码器精度我们用的是13线电机减速后单圈计数约7800直接决定了里程计的准确性和速度闭环的性能。电机扭矩要足够确保小车在载重模拟药品情况下也能顺利启动和爬坡应对医院的小坡度或地毯。电源管理这是血泪教训换来的经验。最初我们使用一块大容量锂电池直接给所有模块供电结果电机启动瞬间的电压跌落导致STM32和OpenMV意外复位。后来改为分级供电方案锂电池先经过一个大的DC-DC降压模块如LM2596稳定到5V这个5V总线给STM32、OpenMV、传感器和舵机供电。然后STM32控制的电机驱动模块TB6612的电源直接取自锂电池通过一个开关与主控电源隔离。同时STM32的ADC实时监测锂电池电压实现低电量预警。4.2 PCB设计与布线抗干扰如果条件允许自制一块主控板能极大提升系统的集成度和可靠性。我们的教训包括电源路径要粗电机驱动部分的电源走线一定要足够宽减少大电流下的压降和发热。模拟数字地分离ADC采样电池电压的路径要远离数字电路特别是电机驱动和PWM信号线并采用单点接地防止噪声串扰导致电量检测不准。信号线保护编码器信号线、串口线等较长信号线在板子上可以预留串联小电阻如22欧姆和并联对地电容的位置用于抑制振铃和噪声。实际调试中我们发现不加这些保护编码器计数在电机运行时偶尔会跳变。预留调试接口多留出几个串口TTL电平的焊盘或排针方便连接额外的传感器或调试器。我们预留了一个SWD接口和一个串口打印接口在排查疑难杂症时起了大作用。4.3 机械结构设计与迭代小车的机械结构经历了三次迭代V1.0 简单双层亚克力板快速验证想法但刚性差传感器位置固定死调整不便。V2.0 铝型材框架结构稳固便于调整传感器高度和角度。我们设计了可上下调节的OpenMV支架和可旋转的超声波传感器云台方便根据赛道环境优化感知范围。V3.0 集成化设计针对递送动作我们设计了一个简单的“升降抽屉”机构。由舵机驱动一个四连杆机构模拟将药品托盘推送到固定高度的取药窗口。所有机械零件使用3D打印制作轻量且可快速迭代。关键点在于机械结构的运动范围、速度和精度必须在软件控制算法的设计之初就考虑进去例如舵机转动角度与抽屉位移的映射关系以及执行动作时是否需要锁定底盘电机等。5. 软件架构、代码管理与调试心得好的软件架构能极大提升开发效率和代码质量。5.1 基于HAL库的模块化驱动层我们充分利用STM32CubeMX生成初始化代码但在此基础上进行了深度封装。为每个外设UART、TIM、PWM、ADC等编写了独立的驱动文件drv_uart.c/h,drv_motor.c/h,drv_encoder.c/h。这些驱动提供简洁、统一的API例如Motor_SetSpeed(int left, int right)Encoder_GetSpeed(void)。应用层如PID控制、状态机只调用这些API完全不关心底层寄存器操作。这使得代码可读性、可移植性和可测试性都大大增强。5.2 实时操作系统RTOS的引入在项目中期当我们尝试同时处理Wi-Fi数据接收、多传感器数据读取、高频率PID运算和状态机更新时发现裸机下的前后台系统有些力不从心容易出现某个任务阻塞导致其他任务响应不及时。我们果断引入了FreeRTOS。任务划分我们创建了多个优先级不同的任务Task_Sensor高优先级定时读取所有传感器、Task_Control最高优先级执行PID计算和电机控制、Task_Communication中优先级处理Wi-Fi和蓝牙数据、Task_StateMachine中优先级运行主状态机、Task_Display低优先级更新OLED。通信与同步任务间通过消息队列Queue传递数据如将OpenMV数据从串口接收中断发送到Task_Control通过信号量Semaphore进行同步如等待一组传感器数据就绪后再进行融合计算。带来的好处系统的实时性和可靠性得到质的提升。电机控制任务总能以固定频率执行不受其他任务阻塞。复杂的通信协议解析可以在独立任务中慢慢处理不会影响小车的实时运动。调试时可以方便地查看各个任务的运行状态和堆栈使用情况。5.3 调试方法与数据可视化调试这样的复杂嵌入式系统printf大法虽好但效率低下。我们建立了一套高效的调试体系SEGGER RTT在STM32上使用SEGGER RTT技术通过J-Link调试器可以在不占用串口的情况下实时向电脑输出打印信息速度极快且不影响程序实时性。我们用它来输出关键变量、状态转换信息和错误码。自定义数据流我们定义了一个轻量级的二进制数据流协议将小车的关键数据如左右轮速度、设定速度、PID偏差、超声波距离、电池电压等打包通过一个专用的串口或通过Wi-Fi发送到上位机。上位机可视化Python PyQt我写了一个简单的Python上位机程序接收数据流并实时绘制曲线图速度曲线、误差曲线、传感器距离曲线。这让我们能直观地看到PID的调节效果、避障算法的响应过程一眼就能发现参数是否合适、算法是否有振荡。图形化的调试效率是看数字打印的十倍以上。日志系统在STM32的Flash中开辟一个环形日志缓冲区将重要的状态事件如“开始识别门牌”、“遇到障碍物”、“任务完成”连同时间戳记录下来。在出现异常时可以通过调试接口导出日志精准还原故障发生前的系统状态序列。6. 从赛题到开源项目总结与代码仓库指南回顾整个项目最大的收获不是奖状而是完整经历了一个从需求分析、方案设计、软硬件实现、集成调试到最终演示的完整工程闭环。其中几个深刻的体会是仿真先行在硬件制作前先用MATLAB/Simulink或简单的Python脚本对控制算法如PID进行仿真能快速验证思路节省大量线下调参时间。测试驱动为每个模块编写单元测试哪怕是简单的验证函数特别是传感器驱动和通信协议解析部分确保每个“零件”在集成前是可靠的。文档即代码从第一天起就用Markdown写设计文档用注释写清关键算法和接口。这不仅利于团队协作在后期调试和开源准备时你会感谢当初勤快的自己。我们将整个项目的核心代码、硬件原理图、3D打印结构件文件、以及详细的说明文档都开源在了GitHub上。仓库地址是https://github.com/mewamew/my_ai_town根据输入的热词关联此仓库名可能与项目相关在此作为示例引用实际项目仓库需团队自行创建。代码仓库结构概览/Firmware/STM32基于STM32CubeIDE的工程包含HAL库驱动、FreeRTOS配置、各模块任务源码和主状态机实现。/Firmware/OpenMVOpenMV Cam H7上的MicroPython脚本包括双线循迹、颜色跟踪、数字识别等算法。/Hardware包含主控板原理图Altium Designer格式、PCB布局图、元器件清单BOM。/Mechanical小车底盘和递送机构的3D设计文件STEP格式及打印用STL文件。/Documents系统设计说明书、算法原理详解、调试手册、组装指南等。/Tools包含数据可视化上位机源码、一些用于生成测试数据的脚本。希望这个项目能成为一个有价值的参考。它不是终点而是一个起点。你可以基于此尝试集成更先进的SLAM算法实现真正的地图构建与自主导航或者加入机械臂实现更复杂的抓取操作又或者探索5G或UWB来实现更高精度的室内定位。智能硬件的乐趣就在于将想法一步步变为现实并在过程中不断解决那些令人头疼又兴奋的问题。