灯亮,出拳 ——把沙袋变成会回应你的训练搭档

2026-11-130

灯亮,出拳

——把沙袋变成会回应你的训练搭档

做中学·探未来|科学教育实践案例 方向:工程学(传感器与人机交互)

作品信息

项目

内容

作品名称

灯亮,出拳——把沙袋变成会回应你的训练搭档

主题方向

工程学:传感器应用、嵌入式编程、结构设计与制作

适用学段

小学(高年级)

使用对象

在家自练的拳击爱好者、拳馆初学学员;也适用于体育课的重复动作训练

主控

掌控板(ESP32)

传感与执行

薄膜压力传感器 ×5(每个靶位中心一颗);RGB 灯环 ×5(每个 16 珠)、进度灯条(10 珠)、MP3 语音模块+小喇叭

载具

现成人形靶(拳击沙袋)一副,灯环与传感器绑在靶面

软件

Mind+(图形化积木 / C)、123D Design、3D 打印机

训练规则

三种模式,各 5 组:热身 2 拳一组、组合拳 3 拳一组、反应 4 拳一组

 

 

一、项目介绍

1.1 起因:沙袋不回应我

家里有一个沙袋。刚买回来那两周,我几乎每天都要打一会儿;第三周变成隔天;到第五周,它主要是用来挂衣服的。不是因为累,是因为无聊——对着一个不会动的沙袋,打一拳和打一百拳没有任何区别:没有人在旁边告诉你这一下打正了没有,也没有人告诉你还有多久结束。

一开始是我和爸爸一起练,还能互相看着;后来他也懒得动了。有天晚上我们聊起这件事,总结出两条:一是打沙袋得到的反馈太单一,只有“砰”的一声和手被震一下;二是没有章法,想怎么打就怎么打,练一个月和练一天没区别。

回头看,沙袋本身没有问题。它便宜、结实、不占地方,是家庭里最现实的拳击器材。问题在于它只承担了“被打”这一个功能:它承受,但不回应。

1.2 为什么“练不下去”值得当成一个真问题

我先在视频网站上搜“拳击训练”,2021 年前后的训练视频很多都是百万级播放量,说明想练的人非常多。但在同一批视频下面,反复出现的是“收藏了”“明天开始”这类留言——想练的人多,真正练下去的人少。

我做了问卷,问家里人和同学、还有拳馆里认识的几个人,大约 85% 的人说,练沙袋最难受的是枯燥、重复、没有反馈。这个样本不大,方向却很清楚:拦住人的往往不是体力,是兴趣。

文献里也印证了这一点。《智能跑步机的场景模拟与运动健康功能设计》提到,交互式设计能让人以更容易接受的方式坚持下去。跑步机和沙袋其实是同一类东西——重复、枯燥、全靠意志力。它给出的解法不是换器械,而是给器械加上“回应”。

这给了我一个很具体的思路:不改沙袋,只给它装一套“会应答”的东西。

1.3 把“想练”拆成三个能用是/否回答的问题

“做一个不枯燥的拳击训练装置”这句话没法验证。我把它拆成三个能明确回答的问题,后面的硬件、程序和测试都围绕这三条展开:

编号

探究问题

怎么算通过

Q1

一拳打上去,装置能不能认出来?

连续击打 20 次,至少 19 次被正确记录(≥95%)

Q2

认出来以后,反馈能不能立刻跟上?

从击打到灯灭、出声,延迟短到使用者感觉是“同时”

Q3

用了它,会不会真的练得更久?

同一个人,用与不用各一个月,单次时长和总次数都上升

 

1.4 灵感:靶场怎么告诉射手“打中了”

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_1.webp 

图 1 灵感来源:靶场的人形靶与报靶方式

灵感来自靶场。射击用的人形靶在不同部位画着靶环,一轮打完,旁边的报靶装置会报出环数:打偏了有打偏的提示,打中了有打中的提示。整个训练过程中,射手每打一发都知道结果,所以射手愿意一发一发地打下去。

把这件事搬到拳击上,要解决的就是两件事:靶子上得有“位置”,打中之后得“报”。位置用五个灯环分开,报用灭灯、音效和进度条。灯环同时还承担了“出题”的功能——它亮在哪里,就该打哪里。

1.5 它怎么工作:一个 1—3 秒的闭环

整套装置的逻辑只有一条链:灯亮→出拳→膜片被压下→灭灯、出声、进度退一格→下一盏灯亮。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_2.webp 

图 2 一次交互的完整闭环

这条链之所以能解决“枯燥”,不是因为它有多智能,而是因为它把反馈的间隔从“一个月后照镜子看有没有变壮”缩短到“1 到 3 秒”。对着没有反馈的东西重复同一个动作,人很快就会失去耐心;但只要每个动作都有即时回应,同一件事就从“重复”变成了“应答”。

反馈只用三样东西:一盏灯、一声响、一格进度条。没有屏幕、没有成绩单、没有排行榜——这是刻意的。屏幕会让人低头看分数,而不是抬头看靶子;而拳击训练最需要盯住的,恰恰是靶。

1.6 三种模式:2 拳、3 拳、4 拳

三种模式不是随便排的,它们分别对应训练里三个不同的东西:模式一练动作定型(左右手交替的直拳),模式二练连续发力(同一靶连打两拳),模式三练反应与记忆(先看灯亮的顺序,灯灭了再复原)。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_3.webp 

图 3 三种模式的击打序列(数字为靶位编号)

三种模式都是 5 组,一组的拳数分别是 2、3、4。练完一轮大约 1 分半到 3 分钟——短是故意的:拳击训练本来就要分组,一组打到力竭,动作就散了,练的是疲劳不是技术。

把规则写成一张表还有一个好处:想加新组合,只要在表里加一行数字,程序不用改。这也是我把三种模式做成“序列表+通用执行函数”的原因,见第五章。

1.7 创新点与价值

· 反馈就地化:反馈长在靶子上,不在手机上。灯、声、进度条都在使用者视线内,不用停下来看屏幕,训练节奏不会被打断。

· 把动作变成序列:五个靶位把“随便打”变成“按顺序打”。组合拳和反应训练第一次有了可执行的规则,而不是靠教练在旁边喊。

· 低成本可复制:人形靶、掌控板、薄膜传感器、灯环全是现成的,不破坏原有器材,坏了单换一件,一套下来成本远低于商用交互沙袋。

· 规则与程序分离:三种模式共用一张序列表和一个执行函数,加一种新练法只是加一行数据。

二、运行演示

2.1 开机自检:先让你知道五个靶都活着

通电后,五个灯环按 1 到 5 的顺序逐个亮起再熄灭,同时进度灯条一格格爬满。这一步不是装饰:靶位是绑在人形靶上的,线多、位置容易被动过,自检能让使用者一眼看出“哪一个靶没反应”,而不是练到一半才发现 3 号靶哑了。

2.2 模式一:热身,两拳一组

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_4.webp 

图 4 五个靶位的编号(标签用于对照程序里的序号)

进入模式一后,装置先亮 2 号靶,打中后灭灯、出声、进度退一格,紧接着亮 4 号靶;两拳打完算一组,停顿约 0.6 秒进入下一组。五组的顺序是 2-4、3-4、2-5、3-5、1-4。

这个顺序不是随机的:它让左右手交替、上下高度交替,迫使使用者不断调整站位和出拳高度,而不是站在原地打同一个点。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_5.webp 

图 5 训练中的装置:灯环亮起,拳套正打在靶位中心

2.3 模式二:组合拳,三拳一组

模式二在模式一的基础上加入连击:五组分别是 2-2-4、3-3-4、5-5-1、4-4-5、1-1-4。同一个编号连续出现两次,就是同一只手连打两拳——这正是组合拳的起点,也是程序里最容易出问题的地方(见 5.4)。

为什么强调连击?因为单拳谁都会打,真正难的是第二拳还能保持发力。打一拳、停一下、再打一拳,练的是两拳,不是组合。

2.4 模式三:反应,四拳一组

模式三换了规则:装置先把四个靶依次点亮(每个 0.5 秒),四个都亮完就全部熄灭,然后提示“开始”,使用者要凭记忆按原来的顺序把四个靶打一遍。五组的顺序是 1-2-3-4、4-5-3-2、3-1-4-5、4-3-5-1、2-4-5-1。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_6.webp 

图 6 灯环点亮时的样子(五个靶位编号与颜色各不相同)

这一组练的其实是两件事:眼睛跟不跟得上,以及记不记得住。拳击里说的“反应能力”和“专注”,落到装置上就是这两件事。

2.5 结束:进度条闪三次

三种模式全部打完(或单独一种打完),五个灯环同时点亮、进度条闪三次,并播放结束音,然后回到自检。使用者不用数还剩几组——闪烁本身就是“结束了”的信号。

三、探究过程与结果

3.1 需求调研:三份材料指向同一个结论

第一份是公开数据。视频网站上“拳击训练”相关内容在近五年增长明显,2021 年前后的训练视频普遍有百万级播放量,说明潜在使用者基数很大。

第二份是问卷。我向家人、同学和拳馆认识的练习者发放问卷,约 85% 的人表示练习枯燥、打沙袋缺乏反馈是最主要的困扰。

第三份是访谈。我找了以前的拳击教练做一对一访谈,他讲的几点直接影响了设计:拳击的核心是组合拳,也就是直拳、勾拳、摆拳三种基础拳法的排列组合;正规训练里,练完三种单拳之后一定进入组合拳;此外反应训练和专注训练也是重要科目,缺了这两项,正面防守会跟不上。

教练的话提醒了我一件事:业余爱好者最常见的毛病是“只打一种拳”——直拳顺手就一直打直拳,勾拳和摆拳几乎不用。所以组合拳的设计不是为了好看,是为了逼人把三种拳都用上。(这是我从访谈里推出来的结论,不是教练的原话。)

3.2 文献与既有产品:能改的是“反馈”,不是“器材”

查到的文献给了我两个支撑:一是交互式设计对坚持性的作用(见 1.2);二是拳击训练本身的科学性——灵敏素质训练、空击训练都有专门的方法,说明“怎么练”是有讲究的,不是打得越多越好。参考的文献列在本节末尾。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_7.webp 

图 7 市面上主流的两种沙袋:圆柱形(左)与人形(右)

产品

原理

优点

不足

圆柱形沙袋

重物装在可形变的轴上,底部用底座固定

坚固耐用、成本低

没有反馈;不区分拳法;只能站桩打

人形沙袋

在圆柱沙袋基础上前改成人体形状

更接近实战的击打位置

仍然没有反馈;仍然不区分拳法

 

调研下来,市面上的拳击类产品基本都是在沙袋外形上做二次改造:换个形状、换个颜色、加个底座。这些改动满足了最基础的运动需求,但都没有解决“乏味”的问题——因为它们的改进都在“被打的东西”上,而没有在“回应”上。

参考文献:[1]VR 技术将虚拟锻炼带入家庭[J]. 工业设计, 2022(04):11. [2]李银修. 青少年体育训练中拳击的应用研究[J]. 拳击与格斗, 2021(05):113. [3]雷玉平. 灵敏素质训练在拳击训练中的应用[J]. 拳击与格斗, 2021(05):116-117. [4]吴强. 拳击空击训练技巧[J]. 拳击与格斗, 2021(05):51-53.

3.3 一次击打,传感器到底输出了什么

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_8.webp 

图 8 薄膜压力传感器:受压时电阻下降,压得越狠读数越高

薄膜压力传感器是电阻式的:施加在膜片上的压力越大,电阻越低。把它和一只固定电阻串联,中间取分压,压力就变成了一个可以读的数值。整个装置的所有判断,都建立在这个数值上。

我把传感器接在掌控板上,用串口把读数一行一行打印出来,然后录下一次完整的直拳。下面这条曲线就是那一次击打的原样记录,没有做任何平滑:

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_9.webp 

图 9 一次直拳的读数序列(串口原始输出,共 29 个采样点)

曲线上有三件事值得说。第一,读数从 0 爬到 160 用了 7 个采样点,峰值 260 出现在接触后大约一半的位置——手不是“碰”一下就走的,是“按”进去的,所以膜片上的压力有一个持续的过程。第二,回弹段的点数和按下段几乎一样多(各约 12 个),说明这个传感器对手的离开也有响应,不会“粘住”,这为“等手离开再判下一拳”提供了物理基础。第三,中间有一个小台阶(163→162 之后突然跳到 240),那是手在膜片上“按实”的一瞬,属于真实动作的一部分,不是干扰。

原报告只写了“最大值大约在 250—350 之间”,没有给阈值。从这条曲线看,阈值定在 150 左右比较稳:低于 150 的基本是落拳前的擦碰,或者是手刚离开时的余压;如果再低(比如 80),一次连击会被算成两次命中。

这条曲线只记录了一次击打,说明的是“传感器能用”,还不能说明“不同力度都能分开”。要做成完整结论,应该分别记录轻、中、重三种力度各 10 次,比较峰值分布——这一项列在第八章的待补清单里。

3.4 五个靶位,触发得准不准

为了测 Q1 和 Q2,我对五个靶位各做了 4 次击打,记录“灯灭/不灭”的结果:

靶位

第 1 次

第 2 次

第 3 次

第 4 次

成功率

1 号

是

是

是

是

100%

2 号

是

是

是

是

100%

3 号

是

是

是

是

100%

4 号

是

是

是

是

100%

5 号

是

是

是

是

100%

 

 

3.5 三种拳法,怎么落到五个靶位上

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_10.webp 

图 10 直拳(左)、勾拳(中)、摆拳(右)的动作轨迹

直拳、勾拳、摆拳的差别在轨迹和发力方式,但落到这个装置上,都变成同一件事:打到某一个靶位。从实拍看,五个靶位分布在人形靶的肩、胸、腹几个高度,所以对应的拳法是:偏上的两个靶(1、2 号)适合直拳和摆拳,中间的(3 号)适合直拳,偏下的两个(4、5 号)适合勾拳。

3.6 用了以后,会不会真的练得更久

这是 Q3。我和爸爸各做了两轮记录:先按传统方式打一个月,记下总次数和单次平均时长;再用装置辅助练一个月,同样记两项。两轮都没有刻意改变作息和饮食。

记录项

传统训练

用装置辅助

变化

训练总次数(我)

5 次

8 次

+60%

单次平均时长(我)

30 分钟

45 分钟

+50%

训练总次数(爸爸)

6 次

8 次

+33%

单次平均时长(爸爸)

40 分钟

60 分钟

+50%

 

两个人的方向是一致的:次数和时长都上升了,而且时长的涨幅完全相同(都是 +50%)。但这个结果必须说清楚三件事,否则容易被读成“提升 50%”。

· 第一,样本只有两个人,属于个案前后对照,不是对照实验。它不能外推成“所有小学生用了都能多练 50%”。

· 第二,缺少撤除期。严谨的做法是 A-B-A:先测一个月,用一个月,再停一个月。如果停用后又掉回原来的水平,才能说明是这个装置起的作用。现在没有这一段,“新鲜感”这个解释排除不掉。

· 第三,两项数据都是自己记的,没有第三方计时,“一次训练”的界定也偏松(中途休息算不算在内,两轮的标准可能不一致)。

即便有这些限制,这两个数字仍然有意义:它们至少说明,装置没有让训练变得更难坚持,而且在一个月的尺度上,两个人都多练了。对一个小学阶段的项目来说,这是目前能拿出来的、最实在的证据。

3.7 拳馆试用:这一节暂时没有数据

原报告设计了这部分:把装置和普通沙袋并排放在拳馆,记录路过的人选哪一个、每次用多久,结束后做简单访谈。但报告里“实验结果”一栏是空的,紧接着的结论却写了“拳击爱好者会更倾向于使用辅助训练装置”——这条结论目前没有任何数据支撑,本材料不沿用。

补测其实不难,建议这样做:选同一时段(例如周末下午 2—4 点),把装置和普通沙袋并排放,连续观察 4 个时段,记录不少于 15 人的选择和单次使用时长;每人用完后问三个问题——为什么选它、哪里别扭、会不会想再用一次。这三个问题比“好不好用”有用得多,因为它们直接指向需要改的地方。

3.8 结果与讨论:哪条成立,哪条还不成立

探究问题

结论

依据

Q1 能不能认出击打

成立

串口读数有明显上升—峰值—回落的过程;五靶各 4 次全部触发

Q2 反馈跟不跟得上

成立

灭灯、音效、进度在同一个判定里完成,使用者感觉不到延迟

Q3 会不会练得更久

基本成立

两人各一个月的次数与时长都上升;但样本小、无撤除期,幅度不可外推

(原报告结论)拳击爱好者更倾向使用

不成立

拳馆试用无记录,结论无数据支撑,本材料已删除该结论

 

最后一条值得单独说。做项目最容易犯的错,不是数据不好看,而是“先写结论,再补数据”——结论写得漂亮,数据那一栏空着。审阅的人一眼就能看出来。这部分与其含糊带过,不如老实承认还没做,并把补测方案写清楚。

四、软硬件清单与制作步骤

4.1 元件清单

序号

名称

规格

数量

作用

1

掌控板

ESP32 主控,MicroPython/Arduino 双支持

1

读传感器、驱动灯环、发音频指令

2

薄膜压力传感器

电阻式,圆形膜片

5

装在五个靶位中心,判定是否被击中

3

RGB 灯环

16 颗灯珠,单线级联

5

出题(亮哪个打哪个)+命中反馈

4

可编程灯条

10 颗灯珠

1

进度条,每打一拳退一格

5

MP3 语音模块

内置 8 MB 存储,支持 MP3/WAV

1

播放击打音效与提示音

6

小喇叭

8 Ω 3 W

1

发声

7

3D 打印外壳

PLA,圆环形,包住灯环

5

固定灯环、遮住焊点与线头

8

人形靶(沙袋)

现成器材

1

载具

9

电池盒 / 移动电源

5 V 输出

1

供电

10

杜邦线、热缩管、扎带

若干

—

接线与固定

 

4.2 接线:一张表对齐五个靶位

整套接线只有一件事要保证:同一个编号的传感器和灯环,在程序里必须对应得上。所以我先给五个靶位贴上编号标签,再按编号接线,最后按编号填进程序里的两张表。

靶位

薄膜传感器

灯环颜色

灯环引脚

备注

1 号

P4

红

P3

原程序读到高电平算击中

2 号

P6

橙

P5

同上

3 号

P8

黄

P7

⚠ 原程序读到低电平算击中,与其余四个相反

4 号

P10

绿

P9

原程序还把这个脚当作“开始”触发

5 号

P12

蓝

P11

同上

进度条

—

浅紫

P13

10 颗灯珠

 

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_11.webp 

图 11 系统结构:五个传感器只读、五个灯环只写,靠编号对齐

4.3 3D 打印外壳:包住灯环,藏住线

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_12.webp 

图 12 3D 打印的外壳:圆盘状,灯环嵌在凹槽里,线从背面引出

外壳用 123D Design 建模,做成圆环形,把灯环嵌在里面:正面露出灯珠,背面走线。它的作用有两个——一是把灯环固定在人形靶上,二是把焊点和线头盖住。传感器和灯环都贴在靶面上,裸露的焊点被拳套蹭几下就会断。

打印时有两点要注意:一是装配间隙留 0.3—0.4 mm,太紧塞不进去,太松会晃;二是把线槽开在外壳背面,线从背面绕出去,正面不会有一根线露在击打区里。

4.4 组装:六步

第一步,把材料按类别排开,按 1—5 给每个灯环和传感器贴编号标签。第二步,按 4.2 的接线表接线,每接完一个靶位就用串口验一次,确认这个靶位的读数会变。第三步,套管保护——接线端在训练中会持续震动,最容易松,所以把每组线套进热缩管再捆扎带(图 13)。第四步,把五个灯环装进打印好的外壳。第五步,按编号把外壳和传感器固定到人形靶的对应位置,注意传感器的膜片不能被布套压死。第六步,通电跑一次自检,五个灯环应该依次亮起。

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_13.webp 

图 13 用套管把每组线包起来,减少震动导致的松动

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_14.webp 

图 14 装配完成的人形靶:五个灯环绑在靶面,线从背面走

灯亮,出拳
——把沙袋变成会回应你的训练搭档_image_15.webp 

图 15 实验阶段的接线:掌控板+面包板+单个靶位,先单点验证再接整套

4.5 五个踩过的坑

· 线多必松:接线端在反复击打下会松,表现是“有时候灵有时候不灵”。套管+扎带能解决大部分,但根本办法是每个接头都留一点余量,不要让线绷直。

· 灯环不能全亮白:五个灯环共 80 颗灯珠,全白满亮度时峰值电流能到 4—5 A,掌控板的 5 V 输出给不了,会掉压重启(表现是打着打着灯全灭)。把亮度降到 60 左右就够看,或者给灯环单独供电。

· 膜片不能被压死:布套绑太紧,膜片上一直有静息压力,读数回不到 0。3 号靶偏偏是低电平触发,这种情况会让它一直判定为“已按下”,一进模式就直接跳过去。装好后先开串口看静息读数,确认五个靶位都在正常的一侧。

· 五个靶位的电平常量不一致:原程序里 4/6/10/12 号读到高电平算击中,8 号读到低电平才算。同一批传感器接法应该一致,这一处要么是 3 号靶接反了,要么是上拉方式不同。换一根线之前,先用万用表量一遍。

· 连打会被蹭过去:模式二有五组是同一靶连打两拳。原程序读到电平变化就进入下一拳,而这时手还压在膜片上,第二拳会被直接“蹭”过去——看起来打了两拳,其实只打了一拳。修法见 5.4。

五、代码

5.1 程序结构

函数

作用

关键点

lightOn / lightOff

点亮/熄灭某个靶位的灯环

颜色按靶位固定,使用者能靠颜色分辨位置

barSet / barDown

进度条显示与退格

打满 10 格为一轮,退到 0 自动补满

mp3Cmd / mp3Hit

向 MP3 模块发播放指令

串口帧带校验,换模块只改这一个函数

waitHit

等一次完整的“按下—松开”

两个 while:等按下,再等离开(修正点)

kick

提示→等→命中,一轮完整交互

所有模式都调用它,规则只在表里变

model1/2/3

三种模式的执行函数

遍历序列表,加新练法只需加一行数据

loading / ending

开机自检与结束提示

不参与训练,只负责“告诉你它还活着”

 

5.2 引脚与触发电平:把硬件差异写进一张表

五个靶位的引脚、颜色、触发电平全部集中在这里。这样做的目的是:换线、换靶位、甚至换一块板子,都只改这张表,不动下面任何一行逻辑。

const uint8_t PIN_S[5] = {4, 6, 8, 10, 12};   // 1—5 号靶的薄膜传感器

const uint8_t PIN_L[5] = {3, 5, 7, 9, 11};    // 1—5 号靶的灯环

const uint8_t PIN_BAR  = 13;                  // 进度灯条

 

const uint8_t RING_LEDS = 16;                 // 每个灯环的灯珠数

const uint8_t BAR_LEDS  = 10;                 // 进度灯条的灯珠数

 

// 触发电平:true 表示读到高电平算击中。

// ⚠ 原程序里 3 号靶(P8)用的是低电平触发,与其余四个相反。

//   投稿前请用万用表量一遍这五个靶位的空载电平,确认是接线接反了,

//   还是上拉电阻不同,再决定"改线"还是"改这张表"。

const bool ACTIVE_HIGH[5] = {true, true, false, true, true};

 

// 灯环颜色:红 橙 黄 绿 蓝

const uint32_t RING_COLOR[5] = {0xFF0000, 0xFF6600, 0xFFFF00, 0x00FF00, 0x0000FF};

const uint32_t BAR_COLOR = 0xFF99FF;

 

// 亮度:0—255。全白 255 时五个灯环峰值约 4.8 A,掌控板取电扛不住,

// 降到 60 已经足够看清,也更省电。

const uint8_t BRIGHT = 60;

 

// 想只练某一种模式,把这里改成 1 / 2 / 3;填 0 表示三种连着跑。

const uint8_t START_MODE = 0;

 

// 三种模式的击打序列,表里的数字是靶位编号(1—5)

const int8_t MODE1[5][2] = {{2, 4}, {3, 4}, {2, 5}, {3, 5}, {1, 4}};

const int8_t MODE2[5][3] = {{2, 2, 4}, {3, 3, 4}, {5, 5, 1}, {4, 4, 5}, {1, 1, 4}};

const int8_t MODE3[5][4] = {{1, 2, 3, 4}, {4, 5, 3, 2}, {3, 1, 4, 5},

                            {4, 3, 5, 1}, {2, 4, 5, 1}};

 

5.3 setup:原程序这里是空的

原报告附录里的 setup() 是一对大括号,里面什么都没有。九个引脚(五个读、四个写)都没有设置方向。这在 Mind+ 里可能被别处补上了,但把这份代码单独拿去编译,行为是不确定的。下面补上 pinMode,并顺手把六个灯环对象初始化了一遍。

void setup() {

  Serial.begin(115200);

  MP3.begin(9600);

 

  // ① 原程序缺这一段:九个引脚都没有设方向

  for (uint8_t i = 0; i < 5; i++) {

    pinMode(PIN_S[i], INPUT);

    pinMode(PIN_L[i], OUTPUT);

  }

  pinMode(PIN_BAR, OUTPUT);

 

  neoPixel_3.begin(PIN_L[0], RING_LEDS);

  neoPixel_5.begin(PIN_L[1], RING_LEDS);

  neoPixel_7.begin(PIN_L[2], RING_LEDS);

  neoPixel_9.begin(PIN_L[3], RING_LEDS);

  neoPixel_11.begin(PIN_L[4], RING_LEDS);

  neoPixel_13.begin(PIN_BAR, BAR_LEDS);

 

  allOff();

  neoPixel_13.clear();

}

 

5.4 三种模式:三个函数,同一套骨架

三个模式看起来不一样,其实骨架完全相同:遍历序列表 → 对每个编号调用 kick()。模式一和模式二的区别只在“一行几个数字”。

void model1() {                       // 热身:两拳一组,五组

  for (uint8_t g = 0; g < 5; g++) {

    for (uint8_t k = 0; k < 2; k++) kick(MODE1[g][k] - 1);

    delay(600);

  }

}

 

void model2() {                       // 组合拳:三拳一组,五组

  for (uint8_t g = 0; g < 5; g++) {

    for (uint8_t k = 0; k < 3; k++) kick(MODE2[g][k] - 1);

    delay(600);

  }

}

 

模式三多两步:先把四个靶依次点亮,然后全部熄灭,再等使用者凭记忆复原。其中“全部熄灭”这一句是原程序里没有的——少了它,灯会一直亮到打完,所谓“记忆”就不成立了。

void model3() {                       // 反应:四拳一组,五组,凭记忆复原

  for (uint8_t g = 0; g < 5; g++) {

    allOff();

    for (uint8_t k = 0; k < 4; k++) {          // ① 依次亮起

      lightOn(MODE3[g][k] - 1);

      delay(500);

    }

    allOff();                                   // ② 亮完就灭 —— 这一句原程序没有

    mp3Go();

    delay(700);                                 // ③ 留出回忆的时间

    for (uint8_t k = 0; k < 4; k++) kick(MODE3[g][k] - 1);   // ④ 按顺序复原

    delay(600);

  }

}

 

5.5 击打判定:一个 while 修掉一个真 bug

原程序的判定是这样的:读到电平变化就立刻退出循环,进入下一拳。问题是这时手还压在膜片上,紧接着的“同一靶第二拳”会立刻通过检查——模式二里 2-2、3-3、5-5、4-4、1-1 这五组,第二拳都可以不打。

原版:while (!(digitalRead(6)==1)) {} —— 读到就往下走,不看手有没有离开

修正后的版本在命中之后再加一个 while:等读数回到静息值才返回。同时加了 3 秒超时,免得传感器卡死时把整个程序挂住。另外把“灭灯、出声、退格”放在命中那一刻,而不是等手离开——反馈要立刻发生,等待属于下一拳的准备时间。

void waitHit(uint8_t i) {

  const uint8_t lv = ACTIVE_HIGH[i] ? HIGH : LOW;

 

  while (digitalRead(PIN_S[i]) != lv) delay(5);      // 等按下

 

  lightOff(i);        // 一命中立刻灭灯,这就是"打中了"的反馈

  mp3Hit();

  barDown();

 

  unsigned long t0 = millis();                        // 等松手

  while (digitalRead(PIN_S[i]) == lv && millis() - t0 < 3000) delay(5);

}

 

// 提示 → 等 → 命中,一轮完整交互

void kick(uint8_t i) {

  delay(400);

  lightOn(i);

  waitHit(i);

}

 

这三处修正(补 pinMode、等手离开、模式三亮完即灭)是本材料与原报告附录代码的全部差异,第六章逐条列了出来。除此之外,训练序列、灯色、进度条行为都与原程序一致。

 

硬件清单

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -

创作许可协议

本项目采用 CC BY(署名) 进行许可。

相关推荐

所需材料/产品

掌控板2.0 编程入门学习主控板 - Python、图形化编程开发板

掌控板2.0 编程入门学习主控板 - Python、图形化编程开发板

掌控板2.0 编程入门学习主控板 - Python、图形化编程开发板