Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Schüttel-Würfel mit Arduino & LED-Matrix – Bewegungsaktiviertes Würfeln

Komponenten und Zubehör

Arduino Nano R3 × 1
3mm 8x8 LED-Matrix mit MAX7219 × 1
Neigungssensor-Modul (digital) × 1
Schiebeschalter × 1
MT3608 DC-DC Step-Up Boost Converter (2V-24V auf 5V/9V/12V/28V) × 1

Benötigte Werkzeuge und Maschinen

Apps und Online-Dienste

Über dieses Projekt

Vor etwa einem Jahr haben mein Sohn und ich einen elektronischen Würfel mit Arduino und einigen LEDs gebaut. Das war ein ideales Einsteigerprojekt. Inzwischen haben wir viel dazugelernt – Zeit für ein Update!

Der Würfel bleibt ein perfektes Starter-Projekt: Die Funktion ist jedem klar, und man lernt Mikrocontroller, einfache Elektronik und Programmierung kennen.

Version 2.0

Der Würfel eignet sich auch hervorragend, um weitere Bereiche zu verknüpfen. Heute gibt es für fast alles fertige Module – LEDs, Taster, Sensoren auf Platinen, die nur wenige Drähte zum GPIO benötigen. Günstige 3D-Drucker (unter 140 €) ermöglichen individuelle Gehäuse. Unser neuer Würfel 2.0 nutzt diese Möglichkeiten.

Neigungssensoren

Der Würfel funktioniert völlig anders: Ein Arduino Nano (platzsparend) steuert das Geschehen. Es gibt einen Ein-/Ausschalter, aber keinen Taster. Gewürfelt wird durch Schütteln des gesamten Würfels.

Dafür nutzen wir Neigungs- bzw. Vibrationssensoren. Sie funktionieren wie ein Taster: In einem Glastrichter bewegt sich eine Kugel. Trifft sie die Kontakte, schließt sich der Stromkreis – manchmal sehr kurz. Dieser Impuls wird als Signal verwendet. Die Bewegung der Metallkugel ist beim Schütteln gut hörbar.

Normalerweise ist die Einbauposition bei Neigungssensoren entscheidend (Auslösung bei bestimmtem Winkel). Beim Schütteln in beliebiger Richtung wird jedoch immer ein Signal erzeugt. Zur Sicherheit verwenden wir zwei Sensoren, um 90° versetzt – so erhalten wir zuverlässig ein Schüttel-Signal.

Interrupts

Um Schüttelbewegungen zu erkennen, müsste man die Sensor-Pins im Sketch abfragen. Je nach Timing und anderen Aufgaben können Ereignisse jedoch verloren gehen. Besser: Hardware-Interrupts mittels attachInterrupt(). Der Arduino bietet zwei Hardware-Interrupts an den Pins D2 und D3.

Display

Statt 7 einzelner LEDs nutzen wir eine 8x8 LED-Matrix mit MAX7219-Treiber. Sie ist kompakt, günstig und einfach zu programmieren. Je nach Bezugsquelle muss man die Matrix noch einlöten – dabei darauf achten, sie nicht verdreht in die Fassung zu stecken (180° drehen falls nötig).

Etwas Physik

Die LED-Matrix zeigt nicht nur das Würfelergebnis, sondern bietet Show-Effekte: Die sechs Würfelaugen bewegen sich auf der Matrix, prallen an den Rändern ab und verlieren langsam an Geschwindigkeit.

Über die zwei Neigungssensoren erkennen wir, wie stark geschüttelt wurde. Diese Information geben wir den Augen als „Geschwindigkeit“ für ihre Bewegung. Auch beim Anzeigen des Ergebnisses rollen die Augen von ihrer Zufallsposition zur korrekten Position im Würfelbild.

Stromversorgung

Zunächst zwei CR2032-Knopfzellen (3V) – nach wenigen Minuten brach die Spannung ein. Besser: zwei AAA-Batterien (zusammen 3V) plus Step-Up-Wandler auf 5V, angeschlossen an den VIN-Pin des Arduino.

Gehäuse-Design

Das Gehäuse wurde in Autodesk Fusion 360 entworfen und 3D-gedruckt. Es besteht aus drei Teilen:

Eine milchige Plexiglas-Abdeckung vor der LED-Matrix verbessert die Lesbarkeit, da ausgeschaltete LEDs nicht mehr sichtbar sind.

Sketch

Zur Steuerung der LED-Matrix wird die LedControl-Bibliothek benötigt (https://playground.arduino.cc/Main/LedControl).

Im Code wird definiert, wie die Würfelaugen auf der Matrix dargestellt werden. Ein Würfelauge besteht aus 4 LED-Punkten; im Array wird die linke obere Ecke als X/Y-Koordinate angegeben (-1 = außerhalb).

int DicePic[8][6][2] = {
  { // leere Matrix / Startposition
    {9,9}, {9,8}, {9,7}, {9,6}, {9,5}, {9,4}
  },
  { // 1
    {4,4}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}
  },
  { // 2
    {2,2}, {6,6}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}
  },
  // ... weitere Werte für 3-6 und Startposition
};

Weitere Erklärungen finden sich direkt im Code.

Aufbau

Der Arduino wird auf eine Stiftleiste gesteckt (wie ein Shield). Die fünf Kontakte der LED-Matrix werden gleich angeschlossen. Zentriert man den Arduino, nutzt man den Platz optimal – Pins 5, 6, 7 für CS, CLK, DIN. 5V und GND per Jumper. Die zwei Neigungssensoren werden mit kurzen Drähten an Pin 2 und 3 sowie 5V/GND angeschlossen.

Alles wird zusammengesetzt: Plexiglas und LED-Matrix mit Heißkleber fixieren, Ein-/Ausschalter einbauen. Die Stromversorgung wird etwas improvisiert: Federn und Stifte aus einem alten Batteriefach, mit Drähten und Heißkleber am Gehäuseboden befestigt. Den Step-Up-Wandler vor dem Einbau auf ca. 5V einstellen (Potentiometer justieren). Ober- und Unterteil passen mit 0,1 mm Spiel zusammen – einfach zusammenstecken, für Batteriewechsel wieder öffnen.

Benötigte Teile (Zusammenfassung)

Weitere Informationen

Mehr Details auf techpluscode.de/arduino-wuerfel-2-0 (nur auf Deutsch).

Code: wuerfel8x8.ino (Arduino)

/* Blog-Artikel: Schüttel-Würfel mit LED Matrix und Bewegungssimulation
   https://techpluscode.de/schuettel-wuerfel-mit-led-matrix-und-bewegungssimulation/
   techpluscode.de Copyright 2019 von Thomas Angielsky */

#include "LedControl.h"

int PinTiltX = 2;
int PinTiltY = 3;
int PinCLK = 7;
int PinCS = 6;
int PinDIN = 5;

LedControl lc = LedControl(PinDIN, PinCLK, PinCS, 1);

int DicePic[8][6][2] = {
  { {9,9}, {9,8}, {9,7}, {9,6}, {9,5}, {9,4} },
  { {4,4}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
  { {2,2}, {6,6}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} },
  { {2,6}, {6,2}, {4,4}, {-1,-1}, {-1,-1}, {-1,-1} },
  { {2,2}, {2,6}, {6,2}, {6,6}, {-1,-1}, {-1,-1} },
  { {2,2}, {2,6}, {6,2}, {6,6}, {4,4}, {-1,-1} },
  { {2,1}, {2,4}, {2,7}, {6,1}, {6,4}, {6,7} },
  { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} }
};

float DiceXpos[6], DiceYpos[6];
float DiceXdir[6], DiceYdir[6];
volatile byte DiceXspeed[6], DiceYspeed[6];
int DiceValue;
unsigned long timestamp;
byte Mode;
volatile int shakes;
int ShakesPerSecond;
int step;

void InterruptChecks() {
  shakes++;
  timestamp = millis();
}

void SetSpeedX() {
  if (Mode == 0) {
    for (int i = 0; i < 6; i++) {
      if (DiceXspeed[i] < 255) DiceXspeed[i] += 5;
    }
  }
  InterruptChecks();
}

void SetSpeedY() {
  if (Mode == 0) {
    for (int i = 0; i < 6; i++) {
      if (DiceYspeed[i] < 255) DiceYspeed[i] += 5;
    }
  }
  InterruptChecks();
}

void ShowLed(int x, int y, bool onoff) {
  if (x < 8 && y < 8 && x >= 0 && y >= 0) lc.setLed(0, x, y, onoff);
}

void ShowDot(int x, int y, bool onoff) {
  ShowLed(x-1, y-1, onoff);
  ShowLed(x, y-1, onoff);
  ShowLed(x-1, y, onoff);
  ShowLed(x, y, onoff);
}

void ShowDicePic(int value) {
  boolean done;
  for (int i = 0; i < 6; i++) {
    DiceXspeed[i] = 100; DiceYspeed[i] = 100;
    DiceXdir[i] = 0;
    if ((int)DiceXpos[i] > DicePic[value][i][0]) DiceXdir[i] = -1;
    else if ((int)DiceXpos[i] < DicePic[value][i][0]) DiceXdir[i] = 1;
    DiceYdir[i] = 0;
    if ((int)DiceYpos[i] > DicePic[value][i][1]) DiceYdir[i] = -1;
    else if ((int)DiceYpos[i] < DicePic[value][i][1]) DiceYdir[i] = 1;
  }
  do {
    for (int i = 0; i < 6; i++) {
      if ((int)DiceXpos[i] != DicePic[value][i][0]) DoStep(DiceXpos[i], DiceXdir[i], DiceXspeed[i], false);
      if ((int)DiceYpos[i] != DicePic[value][i][1]) DoStep(DiceYpos[i], DiceYdir[i], DiceYspeed[i], false);
    }
    lc.clearDisplay(0);
    for (int i = 0; i < 6; i++) ShowDot((int)DiceXpos[i], (int)DiceYpos[i], true);
    delay(50);
    done = true;
    for (int i = 0; i < 6; i++) {
      if ((int)DiceXpos[i] != DicePic[value][i][0]) done = false;
      if ((int)DiceYpos[i] != DicePic[value][i][1]) done = false;
    }
  } while (!done);
  lc.clearDisplay(0);
  for (int i = 0; i < 6; i++) ShowDot(DicePic[value][i][0], DicePic[value][i][1], true);
}

void DoStep(float &pos, float &dir, volatile byte &sp, bool check) {
  pos += float(sp)/255 * dir;
  if (check) {
    if (pos > 7) { pos = 7; dir *= -1; }
    if (pos < 1) { pos = 1; dir *= -1; }
  }
  if (sp > 0) sp--;
}

void MoveDots() {
  for (int i = 0; i < 6; i++) {
    DoStep(DiceXpos[i], DiceXdir[i], DiceXspeed[i], true);
    DoStep(DiceYpos[i], DiceYdir[i], DiceYspeed[i], true);
  }
  lc.clearDisplay(0);
  for (int i = 0; i < 6; i++) ShowDot((int)DiceXpos[i], (int)DiceYpos[i], true);
}

void setup() {
  lc.shutdown(0, false);
  lc.setIntensity(0, 8);
  lc.clearDisplay(0);
  randomSeed(analogRead(0));
  DiceValue = 0;
  for (int i = 0; i < 6; i++) {
    DiceXpos[i] = DicePic[7][i][0];
    DiceYpos[i] = DicePic[7][i][1];
    DiceXdir[i] = random(3)-1;
    DiceYdir[i] = random(3)-1;
    DiceXspeed[i] = random(126)+120;
    DiceYspeed[i] = random(126)+120;
  }
  pinMode(PinTiltX, INPUT_PULLUP);
  pinMode(PinTiltY, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PinTiltX), SetSpeedX, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PinTiltY), SetSpeedY, CHANGE);
  lc.clearDisplay(0);
  timestamp = millis();
  Mode = 1;
  ShowDicePic(6);
  delay(1000);
  lc.clearDisplay(0);
  Mode = 0;
  Serial.begin(9600);
  step = 0;
  shakes = 0;
}

void loop() {
  delay(50);
  step++;
  if (step > 20) {
    step = 0;
    ShakesPerSecond = shakes;
    shakes = 0;
  }
  if (Mode == 0) {
    MoveDots();
    if (millis() - timestamp > 2000) {
      Mode = 1;
      DiceValue = random(6)+1;
      ShowDicePic(DiceValue);
    }
  }
  if (ShakesPerSecond > 5) Mode = 0;
}

Schaltplan

Ein handgezeichneter Schaltplan ist als Bild verfügbar.

Herstellungsprozess

  1. Geschichte, Design und Fertigung von Würfeln: Von antiken Werkzeugen zum modernen Gaming
  2. Arduino-basiertes Schalter- & LED-Panel für Microsoft Flight Simulator 2020
  3. Arduino Digitaler Würfel: LCD-Würfel mit Zufallszahlen (1–6)
  4. Bluetooth-gesteuerter Arduino-Spybot bauen – Überwachungsroboter mit IP-Kamera
  5. FlickMote: Gestensteuerung per Ultraschall & IR für Smart Home (Arduino 101)
  6. DIY Arduino TV-B-Gone: Universelle TV-Aus-Fernbedienung
  7. Einen eigenen LED-Master-Clock mit Alarm bauen – aus 12 Metern Entfernung ablesbar
  8. Tetris-Spiel mit Arduino Nano auf selbstgebauter 16×8 LED-Matrix
  9. Find Me: Smarter Gegenstands-Finder mit Arduino und Bluetooth
  10. Optimierte Stromversorgungslösungen für Arduino-Projekte