简介:面向全国大学生电子设计竞赛参赛团队,围绕2023年E题自动追光云台,提供基于STM32F1微控制器的完整参考方案。内容涵盖光敏传感器信号采集、云台姿态检测、步进或伺服电机驱动、PID控制算法以及电源管理,从硬件电路到软件代码均有对应文件,适合备赛阶段快速理解赛题要点、借鉴设计方案与排错思路。包体共199个文件,压缩后仅6.74MB,包含C源码与头文件,以及编译过程生成的o目标文件、d依赖文件、crf交叉引用文件,链接映射表,axf和hex烧录文件,配合uvprojx工程配置与启动脚本,可完整还原Keil开发工程并直接编译调试。已有7735人学习,资源中定时器、ADC、I2C、USART等外设驱动示例清晰,对学习STM32外设配置和自动追光算法很有帮助,能为竞赛现场快速验证与调试提供可靠参考。 2023年电赛E题“运动目标控制与自动追踪系统”我印象很深。表面上看就是把一个激光笔装到云台上,让它在靶纸上打点、追踪移动光斑,好像每个模块都是常规操作;但真正到了联调那几天,很多队伍才发现,这套系统最大的坑根本不是某一块硬件不行,而是从摄像头画面到舵机角度、从颜色识别到闭环控制,整条链路里的每一个环节都会把误差放大一点,最后全堆在激光点位上。
如果你明年准备电赛,或者对“视觉识别+二维云台”这类项目感兴趣,这篇文章值得当作一份赛前复盘来看。我会把题目拆解、硬件选型思路、坐标标定方法、PID调参踩坑,以及现场最容易翻车的几个细节,按我自己的理解完整讲一遍。
1. 这套题考的不是激光笔,而是整条链路的稳定性
1.1 任务拆解:定点打靶和自动追踪分别卡住谁
E题通常包含两个核心动作。第一个是定点打靶:云台带动激光笔,按照要求依次照射到靶纸上的指定坐标点,测试的是静态精度和标定能力。第二个是自动追踪:人手拿一支激光笔,在靶纸区域内随意移动光斑,系统需要通过摄像头识别这个光斑,并且云台带动另一支激光笔实时跟随。
这两个动作考察的点完全不一样。定点打靶卡在“标定”和“机械精度”上,目标静止不动,算法压力不大,但最终激光点位偏了多少、稳不稳,直接决定了基础得分。自动追踪卡在“动态响应”和“抗干扰”上,目标在动,摄像头每一帧拿到的位置都在变,云台要跟得上、跟得稳,还不能被其他光源干扰。
很多队伍的问题在于:想一口气把两个任务都做得很好,结果两边都糊。我的建议是先集中精力把定点打靶做到极高的重复精度,再在这个基础上做追踪。因为追踪的底层控制逻辑,本质上就是“不断进行定点瞄准”,定点的精度和映射关系一旦稳定,追踪就成功了一半。
1.2 为什么单个模块都跑得通,联调却一塌糊涂
我见过不少队伍,在备赛前一天摄像头识别还特别准,舵机也能灵活转动,但把整个系统拼起来后,激光点就像喝醉了一样乱跑。这种“单模块正常、联调翻车”的现象,根源普遍集中在三个方面。
第一是坐标系不一致。摄像头输出的目标位置是像素坐标,而云台需要接收的是角度值,很多人在这一步直接用一个固定比例系数去换算。表面上看能转过去,但摄像头视角的边缘畸变、安装位置带来的透视误差,都会让固定比例系数在靶纸不同位置产生明显偏差。
第二是数据刷新率不匹配。视觉模块识别一帧目标可能需要几十毫秒甚至上百毫秒,而舵机控制的PWM输出是连续的,如果主控直接用最新识别结果覆盖上一次输出,就会出现角度突变,云台表现为“咔咔”抽动。
第三是供电问题。这个最隐蔽,也最坑。舵机启动和重负载瞬间的电流可以达到几百毫安甚至更大,如果视觉模块和舵机共用一块稳压模块,舵机一转,摄像头画面就会出现横纹甚至黑屏,识别自然全乱了。
所以我说这套题考的不是激光笔,而是整条链路的稳定性。任何一环的误差都会被后级放大,最终全部体现在激光光斑上。
2. 硬件选型的一大三小:摄像头、主控和云台怎么搭才不吃亏
2.1 摄像头和主控:三套方案的取舍
视觉方案的选择,基本决定了团队整个备赛周期的节奏。我把常见方案整理成一张表,大家可以直接对照自己的情况选:
| 方案 | 优点 | 缺点 | 适合队伍 |
|---|---|---|---|
| OpenMV M7系列 | 上手快,IDE成熟,MicroPython写起来省心,LAB色彩空间很好用 | 性能有限,复杂算法和低分辨率下帧率一般 | 视觉基础薄弱、想尽快跑通闭环的队 |
| K210 Maix系列 | 算力强,性价比高,跑图形分类或简单神经网络没问题 | 资料杂,SDK细节需要自己趟,调试不如OpenMV直观 | 有一定开发经验、想在视觉上多留余量的队 |
| 普通USB摄像头 + PC/树莓派 | 调试方便,串口日志、图像窗口、算法库都齐全 | 现场要带笔记本或大板卡,供电和携带都麻烦 | 队伍里有熟练的上位机或Python经验的队 |
从2023年现场参赛队的情况来看,成绩不错的队伍里,OpenMV和K210占了很大比例,主控基本都是STM32系列,负责读取视觉结果、算PID、输出PWM。STM32F103完全够用,不需要上更高端的芯片。
如果你是第一次打电赛,我比较推荐OpenMV起步。不是因为它性能多强,而是它能把“图像处理”这件事的门槛压得很低,让你把时间省下来去啃标定和控制——那才是E题真正拉开差距的地方。
2.2 舵机选择、机械刚性和重心,都会变成实打实的误差
云台结构方面,最常见的是两个舵机组成的二维云台,一个负责偏航,一个负责俯仰。舵机选型上,普通9g舵机(比如SG90、MG90S)扭矩偏小,带支架加激光笔还算勉强,但如果云台结构稍微重一点,转动时就会明显抖动。推荐至少用金属齿轮的数字舵机,扭矩在15kg/cm以上比较稳妥。
这里要特意计算给新手看:假设靶距是1米,舵机转动1度,激光点大约会移动17毫米。而普通模拟舵机在死区附近的控制分辨率,加上机械齿轮间隙,很容易造成0.5度以上的不确定性,已经是一个肉眼可见的偏移了。所以我们队当时宁可牺牲一点点转动速度,也要换回扭力大、回中准的金属舵机。
机械上还有一个很容易被忽略的点:重心。云台是典型的“悬臂梁”结构,激光笔和支架的重心离舵机旋转轴越远,转动时惯性就越大,舵机需要额外用力克服偏载,反而更容易发热、抖动。安装时尽量把激光笔夹短、夹紧,让负载重心靠近旋转轴。再强调一个细节:激光笔必须用夹具加扎带或热熔胶固定死,不能靠摩擦力硬撑,云台一转起来,任何松动都会被放大成光斑抖动。
2.3 供电是个被低估的问题,别让舵机和视觉模块互相干挠
上面提到过供电对摄像头画面的干扰,这里单独提醒一下。我们当时用的是两路供电:一路给舵机,一路给主控和摄像头,两个电源模块的地线还是共地的,这样舵机突转时的电流尖峰就不会直接拉垮摄像头电源。
如果条件限制只能单电源,也要在舵机供电脚并联一个大容量电解电容(比如1000μF以上),并且尽量让舵机的地线直接回到电源负极,不要经过摄像头比较脆弱的那一段。
3. 坐标标定:像素坐标到云台角度,差之毫厘全盘皆输
3.1 为什么线性缩放不够,你到底在标定什么
很多第一次做视觉云台的人,拿到摄像头的目标像素坐标,第一反应是:“我算一下图像中心到目标的像素差,再乘以一个固定系数,转过去不就行了吗?”
这个思路在靶纸很小、云台离得很近的时候勉强能用,但一旦靶纸稍微大一点,或者激光笔初始落点在边缘,线性缩放的误差就会迅速膨胀。原因有两个:一是镜头本身存在径向畸变,画面边缘的像素对应的实际角度变化和中心区域不一样;二是摄像头和激光笔并不共轴,摄像头看到的几何关系和云台转轴实际走过的角度,天然是两套坐标。
打个比方,你用手电筒从侧面照墙上的一个点,手电筒转动相同角度,墙上光斑的移动距离是随照射角度变化的,在正面和侧面完全不一样。摄像头识别和云台转动之间的关系,也是类似的非线性映射,只不过多了一个镜头畸变。
所以标定的本质,不是在找一个固定系数,而是把“摄像头像素坐标”和“云台目标角度”这两个空间真正对齐。
3.2 一套能稳定落地九点标定流程
我们队当时用的九点标定法,步骤很简单,但每一步都有它存在的意义。
第一步,固定靶纸和云台。听起来像废话,但很多队伍就是在这个地方翻车的。比赛过程中靶纸不能被压住或移动,云台底座也要用重物压稳。标定做的是一对一的映射关系,任何一方的位置变动,都会让之前采的标定数据全部作废。
第二步,在靶纸上划分采样点。一般3×3或者4×4就够,覆盖整个靶纸区域。我建议先做3×3,确认误差满足要求后再加密到4×4,不要一上来就采样几十个点,浪费时间还容易抄错数据。
第三步,手动控制云台,让激光笔依次对准每一个采样点。每对准一个点,同时记录两组数据:当前激光点在图中的像素坐标,和云台此刻的目标角度。这一步要用串口把数据打印出来,边做边存。人为目视对准会有小误差,所以每个点可以多打几次,取平均记录。
第四步,根据记录的数据建立映射。最简单的做法是查表加线性插值,4×4的网格足够让相邻点之间近似线性;如果希望更平滑,也可以用二次多项式拟合出“像素坐标到云台角度”的映射函数。两种方法我都试过,查表插值更直观、好调试,现场出了问题能快速定位。
第五步,标定完必须验证。选几个不在采样点上的位置,让系统自动转过去,看看偏差有多大。我一直保留着一个验证程序,让云台依次打一圈目标点,然后把每个实测落点打印出来。如果边缘偏差太大,就需要增加采样密度或者检查机械间隙。实测下来,这套方法能把原先线性公式在边缘三十四毫米的误差,压缩到可见范围内的小几个毫米,完全是质变。
4. PID 调参和追踪抖动:真正拉开分数差距的地方
4.1 为什么普通的PID就够用,关键是怎么接
追踪移动光斑,看上去很像是“机器学习”“目标跟踪”的活儿,实战中发现普通PID就够了。原因很简单:手持激光笔的移动速度相对云台来说并不快,目标轨迹是平滑的,PID这种无模型的经典控制完全吃得开。
我们用的位置式PID思路是:每次从标定映射表得到目标角度,和云台当前目标角度做差,经过PID输出一个角度的修正量,再把修正量折算成舵机PWM脉宽。初次调参可以按照P=3~5、I=0.1~0.3、D=0.3~1这个区间去试。P太大会看到云台明显发抖,I太大会出现来回扫的慢摆动,D太大会对识别噪声特别敏感,一个小误检就会让云台猛地抖一下。
调试的顺序,永远是先去掉I和D,只调P,让系统能在目标附近快速接近且不震荡;再加D看能否抑制超调;最后加一点点I消除静态偏差。别一上来就三个参数一起调,不然你永远不知道系统到底是被哪个参数带着跑的。
4.2 目标短暂丢失,是这个任务最大的敌人
追踪的时候最影响体验的问题,不是云台不够快,而是目标偶尔消失或者颜色误检,导致控制量突然跳变。比如检测目标连续几帧丢失后,系统认为目标没了,把云台转到某个默认角度;下一帧又识别到了,又猛地拉回目标附近。一来一回,整个云台就像在敬礼。
解决思路是加一个“有效帧计数”的防抖逻辑。连续丢帧要先扣计数,计数扣到0才判定目标真正离线;如果识别到的新目标位置相比上一帧跳得太离谱,超过了一个最大位移阈值,很可能就是误检或反光,直接忽略这一帧。伪代码大概是这个样子:
# 伪代码示意,具体按你的工程结构调整 target_valid_count = 0 last_pos = None while True: pos = detect_target() if pos is not None: if last_pos is None or distance(pos, last_pos) < 50: # 更新目标位置,恢复有效计数 update_target(pos) target_valid_count = min(target_valid_count + 1, 5) last_pos = pos else: # 位置跳变过大,当作误检 target_valid_count = max(target_valid_count - 1, 0) else: # 未检测到目标,先衰减计数 target_valid_count = max(target_valid_count - 1, 0) if target_valid_count == 0: clear_target() last_pos = None这个防抖逻辑看起来很朴素,但在赛场上非常能救命。因为光照变强、红外反光、人经过时产生的阴影,都可能导致视觉模块偶尔误判一帧。如果没有这套保护,整个追踪过程就会显得极其不稳。
4.3 激光笔压线、PWM分辨率和靶纸处理
还有一个容易被忽略的点是PWM分辨率。如果主控定时器做PWM的位数不够,角度值经过四舍五入之后,原本连续的小角度调节会变成一跳一跳的台阶动作,肉眼看似平缓,激光点上就是细碎的抖动。建议用16位分辨率输出500~2500微秒的舵机脉宽,这样0.1度的调整也能平滑反映出来。
激光笔固定这一点我再强调也不为过。比赛现场我们用的是金属夹具加热熔胶,把激光笔死死压在云台滑槽里,笔尖指哪就是哪。如果是那种靠弹簧夹的塑料架,云台转几圈后激光笔就会因为振动慢慢移位,导致标定失效。这属于“平时不会出问题、现场一定会出问题”的典型。
靶纸的处理也会影响识别和落点。靶纸不是贴墙上就行,一定要绷紧、压平,不能起皱。激光打在褶皱处,反光会让摄像头识别到的光斑形状发生形变,影响中心点提取。如果你发现追踪时画面里的光斑忽大忽小,先去看靶纸是不是已经皱得不像样了。
5. 现场光照、赛程规划和调试习惯:四天三夜翻车重灾区
5.1 光照一变,颜色识别就跟着崩
颜色识别是激光追踪的基石,而它最怕的就是光照变化。实验室晚上灯光稳定,到了比赛现场各种顶灯、大屏、窗户透进来的自然光相互叠加,同一个红点的RGB分量可能和昨晚差出一大截。
对策是把颜色判断从RGB空间换成LAB空间。LAB空间把亮度信息放在L分量,颜色信息放在A和B分量,这样即使整体亮度变化,红绿色点的A、B值相对稳定得多,识别的鲁棒性会提升一个等级。另外,有条件的话手动锁定摄像头的自动白平衡,别让它在不同色温下自己乱跳。
我在现场看到有些队伍在测试环境里识别得好好的,比赛开始后突然一片白,排查很久才发现是旁边队员穿了一件大面积亮红色T恤,把识别阈值彻底带偏。所以识别阈值要尽量收窄到“目标激光点”的专属范围,并且用形态学开运算把杂散噪点先处理掉,再提取最大光斑。
5.2 四天三夜的赛程,建议这样分配
根据我自己的备赛体会,四天三夜的时间如果平均用力,最后一天往往什么都做不成。建议把时间切成四段:
第一天白天把硬件搭起来,摄像头识别到激光点,舵机能正常转动,整个闭环先“冒烟测试”跑通,哪怕精度很差也先接受。第一晚到第二天主攻标定和定点打靶,这个环节是整个项目的精度基础,越早稳定越好。第三天做自动追踪,在标定基础上调试PID和防抖逻辑。第四天只做一件事:全流程演练和环境适配,别再去动大结构。
这个顺序的理由是:定点打靶解决的是静态映射精度,它是追踪的基础。如果第二天还在纠结硬件能不能动,第三天就很难静下心控制。
5.3 值得保留到赛场上的几个调试小习惯
最后说几个我们队磨合出来、在现场特别值钱的小习惯。
第一,所有关键变量都要能实时看到。目标像素坐标、标定映射后的角度、PID输出值,至少要有一种方式能输出出来。ViewTool的串口助手也好,OLED小屏也好,看不到中间环节就没法定位问题。
第二,代码里把“标定模式”和“运行模式”做成开关,而不是每次切换就去改逻辑再烧录。现场时间非常宝贵,编译一次烧录一次可能就浪费五分钟。
第三,备用硬件多带一套。云台舵机、摄像头、视觉模块、杜邦线,只要能换的全都备一份。很多队伍不是设计不行,而是临场坏了一个传感器,整个节奏全乱了。
第四,赛前手工写一个小脚本,让系统连续自动打靶二十个点,打印出每一次的偏差序列。这套“重复性测试”能暴露出很多偶发问题,比如某个固定角度下舵机偶尔转不到位,或者某个区域的反光导致识别不稳定。别只用眼睛看一两次就打比赛,偶发问题才是比赛现场最致命的。
(以上均为个人赛事复盘和备赛总结,具体题目要求以官方发布为准。)
本文还有配套的精品资源,点击获取