37浏览
查看: 37|回复: 11

[项目] 【Arduino 动手做】摇动电子骰子

[复制链接]
Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。

Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。

【Arduino 动手做】摇动电子骰子图1

【Arduino 动手做】摇动电子骰子图2

驴友花雕  中级技神
 楼主|

发表于 前天 15:32

【Arduino 动手做】摇动电子骰子

一年前,我和儿子一起制作了一个简单的 Arduino 骰子。在此期间,我们学到了很多东西,是时候进行更新了......

【Arduino 动手做】摇动电子骰子图1


本项目使用的东西

硬件组件
Arduino Nano R3
×        1       
3mm 8x8 点阵MAX7219
×        1       
倾斜开关模块和数字接口
×        1       
滑动开关       
×        1       
MT3608 DC 2A 升压电源模块 2V-24V 转 5V/9V/12V/28V 升压转换器
×        1       

软件应用程序和在线服务
Arduino IDE       
Autodesk Fusion

手动工具和制造机
烙铁(通用)       
热胶枪(通用)       

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:35

【Arduino 动手做】摇动电子骰子

项目故事
大约一年前,我和我儿子用 Arduino 和一些 LED 制作了一个电子骰子。对于初学者来说,这仍然是一个理想的项目。今年我们学到了很多东西,所以现在是更新的时候了。

骰子仍然是一个完美的入门项目。功能对每个人都很清楚,并且很容易理解不同的领域:微控制器、简单的电子设备和编码。

版本 2.0
骰子也很棒,更进一步:连接其他区域。

今天,几乎所有东西都有一个现成的组件。在寻找 Arduino 或 Raspberry Pi 的入门套件时,最好看到这一点。LED、按钮和任何类型的传感器等组件都构建在电路板上,因此只需几根电线即可连接到 GPIO 并使用。

简单但足够的 3D 打印机在 ebay 上以不到 140 欧元的价格买到。几乎所有的支架、安装或外壳都可以用它创建。

还有更多机会来开发您自己的项目。这方面的一个例子是我们的新骰子 2.0。

倾斜传感器
我们以完全不同的方式实现骰子。在内部,由于空间原因,Arduino Nano 正在工作。仍然有一个开关,但没有按钮。通过摇动整个立方体来完成切块。

为此,使用了倾斜传感器或振动传感器。它们就像一个按钮一样工作。在玻璃管中,球移动。如果它碰到连接触点,则电路闭合。这个触点有时很短,用于信号。

如果您摇动传感器,可以很好地听到金属球的运动。

通常,安装位置对于倾斜传感器起决定性作用。它应该在某个角度位置触发信号。在我们的例子中,这是通过摇动外壳来实现的。这里的情况并不那么重要,因为当向任何方向摇晃时,都会触发信号。为了安全起见,我们在项目中使用了两个传感器,它们彼此偏移 90°。因此,我们总是能得到可靠的摇动信号。

【Arduino 动手做】摇动电子骰子图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:37

【Arduino 动手做】摇动电子骰子

中断
为了能够在晃动时识别,必须在草图中查询倾斜传感器的输入引脚。但是,根据这种情况何时发生以及草图还必须做什么,总是有可能一个或多个事件被忽视。

【Arduino 动手做】摇动电子骰子图1

更好的解决方案是使用硬件中断。这是由函数 attachInterrupt 定义的。作为参数,指定一个子程序,该子程序将在信号上调用。

Arduino 提供两个硬件中断:引脚 D2 和 D3。

显示
当然,骰子图像的显示也可以再次通过 7 个单独的 LED 来完成。但在这里使用 finished component 也更有趣。

我们在这个项目中选择了很多带有 MAX7219 驱动器 IC 的 8x8 LED 矩阵。它占用的空间非常小,成本很小,而且易于编码。

根据你在哪里买到它,你必须焊接在一起并组装单个部件。这通常没问题。唯一可能犯的错误是将 LED 矩阵拧入插孔。

【Arduino 动手做】摇动电子骰子图2

如上图所示。在这里,小心地将矩阵从插座中拉出并将其旋转 180° 就足够了。

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:46

【Arduino 动手做】摇动电子骰子

一些物理学
LED 矩阵不应仅显示骰子图像。它应该提供一些 show 效果。六个骰子眼睛在矩阵上移动:它们从边缘反弹并慢慢失去速度。

通过两个倾斜传感器,我们可以看到发生了多少摇晃。我们给骰子眼睛的这个信息作为他们移动的 “速度”。

我们在显示骰子结果时也使用了类似的效果。眼睛从随机位置滚动到立方体图像中的正确位置。

电源
首先,由于空间原因,我们安装了两个 3V CR2032 纽扣电池。一开始看起来也不错。Arduino 和 LED 矩阵配合工作,一切正常。然而,运行几分钟后,纽扣电池的功率就坏了。

如果你在每次掷骰子后关闭 Arduino,你可以以这种方式使用它。这并不完美,因此我们安装了两节更好的 AAA 电池。但是,这些只能一起提供 3V 电压。所以我们仍然需要一个升压转换器,将电压提高到 5V。连接仍然发生在 Arduino 的 VIN 引脚上。

外壳设计
合适外壳的最佳选择是通过 3D 打印进行自主设计和生产。有许多用于施工的应用程序。我们在这个项目中使用了 Autodesk Fusion 360。它具有出色的功能,并且 3D 打印与 Print Studio 软件完美集成。如果您对 Autodesk Fusion 360 感兴趣,可以在博客文章参数化外壳(仅德语)中找到一些建议。

我们的外壳由 3 部分组成:

大壳
带电池座的小壳,用于 AAA 电池
Plexiglas 盖(不一定非得如此)

【Arduino 动手做】摇动电子骰子图1


LED 矩阵前面有一个乳白色的有机玻璃盖,看起来更好。这使得无法识别关闭的 LED,并且图像更清晰。

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:50

【Arduino 动手做】摇动电子骰子

驱动
要控制 LED 矩阵,需要 LedControl 库。如果尚未安装,可以从 arduino.cc https://playground.arduino.cc/Main/LedControl 下载。

然后我们进行其他变量定义。首先,我们确定骰子眼睛在矩阵上的显示方式。一个骰子眼由 4 个 LED 点组成。在数组中,左上角指定为 X / Y 坐标(-1 表示在显示之外)。

  1. int DicePic[8][6][2] = {    …   
  2.                         { //1:   
  3.                          {4,4}, //1. Punkt     
  4.                          {-1,-1}, //2. Punkt     
  5.                          {-1,-1}, //3. Punkt     
  6.                          {-1,-1}, //4. Punkt     
  7.                          {-1,-1}, //5. Punkt     
  8.                          {-1,-1}  //6. Punkt   },   
  9.                         { //2:     
  10.                          {2,2}, //1. Punkt     
  11.                          {6,6}, //2. Punkt     
  12.                          {-1,-1}, //3. Punkt     
  13.                          {-1,-1}, //4. Punkt
  14.                          {-1,-1}, //5. Punkt
  15.                          {-1,-1}  //6. Punkt   }, …
复制代码


当然,这里一切皆有可能。让您的想象力自由驰骋。它并不总是典型的眼睛图像。

您可以在代码中直接找到其他注释。

组合
我们将 Arduino 放在插座板上,作为一种扩展板。LED 矩阵的五个触点以相同的方式连接。如果 Arduino 居中,则最好使用空间。因此,最好将引脚 5、6、7 用于矩阵的 CS、CLK 和 DIN。此时只需连接焊点。与 5V 和 GND 的连接是通过一个小跳线进行的。

【Arduino 动手做】摇动电子骰子图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:52

【Arduino 动手做】摇动电子骰子

我们还用短线连接两个倾斜传感器。它们连接到引脚 2 和 3 以及 5V 和 GND。

【Arduino 动手做】摇动电子骰子图1


现在一切都可以组装了。首先用热胶固定有机玻璃。我们对 LED 矩阵执行相同的作。一小点热胶就足够了。


接下来,安装 on/off 开关,用热胶固定并连接到适当的电线。

【Arduino 动手做】摇动电子骰子图2

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:53

【Arduino 动手做】摇动电子骰子

安装电源
电源有点修补。根据您拥有的选项和组件,正号和负号的触点可以相应地进行拉延筋对等值。

我们使用用过的电池仓中的弹簧和销钉。为了连接到外壳底部,我们再次使用电线和少许热胶。

【Arduino 动手做】摇动电子骰子图1


升压升压转换器最好在安装前调整到大约 5V。为此,阻力必须稍微扭转。

然后将大写和小写放在一起。由于贴合度为 0.1 mm,无需进一步固定即可插入在一起。而且它们仍然可以再次打开更换电池。

然后就完成了!


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:56

【Arduino 动手做】摇动电子骰子

骰子乐趣 2.0 可以开始了!

所需条件
Arduino Nano(或 ESP8266)
2 x 倾斜传感器(带集成电阻器)
8x8 LED 矩阵,带 MAX7219 IC、SPC
插座板
开/关开关
印刷电路板
2 节 AAA 电池



定制零件和外壳

外壳上部

【Arduino 动手做】摇动电子骰子图1

外壳下部

【Arduino 动手做】摇动电子骰子图2

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:57

【Arduino 动手做】摇动电子骰子

图表
电路
这是我的电路草图。


【Arduino 动手做】摇动电子骰子图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 15:59

【Arduino 动手做】摇动电子骰子

摇骰代码

  1. /*
  2. Blog-Artikel: Schttel-Wrfel mit LED Matrix und Bewegungssimulation
  3. https://techpluscode.de/schuettel-wuerfel-mit-led-matrix-und-bewegungssimulation/
  4. techpluscode.de
  5. Copyright 2019 von Thomas Angielsky
  6. */
  7. //Bibliothek fr die Ansteuerung der 8x8 LED-Matrix einbinden
  8. //Include lib for the 8x8 LED matrix
  9. #include "LedControl.h"
  10. int PinTiltX = 2; //Pin fr Tiltsensor X
  11. int PinTiltY = 3; //Pin fr Tiltsensor Y
  12. //Pins der LED-Matrix
  13. //Pins of the LED matrix
  14. int PinCLK = 7;  
  15. int PinCS = 6;
  16. int PinDIN = 5;
  17. LedControl lc = LedControl(PinDIN, PinCLK, PinCS, 1);
  18. //Koordinaten der Wrfelaugen in der LED-Matrix
  19. //Coordinates of the Dice points in the LED matrix
  20. int DicePic[8][6][2] =
  21. {
  22.   { //leere Matrix und Startposition:
  23.     {9,9}, //1. Punkt
  24.     {9,8}, //2. Punkt
  25.     {9,7}, //3. Punkt
  26.     {9,6}, //4. Punkt
  27.     {9,5}, //5. Punkt
  28.     {9,4} //6. Punkt
  29.   },
  30.   { //1:
  31.     {4,4}, //1. Punkt
  32.     {-1,-1}, //2. Punkt
  33.     {-1,-1}, //3. Punkt
  34.     {-1,-1}, //4. Punkt
  35.     {-1,-1}, //5. Punkt
  36.     {-1,-1}  //6. Punkt
  37.   },
  38.   { //2:
  39.     {2,2}, //1. Punkt
  40.     {6,6}, //2. Punkt
  41.     {-1,-1}, //3. Punkt
  42.     {-1,-1}, //4. Punkt
  43.     {-1,-1}, //5. Punkt
  44.     {-1,-1}  //6. Punkt
  45.   },
  46.   { //3:
  47.     {2,6}, //1. Punkt
  48.     {6,2}, //2. Punkt
  49.     {4,4}, //3. Punkt
  50.     {-1,-1}, //4. Punkt
  51.     {-1,-1}, //5. Punkt
  52.     {-1,-1}  //6. Punkt
  53.   },
  54.   { //4:
  55.     {2,2}, //1. Punkt
  56.     {2,6}, //2. Punkt
  57.     {6,2}, //3. Punkt
  58.     {6,6}, //4. Punkt
  59.     {-1,-1}, //5. Punkt
  60.     {-1,-1}  //6. Punkt
  61.   },
  62.   { //5:
  63.     {2,2}, //1. Punkt
  64.     {2,6}, //2. Punkt
  65.     {6,2}, //3. Punkt
  66.     {6,6}, //4. Punkt
  67.     {4,4}, //5. Punkt
  68.     {-1,-1}  //6. Punkt
  69.   },
  70.   { //6:
  71.     {2,1}, //1. Punkt
  72.     {2,4}, //2. Punkt
  73.     {2,7}, //3. Punkt
  74.     {6,1}, //4. Punkt
  75.     {6,4}, //5. Punkt
  76.     {6,7}  //6. Punkt
  77.   },
  78.   { //Start:
  79.     {-1,-1}, //1. Punkt
  80.     {-1,-1}, //2. Punkt
  81.     {-1,-1}, //3. Punkt
  82.     {-1,-1}, //4. Punkt
  83.     {-1,-1}, //5. Punkt
  84.     {-1,-1}  //6. Punkt
  85.   }
  86.   };
  87. //Variablen der Wrfelaugen: Position, Richtung, Geschwindigkeit fr X und Y
  88. //Variables of the dice: position, direction, speed for X and Y
  89. float DiceXpos[6];
  90. float DiceXdir[6];
  91. volatile byte DiceXspeed[6];
  92. float DiceYpos[6];
  93. float DiceYdir[6];
  94. volatile byte DiceYspeed[6];
  95. int DiceValue;
  96. unsigned long timestamp;
  97. byte Mode;
  98. int volatile shakes;
  99. int ShakesPerSecond;
  100. int step;
  101. void InterruptChecks() {
  102.   //Schttel-Anzahl zhlen
  103.   //Count Shakes
  104.   shakes=shakes+1;
  105.   //Serial.println(millis());
  106.   timestamp=millis();
  107. }
  108. void SetSpeedX() {
  109.   if (Mode==0) {
  110.     //alle Wrfel in X beschleunigen
  111.     //Speed-up dice in X
  112.     for (int i = 0; i < 6; i++) {
  113.       if (DiceXspeed[i]<255) {DiceXspeed[i]=DiceXspeed[i]+5;}
  114.     }
  115.   }  
  116.   InterruptChecks();
  117. }
  118. void SetSpeedY() {
  119.   if (Mode==0) {
  120.     //alle Wrfel in Y beschleunigen
  121.     //Speed-up dice in Y
  122.     for (int i = 0; i < 6; i++) {
  123.       if (DiceYspeed[i]<255) {DiceYspeed[i]=DiceYspeed[i]+5;}
  124.     }
  125.   }
  126.   InterruptChecks();
  127. }
  128. void ShowLed(int x, int y, bool onoff) {
  129. //LED nur anzeigen, wenn im sichtbaren Bereich
  130. //show only, when x/y in matrix
  131.   if ((x<8) and (y<8) and (x>=0) and (y>=0)) {
  132.     lc.setLed(0, x, y, onoff);
  133.   }
  134. }
  135. void ShowDot(int x, int y, bool onoff) {
  136. //Wrfel-Auge anzeigen oder ausblenden
  137. //Show or hide dice point
  138.   ShowLed(x-1, y-1, onoff);
  139.   ShowLed(x, y-1, onoff);
  140.   ShowLed(x-1, y, onoff);
  141.   ShowLed(x, y, onoff);
  142. }
  143. void ShowDicePic(int value) {
  144. //Wurf anzeigen
  145. //Show dice
  146. boolean done;
  147.   //alle Punkte von der aktuellen Position aus zur Zielposition von DiceValue bewegen
  148.   //move all points from current position to destination of DiceValue
  149.   for (int i = 0; i < 6; i++) {
  150.     DiceXspeed[i]=100;
  151.     DiceYspeed[i]=100;
  152.     //Werte fr X berechnen
  153.     //Calc x values
  154.     DiceXdir[i]=0;
  155.     if (int(DiceXpos[i])>DicePic[value][i][0]) {DiceXdir[i]=-1;}
  156.     else if (int(DiceXpos[i])<DicePic[value][i][0]) {DiceXdir[i]=1;}
  157.    
  158.     DiceYdir[i]=0;
  159.     if (int(DiceYpos[i])>DicePic[value][i][1]) {DiceYdir[i]=-1;}
  160.     else if (int(DiceYpos[i])<DicePic[value][i][1]) {DiceYdir[i]=1;}
  161.   }
  162.   //Serial.println(value);
  163.   //Serial.println("Bewegung Start // Start moving");
  164.   //Punkte bewegen
  165.   do {
  166.     //Serial.println("Bewegung // Moving");
  167.     for (int i = 0; i < 6; i++) {
  168.       if (int(DiceXpos[i])!=DicePic[value][i][0]) {
  169.         DoStep(DiceXpos[i],DiceXdir[i],DiceXspeed[i],false);
  170.       }
  171.       if (int(DiceYpos[i])!=DicePic[value][i][1]) {
  172.         DoStep(DiceYpos[i],DiceYdir[i],DiceYspeed[i],false);
  173.       }
  174.     }
  175.     lc.clearDisplay(0);
  176.     for (int i = 0; i < 6; i++) {
  177.       ShowDot(int(DiceXpos[i]), int(DiceYpos[i]), true);
  178.     }
  179.    
  180.     delay(50);
  181.     //Sind alle Augen an ihrer Zielposition
  182.     //Dice points are on destition position
  183.     done=true;
  184.     for (int i = 0; i < 6; i++) {
  185.       if (int(DiceXpos[i])!=DicePic[value][i][0]) {done=false;}
  186.       if (int(DiceYpos[i])!=DicePic[value][i][1]) {done=false;}
  187.     }
  188.   } while (done==false);
  189.   //Serial.println("Bewegung Ende // End moving");
  190.   lc.clearDisplay(0);
  191.   for (int i = 0; i < 6; i++) {
  192.     ShowDot(DicePic[value][i][0],DicePic[value][i][1], true);
  193.   }
  194. }
  195. void DoStep(float &pos, float &dir, volatile byte &sp, bool check) {
  196.   pos=pos+float(sp)/255*dir;
  197.   if (check==true) {
  198.     if (pos>7) {
  199.         pos=7;
  200.         dir=dir*(-1);
  201.         }
  202.     if (pos<1) {
  203.         pos=1;
  204.         dir=dir*(-1);
  205.       }
  206.   }
  207.   // Geschwindigkeit wird pro Schritt langsamer
  208.   // Velocity decreases every step
  209.     if (sp>0) {sp=sp-1;}
  210. }
  211. void MoveDots() {
  212.   //alle Wrfel einen Schritt weiter bewegen
  213.   //move dice points one step further
  214.   for (int i = 0; i < 6; i++) {
  215.     //neue Koordinaten berechnen
  216.     //calc new coordinates
  217.     DoStep(DiceXpos[i],DiceXdir[i],DiceXspeed[i],true);
  218.     DoStep(DiceYpos[i],DiceYdir[i],DiceYspeed[i],true);
  219.   }
  220.     //Wrfel-Augen anzeigen
  221.     //show dice points
  222.     lc.clearDisplay(0);
  223.     for (int i = 0; i < 6; i++) {
  224.       ShowDot(int(DiceXpos[i]), int(DiceYpos[i]), true);
  225.     }
  226.   
  227. }
  228. void setup() {
  229.   //Der MAX7219 ist beim Starten im Power-Saving Modus,
  230.   //er muss aufgeweckt werden.
  231.   //The MAX7219 is in power-saving mode on startup,
  232.   //we have to do a wakeup call
  233.   lc.shutdown(0, false);
  234.   //Helligkeit auf einen Mittelwert
  235.   //Set the brightness to a medium values
  236.   lc.setIntensity(0, 8);
  237.   //und Display lschen
  238.   //and clear the display
  239.   lc.clearDisplay(0);
  240.   randomSeed(analogRead(0));
  241.   DiceValue=0;
  242.   
  243.   for (int i = 0; i < 6; i++) {
  244.     DiceXpos[i]=DicePic[7][i][0];
  245.     DiceYpos[i]=DicePic[7][i][1];
  246.    
  247.     DiceXdir[i]=random(3)-1;
  248.     DiceYdir[i]=random(3)-1;
  249.     DiceXspeed[i]=random(126)+120;
  250.     DiceYspeed[i]=random(126)+120;
  251.     }
  252.   //Pins einstellen
  253.   //Setup the pins
  254.   pinMode(PinTiltX, INPUT_PULLUP);
  255.   pinMode(PinTiltY, INPUT_PULLUP);
  256.   attachInterrupt(digitalPinToInterrupt(PinTiltX),SetSpeedX,CHANGE);
  257.   attachInterrupt(digitalPinToInterrupt(PinTiltY),SetSpeedY,CHANGE);
  258.   
  259.   lc.clearDisplay(0);
  260.   timestamp=millis();
  261.   Mode=1;
  262.   ShowDicePic(6);
  263.   delay(1000);
  264.   
  265.   lc.clearDisplay(0);
  266.   Mode=0;
  267.   Serial.begin(9600);
  268.   step=0;
  269.   shakes=0;
  270. }
  271. void loop() {
  272.   delay(50);
  273.   step=step+1;
  274.   if (step>20) {
  275.     //1 sek ist vorbei
  276.     //1 sec is over
  277.     step=0;
  278.     ShakesPerSecond=shakes;
  279.     shakes=0;
  280.   }
  281.   if (Mode==0) {
  282.     MoveDots();
  283.     if (millis()-timestamp>2000) {
  284.       //seit 2 sek kein Schtteln mehr
  285.       //there is no shaking since 2 sec
  286.       Mode=1;
  287.       DiceValue=random(6)+1;
  288.       ShowDicePic(DiceValue);
  289.     }
  290.   }
  291.   if (ShakesPerSecond>5) {
  292.     //Es wird wieder geschttelt
  293.     //shaking again
  294.     Mode=0;
  295.   }
  296. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 前天 16:05

【Arduino 动手做】摇动电子骰子

附录
项目链接:https://www.hackster.io/tangielsky/shaking-arduino-dice-39fc6a
项目作者:德国 托马斯·安吉尔斯基
(机械工程师、制造商,喜欢木工,就像 Lazarus 一样)

3D打印文件:https://hacksterio.s3.amazonaws. ... teil_ehbbTeKHvI.stl



【Arduino 动手做】摇动电子骰子图1
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail