
简介面向高校电子、自动化及嵌入式方向的毕设学生这份基于STM32系列单片机的智能清扫机器人设计资源完整覆盖了从硬件选型到算法落地的核心环节。资源包共7个文件包含3份C语言程序源码、1份头文件、1份需求说明、1个完整项目打包以及1段实操演示视频压缩包大小25.2MB结构紧凑便于按模块对照学习。项目重点讲解了STM32的ARM Cortex-M内核架构与外设接口、电机驱动与PID运动控制、超声波/红外等传感器融合避障以及基于Wi-Fi的远程监控和低功耗电源管理代码注释和文档对路径规划、传感器数据处理等关键模块做了分解说明。已有5290人学习下载配套的操作演示视频能直观展示机器人的实际清扫效果适合正在做毕业设计或想深入了解STM32机器人开发的学习者参考、复用与二次开发。 前阵子帮朋友捣鼓了一个基于STM32的智能清扫机器人项目从方案选型、硬件搭建到软件联调前后花了大半个月。这玩意儿在智能家居和嵌入式竞赛里都算是个经典题目但网上能找到的多是零散代码片段或是“看起来能跑”的原理图真正把整套设计逻辑和调试经验讲透的很少。这篇文章我就把整个设计过程摊开来讲包括为什么选STM32F103C8T6、传感器怎么排布、软件任务怎么调度、PID参数怎么调以及我在实际调试中踩过的几个典型坑。适合正在做课程设计、毕业设计或者想入门移动机器人开发的读者照着这篇的思路走一遍能省下不少走弯路的时间。1. 项目目标与整体架构设计1.1 智能清扫机器人到底要解决什么问题先明确一个事清扫机器人不是“遥控车加个吸尘器”那么简单。它要能在没有人工干预的情况下在一个未知环境里自主移动、躲避障碍、完成清扫并且在电量不足时能自动回充。细化下来核心功能点有这么几个自主移动机器人在房间内自由行进不能撞墙不能卡在沙发底下出不来。避障能力实时检测前方和侧方障碍物执行转向或后退动作。清扫执行底部滚刷把灰尘扫起配合吸尘风机把垃圾吸入尘盒。防跌落保护检测楼梯或台阶边缘防止机器人在边缘处栽下去。电量管理实时监测电池电压低于阈值时自动返回充电座或报警。交互反馈通过LED、蜂鸣器或OLED屏显示当前工作状态。这些功能看着多但拆解下来本质上是“感知-决策-执行”的闭环。传感器负责感知环境主控芯片负责决策电机和清扫模块负责执行。STM32在这套系统里扮演的角色就是“大脑”所有传感器的数据汇聚到这里它做出判断再输出控制信号驱动电机。1.2 主控选型与系统模块划分主控我用的是STM32F103C8T6也就是大家常说的“蓝板”最小系统板。选它的原因很实际性价比极高单芯片自带64KB Flash和20KB RAM跑一个不复杂的清扫逻辑绰绰有余外设资源丰富有多路定时器、ADC、USART、I2C和SPI足够应对电机测速、传感器采集、串口调试这些需求开发资料和参考代码在网络上非常齐全遇到问题基本都能搜到解决方案。整个系统按功能模块划分大致可以分成5个部分电源模块7.4V锂电池供电经降压芯片转为5V给电机驱动和传感器供电再经LDO降为3.3V给STM32供电。驱动模块两个直流减速电机配合编码器作为动力轮前部加一个万向轮支撑电机驱动芯片用TB6612FNG。传感器模块红外避障传感器探测近处障碍超声波模块探测较远距离障碍防跌落红外对管检测台阶边缘电压检测通过STM32内部ADC完成。清扫模块一个直流电机带动滚刷一个风机电机产生吸力两者都用MOS管配合PWM调速。交互模块OLED显示屏显示工作模式、电量和状态蜂鸣器做提示按键用于启动和切换模式。系统设计的核心思路是“模块解耦”。每个模块独立供电、独立控制软件上对应独立的驱动文件。这样调试的时候可以逐个模块单独测试出问题能快速定位不用把整个系统绑在一起盲调。2. 硬件设计要点与关键器件选型解析2.1 电机驱动与闭环测速方案清扫机器人的移动性能直接取决于电机驱动方案。我选用的是N20微型直流减速电机额定电压6V减速比1:30自带霍尔编码器输出AB两相互为正交的脉冲信号。之所以选带编码器的电机是因为开环控制下的PWM调速根本无法保证两个轮子转速一致——电池电压变化、地面摩擦不同都会导致机器人走偏直线走不直清扫覆盖率自然上不去。驱动芯片用的是TB6612FNG相比老掉牙的L298N它内部集成了续流二极管体积小、发热低、效率高。TB6612支持两路电机独立控制每路有IN1、IN2两个方向引脚和一个PWM调速引脚。单片机通过改变IN1和IN2的电平组合控制电机正反转通过调节PWM占空比控制转速。电机编码器信号直接接入STM32的定时器通道配置为编码器模式后硬件自动对AB相脉冲进行正交解码不需要软件中断去数脉冲CPU负担非常小。这里有一个需要注意的细节编码器测速归测速但速度环控制的周期必须固定。我在项目中用定时器3产生一个10ms的周期中断每次中断里读取编码器计数值、计算实际转速、运行PID控制器、更新PWM占空比。这个10ms的周期在软件里就是所有控制逻辑的“心跳”后续的避障逻辑和清扫逻辑都挂在这个心跳上。项目参数电机型号N20直流减速电机1:30编码器线数每圈13线AB相经4倍频后每圈52个脉冲驱动芯片TB6612FNG控制周期10ms定时中断工作电压6V额定降压模块输出5V供电2.2 传感器选型与布局思路传感器是机器人的“眼睛”布局合理比单个传感器的参数更重要。我用了以下几种传感器组合红外避障传感器TCRT5000或E18-D80NK安装在车头左右两侧朝向前方偏下45度用于检测近处障碍物检测距离约2~20cm可调。E18-D80NK输出高低电平属于开关量接线简单适合做接近开关用。超声波测距模块HC-SR04安装在车头正前方用于检测较远距离的障碍物量程2cm~400cm。相比红外超声波能测到更远的距离方便机器人提前减速或规划转向。防跌落传感器使用TCRT5000红外对管安装在底盘前缘左右两侧朝下安装用于检测边缘。当红外反射回来的强度变弱说明下方没有地面判断为台阶边缘需要立即后退或转向。碰撞传感器前期调试用了一个机械微动开关装在车头保险杠上。如果红外和超声波都失效撞到障碍物时微动开关触发作为最后一道保护。布局上有一个重要的经验左右避障传感器的间距要大于机器人车身的宽度这样在判断“是否可以通过”时才不会误判。比如机器人宽度是22cm那么左右两个红外传感器的间距至少要25cm以上。另外防跌落传感器的安装位置要尽量靠近车轮的外侧边缘否则机器人在边缘处急停时会因为惯性冲出悬崖。2.3 电源系统设计电源是整个系统里最容易出问题、也最容易被初学者忽略的环节。我用的是两节18650锂电池串联标称电压7.4V容量2600mAh。这个电压经过LM2596降压模块降到5V给电机驱动、超声波、红外传感器供电5V再经过AMS1117-3.3给STM32供电。实际调试中电机启动瞬间的电流可以达到2A以上这会导致系统电压出现明显跌落。如果降压模块的滤波电容容量不够5V电压会跌到4V以下直接导致STM32复位。我踩过这个坑后面在电源设计上做了三个改进在电源输入端并联一个大容量的电解电容470uF/25V作为储能缓冲。在电机驱动板的电源输入处就近加一个100uF电容把电机启动的大电流限定在电机驱动级避免影响主控。STM32的供电入口加一个10uF钽电容和一个0.1uF陶瓷电容分别滤除低频和高频扰动。另外电压检测电路需要把电池电压分压后接到STM32的ADC引脚。我用的分压电阻是10K和4.7K分压比例约为1:3.1这样7.4V电池满电时ADC引脚电压约为2.38V在3.3V量程以内。根据ADC读到的电压值结合电池放电曲线就能大致估算剩余电量。3. 软件框架与核心功能模块实现3.1 裸机开发下的多任务调度方案很多初学者拿到STM32第一反应就是上RTOS实时操作系统但我觉得对于这个量级的项目裸机加“前后台”结构完全够用。所谓前后台就是主循环作为后台定时器中断作为前台。前台负责处理实时性要求高的任务比如编码器测速和PID计算后台负责处理实时性要求低的任务比如避障逻辑、OLED刷新、电量检测。用裸机调度的好处是代码直观、便于理解也避免了RTOS带来的任务切换开销和调试复杂度。具体实现上我定义了一个简单的任务表结构typedef struct { uint8_t running; uint32_t period; uint32_t last_run; void (*task)(void); } task_t; task_t tasks[] { {0, 10, 0, Motor_SpeedLoop}, // 10ms电机速度环 {0, 50, 0, Sensor_Collect}, // 50ms传感器数据采集 {0, 100, 0, Decision_Make}, // 100ms避障决策 {0, 200, 0, UI_Update}, // 200ms界面刷新 {0, 1000, 0, Battery_Check}, // 1s电量检测 };主循环里遍历这个任务表用当前系统时钟和每个任务的“上次运行时间”做差超过周期就执行对应的任务函数。这种结构充分体现了“让每个任务在合适的时间间隔执行”的思想既不浪费CPU也不会因为某个任务卡住而导致整个系统死掉。实际项目里这就是一个轻量级的调度器比硬上RTOS更务实。3.2 传感器采集与数据滤波处理传感器数据直接拿来用会有很多问题比如红外传感器受到环境光干扰、超声波测距偶尔出现跳变、ADC采集电压有噪声。我在进入避障逻辑之前先对传感器数据做了一层滤波和有效性判断。超声波测距我是用定时器输入捕获实现的。发送一个10us的触发脉冲后测量ECHO引脚高电平的持续时间乘以声速340m/s再除以2就得到障碍物距离。单次测量的结果可能因为多重回波而出现异常值我采用的策略是连续采集3次取中值作为有效值。中值滤波能有效剔除偶发的粗大误差而且计算量小在单片机上很容易实现。红外传感器的处理相对简单因为它是开关量输出直接读取GPIO电平即可。但要注意红外传感器的阈值调节旋钮需要在实际环境里校准。我调试时发现传感器在强光直射下检测距离会明显变短所以最终把探测阈值调得比理论值保守一些宁可提前避障也不可撞上障碍物。ADC电压检测我采用了简单的一阶低通滤波公式是filtered filtered * 0.9 newValue * 0.1。这个滤波对快速电压抖动有很好的抑制作用同时保留了电量缓慢变化的趋势信息。3.3 避障决策与清扫路径规划避障决策是整个软件的核心逻辑。我把机器人的运动状态定义成一个简单的状态机包括前进、左转、右转、后退、停止、回充6个状态。每100ms执行一次决策函数根据传感器数据判断当前状态是否切换。基本的避障逻辑如下前方超声波距离大于30cm且左右红外均无触发继续保持前进。前方超声波距离小于30cm停车并判断哪个方向更空旷。左红外触发、右红外正常右转转向避开左侧障碍。右红外触发、左红外正常左转转向避开右侧障碍。左右红外同时触发或防跌落传感器触发直接后退再转向。碰撞传感器触发立即停止并后退一段距离重新规划方向。清扫路径方面我采用的是“弓字形随机转向”的混合策略。正常工作时机器人沿直线前进碰到墙或障碍后旋转180度平行移动一个车身的距离然后继续直线前进。这样能覆盖大面积区域不会像纯随机运动那样原地打转。如果连续多次尝试后仍然检测到前方频繁有障碍则进入随机转向模式先转一个随机角度再继续避免在两个障碍物之间反复横跳。这个策略看着简单但实际清扫覆盖率可以达到70%~80%对于入门级设计完全够用。如果未来想上视觉SLAM或者激光雷达建图那属于另一个层级的话题了。3.4 PID闭环调速的调参实践两个轮子速度不一致是移动机器人最常见的问题。我的解决方案是经典的增量式PID。先看一下最核心的PID更新代码float pid_update(PID_t *pid, float target, float current) { float error target - current; float output; pid-integral error; // 积分限幅防止积分饱和 if (pid-integral pid-integral_limit) pid-integral pid-integral_limit; if (pid-integral -pid-integral_limit) pid-integral -pid-integral_limit; output pid-kp * error pid-ki * pid-integral pid-kd * (error - pid-last_error); pid-last_error error; return output; }在调PID参数的时候我总结出了一个“三步走”的方法非常适合新手先把Ki和Kd设为0只调Kp。从0.1开始逐渐增大观察电机转速响应。当车轮开始出现持续振荡嗡嗡响或转速忽快忽慢时记录这个Kp值然后取它的60%~70%作为最终的Kp。加入Ki减小静差。从0.01开始逐渐增大直到稳态时转速和目标转速之间的偏差在可接受范围内我用的是±5%之内。注意Ki太大会导致超调车轮启动时会突然猛冲一下。加入Kd抑制振荡。从0.001开始微调观察启动和停止时车轮是否平稳。Kd太大时系统会变得很敏感稍微一点编码器噪声就引起输出抖动。我最终调出来的参数是Kp0.8、Ki0.05、Kd0.02。这个参数在满载加上尘盒和电池和空载情况下都能保持两轮转速一致直线行驶偏差几乎可以忽略。调参的时候一定要把机器人架起来让轮子悬空避免地面摩擦干扰判断。4. 联调阶段的典型问题与排查实录4.1 电机一启动STM32就复位的“诡异”故障这个问题我在前面电源设计部分提到过但值得单独说一下现象和排查过程。现象是单独给STM32供电一切正常单独给电机供电一切正常但只要一让电机转起来LCD屏幕就闪一下蜂鸣器响一声程序从头开始跑。我用万用表测了5V电压发现电机启动瞬间电压会掉到别的地方去示波器上能看到一个明显的毛刺。问题根源是电机启动电流过大把系统电源拉垮了。解决办法是双重保险一方面按照2.3节说的加大储能电容另一方面在软件里做了“软启动”处理——电机PWM占空比不是一步到位而是从0开始以每10ms增加1%的速度慢慢爬升到目标值。这样启动电流被摊平了系统电压波动大幅减小。注意软启动不仅保护了电源系统对机械齿轮箱也是一种保护。直接满占空比启动齿轮箱冲击大长期运行容易打齿。4.2 编码器读数跳变导致车轮抖动有一次我在调PID的时候发现左轮速度环输出总是在振荡但右轮是好的。后来用逻辑分析仪抓编码器输出波形发现左轮A相和B相的上升沿时刻很不稳定怀疑是接线接触不良。重新换了杜邦线后问题依旧最后怀疑是编码器信号被电机电流干扰了因为两根编码器信号线是和电机线绑在一块的。解决办法很粗暴把编码器信号线完全分开走线避开电机大电流线并加了上拉电阻STM32内部上拉也能开但效果弱一些我外接了10K上拉到3.3V。之后波形干净了很多车轮抖动也消失了。电机和编码器属于强电与弱电混合的场合布线和地线处理非常重要这个经验在各种机电一体化项目里都适用。4.3 红外传感器在阳光下误报室内调试时红外传感器表现正常但把机器人搬到窗边时靠近窗户的那个红外传感器会一直触发避障指令。这是因为太阳光中含有大量红外成分直接照射到接收管上导致误判。解决方案有两个思路硬件层面给红外发射管、接收管加一个遮光胶套避免阳光直射同时调整安装角度使其朝下倾斜。这个方案最治本。软件层面连续多次读到同一目标信号时才认为障碍真的存在。比如连续3次间隔50ms读到红外触发才执行避障动作。这个措施也能滤除瞬时干扰。4.4 清扫覆盖有盲区怎么办做完联调后我用一个模拟房间测试了清扫覆盖率。测试结果是在墙角、桌腿附近、门槛处出现了明显漏扫。排查后发现原因有三墙角处机器人因为碰撞传感器太灵敏还没靠近墙就转向了导致墙边留下约5cm宽的清扫带。桌腿底部空间高于底盘但低于传感器机器人判断可以通过但身体过去了滚刷没有覆盖到桌腿四周。电池电量低于30%后吸尘风机的转速明显下降大颗粒垃圾吸不进去。针对这些问题我做了三个调整一是装了一个侧边刷在机器人沿墙行进时把墙边的垃圾扫到滚刷范围内二是调整了障碍物的安全距离判断允许机器人贴着桌腿边缘行走三是在电量较低时优先保证风机转速适当降低行走速度。调整后覆盖率明显提升。4.5 定时器配置的潜规则为什么我的delay卡死了最后再提一个调试中遇到的隐藏问题。我在写延时函数时直接用了网上常见的一种写法用SysTick做毫秒级延时。结果在开启了定时器中断和编码器模式之后程序跑一段时间后delay函数就会卡死。排查了很久发现是SysTick中断优先级配置问题和定时器中断优先级冲突导致SysTick中断一直得不到响应。这个问题的本质是中断优先级的分配。我的处理原则是SysTick延时中断优先级设为最高抢占优先级0编码器测速和PID控制中断设为中等抢占优先级1其他外设中断设为低优先级。这样确保延时的准确性同时又不会影响高实时性任务。Keil5里调试的时候用逻辑分析仪或断点确认中断是否正常触发能大幅缩短这类问题的排查时间。实测效果与项目扩展方向整套系统做完之后我实际测试了一个约15平方米的房间障碍物包括桌椅、墙壁、门槛和一个纸箱。清扫覆盖率大约76%电量从满电到低压报警大约能运行35分钟空载直线行驶偏差在10厘米范围内走3米。这个性能作为课程设计或毕业设计的展示项目已经完全够用。后续如果想继续扩展我有三个建议方向第一加装陀螺仪MPU6050通过惯性导航修正运动轨迹让“弓字形”走得更加规整第二把决策逻辑从状态机升级为行为树方便增加回充、防卡困等更多功能第三用蓝牙WiFi模块把机器人的状态上报到手机App实现远程控制和地图显示。嵌入式开发里真正值钱的经验都是在调试过程中“折腾”出来的。这篇分享如果能帮你在自己的项目里少踩几个坑那就值了。本文还有配套的精品资源点击获取