惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
Martin Fowler
Martin Fowler
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
I
InfoQ
A
About on SuperTechFans
GbyAI
GbyAI
宝玉的分享
宝玉的分享
爱范儿
爱范儿
博客园 - 【当耐特】
博客园 - 司徒正美
博客园 - 聂微东
P
Proofpoint News Feed
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
B
Blog RSS Feed
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
J
Java Code Geeks
博客园 - 叶小钗

Exister

谁是人民? 谁是人民? 算盘上的童年 算盘上的童年 倒计时器 · 中断原理 倒计时器 · 中断原理 向死而生 向死而生 爱,死亡与机器人 爱,死亡与机器人 什么是真正的哲学 什么是真正的哲学 LG V30 开源之旅 LG V30 开源之旅 VENI VIDI VICI VENI VIDI VICI 那些不曾察觉的事物 那些不曾察觉的事物 十八之行
那圈不知归途的线
Exister · 2026-08-02 · via Exister

最近参加了个学校主办的循迹、避障小车比赛。宣传的时候说得很简单,只要有兴趣就可以报名。我想可能正因如此,吸引了很多对该领域几乎没有任何了解的学生参加。而到比赛正式开始时,已经有超过四分之一的队伍退赛。实话说,我对这方面没有任何经验,对比赛还有些畏难情绪,不过这比赛是别的同学告诉我的(他想让我跟他组队,我当队长),而他更是连学校里的编程课都没好好学。看他毫无压力的样子,我便答应下来。

赛前

这次比赛的宣传做得确实不好,在参加比赛前,我们连小车有什么要求都不知道。报名结束后,老师给我们发了小车套件。也就是说,组委会提供小车套件,我们只负责焊接编程调试,无需自行设计外壳和电路。而令我惊喜的是,套件使用的正是 51 单片机。我是学过 51 单片机的,虽然已经好久没写程序了,但底子还在,看一下以前的笔记,就能回想起来。更何况,我自认为我用 AI 的能力比同龄人要强不少,加上 AI 的辅助,应该没什么问题。

在某一天晚上,我把队员召集起来,商量分工的事。因为我之前就自己买了焊台,一直没用过,想借这次机会赶紧用用,所以我要求我来负责焊接。但问起编程,我发现我的队员只有一个(下称 A)会 C 语言,而他也只学过 STM32。其实这时候我就有自己一个人比赛的打算了,队员只当充数。但表面上,我们还是商量着,每个人都分配了一些任务,比如完成一个模块的驱动代码。但我说要求十分“弹性”,如果学不会就不用完成了。至于调试,如果连编程都不会,就更不能指望了。

比赛项目有循迹和避障,其中避障功能小车组件中有红外避障和超声波避障,我肯定要使用更加高级的超声波避障。至于循迹,只有两路红外传感器。总的来说,硬件还是十分简陋的。

焊接

老师安排了实验室供我们焊接,并请来了智能车比赛的学长帮我们答疑。可我的积极性太高,在老师安排好之前就焊完了。而上电前检查的时候,我发现了一个令人感到绝望的事:我把上拉排阻焊反了!我一看这玩意这么长,就知道不会拆啊,去网上搜各种教程,吸锡带、吸锡器都买了。吸锡带根本不吸锡,加助焊剂也没用;吸锡器能吸掉背面的焊锡,内侧还残留有锡,排阻纹丝不动。我只能期望实验室能有热风枪,或问问学长如何解决。到了老师安排焊接的那天,我去实验室问老师有没有热风枪,她说:“不知道哎,我问问吧。”我听到这话就知道她要晾我,赶紧找到学长,想让他帮我。他用电烙铁和吸锡器拆了半天没拆下来,然后看了原理图(见下图)说:没太大问题。P07 少了一个上拉电阻,但 P07 根本没用到;P00~P06 变成了 20KΩ,影响不大。听了他这话,我放下心来。但回宿舍后越想越觉得不对,我以前问了多个 AI 模型,都说这是十分严重的问题,难道 AI 都说错了?我仔细分析了一下,发现并非若学长所说那般。

上拉排阻焊反

51 单片机的 P0 口是开漏输出,输出高电平实际上是“悬空”,输出低电平是连接到地。没有上拉电阻,P0 无法输出高电平。

这是 P0 口上拉电阻的原理图:

原理图

如果正确焊接,应当是这样:

正确焊接

如果焊反了,就会变成这样:

焊反

这种接法把 8 个引脚“绑”在了一起,导致引脚之间相互干扰。相当于所有引脚先连到一条公共总线,再通过一个 10K 电阻上拉到 Vcc。当其中某一个引脚被外部拉低时,其他引脚也会被拖累。

举个例子:假设 P00 被拉到地(P00 = 0),其余端口均为高电平。此时电流路径是:

1
Vcc -> 10K(公共) -> 公共节点 -> 10K(P00 支路) -> P00 -> 地

假设 Vcc 5V,此时公共节点电压会被分压到 2.5V,而 P01 到 P07 都连在这条公共总线上,所以当它们只有 2.5V。

若两个 P0 端口拉低,则其余端口的电压为 53\frac{5}{3} V。拉低的端口越多,其余端口的电压越低,完全有可能落入电平不确定的区域。

因此,这确实是一个十分严重的错误。我几近崩溃地下单了热风枪,希望能快点到,因为尽管此时代码已经写得差不多了,我还没有调试过。如果不调试,我再没有其他可推进的方面。

后来在队员 A 的帮助下,我们用热风枪和镊子成功把排阻拆下来了。但因为太用力,把排阻都夹烂了。我早预料到会有这样的情况,提前买好了排阻并焊上了。我回宿舍后,第一次给小车上电,LED 正常点亮;烧上程序后,小车轮子转起来了。这一刻,我终于松了一口气,没烧板子,看起来运行也正常。上拉排阻焊反的问题总算是解决了。

编程

编程几乎全是我一个人完成的。只有队员 A 给我发了一个模块的代码,这些代码还是他从一个 B 站 UP 主那里找到的,我根本没用。我把他的代码发给 AI,并告诉 AI 我的硬件信息,AI 的结果直接就能用。

在这次比赛中,我大量使用了 AI。不过我每一行代码都仔细看过,确保我能完全理解小车运行的逻辑。我也发现了 AI 在嵌入式开发中的一些问题:

  1. 标志位状态容易弄反。AI 只是在概率预测这个标志位是什么,它很容易搞反 0 和 1 的意义。
  2. 使用过大的数据类型,导致 ADDRESS SPACE OVERFLOW。AI 编写的程序很不注重节省资源。如果需要存储一个大数,它很可能会用 long,但如果具体分析,可能 int 就够了。这对资源有限的单片机来说不友好。

当然了,这些问题也许可以通过在上下文中提供更多信息(如编写 AGENTS.md)对 AI 进行约束来解决,但需要逐渐积累经验。

调试

直到比赛前几周,老师才通知我们可以在比赛前一周试车。我自然是等不到那么久的,还没写完代码我和 A 就商量着调试的事了。A 买了黑胶带粘在地上当黑线,我在黑线上调好了红外传感器的电位器,边测试循迹边改代码,最终跑起来没什么问题了。

待比赛场地开放、可以试车后,我才知道比赛跑道使用的是喷绘布。我带着小车过去调试,场地已经有很多队伍了。我把小车放在黑线上,打开开关,却发现完全乱套了,需要重调电位器。看着场地其他队的小车,已经有几个能跑了,我一个人蹲在地上调小车,倍感紧张。调了好久,终于能跑了。根据场地测试,调整了一些参数,避障功能也没问题了。这时候,我看着其他队的小车,有的还在调电位器,有的在黑线上转弯都走不好,心中是洋洋得意啊。但我的小车也还存在几处无法正常处理(这也是场地的难点):

  • 半圆弯:直线连接一个半圆,在连接处切线方向呈 90°。小车走到连接处,一侧红外传感器突然检测到踩线,小车从而向这一侧转弯。而走过这一瞬间,小车两侧传感器均检测到反射的红外线,这种状态与小车骑在线中间无任何区别,你无法判断小车是走到线上了,还是脱线了,因此不好处理。
  • 交叉弯道:跑道的一片区域绕成了“8”字形(有缺口)。如果交叉线是垂直的(十字),相对好处理一些:如果车头两侧传感器都没有检测到反射的红外线(两侧均是黑线),则忽略传感器输入盲走一段距离,从而冲出十字区;但如果不是垂直的,车头会一侧线触线,再两侧都触线,此时车头已经转动一定角度了,如果盲走,可能会产生较大偏差。
  • 直角弯:这种情况与半圆弯类似,但在此次测试中,我的小车能正常走,而且我也并没有注意到这个问题。后来我发现,小车每走到一些区域,就会误触避障,开始转弯,且概率非常大。我移动了布、转动了布的方向,发现仍然在这些区域误触。我怀疑是布的问题,可能是褶皱反射超声波导致距离误判。而有趣的是,直角处也有误触,而正是这次误触,让小车能够通过直角弯(因为小车发现障碍物后要转弯)。我告诉了老师,老师说他们研究一下。同时,我为超声波测距模块添加了防止误触的代码。虽然我不知道他们有没有解决,但下一次来调试的时候确实没有误触了。我不知道是我的代码的作用,还是老师对布做了什么处理。

跑道

当时我觉得,这么些小问题,要不了多久就解决了,但后续的调试难度超乎我的想像。

随着来调试的次数变多,我发现每次测试的结果不一样。往往这次测试还是好的,下次再来就出问题了;也有一些功能,这次测试发现有问题,解决不了,下次再来就莫名其妙好了。后来我意识到小车没有稳压模块,受电池电量的影响很大。因此,我尽量在调试时保持电池电量一致,但仍然隔了一天情况就大不相同。

受限于传感器,很多状态无法识别。为了解决这些问题,我有很多设想,但这些想法只能是开环控制,代码写出来,实际效果未必如愿。事实上,我觉得以当前的硬件限制,这些情况就没有稳定解法。某一次测试通过,可能是多种因素叠加作用的结果,这些因素一旦发生变化,就可能无法正常通过。

以交叉弯道为例,我遇到过的问题有:无法进入内部圆圈、卡死在内部圆圈无法出去。小车的运行结果,取决于进入这段不确定区域的角度,小车运行的速度、转向的速度等,可能调某几个参数,就莫名其妙好了;下次再测试,又不行了。

在一周的时间里,我几乎每天下午到晚上都会在场地调试,而只有队员 A 来陪我调试过几次,其余时候我都是一个人。按照我的观察,其他队伍对调试都不太上心,来的次数不如我多。还有一些队伍把写代码和调试的任务分配给不同的人,让我觉得不可思议。来调试的人就只能扭扭电位器,像是在刷存在感。本身这种比赛一个人搞就行了,没什么分工的必要。

终于在比赛前一天,我把所有项目都测试通过了。可等到比赛那天早上就又出了问题——交叉弯道又过不去了,我吓得赶紧让 AI 给我提建议,但我草草读过 AI 的方案后觉得开环控制还是不靠谱,于是决定不再浪费时间去实施。我心中焦躁不安,脑子里一片空白,不知道该怎么解决。具体代码已经没有时间再去看了,我只能从配置参数入手。我仔细观察了好多次小车的运行状况,脑中模拟如果某些参数微调后会发生什么变化,找到可能有效的参数后就边调边测试。微调几个参数后,小车终于能正常通过交叉弯道了。我多测试了两次,很稳定,然后又完整跑了两圈,没问题。我把小车小心翼翼地装到箱子里,就放在比赛场地,连动都不敢再动它。

比赛

比赛开始前一天,老师通知了比赛的规则:队伍可以自行选择发车的地点和方向,完成避障和循迹两个项目,其中循迹又分很多个小项目。记录小车跑一圈的时间,若小车没有完成某个项目,可以选择重新发车或跳过这个项目,如果选择跳过,要增加一定时长。比赛限时 3 分钟,最多跑两圈,记录最好成绩。每个队伍有 3 分钟在场地试车时间,试完车,要到一个新的场地去比赛,而在此之前我还以为就在那块布上比赛。我庆幸于之前遇到超声波误触的情况后及时解决了这个问题,要是我抱着“能跑起来就行”的想法,依靠超声波误触来走直角弯,在比赛中是绝对无法通过的。我试车的时候,跑了一圈,发现依然全部通过。我怕继续耗电导致情况发生变化,赶紧把小车关了,跟管理人员说:不用试了,让下一队来吧。然后我来到了比赛场地等待。

等待十分令人焦急的,虽然我的小车在那边场地测试毫无问题,但也不能保证比赛过程中不会出差错。关键是我们队前面那队,比赛完了还在评委面前磨磨叽叽不知道干什么,本来我都做好上场准备了,只得在旁边站着。我的腿不住地颤抖。

终于轮到我们队了,我把小车放在跑道上,拨开开关。但发现这张喷绘布的摩擦力好像与之前测试的那张不一样,第一次避障时,转向的角度不够,撞到了障碍物上。我要求重新发车,但重新发车后仍然撞在障碍物上。就这样重复了几次,我内心已几近崩溃。虽然我的目标是所有项目通过,但现实竟如此残酷,我忍不住动摇了:要不放弃这个项目吧?然而就在这次,小车成功绕过了障碍物。

我总算如释重负,转过身决定坐在后面的椅子上看,评委却发出了一些声音,我转头一看,小车脱线后没有正常回归,已经偏离了轨迹。我心如死灰,就计划着重新发车,直接跳过避障项目了。而正当我准备前去拿起小车时,小车却自行转弯回到了线上。评委们都惊讶不已,发出一阵骚动。其实说实话,我也不知道小车是怎么回去的,我不记得我有写相关的代码。

我重新坐回椅子上,看着小车陆续走过半圆弯、交叉弯道……我悬着的心也慢慢放了下来。小车快回到起点时,主持人提示时间还剩 30 秒。小车终于走回起点,我轻轻把小车提起来,说:“不测了。”

走出比赛场地,感觉我的腿有些发软。我还要去上课,就提前走了,而我的队友留下来观察战况。事后得知,我们队是第一名,也是唯一全部项目通过的队伍。大多数队都没成绩,因为 3 分钟都没跑完完整的一圈,有成绩的都获奖了。

总结

实事求是地说,这次比赛所有项目通过,还是有幸运的成分的:

  1. 我选择将发车位置定在障碍物前,首先完成避障。若小车跑了一段时间,才开始避障,这时候发现避障有问题,再要求重新发车,时间肯定不够了。
  2. 避障通过也是概率因素。如果再不通过,我可能就要放弃这个项目了。
  3. 小车偏航后怎么回去的,我完全不知道,这不是我刻意设计的逻辑,可能是某些我不知道的因素在作用。

不过,我觉得我们队拿第一名仍然毋庸置疑。虽然后面的比赛我都没看,但我的队友看了,我让他们录下来。我看了第二名的视频,他们队的小车速度特别快,而且看运行状态十分“轻巧”。我不知道他们是怎么做到的。组委会不让使用非他们发放的配件,但允许机械改造。难道他们的电池比我们轻,或是使用了什么更轻的材料?不过,他们没有通过直角弯,因此最终计算出来的“时长”高于我们队。乍一看非常奇怪,直角弯和半圆弯差不多,为什么前者无法通过,后者能通过呢?可以肯定,这不是概率因素,因为他们跑了两圈,都是这个结果。我仔细观察了他们队小车的运行状态,推测小车的转向是转动固定角度(可能是通过定时器实现的)。对于半圆弯,虽然转折点处切线垂直,但就算转的角度不够 90°,向前走一点,也可以走到线上;而直角弯就不会这样了,转不够 90°,就无法通过。这是逻辑缺陷,并不是不够幸运。

插曲

比赛当天下午我有课,但我不放心把小车交给队友,就向老师申请提前比赛。小车跑完我就走了,刚好赶在上课之前。之后赛场上发生了什么,我就不知道了。比赛后,我听闻了一条参赛学生攻击组委会的言论,推测可能很多学生对此场比赛不满意。听队友说最后颁奖的时候都没几个人了,他们可能是和我一样有事,或许是觉得无趣,又或许是觉得结果对不住自己的“辛勤付出”,便愤而离开了吧。还听说有一位同学,在组委会老师面前哭着要求再让他跑一次,耽误了不少时间。

自己花费了许多精力去完成一件作品,最终竟然连成绩都没有,从感情上实在让人难以接受。后来老师通知所有参赛的队伍都有参与奖,不知道是否与此有关。不过,“3 分钟限时”的要求在比赛前一天便通知了,他们或许是没有仔细看通知。当一个项目无法通过时,是选择跳过而节省时间,还是重试并增加超时的风险,本身就是一种策略,哪来的“既要又要”呢?