PuzzleBox
组件和用品
| × | 1 |
应用和在线服务
|
关于这个项目
注意:本教程可能已过时,请转到 这里 获取最新版本。
让贵重物品远离窥探有时很难,除非你把它放在一个大保险箱或类似的东西里……但谁有空间呢?
相反,使用 MKR IoT Bundle 中的组件和一些纸板创建您自己的拼图盒!我们无法保证您财物的安全,但至少对潜在的小偷来说会是一种有趣的威慑。
当然,我们建议您将糖果藏在那里……而不是真正的贵重物品。
简而言之
为了打开由伺服电机保持关闭的盒子,您必须转动电位计,直到获得正确的组合。可以通过在线应用程序 Blynk 设置组合。 LED 将帮助您猜测,为您提供颜色反馈:距离越近,颜色越暖。
当猜到正确的组合时,蜂鸣器将开始播放歌曲,而伺服将打开盒子。
为了创建我们的拼图盒,我们需要以下组件:
- 蜂鸣器
- RGB LED
- 3 个电位器
- 液晶屏
- 伺服电机
学习目标
- 介绍 Blynk 互联网平台
- 液晶屏接线和使用
- 使用蜂鸣器播放星球大战主题
想了解更多?
本教程是让您熟悉 MKR1000 和 IoT 的一系列实验的一部分。所有实验都可以使用 MKR IoT Bundle 中包含的组件构建。
- 我爱你的枕头
- 拼图盒
- 巴甫洛夫的猫
- 书呆子
- 工厂通讯器
介绍 Blynk
Blynk 是一款流行的物联网移动应用程序,它让我们可以随时随地轻松控制连接到互联网的 Arduino。
它建立在 Kickstarter 上,凭借其出色的文档和简单性,迅速成为该领域最常用的应用程序之一。
Blynk 入门
创建一个新项目真的很容易,只需按照这几个简单的步骤进行操作或查看 Blynk 的官方入门。
图> 图> 图> 图> 图> 图> 图> 图>成功创建新项目后,您还应该通过邮件收到 Auth 令牌。 它是将硬件连接到智能手机所需的唯一标识符。您创建的每个新项目都将拥有自己的身份验证令牌。
为了将 Arduino 连接到应用程序,我们需要安装 Blynk 库。如果您使用的是 Arduino Web 编辑器,当您将其包含在草图中时,库将自动下载,否则您可以从库管理器下载。
现在我们准备好了。 上传此草图 并使用滑块查看结果:
#include #include const char* ssid =SECRET_SSID; // 您的网络 SSID(名称) const char* password =SECRET_PSWD; // 您的网络密码 char auth[] =SECRET_TOKEN; // 您的 Blynk API 令牌 // 存储组合值的变量 // 将初始组合设置为 ( 1 1 1 ) int SliderValueOne =1; int SliderValueTwo =1; int SliderValueThree =1; // Blynk 函数来检索值 BLYNK_WRITE(V1) { SliderValueOne =param.asInt(); // 将来自引脚 V1 的传入值分配给变量 } BLYNK_WRITE(V2) { SliderValueTwo =param.asInt(); // 将来自引脚 V1 的传入值分配给变量 } BLYNK_WRITE(V3) { SliderValueThree =param.asInt(); // 将引脚 V1 的传入值分配给变量 } void setup() { Serial.begin(9600); Blynk.begin(auth, ssid, 密码); // 启动 Blynk 功能并连接到 WiFi} void loop() { // 临时存储组合的变量 int Temp_Slider_One_value =SliderValueOne; int Temp_Slider_Two_value =SliderValueTwo; int Temp_Slider_Three_value =SliderValueThree; Blynk.run(); // 从在线应用程序中轮询新的组合值 // 检查组合值是否已更改并将其打印在控制台上 if(Temp_Slider_One_value !=SliderValueOne || Temp_Slider_Two_value !=SliderValueTwo || Temp_Slider_Three_value !=SliderValueThree){ Serial.print("New组合: ”); Serial.print(SliderValueOne); Serial.print(" "); Serial.print(SliderValueTwo); Serial.print(" "); Serial.println(SliderValueThree); } }
使用液晶屏
是时候连接屏幕了!
LCD 屏幕易于使用,但需要大量电线,因此请准备好证明您的耐心。
请注意,我们使用的是 5V 电源和 220 欧姆电阻。
亮度可以调节,将模拟引脚3的输出值从0改变到255,0为最大值。
analogWrite(A3, 0);
现在我们可以上传示例草图,看看是否一切正常。
// 包含库代码:#include // 通过将任何需要的 LCD 接口引脚与连接到 const int rs =12, en 的 arduino 引脚编号相关联来初始化库=11, d4 =2, d5 =3, d6 =4, d7 =5; LiquidCrystal lcd(rs, en, d4, d5, d6, d7);无效设置(){模拟写入(A3,0); // 将亮度设置为其最大值 // 设置 LCD 的列数和行数:lcd.begin(16, 2); // 向 LCD 打印一条消息。 lcd.print("你好,世界!"); } void loop() { // 将光标设置到第 0 列第 1 行 //(注意:第 1 行是第二行,因为计数从 0 开始):lcd.setCursor(0, 1); // 打印自重置以来的秒数:lcd.print(millis() / 1000); } 代码>
添加电位器
要读取电位计的值,我们只需要一个 analogRead()
在正确的引脚上。我们将它们连接到模拟引脚 0、1、2。
请注意,电位计的值范围从 0 到 1023,因此无法猜测组合。要将这些值从 0 映射到 9,我们将使用 map()
函数,
int PotOne =map(analogRead(A0), 0, 1023, 0, 9);
您可以使用此示例代码在 LCD 屏幕上打印电位器的值。
#include // LCD 屏幕引脚 const int rs =12, en =11, d4 =2, d5 =3, d6 =4, d7 =5; LiquidCrystal lcd(rs, en, d4, d5, d6, d7);无效设置(){模拟写入(A3,0); // 设置液晶屏亮度为最大值 Serial.begin(9600); lcd.begin(16, 2); // 以 16 列 2 行开始 LCD 屏幕 } void loop() { int PotOne =map(analogRead(A0), 0, 1023, 0, 9); int PotTwo =map(analogRead(A1), 0, 1023, 0, 9); int PotThree =map(analogRead(A2), 0, 1023, 0, 9); lcd.setCursor(0, 0);液晶打印(PotOne); lcd.setCursor(2, 0);液晶打印(PotTwo); lcd.setCursor(4, 0);液晶打印(PotThree); } 代码>
添加RGB LED
我们将使用 RGB LED 作为反馈来帮助人们猜测组合,他们越接近正确的值,LED 的颜色越暖,包括蓝色、浅绿色、黄色和红色。
图>您可以使用此示例草图查看 RGB 的作用!
// RGB LED 引脚 int redPin =6; int greenPin =8; int bluePin =7;无效设置(){ pinMode(redPin,输出); pinMode(greenPin, OUTPUT); pinMode(bluePin,输出); Serial.begin(9600); } void loop() { setColor(0, 0, 255); // 蓝色延迟(1000); setColor(0, 255, 255); // 水延迟(1000); setColor(255, 255, 0); // 黄色延迟(1000); setColor(255, 0, 0); // 红色延迟(1000); } // 将 RGB 值发送到 LED 引脚 void setColor(int red, int green, int blue){analogWrite(redPin, red);模拟写入(greenPin,绿色);模拟写入(bluePin,蓝色); } 代码>
将其连接到 Blynk
现在我们准备把东西放在一起:将电路板连接到 Blynk,将电位器连接到 LCD 屏幕,并在组合正确时使 LED 闪烁绿色。
- 请注意,我们将使用函数
giveColorFeedback()
当每个电位器的绝对值接近某个阈值时,设置 LED 的颜色以正确组合。
void giveColorFeedback(int PotOne, int PotTwo, int PotThree){...}
- 我们还将使用这些变量来存储从应用发送的值以及组合。
int SliderValueOne =1; int SliderValueTwo =1; int SliderValueThree =1;
请注意,初始值设置为 1,只有在您修改应用程序上滑块的值时才会更改。 如果您重置电路板,组合将恢复为默认值。
- 一个布尔变量
bool start =true;
用于检测何时已经猜到了组合,以避免在每次循环时重新打开盒子。
上传此示例草图以查看其实际效果:
#include #include #include #include // RGB LED 引脚 int redPin =6; int greenPin =8; int bluePin =7; const char* ssid =SECRET_SSID; // 您的网络 SSID(名称) const char* password =SECRET_PSWD; // 您的网络密码 char auth[] =SECRET_TOKEN; // 你的 Blynk API 令牌 // LCD 屏幕引脚 const int rs =12, en =11, d4 =2, d5 =3, d6 =4, d7 =5;布尔开始=真; // 存储组合值的变量 // 将初始组合设置为 ( 1 1 1 ) int SliderValueOne =1; int SliderValueTwo =1; int SliderValueThree =1; // Blynk 函数来检索值 BLYNK_WRITE(V1) { SliderValueOne =param.asInt(); // 将来自引脚 V1 的传入值分配给变量 } BLYNK_WRITE(V2) { SliderValueTwo =param.asInt(); // 将来自引脚 V1 的传入值分配给变量 } BLYNK_WRITE(V3) { SliderValueThree =param.asInt(); // 将来自引脚 V1 的传入值分配给变量 } LiquidCrystal lcd(rs, en, d4, d5, d6, d7);无效设置(){ pinMode(redPin,输出); pinMode(greenPin, OUTPUT); pinMode(bluePin,输出);模拟写入(A3,0); // 设置液晶屏亮度为最大值 Serial.begin(9600); lcd.begin(16, 2); // 以 16 列 2 行开始 LCD 屏幕 Blynk.begin(auth, ssid, password); // 启动 Blynk 功能 } void loop() { // 临时存储组合的变量 int Temp_Slider_One_value =SliderValueOne; int Temp_Slider_Two_value =SliderValueTwo; int Temp_Slider_Three_value =SliderValueThree; Blynk.run(); // 从在线应用程序中轮询新的组合值 // 检查组合值是否已更改并将其打印在控制台上 if(Temp_Slider_One_value !=SliderValueOne || Temp_Slider_Two_value !=SliderValueTwo || Temp_Slider_Three_value !=SliderValueThree){ Serial.print("New组合: ”); Serial.print(SliderValueOne); Serial.print(" "); Serial.print(SliderValueTwo); Serial.print(" "); Serial.println(SliderValueThree); int PotOne =map(analogRead(A0), 0, 1023, 0, 9); int PotTwo =map(analogRead(A1), 0, 1023, 0, 9); int PotThree =map(analogRead(A2), 0, 1023, 0, 9); lcd.setCursor(0, 0);液晶打印(PotOne); lcd.setCursor(2, 0);液晶打印(PotTwo); lcd.setCursor(4, 0);液晶打印(PotThree); if (start) { giveColorFeedback(PotOne, PotTwo, PotThree);如果(PotOne ==SliderValueOne &&PotTwo ==SliderValueTwo &&PotThree ==SliderValueThree){blinkGreenLed();开始=假; } } if(!start) { if(PotOne ==0 &&PotTwo ==0 &&PotThree ==0){ start =true; } } } // 根据电位器与组合值的接近程度给出反馈 // 越接近 LED 的颜色越暖 void giveColorFeedback(int PotOne, int PotTwo, int PotThree) { if (abs(PotOne) - SliderValueOne) <=1 &&abs(PotTwo - SliderValueTwo) <=1 &&abs(PotThree - SliderValueThree) <=1 ) { // 红色 setColor(255, 0, 0); } else if (abs(PotOne - SliderValueOne) <=3 &&abs(PotTwo - SliderValueTwo) <=3 &&abs(PotThree - SliderValueThree) <=3 ) { // 黄色 setColor(255, 255, 0); } else if (abs(PotOne - SliderValueOne) <=4 &&abs(PotTwo - SliderValueTwo) <=4 &&abs(PotThree - SliderValueThree) <=4 ) { // aqua setColor(0, 255, 255); } else { // 蓝色 setColor(0, 0, 255); } } void browseGreenLed() { for (int a =0; a <2; a++) { for (int b =0; b <=255; b +=5) { setColor(0, b, 0);延迟(5); } for (int b =255; b>=0; b -=5) { setColor(0, b, 0);延迟(5); } } for (int b =0; b <=255; b +=5) { setColor(0, b, 0);延迟(5); } } // 将 RGB 值发送到 LED 引脚 void setColor(int red, int green, int blue){analogWrite(redPin, red);模拟写入(greenPin,绿色);模拟写入(bluePin,蓝色); } 代码>
添加蜂鸣器
当盒子打开时,我们将使用蜂鸣器播放一段旋律。更准确地说,我们将播放星球大战主题曲!
连接蜂鸣器很简单:
上传此示例代码并收听:
const int c =261; const int d =294; const int e =329; const int f =349; const int g =391; const int gS =415; const int a =440; const int aS =455; const int b =466; const int cH =523; const int cSH =554; const int dH =587; const int dSH =622; const int eH =659; const int fH =698; const int fSH =740; const int gH =784; const int gSH =830; const int aH =880;整数计数器 =0; #define buzzerPin 1 void setup() { pinMode(buzzerPin, OUTPUT); Serial.begin(9600); } void loop() { play_jingle();延迟(3000); } void play_jingle() { beep(a, 500);哔(一,500);哔(一,500);哔(f,350);哔(CH,150);哔(一,500);哔(f,350);哔(CH,150);哔(一,650);延迟(500);哔(eH,500);哔(eH,500);哔(eH,500);哔(fH,350);哔(CH,150);哔(gS,500);哔(f,350);哔(CH,150);哔(一,650);延迟(500); } void beep(int note, int duration) { //在蜂鸣器上播放音调Pintone(buzzerPin, note, duration); // buzzerPin 上的停止音 noTone(buzzerPin);延迟(50); //递增计数器counter++; } 代码>
添加伺服电机
伺服电机是我们盒子的锁,当组合正确时,我们需要它转动90度,这样盒子才能打开。
连接舵机只需要三根线。
为了将其旋转 90 度,我们将使用以下函数:
#include int pos =0; // 存储伺服位置的变量 Servo myservo; // 创建伺服对象来控制伺服 void setup() { myservo.attach(9); // 将引脚 9 上的伺服连接到伺服对象 myservo.write(pos); // 将舵机设置在位置 0 } void loop() { open_the_box();延迟(2000); close_the_box();延迟(2000); } void open_the_box(){ for (pos =0; pos <=90; pos +=1) { // 从 0 度到 90 度 myservo.write(pos); // 告诉伺服器转到变量“pos”延迟(15)中的位置; // 等待 15 毫秒让舵机到达位置 } } void close_the_box(){ for (pos =90; pos>=0; pos -=1) { // 从 90 度变为 0 度 myservo.write(pos); // 告诉伺服器转到变量“pos”延迟(15)中的位置; // 等待 15ms 等待舵机到达位置 } }
请注意,为了将伺服器转回并关闭盒子,您所要做的就是将所有电位器转为 0。
拼图盒
没有盒子就不是盒子,所以下载下面的案例文件,并用它作为指南来构建你自己的。
请注意,我们使用了 2 毫米厚的纸板。
代码
完成草图
定制零件和外壳
2 毫米纸板 box_E5j7tnFdNC.dxf示意图
制造工艺