1. 项目概述:一个会“抓人”的互动龙
如果你对Arduino、传感器和手工制作都感兴趣,那么把这三者结合起来,做一个能和你玩“红灯停,绿灯行”游戏的自动机,绝对是个让人兴奋的挑战。这个项目源于一个课程作业,但它的魅力远不止于此。它本质上是一个集成了环境感知、逻辑判断和物理动作的微型嵌入式系统。核心玩法很简单:你按下按钮,游戏开始,系统进入“绿灯”状态,此时你可以移动;当系统切换到“红灯”状态时,你必须立刻静止,否则就会被PIR运动传感器捕捉到,判定为失败,伴随着灯光闪烁和蜂鸣器警报,一只手工钩织的龙还会“愤怒”地动起来。
我选择这个项目,是因为它完美地融合了代码的逻辑之美、电路的精准控制和手工的温暖触感。对于第一次接触Arduino和电子制作的我来说,它涵盖了从电路搭建、状态机编程、传感器调试到结构设计与手工制作的完整流程。最终,这个会“监视”你、会“生气”的小龙,不仅是一个有趣的游戏装置,更是一个生动的学习成果,它让我深刻理解了从传感器信号输入到物理世界动作输出的整个闭环是如何实现的。
2. 核心系统设计与思路拆解
2.1 游戏逻辑与状态机设计
这个项目的“大脑”是一套清晰的状态机逻辑。状态机是嵌入式系统中处理复杂流程的经典模型,特别适合这种有明确状态和转换规则的游戏。我们的系统主要包含以下几个状态:
- 待机状态:系统上电后的初始状态,等待玩家按下启动按钮。
- 绿灯状态:玩家可以自由移动。系统持续监控PIR传感器,但在此状态下,移动信号被忽略。玩家需要在此状态下尽可能向后退(远离传感器),为后续的“红灯”阶段争取时间。玩家可以随时按下按钮来宣布胜利(假设已到达安全距离)。
- 红灯状态:玩家必须保持绝对静止。系统持续监控PIR传感器,任何检测到的移动都会被视为违规,立即触发失败流程。同时,红色LED亮起,伺服电机驱动龙做出动作,模拟“监视”或“警告”。
- 胜利/失败状态:游戏的终结状态。无论是玩家主动按下按钮获胜,还是因移动被检测到而失败,都会进入此状态。系统会通过LED的特定闪烁模式和蜂鸣器的音效给出明确反馈。
状态之间的转换由两个主要事件驱动:时间事件(例如绿灯持续10秒后自动切换到红灯)和外部触发事件(按钮按下、传感器触发)。在代码中,我们通常使用一个enum来定义这些状态,并用一个switch-case结构来组织每个状态下的行为逻辑和状态转换条件。
2.2 硬件选型与交互架构
硬件是项目的“躯体”,选型直接决定了系统的可靠性、成本和最终体验。
- 主控:Arduino Uno R3。这是创客项目的经典起点。它拥有足够的数字I/O引脚(本项目用了约7个),易于编程,社区资源丰富,对于实现我们的状态机和驱动外围设备绰绰有余。
- 感知核心:HC-SR501 PIR运动传感器。这是项目的“眼睛”。它通过探测红外辐射的变化来感知移动,非常适合检测人体这样的热源。其输出是简单的数字信号(高电平代表检测到移动),极大简化了编程。需要注意其两个可调旋钮:灵敏度(探测距离)和延时时间(触发后输出高电平的持续时间)。在本游戏中,为了快速响应违规,我们将延时时间调到最小。
- 执行单元:
- SG90微型伺服电机:作为“肌肉”,负责驱动龙形玩偶上下运动。伺服电机可以精确控制角度,我们通过Arduino的
Servo库发送脉宽调制(PWM)信号来控制它。 - 红/绿LED与330Ω限流电阻:作为“信号灯”,直观显示游戏状态。绿色代表安全(可移动),红色代表危险(静止)。必须串联电阻,防止过电流烧毁LED或Arduino引脚。
- 有源蜂鸣器:作为“警报器”,发出提示音和失败音效。有源蜂鸣器只需给高电平就会响,控制简单。
- SG90微型伺服电机:作为“肌肉”,负责驱动龙形玩偶上下运动。伺服电机可以精确控制角度,我们通过Arduino的
- 输入设备:轻触开关按钮与10kΩ上拉电阻。按钮用于启动游戏和宣告胜利。连接时使用上拉电阻,确保引脚在按钮未按下时处于稳定的高电平状态,避免因引脚悬空导致的误触发。
- 动力与连接:整个系统由5V移动电源通过USB口供电,确保了便携性。使用杜邦线在面包板或洞洞板上搭建电路,方便调试和修改。
整个交互架构形成了一个清晰的链条:按钮/PIR传感器(输入) -> Arduino(处理) -> LED/蜂鸣器/伺服电机(输出)。理解这个链条,是调试和扩展项目的基础。
2.3 结构设计与工艺融合
为了让电子部分和手工玩偶协同工作,结构设计至关重要。核心挑战在于如何将伺服电机的旋转运动,转化为龙玩偶稳定、可靠的上下往复运动。
我设计的解决方案是使用一根铁艺线作为传动杆。一端用胶带或热熔胶固定在伺服电机的舵盘上,另一端穿过外壳顶部的孔,并弯折成一个钩子,钩住龙的身体。当伺服电机在一定角度范围内来回转动时,就会带动铁艺线,从而牵引龙上下运动。为了确保传动顺畅且龙不会因自身重量下垂,需要在箱体内部安装一个自制的“线缆支架”,作为铁艺线的滑动轴承。
外壳采用3mm MDF板激光切割而成,这种材料易于加工、强度足够且外观整洁。设计时需要在前面板为PIR传感器和LED开孔,在顶板为按钮和传动铁艺线开孔,在侧板为USB电源线开槽。内部还需要设计隔板或支架,用来固定电路板、伺服电机和线缆支架,实现整洁的内部走线和稳定的机械结构。
注意:在最终组装前,务必进行“空载测试”和“负载测试”。先让伺服电机带着铁艺线空跑,观察运动范围是否合适、有无卡滞。再装上龙玩偶测试,确保伺服电机有足够的扭矩带动它,且运动轨迹符合预期。我的初版设计就低估了龙的重量和体积,导致不得不从“空中飞舞”改为“趴在盒子上起伏”,这是一个重要的经验教训。
3. 电路搭建与核心代码解析
3.1 电路连接详解与避坑指南
电路是项目的神经系统,连接错误轻则功能失常,重则损坏元件。以下是基于原理图的引脚连接详解及关键注意事项:
| 元件 | 引脚/端 | 连接至 Arduino Uno 引脚 | 说明与注意事项 |
|---|---|---|---|
| PIR传感器 | VCC | 5V | 供电 |
| GND | GND | 接地 | |
| OUT | 数字引脚 2 | 建议使用中断引脚(2或3),可实现更即时响应。 | |
| 按钮 | 一端 | 数字引脚 3 | 配合上拉电阻使用。 |
| 另一端 | GND | 按下时,将引脚3拉低到GND。 | |
| 10kΩ电阻 | 一端 | 数字引脚 3 | 上拉电阻,接在按钮与引脚3之间。 |
| 另一端 | 5V | 确保按钮未按下时,引脚3为高电平。 | |
| 红色LED | 阳极(长脚) | 数字引脚 4 | 通过330Ω限流电阻连接。 |
| 330Ω电阻 | 一端 | 数字引脚 4 | 必须串联,保护LED和Arduino。 |
| 另一端 | 红色LED阳极 | ||
| 红色LED | 阴极(短脚) | GND | |
| 绿色LED | 阳极 | 数字引脚 5 | 通过另一个330Ω电阻连接。 |
| 330Ω电阻 | 一端 | 数字引脚 5 | |
| 另一端 | 绿色LED阳极 | ||
| 绿色LED | 阴极 | GND | |
| 有源蜂鸣器 | VCC (+) | 数字引脚 6 | 控制端,高电平鸣响。 |
| GND (-) | GND | ||
| SG90伺服电机 | 红色线 (VCC) | 5V | 注意:最好通过外部5V电源供电,或确保USB电源能提供足够电流。 |
| 棕色线 (GND) | GND | ||
| 橙色线 (信号) | 数字引脚 9 | 标准PWM引脚,用于控制角度。 |
搭建与调试心得:
- 电源管理:伺服电机在启动和堵转时电流较大,如果和Arduino共用USB的5V,可能导致Arduino复位。最稳妥的做法是,所有元件(包括Arduino)都从一个能提供足够电流(建议1A以上)的5V电源取电。
- PIR传感器调试:刚上电时,PIR需要30-60秒初始化时间,期间输出可能不稳定,这是正常的。将跳线帽设置在H(可重复触发)模式,这样只要一直有移动,输出就一直为高。将延时旋钮逆时针拧到最小,以减少触发后的保持时间,让检测更灵敏。将灵敏度旋钮调到中间位置,根据实际游戏距离微调。
- 按钮防抖:机械按钮在按下和松开时,触点会产生物理抖动,导致Arduino误读多次按下。必须在软件中做防抖处理,例如检测到按下后,延时50毫秒再读取状态。
3.2 核心代码逻辑与状态机实现
代码是项目的灵魂,它定义了游戏的所有规则。以下是基于状态机模型的核心代码框架解析。
#include <Servo.h> // 引脚定义 const int pirPin = 2; const int buttonPin = 3; const int redLedPin = 4; const int greenLedPin = 5; const int buzzerPin = 6; const int servoPin = 9; // 游戏参数 const unsigned long greenLightDuration = 10000; // 绿灯持续时间10秒 const unsigned long redLightDuration = 5000; // 红灯持续时间5秒(示例) const int winDistance = 700; // 假设的“7米”对应传感器阈值,实际需校准 // 状态枚举 enum GameState { STATE_IDLE, // 待机 STATE_GREEN, // 绿灯 STATE_RED, // 红灯 STATE_WIN, // 胜利 STATE_LOSE // 失败 }; GameState currentState = STATE_IDLE; // 计时器 unsigned long stateStartTime; unsigned long lastMoveTime; int playerDistance = 0; // 模拟或记录玩家后退距离 Servo dragonServo; // 伺服电机对象 void setup() { pinMode(pirPin, INPUT); pinMode(buttonPin, INPUT_PULLUP); // 启用内部上拉电阻 pinMode(redLedPin, OUTPUT); pinMode(greenLedPin, OUTPUT); pinMode(buzzerPin, OUTPUT); dragonServo.attach(servoPin); dragonServo.write(90); // 初始位置 Serial.begin(9600); // 用于调试 Serial.println("System Ready. Press button to start."); } void loop() { int buttonState = digitalRead(buttonPin); int motionDetected = digitalRead(pirPin); switch (currentState) { case STATE_IDLE: digitalWrite(redLedPin, LOW); digitalWrite(greenLedPin, LOW); if (buttonState == LOW) { // 按钮被按下(上拉模式,按下为LOW) delay(50); // 简单防抖 if (digitalRead(buttonPin) == LOW) { startGame(); } } break; case STATE_GREEN: digitalWrite(greenLedPin, HIGH); digitalWrite(redLedPin, LOW); // 绿灯状态下,可以记录“后退”动作,这里用计时模拟 // 或者通过其他传感器测量真实距离 if (motionDetected == HIGH) { // 假设检测到一次移动代表后退了一步 playerDistance += 10; // 示例增量 lastMoveTime = millis(); } // 检查是否按下胜利按钮 if (buttonState == LOW) { delay(50); if (digitalRead(buttonPin) == LOW && playerDistance >= winDistance) { winGame(); } } // 检查绿灯时间是否结束 if (millis() - stateStartTime > greenLightDuration) { enterRedState(); } break; case STATE_RED: digitalWrite(redLedPin, HIGH); digitalWrite(greenLedPin, LOW); // 让龙动起来 animateDragon(); // 在红灯状态下检测移动即为失败 if (motionDetected == HIGH) { loseGame(); } // 红灯状态持续时间(可选项,也可以一直持续直到被触发) if (millis() - stateStartTime > redLightDuration) { enterGreenState(); // 切换回绿灯,继续游戏 } break; case STATE_WIN: // 胜利动画:绿灯闪烁,欢快音效 celebrateWin(); // 一段时间后回到待机状态 if (millis() - stateStartTime > 3000) { resetGame(); } break; case STATE_LOSE: // 失败动画:红灯闪烁,警报音效,龙剧烈动作 indicateLoss(); // 一段时间后回到待机状态 if (millis() - stateStartTime > 3000) { resetGame(); } break; } } // 状态转换函数 void startGame() { Serial.println("Game Start!"); currentState = STATE_GREEN; stateStartTime = millis(); playerDistance = 0; playStartTone(); } void enterRedState() { Serial.println("Red Light! FREEZE!"); currentState = STATE_RED; stateStartTime = millis(); playStateChangeTone(); } void enterGreenState() { Serial.println("Green Light! GO!"); currentState = STATE_GREEN; stateStartTime = millis(); playStateChangeTone(); } void winGame() { Serial.println("You Win!"); currentState = STATE_WIN; stateStartTime = millis(); playWinTone(); } void loseGame() { Serial.println("You Moved! You Lose!"); currentState = STATE_LOSE; stateStartTime = millis(); playLoseTone(); } void resetGame() { currentState = STATE_IDLE; dragonServo.write(90); digitalWrite(buzzerPin, LOW); } // 辅助功能函数 void animateDragon() { // 让伺服电机在80-100度之间缓慢摆动,模拟“监视” int angle = 90 + 10 * sin(millis() / 500.0); // 每5秒一个周期 dragonServo.write(angle); } void playStartTone() { tone(buzzerPin, 523, 200); } // Do void playStateChangeTone() { tone(buzzerPin, 659, 150); } // Mi void playWinTone() { tone(buzzerPin, 784, 200); delay(200); // Sol tone(buzzerPin, 1047, 400); // Do(高八度) } void playLoseTone() { for (int i = 0; i < 3; i++) { tone(buzzerPin, 200, 200); // 低音警报 delay(250); } } void celebrateWin() { /* 控制LED闪烁模式 */ } void indicateLoss() { /* 控制LED闪烁和伺服电机快速震动 */ }代码关键点解析:
- 状态机核心:
GameState枚举和switch-case结构是骨架。每个case里只处理该状态下的逻辑和退出条件。 - 非阻塞延时:游戏计时使用
millis()函数而非delay()。delay()会阻塞整个程序,导致无法检测按钮或传感器。millis()通过记录状态开始时间并与当前时间比较来实现计时,不影响主循环。 - 传感器读取:PIR传感器输出在触发后会有几秒高电平。在红灯状态,一旦读到
HIGH即判负,反应迅速。 - 音效生成:使用
tone(pin, frequency, duration)函数可以产生简单的方波音调,通过组合不同频率和时长,能创造出开始、状态切换、胜利、失败等多种音效。
4. 手工制作:钩织龙形玩偶
4.1 钩织基础与材料准备
钩织部分为项目注入了独特的个性与温度。即使你不是钩织高手,跟着步骤也能完成。你需要准备:
- 中粗棉线:2团,颜色自选。棉线质地挺括,易于塑形。
- 3mm钩针:适合中粗线。
- 缝合针、剪刀。
- 填充棉:用于填充头部、身体和手臂,使其饱满。
- 10mm安全眼珠:2颗,让龙更有神。
- 铁艺线:用于翅膀定型,约1-2毫米粗,易于弯折又足够支撑。
钩织使用美式缩写,文中已列出。核心针法包括短针(sc)、加针(inc,同一针目钩两针)、减针(dec,两针并一针)。环形起针(mr)是制作球形部件的关键。
4.2 分部件钩织详解
龙玩偶由头部、身体、翅膀手臂、翅膀、角五个部分组成,分开钩织再缝合。
头部:从环形起针4针开始,通过规律加针形成半球,再钩织多圈短针形成头部主体,最后减针收口。关键点:在钩织第10-11圈之间,在两侧对称位置安装安全眼珠。填充要均匀、饱满,但不要过紧导致变形。
身体:这是最复杂的部分,需要塑造出龙的大致体型。起24个锁针然后首尾连接成环,钩织短针形成圆柱。通过有规律的加针和减针,在特定行数塑造出身体的曲线。务必使用记号扣标记每一圈的起始点和身体侧面的中心线,这是保持对称性的生命线。原作者在身体中后段减少了钩织圈数,使身体更短粗,更稳定。
翅膀手臂(2个):作为连接身体和翅膀的关节,需要一定的厚度。从环形起针开始,钩织一个细长的圆柱体,并轻微加针使其一端略粗。只需轻微填充,保持可弯折性。
翅膀(2个):这是视觉效果的关键。从翅膀手臂的顶端接入线,钩织30个锁针作为翅膀骨架,然后沿着骨架两侧钩织短针,形成一个扁平的三角形基底。最后一行使用从半双针到八倍长针的各种长针,快速增加针数,模拟出翅膀边缘的羽毛或薄膜质感。核心步骤:钩织完成后,必须用铁艺线进行骨架加固。将铁艺线沿着翅膀的顶部、底部边缘以及中心轴线,用针小心地穿入针目缝隙中,然后弯折出翅膀展开的造型。这能防止翅膀软塌,保持灵动姿态。
角(大、中、小各2个):简单的圆锥体,从环形起针开始,通过少量加针或直接钩织短针形成。只需在缝合前填入少许填充棉即可。
4.3 缝合与整体组装
缝合决定最终成品的美观度。
- 定位:在缝合前,先用珠针将角、翅膀在头部和身体上大致固定,从各个角度观察调整,找到最协调的位置后再开始缝合。
- 缝合头部与身体:将头部的收口边缘与身体顶部的开口边缘对齐。眼睛应位于身体两侧。使用卷缝或挑针缝合,确保牢固且线迹隐蔽。
- 缝合角与翅膀:将角缝合在头顶。将翅膀手臂的根部牢固地缝合在身体两侧预定位置,然后将已用铁艺线定型的翅膀与翅膀手臂的顶端缝合。确保翅膀的加固线朝下(即贴近身体),这样外观更整洁。
- 最终调整:检查所有缝合点是否牢固,填充是否均匀,造型是否满意。可以适当弯曲铁艺线,微调翅膀的角度。
实操心得:钩织是一个需要耐心的过程,尤其是数针目。每钩完一圈,最好用记号扣标记,并核对针数是否正确。身体部分因为加减针频繁,最容易出错。如果某圈针数不对,宁愿拆掉几行重来,也不要将就,否则后续形状会越来越歪。填充时使用钩针柄或镊子将棉塞到角落,但要避免戳破织物。
5. 机械结构与外壳组装
5.1 外壳设计与激光切割
外壳的作用是容纳电路、支撑机械结构并呈现整体外观。使用激光切割MDF板是高效精准的方法。
- 设计工具:我使用了MakerCase网站生成一个基础盒子的矢量图(DXF格式),然后导入到Inkscape(免费开源矢量软件)中进行自定义修改。
- 开孔设计:
- 前面板:根据PIR传感器和LED的尺寸,精确绘制并切割出安装孔。
- 顶板:切割一个圆孔用于传动铁艺线穿过;切割一个方孔用于安装按钮。
- 侧板:切割一个矩形槽,用于USB电源线引出。
- 内部结构件设计:
- 伺服电机支架:一个带卡槽的零件,能将伺服电机牢牢固定在底板或侧板上。
- 线缆导向支架:一个带有小圆孔的零件,安装在顶板下方,作为铁艺线的垂直运动导轨,防止它左右晃动。
- 按钮加固板:一个小零件,从内部粘在顶板按钮孔周围,增加按钮安装点的强度。
- 电路板支架/隔板:用于固定面包板或洞洞板,并将其与机械运动部分适当隔离。
- 切割与打磨:将设计好的DXF文件交给激光切割机。切割完成后,务必对所有零件进行试组装,特别是各开孔。MDF激光切割后孔洞可能偏小,需要用砂纸仔细打磨扩大,确保传感器、按钮、USB线能严丝合缝地装入。
5.2 传动机构制作与调试
这是连接电子世界和物理世界的桥梁。
- 制作传动杆:取一段足够长的铁艺线(比如30厘米),根据伺服电机舵盘到顶板孔洞的距离,以及希望龙运动的幅度,将其弯折成“L”形或“Z”形。一端留出一个小环,用于固定在伺服电机舵盘上(用螺丝或强力胶);另一端向上穿过顶板孔和线缆导向支架后,弯折成一个钩子。
- 连接伺服电机:将传动杆用螺丝或胶水固定在伺服电机舵盘上。确保安装牢固,且伺服电机转动时,传动杆不会碰到其他部件。
- 空载测试:上传一段简单的测试代码(如让伺服电机在0-180度间往复运动),观察传动杆的运动是否平滑、范围是否合适。调整代码中的角度限制,使其运动范围与顶板孔洞和线缆导向支架匹配。
- 负载测试与调整:将龙玩偶挂到传动杆顶部的钩子上。再次运行测试代码。观察:
- 伺服电机是否有力带动龙?如果出现抖动或无法到达指定位置,可能是扭矩不足,需减轻龙的重重或换用扭矩更大的伺服电机。
- 龙的运动轨迹是否笔直?是否有卡顿?调整线缆导向支架的位置,确保传动杆垂直运动。
- 运动幅度是否美观?通过调整代码中的角度值和传动杆弯曲的形状,可以改变龙上下起伏的幅度。
5.3 总装与内部理线
按照由内到外、先机械后电子的顺序进行总装。
- 粘合主体结构:使用木工胶或快干胶,将盒子的底板、侧板、前面板粘合起来。顶板和背板先不要粘,以便内部操作。
- 安装内部支架:将伺服电机支架、线缆导向支架、电路板支架用热熔胶或强力胶粘在盒内预定位置。确保伺服电机支架和线缆导向支架在垂直方向上对齐。
- 安装电子元件:
- 将PIR传感器、LED从内部插入前面板的孔中,用热熔胶从内部固定。
- 将伺服电机卡入支架并粘牢。
- 将按钮穿过顶板孔,从内部用螺母拧紧,或在内部用加固板和热熔胶固定。
- 布置电路:将Arduino、面包板等放入盒内,放在电路板支架上。尽量使用短线连接,并使用扎带或胶水固定线束,避免杂乱。将传动杆与伺服电机连接好,并穿过线缆导向支架和顶板孔。
- 连接与测试:将所有电子元件按照电路图连接到Arduino。此时背板还未封闭,方便调试。上电,运行完整游戏代码,测试所有功能:按钮启动、LED状态切换、PIR检测、蜂鸣器发声、伺服电机带动龙运动。
- 最终封闭:确认所有功能正常后,将龙玩偶挂上。用热熔胶在传动杆与龙身体的连接点附近少量点胶加固(避免影响可拆卸性)。最后,粘上顶板和背板,完成组装。
6. 系统调试与问题排查实录
即使按照步骤精心制作,调试阶段也总会遇到各种问题。以下是可能遇到的典型问题及解决方法。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 上电后无任何反应 | 1. 电源未接通或损坏。 2. Arduino未正确烧录程序或死机。 | 1. 检查移动电源开关、USB线连接。用万用表测Arduino Vin或5V引脚是否有电。 2. 重新插拔USB线,尝试上传一个简单的Blink示例程序测试Arduino。 |
| 按钮按下无反应 | 1. 按钮接线错误或虚焊。 2. 引脚模式设置错误(应为 INPUT_PULLUP)。3. 代码中按钮检测逻辑有误。 | 1. 用万用表通断档检查按钮按下时是否导通。 2. 检查 setup()中是否设置了pinMode(buttonPin, INPUT_PULLUP)。3. 在 loop()中打印按钮引脚的电平值,观察按下前后的变化。 |
| PIR传感器一直触发或不触发 | 1. 传感器未初始化完成。 2. 灵敏度或延时调节不当。 3. 安装环境有干扰源(如通风口、热源)。 4. 接线错误。 | 1. 上电后等待一分钟再测试。 2. 逆时针调节延时旋钮到最小;灵敏度先调至中间。用手在传感器前缓慢移动测试。 3. 改变传感器安装位置或角度,避开干扰。 4. 检查VCC、GND、OUT是否对应连接5V、GND、数字引脚。 |
| LED不亮或亮度异常 | 1. LED正负极接反。 2. 限流电阻阻值过大或忘记接。 3. 引脚输出模式错误。 | 1. LED长脚为正(阳极),应接电阻再到IO口;短脚为负(阴极),接GND。 2. 确保使用了330Ω电阻。用万用表测量电阻两端电压。 3. 确认 pinMode设置为OUTPUT。 |
| 蜂鸣器不响 | 1. 有源/无源蜂鸣器混淆。 2. 引脚控制错误。有源蜂鸣器高电平触发。 | 1. 本项目用有源蜂鸣器。直接给VCC接5V,GND接地,应常响。确认类型。 2. 检查代码是否为 digitalWrite(buzzerPin, HIGH)或tone()函数。 |
| 伺服电机不转或抖动 | 1. 供电不足。 2. 信号线接触不良。 3. 机械负载过重或卡死。 | 1.最常见原因!尝试单独用5V/2A电源给伺服电机供电。 2. 检查信号线是否连接到了PWM引脚(如9号)。 3. 断开传动杆,测试电机空载是否正常。检查传动机构是否顺畅。 |
| 龙玩偶运动不顺畅 | 1. 传动杆弯曲角度不当,与孔壁摩擦。 2. 线缆导向支架未对齐。 3. 玩偶过重。 | 1. 调整传动杆形状,确保其垂直运动无阻碍。 2. 重新调整线缆导向支架的位置,使其与伺服电机舵盘中心对正。 3. 减少玩偶内部填充棉,或选用更轻的纱线。 |
| 游戏逻辑混乱(如状态切换错误) | 1. 状态机逻辑有bug。 2. 使用了 delay()导致无法及时检测输入。3. 变量未正确初始化或溢出。 | 1. 在串口监视器中打印当前状态(currentState)和关键变量,观察其变化是否符合预期。2.确保所有计时都使用 millis(),杜绝delay()。3. 检查 unsigned long类型变量在millis()回滚(约50天后)后的处理。 |
调试核心心法:分模块测试,逐步集成。不要一次性组装完所有东西再调试。应先确保Arduino能控制单个LED、蜂鸣器、伺服电机;再单独测试PIR和按钮输入是否正常;然后将输入输出结合起来测试简单逻辑;最后集成机械部分和完整游戏逻辑。善用串口监视器输出调试信息,它是你窥探程序运行状态的“眼睛”。
完成这个项目,你收获的不仅仅是一个有趣的玩具。你实践了嵌入式系统开发的完整流程:从需求分析、方案设计、硬件选型、电路搭建、软件编程,到机械结构设计、手工制作和系统集成调试。每一个环节遇到的问题和解决的方法,都是宝贵的经验。这条钩织的龙,最终能否栩栩如生地动起来,并和你成功互动,取决于你在每个细节上的耐心和思考。这正是创客精神的迷人之处——将想法,通过双手,变为现实。