
简介2022年广东省大学生电子设计竞赛三等奖作品——智能送餐机器人完整项目包面向电子设计、机器人竞赛参赛者和嵌入式系统学习者。项目集合了系统设计方案、软件源码与调试环境配置覆盖感知、控制、通信等模块可帮助读者快速理解功能型服务机器人的实现思路适用于备赛参考与二次开发。资源共128个文件压缩包大小约26.15MB。主要文件类型包括Python及C源码、Arduino程序、ROS launch/yaml配置、微信小程序前端(wxml/wxss/js/json)以及多张PNG/JPG设计示意图既有核心控制代码也有上位机交互界面与可视化资料便于按模块对照学习。目前已有50人学习下载。这份资料能让参赛者直接获得一套可参考的赛题完整方案从框架搭建到细节实现均有迹可循对于准备智能机器人、嵌入式系统类竞赛的学生是集文档、源码、交互界面于一体的实用参考具有较高的借鉴与扩展价值。 这个项目是我在2022年广东省大学生电子设计竞赛里的参赛作品定位就是智能送餐机器人。当时拿到题目脑子里第一反应是这不就是把小车加上机械臂再让它跑起来吗真正动手之后才发现把这句“跑起来”变成稳定跑完整个赛道背后全是细节。团队四个人花了两周时间搭完硬件又花了两周反复调软件最后拿了个三等奖。回头看这个成绩不算亮眼但整个项目从方案选型到现场调试踩过的坑和摸出来的经验我觉得比奖项本身更值得记一笔。这篇文章我会把当时整个项目是怎么拆解、怎么选型、怎么实现以及怎么踩坑的完整复盘一遍。内容不会写成比赛说明书而是偏实战记录适合正在准备电子设计竞赛、智能车比赛或者想自己做一台送餐机器人的朋友参考。哪怕你还没开始碰单片机只要跟着思路走一遍也能搞清楚一台“能送餐”的机器到底需要解决哪些问题。1. 项目拆解从题目到需求1.1 先别急着选硬件把得分点拆开很多队伍拿到“智能送餐机器人”这种题目第一件事就是打开网购平台找底盘、找机械臂这其实是最容易走偏的一步。竞赛题目不是企业产品需求它本质上是“在限定场地、限定时间内完成规定任务”的工程挑战所以第一步永远是把题目里的得分点拆出来。当时我们反复读题总结出几个核心考核方向第一机器人能不能沿着规划路线稳定行走这里涉及底盘运动控制和定位第二能不能识别送餐目标点通常场地里会有模拟餐桌、餐盘或标签涉及视觉或传感器检测第三能不能完成餐盘的抓取或放置动作涉及机械结构和执行机构的可靠性第四整套系统在现场能不能快速恢复因为在比赛现场经常会出现突发状况你不可能像在实验室一样反复改代码。把这些需求翻译成工程模块就变成了移动底盘、传感器导航、视觉识别、机械执行和主控逻辑五大部分。分好模块以后团队每个人负责一块进度才推得动。我们当时就是没做这一步拆分前三天全在讨论“要不要上ROS”浪费了不少时间。后来把目标收敛为“先跑通一趟完整送餐”事就简单了。1.2 整体方案选型别迷信高端平台选型这件事方向比性能重要。当时我们内部争论过两套方案。一套是树莓派加ROS激光雷达建图导航听着很唬人Walkthrough看起来也完备。但问题是我们四个人里没有一个真正系统性学过ROS光是环境配置、节点通信、TF变换这些就够吃一壶更别说比赛现场要是调度出了问题可能连日志都看不明白。另一套是STM32做主控OpenMV做视觉传感器用灰度循迹加超声波避障机械部分用舵机加滑台。这套方案的优势在于每个模块都相对独立可以用最简单的逻辑把整条链路打通。我们最终选了这套不是因为技术上有多高级而是它把“工程不确定性”压缩到了最低。评委看的是你能不能稳定完成任务不是看你用了多贵的板子。具体分工是STM32F103C8T6负责底盘运动、传感器采集、执行机构控制和状态机调度OpenMV负责识别餐桌编号和二维码两者通过串口通信。机器人身上没有用嵌入式Linux也就少了掉电文件损坏、开机启动慢这些麻烦。事实证明这个选择在现场救了我们很多次有一次隔壁队树莓派启动花了将近半分钟我们这边按下开关三秒就能开始跑。2. 核心硬件与机械结构2.1 车体与机械臂越简单越可靠送餐机器人的底盘我们一开始想上麦克纳姆轮毕竟全向移动看起来很灵活。但后来想了下比赛场地大概率是平整的KT板或地砖路线也都是规则直线和弯道用麦克纳姆轮反而引入了额外的打滑和坐标系换算问题。普通双轮差速加两个万向支撑轮就够用了控制逻辑简单轮胎特性也稳定。最后底盘用的是两块铝合金板加四个铜柱搭的前轮是万向轮后轮是两个带编码器的直流减速电机驱动轮径选65mm电机减速比1:30速度上限大概能到0.8m/s但实际比赛时只跑了0.3m/s左右这个速度下循迹和避障都比较稳。机械臂是重头戏。当时看过很多队伍用六自由度机械臂能夹杯子能倒水看起来很帅但问题也明显自由度越多运动学解算越复杂任何一点舵机误差都会被放大最后往往连一个简单的“放到指定位置”都做不到。我们最后选择的是“升降滑台餐盘托架”的结构用一根丝杆加步进电机控制升降托架是一个L型亚克力板餐盘直接放在托架上。这样做的思路是比赛要求的动作是“把餐盘送到对应餐桌”并不需要模拟人手去捏住杯子托架比夹爪可靠得多因为夹爪要考虑抓取位置、夹持力度、防滑而托架只需要在到达目标后把餐盘放下。这里有一个特别容易被忽略的细节餐盘放在托架上以后车身停止和起步的瞬间餐盘会因为惯性滑动。我们一开始没有在托架表面做任何处理结果放好的餐盘总是偏位。后来在托架上贴了一层防滑垫又加了两个小的定位挡边问题立刻解决。这个改动花了不到十块钱但效果比调半天PID还明显。2.2 电机驱动与电源分配稳电是稳定性的地基电源方案一开始我们走了弯路。最初图省事直接用一块12V锂电池给电机和单片机供电电机一转单片机就复位OLED屏幕跟着闪。后来检查发现电机启动瞬间电流冲击能把电压拉低到7V左右而单片机的稳压芯片根本扛不住这种波动。解决办法其实很基础电机驱动单独从电池取电主控和传感器通过降压模块供电同时把各个模块的电源地线汇集到一个公共点也就是共地。电机电源线也做了绞线处理减少对信号的干扰。驱动芯片选了TB6612FNG没用L298N。TB6612的导通压降小发热低体积也小最重要的是它的PWM频率响应比L298N好配合STM32的定时器输出用起来很顺手。电机的速度控制信号频率放在10kHz能听到轻微啸叫但工作正常。编码器是霍尔式的装在电机尾轴上用于测速闭环。电源分配上总体是12V电池进来看压然后再分成两路一路直接给TB6612一路经DC-DC降到5V给主控、OpenMV和舵机5V后面再经AMS1117降出3.3V给单片机外设。最初想着省一个降压模块让舵机直接吃电池电压结果舵机一抖动引发整机电压波动后来老老实实加了独立稳压。3. 软件与控制逻辑3.1 主控流程状态机比什么都好使送餐流程看起来简单但真要让机器人连续跑完“出发、循迹、识别、停靠、放盘、返回”这一整套动作主控逻辑一旦写成“从上到下顺序执行”中途任何一个传感器误判都会导致整个程序卡死。我们的做法是写一个状态机每个环节对应一个状态状态之间靠传感器事件触发切换。状态机的大致划分是IDLE、MOVE、DETECT、STOP、PLACE、BACK。在IDLE状态下等待启动指令按一下按键进入MOVEMOVE状态下循迹行驶行驶中如果OpenMV发来“检测到目标餐桌”的消息就切入DETECT在DETECT里判断车头是否正对餐桌确认后切入STOP并刹车然后机械结构执行PLACE最后BACK沿原路返回。这个逻辑的好处是任何时刻系统只处于一个明确状态调试时通过串口把当前状态打印出来就能立刻知道机器人卡在哪一步。状态机的实现代码并不复杂但是要注意状态切换的“条件”必须带消抖和超时保护。比如识别信号不能只读一次连续收到三次一致信号才确认切换避免OpenMV一帧误判影响全流程。每个状态也可以加一个最大执行时间超过时间强制回到IDLE并报警这算是一种软件看门狗现场演示时很管用。3.2 PID巡线与避障参数靠手感不如靠方法路径循迹用的是五路灰度传感器发射红外光并检测反射光线。场地上的引导线是黑色背景是白色传感器返回的模拟值经过阈值二值化以后可以判断当前车体是偏左、偏右还是居中。一开始我只做了简单的“查表转向”就是检测到最左侧传感器压线就往右打一点方向反之亦然。这种开关量控制在直道上没问题一进弯道就左右来回摆车头像喝醉一样。后来改成PID控制误差定义为五个传感器加权偏移量比如中间传感器权重0左侧负值、右侧正值把这个误差作为PID输入输出作为左右轮的速度差。调参过程比较费时间我和队友在实验室地胶上把速度分了三档先调P把P调到车过弯不冲出去再加一点D抑制震荡I加得很小主要消除直道上的静态误差。实测下来比例项在0.8左右微分项在0.2左右积分项只有0.02。参数范围没有普适性但整定方法是一致的先把I和D设成0只加P直到系统开始震荡然后把P乘以0.6作为初值再加D让震荡收敛最后加一点I修正稳态误差。避障模块用的是超声波HC-SR04安装高度大概8厘米能探测到前方模拟的障碍物或动态走来的人。策略很简单距离小于25厘米时减速小于15厘米时停车并等待。送餐机器人不太需要做复杂的动态避障毕竟场地就是在固定路线里超声波的作用更多是安全保护防止撞到评委或者观众。有一次现场测试有人突然从赛道前走过超声波检测到障碍后车直接刹停等人走了才继续走这个小细节在答辩时被评委问到了他们觉得这个安全意识不错。3.3 视觉识别OpenMV当眼睛够用了视觉部分是整个项目中我担心最多的地方。OpenMV是一款基于MicroPython的视觉开发板用它做色块识别、二维码识别都比较方便不至于像纯跑OpenCV那样写一大堆依赖。送餐场景里每张模拟餐桌前贴一个二维码二维码内容就是餐桌编号比如“table1”“table2”。机器人巡线走到某个位置后OpenMV开始扫描前方区域一旦读到有效的二维码就把编号和二维码中心相对画面的横坐标偏差发回STM32。代码思路是OpenMV在主循环里抓取画面使用find_apriltags()或find_qrcodes()函数识别标签识别到以后解析payload同时计算标签中心坐标。如果标签中心在画面中心偏左说明车头偏右需要向左微调反之亦然。这个调整通过串口发送一个简单的协议给主控主控再控制左右轮差速让车头逐渐对准标签方向。整个调整过程是一个开环微调不需要做复杂的视觉伺服因为我们的机械结构允许一定的对准误差托架伸出去以后还有一点冗余空间。这里要特别提醒OpenMV对光照极其敏感。比赛现场灯光一般是演播室那种大功率射灯角度一换画面亮度变化非常明显很容易导致标签识别断断续续。我们的解决办法是在OpenMV里固定曝光时间和白平衡取消自动调节同时给镜头加了一个可以转的偏振片。虽然颜色信息会有损失但二维码是黑白块对比度反而更稳定。现场实测下来识别率从七成提到了九成五以上。4. 竞赛调试与避坑实录4.1 现场最容易翻车的几个地方比赛现场和实验室最大的不同是环境的不可控性。第一是地面条件实验室里我们自己买的地胶平整度比较好比赛场地是拼接的展板板与板之间会有几毫米的缝隙灰度传感器经过缝隙时读数会跳变。我们当时在灰度二值化阈值里加了一个“连续采样三次相同才更新状态”的保护相当于软件滤波才把跳变问题压下去。第二是灯光前面提过视觉识别受光照影响如果现场有几盏灯在机器人头顶正上方OpenMV会出现镜头反光停车区识别很容易失灵。最直接的办法是在Debug模式下让OpenMV把画面经过WiFi传到手机上看现场快速调整曝光参数。第三是电池电压刚充满的电池和跑了几圈之后的电池舵机力量和电机速度都会有差别。这不是玄学是实实在在的工程问题。我们准备了两块电池轮换并且给系统做了低压提示电压低于11V时OLED会闪烁提醒换电池。还有一个很反直觉的坑每轮比赛前都有准备时间机器人在待机状态时OpenMV和主控都在运行但机械臂的舵机一直在通电保持位置。舵机比较大堵转电流很高会让电池电压掉得特别快。我们后来在PLACE状态之前才给机械臂舵机通电待机时彻底断电一个看似无关紧要的改动让整套系统的续航时间多了将近三分之一。4.2 调试工具和参数标定如果让我给准备比赛的人一条建议那就是“调试工具越早做越好”。我们前期太相信代码本身总是用串口打印一堆原始数据去猜问题效率很低。后来花一个晚上写了一个简单的串口调试上位机通过USB转TTL连接主控可以实时显示当前状态、传感器值、PID输出和目标车速还能直接下发参数不用反复编译烧录程序。参数标定速度至少快了三倍。所以我非常推荐准备一个可以离线调参的方案哪怕是用蓝牙透传模块加手机APP也好过每次改参数都重新烧录。PID参数的整定要有记录习惯。我们当时用坐标纸画了一条测试赛道每一组参数跑一圈记录超调量、摆动次数、过弯是否压线然后把参数记录到表格里。这种方法很笨但非常有效尤其是到了比赛前一天你会发现之前记录的某一组参数可能正是现场条件下最优的。还有灰度阈值标定不要在代码里写死要在程序启动时做一个校准流程让机器人静止在黑白交界面自动记录当前最大和最小值然后将阈值设为两者中点。这个校准逻辑最多二十行代码却能省去大量手工调试时间。参数标定最容易忽略的是机械结构的一致性。比如两个驱动电机虽然型号相同但实际转速可能存在5%左右的差异这会导致直道跑不直。我们只在软件上做速度闭环不够还要在开机时执行一次“直道校正”让机器人空跑两米测量偏移方向然后把对应的PWM补偿系数写进flash。其实就是简单校准没有那么高大上但现场如果跑偏至少不会让你束手无策。4.3 复盘三等奖到底输在哪里最后说说成绩。我们拿了三等奖往上差一步。复盘的时候我们发现主要输在三个地方。一是稳定性的边界不够强整个流程虽然跑通了但现场跑了五次只有三次是完全顺利的有一次卡在灰度传感器缝附近有一次机械臂没放正。评委打分时顺利完成次数是一个很重要的指标稳定性不足直接拉低了印象分。二是视觉识别没有冗余OpenMV只认二维码一旦现场有一个餐桌的二维码贴的位置偏高或偏低超出画面上边缘识别就直接失败。改进方案其实也很简单在二维码下方加一个色块引导区先用颜色粗定位再用二维码精识别这样鲁棒性会好很多。三是团队分工前期不清晰硬件和软件没有并行推进导致软硬件联调时间被压缩。当然这个项目也不是没有收获。最值钱的是整套系统的“问题定位方法论”。我们后来总结出一套排查顺序先看电源再看接线然后看传感器状态最后才怀疑算法问题。这个顺序在之后的智能车比赛里也帮我省了大量时间。另一个收获是明白了“完成比完美重要”比赛不需要展示最前沿的技术而是需要你在有限时间内交付一套可靠的东西。这个认知直到现在都很影响我做工程项目的思路。最后再分享一个小经验送餐机器人这类比赛项目赛后一定要把所有代码、机械图纸、接线图、调参记录整理到一个压缩包里按日期命名好。那段时间你想不通的bug过半年再看可能一眼就能找出问题。这个zip文件里不只是代码更是一份完整的工程日志是这段经历最实在的沉淀。本文还有配套的精品资源点击获取