Project tutorial

Shaking Arduino Dice © GPL3+

One year ago I built a simple Arduino dice with my son. We have learned a lot in the meantime and it's time for an update...

  • 2,740 views
  • 5 comments
  • 46 respects

Components and supplies

Ard nano
Arduino Nano R3
×1
3mm 8x8 Dot Matrix MAX7219
×1
Tilt switch module and a digital interface
×1
E switch eg1218 image 75px
Slide Switch
×1
MT3608 DC 2A Step Up Power Module 2v-24v to 5v/9v/12v/28V Boost Converter
×1

Necessary tools and machines

09507 01
Soldering iron (generic)
Hy gluegun
Hot glue gun (generic)

Apps and online services

About this project

About a year ago my son and I built an electronic dice with an Arduino and a few LEDs. This is still an ideal project for beginners. We have learned a lot this year, so it's high time for an update.

The dice is still a perfect starter project. The function is clear to everyone and it is easy to understand the different areas: microcontroller, simple electronics and coding.

Version 2.0

The dice is also fantastic, to go one step further: linking other areas.

Today there is a ready-built component for almost everything. This is best seen when looking for a starter kit for an Arduino or Raspberry Pi. Components such as LEDs, pushbuttons and any type of sensor are built on a circuit board and can thus be connected and used with just a few wires to GPIOs.

Simple, but sufficient, 3D printers are available on ebay for less than 140 €. Almost all bracket, mounting or casing variations can be created with it.

There are a number of more opportunities to develop your own projects. An example of this is our new dice 2.0.

Tilt Sensors

We implement the dice in a completely different way. Inside, an Arduino Nano is working for space reasons. There is still an on-off switch, but no button. The dicing is done by shaking the whole cube.

For this purpose, tilt sensors or vibration sensors are used. They work just like a button. In a glass tube, a ball moves. If it hits the connection contacts, the circuit is closed. This contact, sometimes very short, is used for a signal.

The movement of the metal ball can be heard quite well if you shake the sensor.

Normally the installation position is decisive for a tilt sensor. It is supposed to trigger a signal at a certain angular position. In our case, this happens by shaking the case. Here the situation is not so important, because when shaking in any direction a signal is triggered. To be on the safe side, we use two sensors in the project, which are arranged offset by 90 ° to each other. So we always get a reliable shake signal.

Interrupts

In order to be able to recognize when shaking, the input pins of the tilt sensors would have to be queried in the sketch. However, depending on when this happens in time and what else the sketch has to do, there is always the possibility that one or more events go unnoticed.

A better solution is to use hardware interrupts. This is defined by the function attachInterrupt. As a parameter a subprogram is specified which is to be called on the signal.

The Arduino provides two hardware interrupts: pins D2 and D3.

Display

Of course, the display of the dice image could again be done with 7 individual LEDs. But it is also more interesting to use a finished component here.

Our choice for this project is much on an 8x8 LED matrix with MAX7219 driver IC. It takes up very little space, costs only a small amount of money and is easy to code.

Depending on where you buy it, you have to solder together and assemble the single parts. That is normally no problem. The only mistake that can be made is to put the LED matrix twisted into the jacks.

This is shown by the above picture. Here it is sufficient to carefully pull the matrix out of the sockets and turn it through 180 °.

Some Physics

The LED matrix should not just show the dice image as a result. It should offer some show effects. The six dice eyes move on the matrix: they bounce off the edges and slowly lose speed.

Through the two tilt sensors, we can see how much shaking was done. This information we give the dice eyes as "speed" for their movement.

We also use a similar effect when displaying the dice result. The eyes roll from their random position to their correct position in the cube image.

Power Supply

First, we have installed two 3V CR2032 button cells for space reasons. At the beginning it looked pretty good too. The Arduino and LED matrix played along and everything worked. After a few minutes of operation, however, the power of the button cells break down.

If you turn off the Arduino after every dice, you could use it that way. That's not perfect, so we install better two AAA batteries. However, these only deliver together 3V. So we still need a step-up converter, which raises the voltage to 5V. The connection still takes place at the VIN pin of the Arduino.

Housing Design

The best option for a suitable housing is a own design and production via 3D printing. There are many apps for the construction. We have used Autodesk Fusion 360 for this project. It has great features and 3D printing is well integrated with the Print Studio software. If you are interested in Autodesk Fusion 360, you will find some suggestions in the blog article Parametric Enclosures (only German).

Our housing consists of 3 parts:

  • Upper case
  • Lower case with battery holder for AAA cells
  • Plexiglas cover (does not necessarily have to be)

The LED matrix looks even better with a milky plexiglasscover in front of it. This makes it impossible to recognize the off LEDs and the picture is clearer.

Sketch

To control the LED Matrix, the LedControl library is required. If it is not already installed, it can be downloaded from arduino.cc https://playground.arduino.cc/Main/LedControl.

Then we do the other variable definitions. First, we determine how the dice eyes are displayed on the matrix. A dice-eye consists of 4 LED-points. In the array, the upper left corner is specified as the X / Y coordinate (-1 means outside the display).

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   }, …

Of course, everything is possible here. Let your imagination run wild. It does not always have to be the typical eye image.

Other remarks you'll find direct in the code.

Assembly

We put our Arduino on a socket strip, as a kind of shield. The five contacts of the LED matrix are connected in the same way. If the Arduino is centered, the space is best used. Therefore it is best to use pins 5, 6, 7 for CS, CLK and DIN for the matrix. Here then only the solder points must be connected. The connection to 5V and GND is via a small jumper.

We also connect the two tilt sensors with short wires. These are connected to pin 2 and 3 and 5V and GND.

Now everything can be assembled. The plexiglass is first fixed with hot glue. We do the same with the LED matrix. A small point of hotglue is enough.

Next, the on / off switch is installed, secured with hotglue and connected to the appropriate wires.

Mounting the Power Supply

The power supply is a bit tinkered. Depending on which options and components you have, the contacts for plus and minus can bead justed accordingly.

We use the springs and pins from a used battery compartment. To attach to the bottom of the housing we use wires and a little hotglue again.

The step-up boost converter is best adjusted to the approx. 5V before installation. For that the resistance has to be twisted a little bit.

Then upper and lower case are put together. Due to the fit of 0.1 mm, plugging together without further securing is sufficient. And they can still open again for a battery change.

And then it's finished!

The dice fun 2.0 can begin!

What You Need

  • Arduino Nano (or ESP8266)
  • 2 x tilt sensors (with integrated resistors)
  • 8x8 LED Matrix with MAX7219 IC, SPC
  • Socket strip
  • On / Off switch
  • PCB
  • 2 x AAA batteries

More Information

If you want do read more, check our website techpluscode.de/arduino-wuerfel-2-0.

Sorry this extended blog is available only in German ;-)

Code

wuerfel8x8.inoArduino
Code for the shaking dice
/*
Blog-Artikel: Schttel-Wrfel mit LED Matrix und Bewegungssimulation

https://techpluscode.de/schuettel-wuerfel-mit-led-matrix-und-bewegungssimulation/

techpluscode.de
Copyright 2019 von Thomas Angielsky
*/

//Bibliothek fr die Ansteuerung der 8x8 LED-Matrix einbinden
//Include lib for the 8x8 LED matrix
#include "LedControl.h"


int PinTiltX = 2; //Pin fr Tiltsensor X
int PinTiltY = 3; //Pin fr Tiltsensor Y

//Pins der LED-Matrix
//Pins of the LED matrix
int PinCLK = 7;  
int PinCS = 6;
int PinDIN = 5;

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

//Koordinaten der Wrfelaugen in der LED-Matrix
//Coordinates of the Dice points in the LED matrix
int DicePic[8][6][2] =
{
  { //leere Matrix und Startposition:
    {9,9}, //1. Punkt
    {9,8}, //2. Punkt
    {9,7}, //3. Punkt
    {9,6}, //4. Punkt
    {9,5}, //5. Punkt
    {9,4} //6. Punkt
  },
  { //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
  },
  { //3:
    {2,6}, //1. Punkt
    {6,2}, //2. Punkt
    {4,4}, //3. Punkt
    {-1,-1}, //4. Punkt
    {-1,-1}, //5. Punkt
    {-1,-1}  //6. Punkt
  },
  { //4:
    {2,2}, //1. Punkt
    {2,6}, //2. Punkt
    {6,2}, //3. Punkt
    {6,6}, //4. Punkt
    {-1,-1}, //5. Punkt
    {-1,-1}  //6. Punkt
  },
  { //5:
    {2,2}, //1. Punkt
    {2,6}, //2. Punkt
    {6,2}, //3. Punkt
    {6,6}, //4. Punkt
    {4,4}, //5. Punkt
    {-1,-1}  //6. Punkt
  },
  { //6:
    {2,1}, //1. Punkt
    {2,4}, //2. Punkt
    {2,7}, //3. Punkt
    {6,1}, //4. Punkt
    {6,4}, //5. Punkt
    {6,7}  //6. Punkt
  },
  { //Start:
    {-1,-1}, //1. Punkt
    {-1,-1}, //2. Punkt
    {-1,-1}, //3. Punkt
    {-1,-1}, //4. Punkt
    {-1,-1}, //5. Punkt
    {-1,-1}  //6. Punkt
  }
  };


//Variablen der Wrfelaugen: Position, Richtung, Geschwindigkeit fr X und Y
//Variables of the dice: position, direction, speed for X and Y
float DiceXpos[6];
float DiceXdir[6];
volatile byte DiceXspeed[6];
float DiceYpos[6];
float DiceYdir[6];
volatile byte DiceYspeed[6];


int DiceValue;
unsigned long timestamp;
byte Mode;
int volatile shakes;
int ShakesPerSecond;
int step;

void InterruptChecks() {
  //Schttel-Anzahl zhlen
  //Count Shakes
  shakes=shakes+1;
  //Serial.println(millis());
  timestamp=millis();
}

void SetSpeedX() {
  if (Mode==0) {
    //alle Wrfel in X beschleunigen
    //Speed-up dice in X
    for (int i = 0; i < 6; i++) {
      if (DiceXspeed[i]<255) {DiceXspeed[i]=DiceXspeed[i]+5;}
    }
  }  
  InterruptChecks();
}

void SetSpeedY() {
  if (Mode==0) {
    //alle Wrfel in Y beschleunigen
    //Speed-up dice in Y
    for (int i = 0; i < 6; i++) {
      if (DiceYspeed[i]<255) {DiceYspeed[i]=DiceYspeed[i]+5;}
    }
  }
  InterruptChecks();
}

void ShowLed(int x, int y, bool onoff) {
//LED nur anzeigen, wenn im sichtbaren Bereich
//show only, when x/y in matrix
  if ((x<8) and (y<8) and (x>=0) and (y>=0)) {
    lc.setLed(0, x, y, onoff);
  }
}

void ShowDot(int x, int y, bool onoff) {
//Wrfel-Auge anzeigen oder ausblenden
//Show or hide dice point
  ShowLed(x-1, y-1, onoff);
  ShowLed(x, y-1, onoff);
  ShowLed(x-1, y, onoff);
  ShowLed(x, y, onoff);
}

void ShowDicePic(int value) {
//Wurf anzeigen
//Show dice

boolean done;

  //alle Punkte von der aktuellen Position aus zur Zielposition von DiceValue bewegen
  //move all points from current position to destination of DiceValue
  for (int i = 0; i < 6; i++) {
    DiceXspeed[i]=100;
    DiceYspeed[i]=100;

    //Werte fr X berechnen
    //Calc x values
    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;} 
  }

  //Serial.println(value);
  //Serial.println("Bewegung Start // Start moving");
  //Punkte bewegen
  do {
    //Serial.println("Bewegung // Moving");
    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);

    //Sind alle Augen an ihrer Zielposition
    //Dice points are on destition position
    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);
  //Serial.println("Bewegung Ende // End moving");

  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=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;}
}

void MoveDots() {
  //alle Wrfel einen Schritt weiter bewegen
  //move dice points one step further
  for (int i = 0; i < 6; i++) {
    //neue Koordinaten berechnen
    //calc new coordinates
    DoStep(DiceXpos[i],DiceXdir[i],DiceXspeed[i],true);
    DoStep(DiceYpos[i],DiceYdir[i],DiceYspeed[i],true);
  }

    //Wrfel-Augen anzeigen
    //show dice points
    lc.clearDisplay(0);
    for (int i = 0; i < 6; i++) {
      ShowDot(int(DiceXpos[i]), int(DiceYpos[i]), true);
    }
  
}



void setup() {
  //Der MAX7219 ist beim Starten im Power-Saving Modus,
  //er muss aufgeweckt werden.
  //The MAX7219 is in power-saving mode on startup,
  //we have to do a wakeup call
  lc.shutdown(0, false);
  //Helligkeit auf einen Mittelwert
  //Set the brightness to a medium values 
  lc.setIntensity(0, 8);
  //und Display lschen
  //and clear the display 
  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;
    }

  //Pins einstellen
  //Setup the pins
  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=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 Schtteln mehr
      //there is no shaking since 2 sec
      Mode=1;
      DiceValue=random(6)+1;
      ShowDicePic(DiceValue);
    }
  }

  if (ShakesPerSecond>5) {
    //Es wird wieder geschttelt
    //shaking again
    Mode=0;
  }

}

Custom parts and enclosures

Upper part of the casing
Lower part of the casing

Comments

Similar projects you might like

MicroView Digital Dice

Project tutorial by Giovanni Gentile

  • 634 views
  • 1 comment
  • 2 respects

Settlers Of Catan Dice

Project tutorial by joshi

  • 5,726 views
  • 13 comments
  • 28 respects

Otto DIY+ Arduino Bluetooth Robot Easy to 3D Print

Project tutorial by Team Otto builders

  • 51,325 views
  • 120 comments
  • 170 respects

LED Dice

Project showcase by EvdS

  • 16,142 views
  • 11 comments
  • 58 respects

Integrated Solar ChargeController, Inverter, PowerBank, Lamp

Project tutorial by Shahariar

  • 8,511 views
  • 25 comments
  • 34 respects

ATTiny Dice Christmas Gift Project

Project in progress by wrightmac

  • 1,232 views
  • 1 comment
  • 3 respects
Add projectSign up / Login