Vor ungefähr einem Jahr habe ich zusammen mit meinem Sohn einen elektronischen Würfel, bestehend aus einem Arduino und ein paar LEDs, gebaut. Das ist für Einsteiger ein ideales Projekt. Wir haben in diesem Jahr vieles gelernt, also höchste Zeit für ein Update.
Der Würfel eignet sich für mich immer noch als perfektes Starter-Projekt. Die Funktion ist jedem klar und man kann damit verschiedene Bereiche gut verständlich machen: Mikrocontroller, einfache Elektronik und Programmierung.
Version 2.0
Der Würfel eignet sich aber auch fantastisch, um noch einen Schritt weiter zu gehen: Weitere Bereiche verknüpfen.
Heute gibt es fast für jede Aufgabe eine fertige Komponente. Das sieht man am besten, wenn man sich nach einem Starter-Kit für einen Arduino oder Raspberry Pi umsieht. Bauteile wie LEDs, Taster, jede Art von Sensor sind fertig auf einer Platine aufgebaut und können so mit wenigen Leitungen an GPIOs angeschlossen und genutzt werden.
Einfache, aber ausreichende, 3D-Drucker bekommen Sie bei ebay bereits ab 130 €. Damit lassen sich fast alle Halterungen, Befestigungen oder Gehäuse-Variationen umsetzen.
Damit gibt es eine Reihe mehr Möglichkeiten, eigene Projekte zu entwickeln. Ein Beispiel dafür ist unser Würfel 2.0.
Tiltsensoren
In dieser verbesserten Version setzen wir den Würfel ganz anders um. Im Inneren arbeitet aus Platzgründen ein Arduino Nano. Es gibt zwar noch einen Ein- und Ausschalter, aber keinen Taster mehr. Das Würfeln erfolgt über schütteln des ganzen Würfels.
Dafür werden Tiltsensoren oder Erschütterungs-/Neigungssensoren eingesetzt. Sie funktionieren genauso wie ein Taster. In einem Glasröhrchen bewegt sich eine Kugel. Trifft sie auf die Anschlusskontakte, wird der Stromkreis geschlossen. Dieser – manchmal auch sehr kurze – Kontakt wird für ein Signal verwendet.
Die Bewegung der Kugel kann man ganz gut hören, wenn man den Sensor schüttelt.
Gibt es in Ihrem Haushalt schon ein Arduino oder Raspberry Pi Starterkit? Dann finden Sie darunter bestimmt auch Tiltsensoren. Die Sensoren sind meistens vorbereitet auf einer Platine mit entsprechenden Pull-Up oder Pull-Down Widerständen. Dadurch können Sie gleich, ohne weitere Umwege, an einen Input-Pin des Arduino angeschlossen werden.
Normalerweise ist bei einem Tiltsensor die Einbaulage entscheidend. Er soll ja bei einer bestimmten Winkellage ein Signal auslösen. In unserem Fall passiert das durch das Schütteln des Gehäuses. Hier ist die Lage nicht so wichtig, da beim Schütteln auf jeden Fall ein Signal ausgelöst wird. Um sicher zu gehen verwenden wir im Projekt zwei Sensoren, die um 90° versetzt zueinander angeordnet sind. So bekommen wir immer ein zuverlässiges Schüttelsignal.
Interrupts
Damit erkennbar ist, wann geschüttelt wurde, müssten im Sketch die Input-Pins der Tiltsensoren abgefragt werden. Je nachdem wann das aber zeitlich erfolgt und was der Sketch sonst noch alles zu tun hat, gibt es hier immer die Möglichkeit, dass ein oder mehrere Ereignisse unbemerkt bleiben.
Eine bessere Lösung ist es, Hardware-Interrupts – also Unterbrechungen – zu verwenden. Das wird über die Funktion attachInterrupt definiert. Als Parameter wird u. a. angegeben, welches Unterprogramm bei einem Signal aufgerufen werden soll.
Der Arduino stellt zwei Hardware-Interrupts zur Verfügung: die Pins D2 und D3.
attachInterrupt(digitalPinToInterrupt(interruptPin), Unterprogramm, CHANGE);
In der void Unterprogramm erfolgt die Auswertung des Ereignisses.
Display
Die Anzeige des Würfelbildes könnte natürlich wieder mit 7 einzelnen LEDs erfolgen. Interessanter ist es aber auch hier, eine fertige Komponente zu verwenden.
Unsere Wahl für dieses Projekt viel auf eine 8×8 LED Matrix mit MAX7219 Treiber IC. Sie benötigt sehr wenig Platz, kostet nur geringes Geld und ist einfach zu programmieren.
Je nachdem wo sie eingekauft wird, muss man die Einzelteile selber zusammenlöten und montieren. Das ist aber sicherlich kein Problem. Den einzigen Fehler, den man machen kann, ist die LED Matrix verdreht in die Buchsen zu stecken.
Das zeigt sich über das obige Bild. Hier reicht es, die Matrix vorsichtig aus den Buchsen zu ziehen und um 180° zu drehen.
Die 8×8 LED Matrix hat zwei Seiten IN und OUT mit gleichen Anschlüssen. Es werden immer VCC, GND, DIN (DOUT), CS und CLK benötigt. Ist nur eine Matrix vorhanden, erfolgt der Anschluss nur auf der Seite IN. Mit OUT könnten weitere 8×8 LED Matrix Elemente verbunden werden.
Die Pinbelegung für den Würfel kann frei gewählt werden. Es bietet sich aber an, passende zu wählen, um möglichst kompakt zu bauen.
Wir haben den Arduino mittig zur LED Matrix über Buchsenleisten auf einer Platine verbunden. Dadurch passt diese Pinbelegung perfekt.
Pinbelegung:
- D7 – CLK
- D6 – CS
- D5 – DIN
- GND – GND
- 5V – VCC
Ablaufsteuerung
Wie üblich besteht der Arduino Sketch aus einem SETUP- und LOOP-Teil. In unserem Fall kommt eine weitere Komponente dazu. Durch das Interrupt-Ereignis, der Bewegung des Tiltsensors, werden Variablen verändert und über die LOOP ausgewertet.
Etwas Physik
Die LED Matrix soll aber nicht einfach das Würfelbild als Ergebnis anzeigen, sondern etwas mehr Show bieten. Die sechs Würfelaugen sollen sich auf der Matrix bewegen und das sollen sie einigermaßen realistisch tun: sie sollen an den Rändern abprallen und langsam Geschwindigkeit verlieren.
Über die beiden Tiltsensoren können wir erkennen, wie stark geschüttelt wurde. Diese Information geben wir den Würfelaugen als „Geschwindigkeit“ für ihre Bewegung mit.
Einen ähnlichen Effekt nutzen wir auch beim Anzeigen des Würfelergebnisses. Die Augen rollen von ihrer zufälligen Position auf Ihre richtige Position im Würfelbild.
Stromversorgung
Als Stromversorgung kommen für den Arduino viele Möglichkeiten in Betracht. Zuerst haben wir aus Platzgründen zwei 3V CR2032 Knopfzellen eingebaut. Das funktioniert spannungstechnisch über den Pin VIN des Arduino problemlos.
Am Anfang sah das auch recht gut aus. Der Arduino und die LED-Matrix spielten mit und alles funktionierte. Nach ein paar Minuten Betrieb bricht aber die Leistung der Knopfzellen zusammen.
Wenn nach jedem würfeln ausgeschaltet wird, könnte man das schon so verwenden. Wir wollen aber den Würfel eingeschaltet lassen können. Aus diesem Grund bauen wir zwei AAA Batterien ein. Mit diesen haut es problemlos hin. Allerdings liefern diese zusammen nur 3V. Wir brauchen also noch einen Step-Up-Converter, der die Spannung auf 5V anhebt. Der Anschluss erfolgt trotzdem am VIN Pin des Arduino.
Gehäusedesign
Die beste Möglichkeit für ein passendes Gehäuse ist ein eigenes Design und die Herstellung über 3D-Druck. Gibt es für diese Variante keine Druckmöglichkeit, sind auch einige Gehäuse bei conrad.de oder pollin.de zu finden.
Für die Konstruktion gibt es viele Programme. Ich nutze Autodesk Fusion 360 oder Trimble Sketchup. Autodesk Fusion finde ich für 3D-Konstruktionen wesentlich besser geeignet und habe es auch für dieses Projekt verwendet.
Es bietet tolle Features und der 3D-Druck ist über die Software Print Studio gut integriert. Wenn Sie an Autodesk Fusion 360 interessiert sind, finden Sie im Blog-Artikel Parametrische Gehäuse einige Anregungen.
Unser Gehäuse besteht aus 3 Teilen:
- Oberteil
- Unterteil mit Batteriehalterung für AAA-Zellen
- Plexiglasabdeckung (muss nicht unbedingt sein)
Die LED-Matrix sieht noch besser aus, wenn vor ihr eine milchige Plexiglasabdeckung ist. Dadurch kann man die ausgeschalteten LEDs nicht mehr erkennen und das Bild ist dadurch klarer.
Im Projekt verwenden wir eine vorhandene rote Scheibe.
Das Gehäuse ist in beiden Varianten downloadbar: mit AAA-Batterien und als CR2032-Lösung.
Sketch
Jetzt wird es ernst. Alles was bis jetzt beschrieben wurde, setzen wir nun im Arduino Sketch um.
Für die Ansteuerung des LED Matrix wird noch die Bibliothek LedControl benötigt. Falls Sie noch nicht installiert ist, kann sie arduino.cc heruntergeladen werden.
#include “LedControl.h“
Dann legen wir die Pinbelegung fest. Die Tiltsensoren liegen an den Hardware-Interrupt-Pins und können nicht verändert werden. Die anderen sind frei wählbar.
int PinTiltX = 2;
int PinTiltY = 3;
int PinDIN = 6;
int PinCS=7;
int PinCLK=8;
Die Initialisierung der LED-Matrix erfolgt in der nächsten Zeile. Die 1 steht für die Anzahl der Matrix-Module. Wir verwenden nur 1 Modul.
LedControl lc = LedControl(pinDIN,PinCLK,PinCS,1);
Augenbilder
Dann geht es an die weiteren Variablen-Definitionen. Zuerst legen wir fest, wie die Würfel-Augen auf der Matrix dargestellt werden. Ein Würfel-Auge besteht aus 4 LED-Punkten. In dem Array wird jeweils die linke obere Ecke als X/Y-Koordinate angegeben.
int DicePic[8][6][2] =
{
…
{ //1:
{4,4}, //1. Punkt
{-1,-1}, //2. Punkt
{-1,-1}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
{ //2:
{2,2}, //1. Punkt
{6,6}, //2. Punkt
{-1,-1}, //3. Punkt
{-1,-1}, //4. Punkt
{-1,-1}, //5. Punkt
{-1,-1} //6. Punkt
},
…
Hier kann natürlich alles Mögliche stehen. Lassen Sie Ihrer Fantasie freien Lauf. Es muss ja nicht immer das typische Augenbild sein.
Definitionen und SETUP
Da sich die Augen bewegen, brauchen wir für jedes Auge mehrere Parameter jeweils für X und Y:
- Position oder Koordinate (LED 1 bis 8) als Fließkommazahl: DiceXpos / DiceYpos
- Bewegungsrichtung (1,0 oder -1): DiceXdir / DiceYDir
- Geschwindigkeit (0 bis 255): DiceXspeed / DiceYspeed
Da DiceXspeed und DiceYspeed sich in der Interrupt-Routine ändern, müssen sie als volatile definiert werden.
float DiceXpos[6];
float DiceXdir[6];
volatile byte DiceXspeed[6];
float DiceYpos[6];
float DiceYdir[6];
volatile byte DiceYspeed[6];
In der SETUP void stellen wir am Anfang die LED Matrix ein. Zuerst wird sie aus dem Power-Saving-Modus geweckt, dann die Helligkeit festgelegt und alle LEDs ausgeschaltet.
void setup() {
lc.shutdown(0, false);
lc.SetIntensity(0,8);
lc.clearDisplay(0);
Als nächstes werden die Anfangswerte für die Augen eingestellt. Das sind jeweils Zufallswerte. Die Zufallswerte kann man noch zufälliger gestalten. Das können Sie beispielsweise auf arduino.cc sehr gut nachlesen.
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; }
LOOP
In der LOOP Void fragen wir nur verschiedene Zustände des Würfels ab. Dafür nehmen wir die Variable Mode her.
Mode=0: Würfel-Augen bewegen sich, d. h. es wird gerade geschüttelt
Mode=1: Ein Würfel-Augen-Bild wird angezeigt. Sonst passiert nichts
Wie können wir nun erkennen, ob geschüttelt wurde? Über die beiden Interrupts der Tiltsensoren und deren Einstellung ist es ganz einfach.
Sie werden in der SETUP void so definiert:
pinMode(PinTiltX, INPUT_PULLUP);
pinMode(PinTiltY, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PinTiltX),SetSpeedX,CHANGE);
attachInterrupt(digitalPinToInterrupt(PinTiltY),SetSpeedY,CHANGE);
Bei jedem Ereignis (CHANGE) ruft unser Arduino entweder die void SetSpeedX oder SetSpeedY auf.
In diesen beiden Void’s zählen wir die Schüttel-Ereignisse und merken uns einen Timestamp mit millis().
shakes=shakes+1;
timestamp=millis();
Nebenbei erhöhen wir die Geschwindigkeit DiceXspeed oder DiceYspeed in der entsprechenden Schüttelrichtung.
Nun aber zurück zur Schüttel-Erkennung. In der Variable shakes zählen wir die Schüttelanzahl. Das rechnen wir in der LOOP um in einen Wert pro Zeiteinheit: Die Schüttel-Anzahl pro Sekunde ShakesPerSecond.
Ist die Schüttel-Anzahl pro Sekunde kleiner als 5, nehmen wir an, dass keine Bewegung mehr erfolgt. So kann der Tiltsensor noch ein wenig zucken, ohne dass neu gewürfelt wird.
Mit unserem timestamp schauen wir nach, ob das letzte Schütteln 2 sek her ist. Erst dann soll das Würfelbild angezeigt werden.
Sobald die Schüttel-Anzahl pro Sekunde wieder größer als 5 ist, können wir davon ausgehen, dass ein neues Würfelbild verlangt wird. Der ganze Code sieht dann so aus:
void loop() {
delay(50);
step=step+1;
if (step>20) {
//1 sek ist vorbei
//1 sec is over
step=0;
ShakesPerSecond=shakes;
shakes=0;
}
if (Mode==0) {
MoveDots();
if (millis()-timestamp>2000) {
//seit 2 sek kein Schütteln mehr
//there is no shaking since 2 sec
Mode=1;
DiceValue=random(6)+1;
ShowDicePic(DiceValue);
}
}
if (ShakesPerSecond>5) {
//Es wird wieder geschüttelt
//shaking again
Mode=0;
}
}
Bewegung der Würfelaugen
In der Loop im Mode 0 rufen wir die Void MoveDots auf. In dieser bewegen sich die Würfelaugen mit ihrer Geschwindigkeit auf der LED Matrix. Stoßen sie an den Rändern an, prallen sie ab.
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);
}
}
Die eigentliche Bewegung ist nochmal in DoStep ausgelagert. Dort finden die Prüfungen statt, ob das Würfel-Auge am Rand abprallt. Denn dann wird die Richtung umgekehrt. Mathematisch heißt das einfach: mal minus 1.
void DoStep(float &pos, float &dir, volatile byte &sp, bool check) {
pos=pos+float(sp)/255*dir;
if (check==true) {
if (pos>7) {
pos=7;
dir=dir(-1); } if (pos<1) { pos=1; dir=dir(-1);
}
}
// Geschwindigkeit wird pro Schritt langsamer
// Velocity decreases every step
if (sp>0) {sp=sp-1;}
}
Anzeigen des Würfelergebnisses
Wird seit zwei Sekunden kein Interrupt mehr erzeugt, wechseln wir in Mode = 1. Damit zeigen wir das Würfelergebnis an. Das ist natürlich ein Zufallswert.
Obwohl man hier auch sicher „optimieren“ könnte, siehe Blog-Artikel Spezialfunktionen für den Arduino-Würfel.
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][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==false);
lc.clearDisplay(0);
for (int i = 0; i < 6; i++) {
ShowDot(DicePic[value][i][0],DicePic[value][i][1], true);
}
}
Alles weitere und auch zusätzliche Erklärungen finden Sie im Quelltext. Den Download-Link gibt es am Ende des Artikels.
Zusammenbau
Den Arduino montieren wir so, dass er auch einfach wieder für andere Projekt entnommen werden kann. Das geht am besten, wenn man ihn auf eine Buchsenleiste – als eine Art von Shield – steckt. Die Die fünf Kontakte LED Matrix werden genauso angeschlossen. Die Buchsenleisten löten wir dafür auf einen Platinenrest. Die Abmessungen sollen für unseren Würfel kompakt sein, deshalb ist die Platine sehr klein (siehe Abbildung). Wird der Arduino mittig angeordnet, wird der Platz am besten ausgenutzt. Deshalb werden, wie oben beschrieben, am besten die Pins 5,6,7 für CS, CLK und DIN für die Matrix verwendet. Hier müssen dann nur die Lötpunkte verbunden werden. Die Verbindung zu 5V und GND erfolgt über eine kleine Drahtbrücke.
Die beiden Tiltsensoren schließen wir auch mit kurzen Drähten an. Das sind neben Input-Pin 2 oder 3 jeweils 5V und GND.
Die Stromversorgung über den Ein-/Ausschalter erfolgt über den Pin VIN und GND. Wir löten dafür auch Drähte an der Platine fest.
Jetzt kann alles montiert werden. In unserem Fall wird zuerst das Plexiglas mit Heißkleber befestigt. Das machen wir mit der LED Matrix genauso. Dafür reicht schon ein kleiner Punkt Heißkleber aus.
Als nächstes wird der Ein-/Ausschalter eingebaut, mit Heißkleber gesichert und mit den entsprechenden Drähten verbunden.
Montage der Stromversorgung
Bei der Stromversorgung wird ein bisschen gebastelt. Je nachdem welche Möglichkeiten und Bauteile Sie haben, können entsprechend die Kontakte für Plus und Minus angepasst werden.
Wir verwenden die Federn und Pins von einem gebrauchten Batteriefach. Zur Befestigung mit dem Gehäuse-Unterteil verwenden wir Draht und ein wenig Heißkleber.
Den Step-Up Boost Converter stellt man am besten vor dem Einbau auf die ca. 5V ein. Dafür muss der Widerstand ziemlich lange verdreht werden. Zwischen dem Pluspol der Batterie und dem Step-Up Converter bauen wir noch den Ein-/Ausschalter ein.
Dann werden Oberteil und Unterteilt zusammengesteckt. Durch die Passung mit 0,1 mm reicht ein Zusammenstecken ohne weitere Sicherung aus. Und sie lassen sich trotzdem für einen Batteriewechsel auch wieder öffnen.
Fertig! Der Würfelspaß 2.0 kann beginnen!
Bauelemente
- Arduino Nano (bei gewünschter kleiner Bauform, sonst auch andere oder ESP8266)
- 2 x Tiltsensoren (mit integrierten Widerständen)
- 8×8 LED Matrix mit MAX7219 IC, SPC
- Buchsenleiste
- Ein-/Ausschalter
- Punktraster-Platine
- Gehäuse
- 2 x AAA Batterien
- MT3608 DC 2A Step Up Power Module 2v-24v to 5v/9v/12v/28V Boost Converter
- Tools: Lötstation, Heißkleber
Download
LedMatrix Bibliothek für die Ansteuerung der 8×8 LED Matrix https://playground.arduino.cc/Main/LedControl
Links
Artikel Arduino Würfel
Tolle Erklärung und Anschluss eines Tiltsensors auf Makerblog.at https://www.makerblog.at/2015/01/tilt-sensor-mit-dem-arduino-abfragen/
Erklärung attachInterrupt auf arduino.cc https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
Ein guter Blogbeitrag zum Thema Interrupts auf Funduino.de https://funduino.de/25-der-interrupt-befehl-attachinterrupt
MAX7219 Datasheet https://www.sparkfun.com/datasheets/Components/General/COM-09622-MAX7219-MAX7221.pdf
Autodesk Fusion 360 https://www.autodesk.de/products/fusion-360/overview
Artikel Parametrische Gehäuse aus dem 3D-Drucker
Für Anfänger immer noch perfekt geeignet: http://www.netzmafia.de/skripten/hardware/Arduino/Arduino_Programmierhandbuch.pdf