陀螺小车传奇之00011000

最后橘猫说

?

最后蜘蛛说

黑胶带绕到第一个弯的时候,我还站在旁边笑。

车走得比我预想中稳。它沿着白纸中央那条线向前,车头偶尔轻轻晃一下,随即又摆正。我刚想拿起手机拍下来,轮子忽然朝左边猛推了一把。

车头转过去了。

它没有转回来。

黑线已经落到车后,两个轮子却还在一左一右地朝同一个方向使劲。车身贴着地面打转,先是一圈,接着第二圈。电机的声音从平稳的嗡鸣拉成尖细的一线,像有人把一根弦越拧越紧。

我伸手去拦。车壳碰到手背时还有点烫。

那一刻,我没觉得是代码的事。基础速度是 40,我把它改成 30。重新下载,小车慢了下来。它几乎走过了那个弯,轮子也没有刚才那么急。我蹲在地上,看着它一点点靠近弯道,指头已经从复位键旁边挪开了。

然后它又往左转了。

这次转得慢些,像一枚收着力气的陀螺。白纸面上被轮胎磨出一道浅浅的灰印。

我把左边的修正量从 20 改成 10,又把右边加了补偿。两只电机本来就不一样,这很合理。再下载,再放下去。它走得更远,甚至在第二个弯前自己挣回来一点。我蹲久了腿麻,站起来的时候膝盖咔嗒响了一声。

第三个弯,它又开始转。

后来我不记得自己一共下载了多少次。PWM 改过,基础速度改过,左右补偿改过。传感器离地高度抬高一点,压低一点;模块上的电位器拧到左边,又拧回右边。桌上的便签纸越贴越多:

text 复制代码
30 好像稳
右轮 +3
再低会不动
可能是反光

每一条都像个挺有道理的解释。

小车也很配合这些解释。它总会在我刚改完参数的时候表现好一点:直线走得很直,进入弯道时也肯收车头。可只要它经过某个说不清的位置,左轮就慢下来,右轮推上去,车又开始打圈。电机声再尖起来的时候,我就蹲下去按复位,指腹在复位键上多停了一会儿才松开。

换了白纸,换了黑胶带,甚至怀疑那条线贴得不够黑。凌晨以后,地面上全是被撕下又贴回去的短线段。

后半夜,我做了最后一次修改。基础速度提回去一点,转向差拉大。前几次失败让我觉得它是"转得不够果断"------左修的时候左轮还在拖,右轮推得也不够狠,所以它才会在弯道边缘磨来磨去。

下载的时候我盯着进度条,进度条走完那一秒,我把车摆在线的起点,手指在复位键上停了一秒,才松开。

它冲了出去。

第一段直线很干净。第一个弯,它过了;第二个弯,它也过了。小车跑得比刚才所有版本都漂亮,车头几乎贴着黑线走。我从地上站起来,膝盖又响了一声。

黑线在前面收成一个很窄的弯。

OLED 先闪出:11110000。

车头像被谁攥住了一样,猛地向左甩过去。那一甩很漂亮,甚至可以说是正确的。可黑线没有停在原处。它从车头下继续掠过去,OLED 又跳成 01110000,再跳成 00110000、00011000、00001100。小车没有跟着这些变化收回车头。左轮和右轮仍维持着刚才那道最大的转向命令,把车钉在原地。轮胎在白纸上擦出尖锐的声音,车壳震得发颤。

它原地转了一整圈。

没有停。

第二圈、第三圈、第四圈。黑线、桌腿、我的鞋尖、黑线、桌腿、我的鞋尖,眼前的东西被它卷成一个飞快重复的圆。电机声已经听不出左右轮的分别,只有一团持续拔高的嗡鸣。

我扑过去按复位,没有按准。车壳擦着手背滑开,继续在原地转。最后我直接拔掉电源,它才忽然停下。纸面上留着一圈被轮胎反复磨出的灰痕。

我看着那圈灰痕,蹲得太久,小腿有点发酸。

我把车架回书本上,接上 OLED,拿了一小条黑纸。既然它总在某个位置出问题,那我就不让它跑了。我只让黑纸一个探头一个探头地经过。

屏幕上的数字跟着亮灭。

最左边单独压住,10000000,正常。

左边两路一起压住,11000000,正常。

整排压住,11111111,正常。

再把黑纸压到左侧四路,11110000。小车立刻给出那道最凶的左转命令,和最后一次冲进弯道时一模一样。

最右边单独压住,00000001,还是正常。

我在纸上写下四个勾。笔尖顿了一下,又写了一个勾。

黑纸往右挪一格。

OLED 显示:01110000。

小车没有接住它。轮子还保持着11110000留下的左转,像把那一声命令钉死在了原地。

第一个叉。

黑纸继续移到中间。

OLED 显示:00110000。

轮子还是没有换方向。

第二个叉。

再试右边中间两路。

00001100。

又是一个叉。

我开始把每一种状态都写下来。写到后来,纸上的勾和叉像两群人站在两边。我没有马上看出它们的区别,只觉得那几个叉很刺眼,眼睛有点干,揉了揉。

过了一会儿,我把纸转了九十度。

勾那一边是:

text 复制代码
10000000
11000000
11110000
11111111
00000001

叉那一边是:

text 复制代码
00110000
00011000
00001100

我的视线从第一列移到第二列。停了一下,又从第一列移到第二列。

那些叉,全是从零开始的。

代码窗口还开着。那张很早就写好的 switch 表安安静静地停在那里,case 00011000: 和 OLED 上的 00011000 长得一模一样。我曾经就是因为它们一模一样,才放心把整张表一次写完。

00011000 在代码里不是一排传感器状态。最前面的零把它变成了八进制数,值是 4608;而我用十进制乘法拼出的 uint32_t value,在那一刻是 11000。

OLED没有骗我。

勾旁边的10000000、11000000、11110000、11111111 前面没有零,所以侥幸走进了正确的 case。00000001 更坏,它无论按哪种方式读都是 1,替这段错误代码作了一次伪证。

最后一次失控的顺序也有了答案:11110000 真的触发了最高速左转;随后循迹状态已经变成 01110000、00110000、00011000、00001100,它们却一个也没有进入对应的 case。没有新命令覆盖旧命令,最高速左转就被一直保留下来。

我坐了很久,看着转圈算法、补偿参数、被撕掉的黑胶带......翻了一页便签纸,把十进制拼接删掉。八路状态不再假装成一串十进制数字,收进真正的掩码。

c 复制代码
switch (mask)
{
case 0x18:      /* 0001 1000:中间两路压线 */
    /*
    0b00011000 这种二进制字面量不是 C90 里的写法(C23 才收进标准):Keil 里新的 AC6(armclang) 认它,老的 AC5(armcc) 不认,实测在 AC5 下 C90、C99 两档都报 #53。这一路工程是按 AC5 建的,所以代码里写成十六进制,我当时用的是AC6,所以直接写 0b00011000 是可以的,也很直观。
    */
    break;
}

再放回地面时,黑线经过车头中央。小车往左修了一下,又把自己带回了线上。

没有转成陀螺。

台灯底下,那张记满勾和叉的纸还摊着。00011000 被我圈在最中间,笔圈画得有点重,纸面凹进去一道痕。

相关推荐
Zhang.Yi1 小时前
STM32-BKP和RTC
stm32·嵌入式硬件·实时音视频
万年咸鱼1 小时前
C语言内功心法篇——变量与数据类型
c语言·jvm·算法
意法半导体STM322 小时前
【官方原创】LAT1724 STM32CubeIDE for VSCode 修改链接文件中的起始地址无效?
vscode·stm32·单片机·嵌入式硬件·mcu·stm32cube
Zw-awa14 小时前
八路循迹模块的 DO:先让小车沿着线跑起来
stm32
Escalating_xu16 小时前
【C 语言】深入理解指针(5):sizeof、strlen、数组名语义与指针笔试题全解析
java·c语言·开发语言
Code_Solitude16 小时前
c语言:递归
java·c语言·算法
万年咸鱼16 小时前
解决C语言的内存释放机制
java·c语言·python
老王爱玩车18 小时前
自定义类型:结构体
c语言·开发语言·学习
新晨单片机设计18 小时前
S017C-基于STM32汽车防酒驾系统(心率、血氧、短信)【Proteus仿真+Keil程序+原理图】
stm32·单片机·proteus·防酒驾报警系统