
1. 项目概述一个可玩性十足的桌面互动游戏几年前我偶然在朋友的工作室里看到一个用废旧风扇和纸板做的简易投篮机虽然简陋但大家玩得不亦乐乎。这让我萌生了一个想法能不能用更“正经”的电子元件做一个既保留动手乐趣又具备现代交互体验的迷你篮球游戏机于是这个基于Arduino和Grove套件的项目就诞生了。它不仅仅是一个玩具更是一个融合了传感器应用、电机控制、灯光效果和用户界面设计的综合性电子制作实践。这个项目的核心目标是打造一个完整的、可交互的游戏系统。玩家投篮系统需要能精准检测到球是否入筐并实时在OLED屏幕上更新分数同时用炫酷的LED灯带和欢快的蜂鸣器旋律给予反馈。为了增加挑战性我还设计了一个由旧风扇电机驱动的移动障碍物。整个系统以Arduino Uno或兼容板为大脑通过Grove Beginner Kit快速搭建基础电路再扩展超声波传感器和WS2812B灯带最终封装在一个手工制作的纸板外壳里。无论你是刚接触Arduino的新手想通过一个有趣的项目串联起多个知识点还是有一定经验的爱好者希望探索传感器整合与游戏逻辑设计这个项目都能提供从硬件连接到软件编程再到机械结构搭建的全流程参考。2. 核心设计思路与方案选型2.1 为什么选择Grove Beginner Kit作为起点对于电子制作项目尤其是整合了多种传感器的项目前期在电路连接和调试上花费的时间往往远超预期。杜邦线接错、接触不良、电源短路等问题层出不穷非常打击初学者的热情。Grove Beginner Kit完美地解决了这个痛点。这套件的最大优势在于其“即插即用”的模块化设计。板载的OLED屏幕、按钮、蜂鸣器、光线传感器等常用模块已经通过PCB上的印刷电路连接到了Arduino主控的特定引脚上你不需要焊接甚至不需要面包板和跳线开箱即用。这让我们能将精力完全集中在编程逻辑和功能实现上而不是纠结于电路连接。例如在本项目中OLED显示和复位按钮就直接使用了板载模块省去了大量接线工作。对于初学者而言这极大地降低了门槛对于熟练者则能显著提升原型开发效率。2.2 篮球检测方案的权衡与选择检测篮球是否入筐是整个游戏逻辑的基石。原文提到了三种方案超声波传感器、霍尔效应传感器和压电传感器。我最终选择了超声波传感器HC-SR04这是经过深思熟虑的。超声波传感器 (HC-SR04)其原理是发射超声波并接收回波通过计算时间差来测量距离。我们将它安装在篮筐下方指向篮筐入口平面。当没有球时传感器测量到的是一个固定的“空筐”距离。一旦篮球入筐穿过这个平面就会瞬间大幅改变测量距离从而触发得分。它的优点是非接触式对篮球材质无要求塑料球、乒乓球都可安装相对简单只需在纸板外壳上开个孔将其固定对准即可。缺点是可能受到环境声波干扰且需要一定的检测区域。霍尔效应传感器 (如A3144)需要在小篮球里嵌入一块强磁铁。当带磁铁的球经过安装在篮筐处的传感器时磁场变化会触发传感器。这种方案检测非常精准、迅速。但缺点也很明显你必须有一个带强磁铁的球制作或改造有难度并且磁铁的位置需要非常精确地对准传感器容错率低增加了制作的复杂性。压电传感器需要篮球有足够的重量去“撞击”传感器产生电压信号。这对于轻质的塑料空心球来说基本不可行需要更重的实心球不仅增加了成本也改变了游戏的物理手感。注意超声波传感器的安装角度和距离阈值设置是关键。传感器应尽可能垂直对准篮筐入口中心测量距离的阈值需要在实际安装后通过串口监视器读取有球/无球状态下的数值来校准留出合理的缓冲区间防止误触发。2.3 动态反馈系统的设计光与声游戏的沉浸感离不开及时的反馈。我设计了由WS2812B可编程LED灯带和蜂鸣器组成的视听反馈系统。WS2812B LED灯带我选择了1米30灯珠的规格缠绕在篮球架背板或底座周围。每个灯珠都可以独立控制RGB颜色和亮度。当玩家得分时我编写了一段“彩虹追逐”或“爆炸色彩”的动画效果让灯光从进球点向四周扩散视觉冲击力很强。选择WS2812B是因为它只需要Arduino的一个数字引脚通过单总线通信就能控制上百个灯珠极大地节省了IO口并且有成熟的FastLED库支持编程实现各种效果非常简单。蜂鸣器Grove套件自带了蜂鸣器。得分时我会让它播放一段简短的、欢快的旋律例如《超级玛丽》的过关音效。这里需要注意的是蜂鸣器播放音乐需要使用tone()函数它会占用一个定时器在播放期间要避免进行其他依赖同一定时器的操作如delay()的精度可能会受影响。好的做法是将旋律的播放放在非阻塞的代码逻辑中或者使用状态机来管理。2.4 驱动移动障碍物的创意方案一个静态的篮筐玩久了难免单调。我借鉴了原文中“黑客风扇”的创意增加了一个旋转的障碍物用来间歇性地遮挡篮筐提升游戏难度。我没有选择常用的伺服电机舵机因为它的运动是角度定位虽然精准但速度不够快不够“刺激”。步进电机速度可控但需要驱动电路稍显复杂。而一个废弃的5V电脑散热风扇其内部的直流电机转速极高通常几千转/分钟成本几乎为零且非常容易获得。但问题来了电机转速太快直接连接障碍物会变成一片模糊的影子毫无游戏性。因此需要一个“减速机构”。原文用硬纸板做成了一个简单的“曲柄滑块机构”将一个小纸圆盘粘在电机轴上作为驱动轮在偏离圆心的位置打孔连接一根吸管连杆连杆的另一端再连接障碍物。这样电机的高速旋转就转化为了障碍物缓慢的、往复的摆动。这是一个非常巧妙的机械设计用最简单的材料实现了核心功能充分体现了创客精神。3. 硬件搭建与电路连接详解3.1 核心元件清单与作用在开始动手前理清每个元件的作用至关重要主控板Arduino Uno 或 Seeeduino与Grove Kit兼容。项目的大脑负责运行所有代码逻辑。Grove Beginner Kit for Arduino提供板载的OLED显示屏用于显示分数、按键用于复位游戏、蜂鸣器用于播放声音。超声波传感器 (HC-SR04)用于检测篮球入筐。Trig引脚触发测距Echo引脚接收回波。WS2812B LED灯带 (1m 30LEDs)提供得分时的炫彩灯光效果。需外接5V电源和一根信号线。5V直流风扇电机从旧风扇拆解获得作为移动障碍物的动力源。电位器 (10kΩ)用于调节风扇电机的转速以控制障碍物摆动快慢。面包板及跳线用于连接非Grove模块的元件如超声波传感器、LED灯带、风扇电机。外接5V电源当连接LED灯带和电机时仅靠Arduino的USB供电可能不足需要一个能提供至少2A电流的5V电源适配器通过面包板为大功率元件供电。结构材料硬纸板用于制作游戏机外壳、篮筐、障碍物、吸管用于制作连杆、塑料小球、胶水、裁纸刀等。3.2 电路连接图与接线表由于Grove Kit板载了部分元件实际需要额外接线的并不多。请务必在断电状态下操作。元件引脚/线缆连接至 Arduino 引脚说明超声波传感器 HC-SR04VCC5V接面包板正极Trig数字引脚 9Echo数字引脚 10需通过1kΩ电阻降压或确认模块为5V兼容GNDGND接面包板负极WS2812B LED灯带5V外接5V电源正极切勿直接接Arduino 5VDIN (数据输入)数字引脚 8数据信号线GND外接5V电源负极 Arduino GND共地至关重要风扇电机红线 (正极)晶体管/MOSFET的集电极/漏极电机电流大需用晶体管驱动黑线 (负极)外接电源负极电位器两侧引脚接在5V和GND之间作为分压器中间引脚 (信号)模拟引脚 A5读取电压值控制电机速度驱动风扇的晶体管基极/栅极数字引脚 7通过PWM信号控制速度发射极/源极GND集电极/漏极接电机正极核心注意事项驱动风扇电机是电路中最容易出错的部分。绝对不能将电机直接接到Arduino的数字引脚上Arduino引脚最大只能提供约40mA电流而一个小风扇电机的工作电流可能达到100-200mA直接连接会烧毁引脚甚至主控芯片。必须使用一个NPN型晶体管如2N2222A或N沟道MOSFET如IRF520来驱动。Arduino的引脚仅用于控制晶体管的通断电机的大电流由外接电源提供流经晶体管。这是一个非常重要的电子学基础实践。3.3 机械结构制作要点游戏机外壳用厚实的瓦楞纸板制作主体结构。设计时要留出OLED屏幕的显示窗口、篮筐安装口、超声波传感器的探测孔、以及障碍物的活动空间。所有接缝处用热熔胶或白乳胶加固。篮筐用铁丝或弯曲的吸管制作一个迷你篮筐固定在面板上方。确保其下方正对超声波传感器的探测路径。减速与传动机构从旧风扇上小心拆下电机焊上两根较长的导线。剪一个直径约3-4厘米的圆形硬纸板用热熔胶牢牢固定在电机轴上作为驱动盘。在驱动盘边缘非中心钻一个小孔。取一根细吸管作为连杆一端用牙签或小铁丝与驱动盘上的小孔连接确保可以灵活转动。取一根粗吸管作为导轨在侧面开一个长条形的槽。将细连杆的另一端与障碍物可以用轻质木棍或纸板制作连接然后将这个连接点穿过粗吸管的槽。这样电机转动就会带动驱动盘驱动盘通过连杆将圆周运动转化为障碍物在槽内的往复直线运动速度也因此大大降低。整合将组装好的障碍物机构安装在外壳内部合适的位置使其摆动路径能够部分遮挡篮筐。将超声波传感器固定在篮筐正下方的内部探头对准篮筐中心。4. 软件编程与核心逻辑实现4.1 开发环境配置与库安装首先确保已安装Arduino IDE。然后需要安装两个关键的第三方库U8g2库用于驱动OLED屏幕。在IDE中点击「工具」-「管理库」搜索“U8g2”选择由olikraus发布的版本进行安装。这个库功能强大支持多种字体和图形绘制。FastLED库用于驱动WS2812B灯带。同样在库管理中搜索“FastLED”由FastLED团队发布安装它。这是控制这类可编程LED的事实标准库效率高效果丰富。4.2 核心代码逻辑拆解项目的代码可以按功能模块组织成多个.ino文件但最终编译时Arduino IDE会将它们合并。以下是hardware_final.ino主文件的核心逻辑解析。// 引脚定义 - 这里是项目的“地图”修改引脚必须同步修改硬件连接 #define LED_PIN 8 #define NUM_LEDS 30 #define buttonPin 6 // Grove Kit板载按键已接好此处是软件映射 #define buzzerPin 5 // Grove Kit板载蜂鸣器 #define fanPin 7 // 连接晶体管基极控制风扇 #define Potentiometer A5 // 读取电位器控制速度 #define trigPin 9 #define echoPin 10 // 全局变量 - 记录游戏状态 int score 0; bool ballDetected false; unsigned long lastDetectTime 0; const unsigned long debounceDelay 500; // 防抖延时防止一次入筐多次计分 // 初始化对象 U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset*/ U8X8_PIN_NONE); CRGB leds[NUM_LEDS]; void setup() { Serial.begin(9600); // 用于调试输出传感器数据 pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(buttonPin, INPUT_PULLUP); // 板载按键已启用内部上拉 pinMode(fanPin, OUTPUT); u8g2.begin(); // 初始化OLED FastLED.addLedsWS2812B, LED_PIN, GRB(leds, NUM_LEDS); // 初始化灯带 FastLED.setBrightness(50); // 设置亮度避免电流过大 displayScore(); // 开机显示初始分数 } void loop() { // 1. 检查复位按钮 if (digitalRead(buttonPin) LOW) { // 按键被按下低电平有效 delay(50); // 简单防抖 if (digitalRead(buttonPin) LOW) { score 0; displayScore(); clearLEDs(); Serial.println(Game Reset!); } } // 2. 读取电位器控制风扇速度 int potValue analogRead(Potentiometer); int fanSpeed map(potValue, 0, 1023, 0, 255); // 将0-1023映射到PWM的0-255 analogWrite(fanPin, fanSpeed); // 3. 超声波测距检测篮球 long duration, distance; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); duration pulseIn(echoPin, HIGH); distance duration * 0.034 / 2; // 计算距离单位厘米 // 4. 判断是否得分 if (distance 5 distance 15) { // 距离阈值需根据实际安装校准 if (!ballDetected (millis() - lastDetectTime) debounceDelay) { ballDetected true; lastDetectTime millis(); score; // 增加分数 displayScore(); // 更新显示 playScoreMelody(); // 播放音效 showLEDEffect(); // 触发灯光效果 Serial.print(Score! Distance: ); Serial.println(distance); } } else { ballDetected false; // 球已离开检测区域 } // 5. 可以在这里添加一些非阻塞的LED动画更新逻辑 }4.3 关键功能模块实现OLED显示 (oled.ino)void displayScore() { u8g2.clearBuffer(); // 清除缓冲区 u8g2.setFont(u8g2_font_ncenB14_tr); // 设置字体 u8g2.setCursor(0, 20); // 设置光标位置 u8g2.print(Score:); u8g2.setCursor(0, 50); u8g2.print(score); // 打印分数变量 u8g2.sendBuffer(); // 将缓冲区内容发送到显示屏 }心得U8g2库的clearBuffer()、drawStr()/print()、sendBuffer()三步曲是标准操作。避免在loop()中频繁调用clearBuffer()和sendBuffer()除非内容需要更新否则可能造成屏幕闪烁。LED灯效 (led.ino)void showLEDEffect() { // 示例彩虹追逐效果 for (int i 0; i NUM_LEDS; i) { leds[i] CHSV((i * 10 millis() / 50) % 255, 255, 255); // 使用HSV色彩模式生成彩虹 FastLED.show(); delay(30); // 控制追逐速度 } clearLEDs(); } void clearLEDs() { fill_solid(leds, NUM_LEDS, CRGB::Black); // 将所有灯珠设置为黑色熄灭 FastLED.show(); }注意FastLED.show()是一个相对耗时的操作它会阻塞程序运行直到数据发送完毕。在复杂的动画中可以考虑使用非阻塞的定时器来控制动画帧率以免影响传感器检测的实时性。蜂鸣器音效 (buzzer.ino)void playScoreMelody() { // 播放一段简单的“叮咚”音 tone(buzzerPin, 523, 200); // Do (C5) 200ms delay(200); tone(buzzerPin, 659, 300); // Mi (E5) 300ms delay(300); noTone(buzzerPin); // 停止发声 }警告tone()函数会与PWM输出analogWrite()在引脚3和11上产生冲突在Arduino Uno上因为它们共享同一个定时器。确保蜂鸣器和PWM控制的设备不使用冲突的引脚。5. 系统调试与问题排查实录即使按照步骤操作也难免会遇到问题。以下是我在制作和调试过程中遇到的一些典型情况及解决方法。5.1 超声波传感器读数不稳定或误触发现象分数莫名增加或者投篮后不记分串口监视器显示的距离值乱跳。排查与解决电源干扰确保超声波传感器的VCC和GND连接稳定最好单独从Arduino的5V和GND引脚接线而不是从面包板远端取电。可以在传感器电源引脚附近并联一个10uF和0.1uF的电容滤波。环境干扰超声波可能被机箱内其他物体如旋转的障碍物反射或者环境中有其他类似频率的声源干扰。尝试在代码中增加滤波算法比如连续读取5次距离去掉最大最小值后取平均。阈值校准不当if (distance 5 distance 15)这个范围需要精确校准。打开串口监视器分别观察篮球入筐瞬间和空筐状态时打印出的distance值。根据实际数据调整阈值范围并留出足够的裕量例如空筐距离是20cm有球距离是8cm那么阈值可以设为distance 15。防抖逻辑确保使用了debounceDelay如500毫秒。一次入筐动作可能导致传感器在短时间内读到多次“有效”距离防抖逻辑能确保只计一次分。5.2 WS2812B灯带不亮或颜色错乱现象灯带完全不亮或只有部分亮或显示的颜色与程序设定不符。排查与解决电源不足这是最常见的问题。30个灯珠全白最亮时电流可能超过1.5A。必须使用独立的外接5V电源供电并将此外接电源的地线GND与Arduino的GND连接在一起共地。数据线方向接反WS2812B灯带有明确的输入DIN和输出DOUT端。数据信号必须从Arduino引脚连接到灯带的DIN端。如果接反灯带不会工作。信号电平问题Arduino是5V逻辑而WS2812B对信号电压敏感。如果灯带较长或环境有干扰可能在数据线上串联一个100-500欧姆的电阻靠近Arduino输出端以改善信号质量。库初始化错误检查FastLED.addLedsWS2812B, LED_PIN, GRB(leds, NUM_LEDS);这行代码。GRB是常见的色彩顺序但有些灯带可能是RGB或BRG。如果颜色错乱尝试修改这个参数。也可以使用FastLED.addLedsNEOPIXEL, LED_PIN(leds, NUM_LEDS);这种更通用的写法。5.3 风扇电机不转或无法调速现象电机不转或者一直全速转电位器调节无效。排查与解决晶体管/MOSFET接线错误这是硬件层面的首要检查点。以NPN晶体管2N2222A为例基极B通过一个1kΩ电阻接Arduino Pin 7。发射极E接电源地GND。集电极C接电机的负极电机正极接外接电源5V。务必确认晶体管型号和引脚排列。PWM引脚错误确保控制风扇的引脚本例中Pin 7支持PWM输出。在Arduino Uno上引脚3, 5, 6, 9, 10, 11旁边有“~”标记支持analogWrite()。电位器接线错误电位器三个引脚两侧接5V和GND中间引脚接A5。用万用表测量中间引脚对GND的电压转动旋钮时电压应在0-5V间平滑变化。代码映射错误map(potValue, 0, 1023, 0, 255);这行代码将电位器读数映射到PWM范围。如果电机在电位器一端不转另一端全速可以尝试调整映射的起始和结束值例如map(potValue, 200, 800, 50, 250)避开电位器两端的死区。5.4 OLED屏幕无显示现象屏幕一片漆黑。排查与解决初始化失败确认u8g2.begin();语句被执行且没有编译错误。Grove Kit的OLED是I2C接口地址通常是0x3C。库冲突确保只安装了U8g2库如果之前安装过其他OLED库如Adafruit_SSD1306可能会引起冲突。显示缓冲区未发送绘制完内容后必须调用u8g2.sendBuffer()才能显示。检查是否漏掉了这行代码或者将它放在了不会被执行到的条件分支里。6. 项目优化与扩展思路完成基础版本后你可以从以下几个方向让这个游戏机变得更酷、更智能增加游戏模式在代码中引入状态机实现“限时挑战赛”比如30秒内投进越多分越高、“精准模式”只有障碍物摆动到特定位置时投篮才计分等。升级检测方案尝试使用红外对管替代超声波传感器。在篮筐两侧安装红外发射管和接收管当球落下阻断红外线时触发得分。这种方式响应更快抗干扰能力可能更强。加入声音模块使用DFPlayer Mini等MP3模块替换简单的蜂鸣器播放真实的篮球入网声、观众欢呼声等体验更佳。联网与排行榜引入ESP8266或ESP32模块让游戏机连接Wi-Fi。每次游戏结束后将分数上传到云端服务器如Blynk、ThingSpeak或自建服务实现全球排行榜功能。结构强化与美化用亚克力板或激光切割木板替代纸板制作更坚固、更美观的外壳。为LED灯带设计导光槽让光线更柔和均匀。这个项目从创意到实现涉及了电子、编程、机械三个维度的知识。最让我有成就感的时刻不是代码第一次跑通而是看到朋友们围在桌边为投进一个球而欢呼并好奇地问“这东西是怎么做出来的” 那时你就知道所有的调试和折腾都是值得的。动手去试错在问题中学习这才是创客精神的真谛。如果你在复现过程中卡在了某个环节不妨回头仔细检查电源和接地——这是我踩过最多的坑也往往是解决问题的钥匙。