亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Squid Games Doll 使用 Arduino UNO

组件和用品

RGB 扩散共阴极
眼睛
× 2
SparkFun 7 段串行显示 - 红色
定时器
× 1
Texas Instruments 移位寄存器 - 并行到串行
4 位 7 段显示
× 1
字母数字 LCD,16 x 2
菜单显示
× 1
红外接收器(通用)
用于远程控制
× 1
Arduino UNO
大脑
× 1
SG90 微伺服电机
旋转头部
× 1
PIR 运动传感器(通用)
运动检测
× 1
超声波传感器 - HC-SR04(通用)
输赢距离检测
× 1
DFRobot DFPlayer - 迷你 MP3 播放器
语音
× 1
按钮开关,瞬时
菜单按钮和开始按钮
× 1

必要的工具和机器

3D 打印机(通用)

应用和在线服务

Arduino IDE

关于这个项目

构建了一个功能齐全的鱿鱼游戏玩偶。她和你玩红灯绿灯游戏。完成旋转的头部,彩色的眼睛,她会说话!她使用超声波和运动检测来确定您是输还是赢。不过别担心,如果你输了,她只会问你是否想再玩一次。

观看视频,让我知道您的想法。

我使用了 Arduino UNO 上的每个引脚!这是我以前从未做过的,所以这对我自己来说是一个成就。这个项目花了我 3 周的时间来构建,其中 1 周完全用于打印!我花了 6 天的时间来打印这个娃娃。 1 周用于构建,另外一周用于编辑视频。

如果我制作了视频,ELEGOO 会免费寄给我一个 UNO 套件,所以这就是我制作娃娃的原因。要么就是这个,要么建一个逃生室。我很高兴他们选择了这个项目。我希望人们喜欢它,因为它是一个有趣的构建,它看起来非常漂亮并且让一群人毛骨悚然。但更重要的是,它有效。

这是我将用于此构建的所有部件。

1. 开始打印

打印需要很长时间。我花了 6 天的时间打印出整个娃娃。我还使用了不同颜色的灯丝,这样我就可以减少绘画的数量。

我重新混合了我在 thingiverse.com 上找到的模型,挖空了中心,并为电子设备添加了检修孔。我还修改了要安装的伺服和超声波的胸板。

2.没有人喜欢画画

是时候画画了。我为此使用了通用喷漆。我画了娃娃头的内部(遮住了眼睛),这样眼睛的 LED 就不会让整个脸发光。虽然这可能是您正在寻找的效果。我只想让眼睛发光。

3. 磁铁吸,胶粘

连接娃娃所有四肢的一种方法是将磁铁熔化到塑料中。这是如果你想能够把她分开。如果我再做这个项目,我可能会把所有的四肢都粘在她身上。正如我现在所看到的,除了她可以放入一个较小的盒子中进行存储之外,使用磁铁几乎没有什么优势。此时您唯一不应该附加的是头部。

4. 护眼

从最简单的步骤开始,眼睛。我为眼睛使用了三色 LED。如您所知,您可以混合和匹配 RGB 颜色以获得您喜欢的任何基本颜色。我坚持使用原色和副色,所以我不必对信号进行 PWM。但是,如果您正在寻找它,则可以。

最长的引脚是地线,即引脚 2。

使用 220 欧姆电阻器连接 LED,如图所示,除接地外的每条引线都使用 220 欧姆电阻器。

对于安装,我只是将 LED 热粘在尽可能靠近眼睛中心的位置,但在反面。一定要留足够长的金属丝穿过脖子并进入她身体的下半部分。

5.液晶菜单

下一个最简单的组件是 16x2 LCD 屏幕。您应该使用带有 I2C 适配器的 LCD 屏幕。它将使您的生活更轻松,并将 IO 计数从 6 个减少到 2 个。一旦连接,LCD 应启动并显示“欢迎来到鱿鱼游戏!”在显示器上。

为了安装,我打印了一个 1 毫米厚的圆圈。我把它做得很薄,这样我就可以用热风枪把它塑造到娃娃的背上。这比弄清楚她背部的轮廓要容易得多(至少对我而言)。我为显示器安装了螺纹嵌件,背面带有螺母,以将显示器和显示器支架固定到机身上。

6.只有猫头鹰头旋转180度

伺服很难的一个主要原因是,我不使用伺服库。我知道这听起来很奇怪,但我不得不使用 timer1 进行 4 位显示更新,伺服库也使用它。幸运的是,伺服是 0 度或 180 度,中间没有任何关系,使这变得容易多了。

Timer1 设置为 .5ms 间隔,2000hz。伺服周期为20ms。在 0 度时,引脚只需要在 2 次计数时处于高电平,在其余时间段内保持低电平。对于 180 度,引脚需要高 4 次计数,其余时间低。

伺服器的胸板上有一个很好的安装座。您可以将其拧入到位或将其粘合到位。我使用环氧树脂将伺服器固定到胸板上,因为它还会增加胸板的强度并希望防止其损坏。

7. 听起来像蝙蝠

接下来我们将安装超声波测距模块。我每 250 毫秒更新一次。它还在胸板上有一个很好的安装位置。该模块只有 2 根电线。

我使用环氧树脂将超声波安装到胸板上。

8. 无附加条件

只有当您想控制游戏时,才需要遥控器的红外传感器。我以为这会很有趣,但不要真正使用这种模式,自动游戏就足够有趣了。

我选择将红外传感器安装在娃娃头发的夹子内。您显然可以选择将其放置在其他地方。我试图隐藏它,但也许有一个更好的地方,因为当她转过头并且传感器在另一侧时,红外线并不总是能看到遥控器。

9. 时不时

接下来我们将设置定时器显示。对于 4 位显示器来说,这是一项大量工作。我将包括来自 ELEGOO 的连接图。游戏最多只有5分钟,所以我也去掉了最高位数字的使用。但是,如果您有可用的 IO 引脚,您可以决定保留它。要更新显示,您必须非常快速地循环 LED,因为您一次只能激活一位数字。这就是为什么它们在通过相机观看时似乎会闪烁的原因。我使用了 2ms 的刷新率,它足够快,您看不到闪烁。在 5 毫秒时,我可以开始在您的周边视觉中查看显示时看到它在闪烁。此外,您将需要移位寄存器 74HC595。

安装显示器有什么不好玩的。我决定最好将显示器集成到她的腰带中。 Squid Games 中的原始玩偶当然没有腰带,但必须做出牺牲才能在她身上展示这一点。如果您也选择这条路线,请遮住与显示器大小相同的正方形,然后用 Dremel 剪下。然后我使用环氧腻子为显示器添加渐变。但这不是必需的,我只是觉得这样看起来更好。

我将 74HC595 安装到原型屏蔽上,否则你的电线会到处都是。另一种解决方案是使用不同的计时器显示,它具有更方便的通信和更少的引脚。

10.我看到你动了

运动检测器是一个奇怪的小家伙。这东西使用红外线来检测运动。我学到的一件事是这个传感器需要时间来预热。启动时需要 1 分钟预热。这就是为什么娃娃有 1 分钟的启动时间。该模块的另一个烦恼是它更新运动检测的最快速度约为 5 秒。最后一个烦恼是这个传感器有多灵敏。即使灵敏度一直调低,它仍然可以看到最小的动作,有时甚至我都不知道它在说什么。为了帮助防止这些“误报”,我将传感器安装在马盲盒内。盒子有一个小孔(7 毫米),供运动探测器观察。作为奖励,这可以防止您将这个巨大的传感器安装在玩偶的外部。运动传感器只有一根二进制线用于反馈,运动与否。

为了安装传感器,我打印了马眼罩并将其粘在玩偶的内部。然后我在身体上钻了一个洞。我在盲盒上使用螺纹插件来固定运动传感器。

11.不要按我的按钮

最后,我们在按钮上。如果您有额外的 I/O 引脚,则更容易将每个引脚连接到数字输入。但我对 UNO 没有这种奢侈。相反,我不得不使用模拟输入来读取电阻值以确定按下的是哪个按钮。我使用的值为 1K、2K 和 5K。然后我有一个 220 欧姆的电阻器来拉低模拟输入。否则它会浮动并随机按下按钮。

我将按钮安装在与 LCD 相同的安装板上。这并不容易,但我没有更好的方法。将电线焊接到这些按钮上,然后让它们穿过塑料上钻的小孔,这将对您的患者进行测试。

12. 你现在能听到我说话吗?

最后一步,可能也是最重要的是声音模块。这将使用 UNO 上的串行端口,因此您必须在 Tx 和 Rx 引脚上添加 1K 欧姆电阻,否则,在建立此连接后,您将无法对 UNO 进行编程。此外,您将需要使用“忙碌”引脚,以便 UNO 知道声音已经在播放。如果您要连续播放 MP3,这一点非常重要。

我将 MP3 播放器模块安装在原型防护罩上。这种屏蔽使安装此类组件非常方便,因为它只需插入 UNO。该模块需要一个 8 欧姆的扬声器,输出功率为 3W。扬声器只是粘在娃娃的底座上。我在扬声器下方钻了一些小孔,以便更好地播放声音。

13. 挂载 UNO

将 UNO 安装到平台上并将原型护罩插入 UNO。确保您已标记所有电线,否则您现在可能不知道它们中的任何一个。通过一点点协商,您可以在所有电线都连接好后将安装在娃娃内的 UNO 安装起来。

我使用螺纹插件将平台安装到娃娃的底部。

14. Test Fix Test

This is when you get to put your debugging hat on. I can tell you the software is working on GitHub so at least that is one less thing to debug. But go ahead anyway if you have doubts and send me any updates you find.

15. Let's play

Time to test her out and play a game. Here is how the game is programmed.

On startup she turns her head forward.

The motion sensor take a full minute to startup. So there is a timer when it starts. Half way through she giggles and turns her head around. Then announces when she is ready.

Depending on if you have the game set to remote she says different things. In Auto mode she asks you to press the play button. In my case, this is the far right button. In remote mode she will ask you to press the power button when you are ready. Then press the play button to toggle to red light or green light.

So when you are ready, press the go button and she will give you 10 seconds to get in place. Usually someone else nearby will press this button.

Then the game begins. She will start with Green light. For green light you have to get within 50cm to trigger a win. If you are within 100cm she will say indicate that you are getting closer. Green light is only using the sonar.

For red light the motion sensor and the distance sensor is being used. If you move enough for the motion sensor to trip or if you move more than 10cm forward, you will loose the game. You will also loose the game if time runs out. She will remind you that time is almost out at 5 seconds left.

The last cool feature is that she will also speak in the Korean voice for the red light. This is a menu feature. Press the far left button to toggle the menu item, and the center button to toggle the item options.

16. Watch Video

This video took me a long time to edit. I have probably 30 hours in just editing. But it was fun making it. I think it came out good and is funny but want you to see for yourself. Please let me know what you think and if you have any questions.

https://youtu.be/jd_4a4x3uCw

Thank You!

Code

  • Squid Game Doll Sketch
Squid Game Doll SketchC/C++
This will control all of the sensor and the game logic.
/// CodeMakesItGo Dec 2021#include #include #include #include #include #include #include /*-----( Analog Pins )-----*/#define BUTTONS_IN A0#define SONAR_TRIG_PIN A1#define SONAR_ECHO_PIN A2#define MOTION_IN A3/*-----( Digital Pins )-----*/#define LED_BLUE 13#define LED_GREEN 12#define LED_RED 11#define SEGMENT_DATA 10 // DS#define SEGMENT_CLOCK 9 // SHCP#define SEGMENT_LATCH 8 // STCP#define SEGMENT_1_OUT 7#define SEGMENT_2_OUT 6#define SEGMENT_3_OUT 5#define IR_DIGITAL_IN 4 // IR Remote#define SERVO_OUT 3#define DFPLAYER_BUSY_IN 2/*-----( Configuration )-----*/#define TIMER_FREQUENCY 2000#define TIMER_MATCH (int)(((16E+6) / (TIMER_FREQUENCY * 64.0)) - 1)#define TIMER_2MS ((TIMER_FREQUENCY / 1000) * 2)#define VOLUME 30 // 0-30#define BETTER_HURRY_S 5 // play clip at 5 seconds left#define WIN_PROXIMITY_CM 50 // cm distance for w inner#define CLOSE_PROXIMITY_CM 100 // cm distance for close to winning#define GREEN_LIGHT_MS 3000 // 3 seconds on for green light#define RED_LIGHT_MS 5000 // 5 seconds on for green light#define WAIT_FOR_STOP_MOTION_MS 5000 // 5 seconds to wait for motion detection to stop/*-----( Global Variables )-----*/static unsigned int timer_1000ms =0;static unsigned int timer_2ms =0;static unsigned char digit =0; // digit for 4 segment displaystatic int countDown =60; // Start 1 minute countdown on startupstatic const int sonarVariance =10; // detect movement if greater than thisstatic bool gameInPlay =false;static bool faceTree =false;static bool remotePlay =false;// 0 , 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, NULLconst unsigned char numbers[] ={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00};const char *MenuItems[] ={"Language", "Play Time", "Play Type"};typedef enum{ LANGUAGE, PLAYTIME, PLAYTYPE, MENUITEM_COUNT} MenuItemTypes;const char *Languages[] ={"English", "Korean"};typedef enum{ ENGLISH, KOREAN, LANUAGE_COUNT} LanguageTypes;static int language =0;const char *PlayTime[] ={"300", "240", "180", "120", "60", "30", "15"};typedef enum{ PT300, PT240, PT180, PT120, PT60, PT30, PT15, PLAYTIME_COUNT} PlayTimeTypes;const int playTimes[] ={300, 240, 180, 120, 60, 30, 15};static int playTime =0;const char *PlayType[] ={"Auto", "Remote"};typedef enum{ AUTO, REMOTE, PLAYTYPE_COUNT} PlayTypeTypes;static int playType =0;typedef enum{ BLACK, RED, GREEN, BLUE, WHITE, YELLOW, PURPLE} EyeColors;EyeColors eyeColor =BLACK;typedef enum{ WARMUP, WAIT, READY, GREENLIGHT, REDLIGHT, WIN, LOSE} GameStates;static GameStates gameState =WARMUP;/*-----( Class Objects )-----*/FireTimer task_50ms;FireTimer task_250ms;DFPlayerMini_Fast dfPlayer;SR04 sonar =SR04(SONAR_ECHO_PIN, SONAR_TRIG_PIN);IRrecv irRecv(IR_DIGITAL_IN);decode_results irResults;LiquidCrystal_I2C lcdDisplay(0x27, 16, 2); // 16x2 LCD display/*-----( Functions )-----*/void translateIR() // takes action based on IR code received{ switch (irResults.value) { case 0xFFA25D:Serial.println("POWER"); if (gameState ==WAIT) { gameInPlay =true; } break; case 0xFFE21D:Serial.println("FUNC/STOP");休息; case 0xFF629D:Serial.println("VOL+");休息; case 0xFF22DD:Serial.println("FAST BACK");休息; case 0xFF02FD:Serial.println("PAUSE"); remotePlay =!remotePlay;休息; case 0xFFC23D:Serial.println("FAST FORWARD");休息; case 0xFFE01F:Serial.println("DOWN");休息; case 0xFFA857:Serial.println("VOL-");休息; case 0xFF906F:Serial.println("UP");休息; case 0xFF9867:Serial.println("EQ");休息; case 0xFFB04F:Serial.println("ST/REPT");休息; case 0xFF6897:Serial.println("0");休息; case 0xFF30CF:Serial.println("1");休息; case 0xFF18E7:Serial.println("2");休息; case 0xFF7A85:Serial.println("3");休息; case 0xFF10EF:Serial.println("4");休息; case 0xFF38C7:Serial.println("5");休息; case 0xFF5AA5:Serial.println("6");休息; case 0xFF42BD:Serial.println("7");休息; case 0xFF4AB5:Serial.println("8");休息; case 0xFF52AD:Serial.println("9");休息; case 0xFFFFFFFF:Serial.println(" REPEAT");休息; default:Serial.println(" other button "); }}bool isPlayingSound(){ return (digitalRead(DFPLAYER_BUSY_IN) ==LOW);}void updateTimeDisplay(unsigned char digit, unsigned char num){ digitalWrite(SEGMENT_LATCH, LOW); shiftOut(SEGMENT_DATA, SEGMENT_CLOCK, MSBFIRST, numbers[num]); // Active LOW digitalWrite(SEGMENT_1_OUT, digit ==1 ? LOW :HIGH); digitalWrite(SEGMENT_2_OUT, digit ==2 ? LOW :HIGH); digitalWrite(SEGMENT_3_OUT, digit ==3 ? LOW :HIGH); digitalWrite(SEGMENT_LATCH, HIGH);}void updateServoPosition(){ static int servoPulseCount =0; static bool lastPosition =false; // Only get new value at start of period if (servoPulseCount ==0) lastPosition =faceTree; if (!lastPosition) // 180 degrees { digitalWrite(SERVO_OUT, servoPulseCount <5 ? HIGH :LOW); } else // 0 degrees { digitalWrite(SERVO_OUT, servoPulseCount <1 ? HIGH :LOW); } servoPulseCount =(servoPulseCount + 1) % 40; // 20ms period}void updateMenuDisplay(const int button){ static int menuItem =0; static int menuOption =0; switch (button) { case 1:menuItem =(menuItem + 1) % MENUITEM_COUNT; if (menuItem ==LANGUAGE) { menuOption =language; } else if (menuItem ==PLAYTIME) { menuOption =playTime; } else if (menuItem ==PLAYTYPE) { menuOption =playType; } else { menuOption =0; } break; case 2:if (menuItem ==LANGUAGE) { menuOption =(menuOption + 1) % LANUAGE_COUNT; language =menuOption; } else if (menuItem ==PLAYTIME) { menuOption =(menuOption + 1) % PLAYTIME_COUNT; playTime =menuOption; } else if (menuItem ==PLAYTYPE) { menuOption =(menuOption + 1) % PLAYTYPE_COUNT; playType =menuOption; } else { menuOption =0; } break; case 3:if (gameState ==WAIT) { gameInPlay =true; } if (gameState ==GREENLIGHT || gameState ==REDLIGHT) { gameInPlay =false; } default:break; } if (menuOption !=-1) { lcdDisplay.clear(); lcdDisplay.setCursor(0, 0); lcdDisplay.print(MenuItems[menuItem]); lcdDisplay.setCursor(0, 1); if (menuItem ==LANGUAGE) { lcdDisplay.print(Languages[menuOption]); } else if (menuItem ==PLAYTIME) { lcdDisplay.print(PlayTime[menuOption]); } else if (menuItem ==PLAYTYPE) { lcdDisplay.print(PlayType[menuOption]); } else { lcdDisplay.print("unknown option"); } } else { menuItem =0; menuOption =0; }}void handleButtons(){ static int buttonPressed =0; int value =analogRead(BUTTONS_IN); if (value <600) // buttons released { if (buttonPressed !=0) updateMenuDisplay(buttonPressed); buttonPressed =0;返回; } else if (value <700) { Serial.println("button 1"); buttonPressed =1; } else if (value <900) { Serial.println("button 2"); buttonPressed =2; } else if (value <1000) { Serial.println("button 3"); buttonPressed =3; } else { Serial.println(value); buttonPressed =0; }}static int lastSonarValue =0;void handleSonar(){ int value =sonar.Distance(); if (value> lastSonarValue + sonarVariance || value  30000 || sequence ==0) { internalTimer =millis(); if(playType ==AUTO) { // press the go button when you are ready Serial.println("Press the go button when you are ready"); dfPlayer.playFolder(1, 5); } else { Serial.println("Press the power button on the remote when you are ready"); dfPlayer.playFolder(1, 6); } // eyes are blue eyeColor =BLUE; // facing players faceTree =false; gameInPlay =false; sequence++; } } else if (gameState ==READY) { currentTimer =millis(); if (sequence ==0) { // get in position, game will start in 10 seconds Serial.println("Get in position."); dfPlayer.playFolder(1, 7); countDown =10; // eyes are green eyeColor =WHITE; // facing players faceTree =false; sequence++; internalTimer =millis(); } else if (sequence ==1) { if (playType ==REMOTE) { if (remotePlay) sequence++; } else sequence++; } else if (sequence ==2) { // at 0 seconds, here we go! if (countDown ==0) { countDown =playTimes[playTime]; Serial.print("play time set to "); Serial.println(countDown); Serial.println("Here we go!"); dfPlayer.playFolder(1, 8); gameState =GREENLIGHT; sequence =0; } } } else if (gameState ==GREENLIGHT) { currentTimer =millis(); if (sequence ==0) { // eyes are green eyeColor =GREEN; // play green light Serial.println("Green Light!"); dfPlayer.playFolder(1, 9); sequence++; } else if(sequence ==1) { // play motor sound dfPlayer.playFolder(1, 19); // facing tree faceTree =true; sequence++; internalTimer =millis(); } else if (sequence ==2) { // wait 3 seconds or until remote // switch to red light if (playType ==AUTO &¤tTimer - internalTimer> GREEN_LIGHT_MS) { sequence =0; gameState =REDLIGHT; } else if (playType ==REMOTE &&remotePlay ==false) { sequence =0; gameState =REDLIGHT; } else { // look for winner button or distance if (gameInPlay ==false || lastSonarValue  WAIT_FOR_STOP_MOTION_MS) { internalTimer =millis(); sequence++; Serial.println("Done settling"); } Serial.println("Waiting to settle"); } else if (sequence ==3) { // back to green after 5 seconds if (playType ==AUTO &¤tTimer - internalTimer> RED_LIGHT_MS) { sequence =0; gameState =GREENLIGHT; } else if (playType ==REMOTE &&remotePlay ==true) { sequence =0; gameState =GREENLIGHT; } else { // can't push the button while red light // detect movement // detect distance change if (gameInPlay ==false || lastMotion ==1 || lastSonarValue  
Project files
All of the files for this buildhttps://github.com/CodeMakesItGo/SquidGamesDoll

Schematics

This is how I connected all of the components to the UNO.
The project repo
All of the files for this build are stored here. https://github.com/CodeMakesItGo/SquidGamesDoll

制造工艺

  1. 使用 Arduino 制作流光溢彩监视器
  2. Arduino Pong Game - OLED 显示器
  3. 使用 Arduino Uno 的人体检测机器人系统
  4. 使用 Arduino 和智能手机的 DIY 电压表
  5. 使用物联网的心率监测器
  6. WebServerBlink 使用 Arduino Uno WiFi
  7. 简单的 UNO 计算器
  8. Sonar 使用 arduino 并在处理 IDE 上显示
  9. 视觉的坚持
  10. Arduino 培训平台
  11. 使用 Nextion Display 构建 Fridgeye 应用程序
  12. 使用 Arduino 和 RDA8057M 的 FM 收音机