Digital Dice

by frogdotpng in Circuits > Arduino

43 Views, 2 Favorites, 0 Comments

Digital Dice

IMG_20240627_090136.jpg

Mijn idee voor dit project kwam eigenlijk toen in in een bordspelwinkel was. Daar zag ik ge3dprinte dice towers (torens waar je een dobbelsteen in kan gooien, en dan rolt die er weer uit. Eigenlijk alleen om het gooien van dobbelstenen leuker te maken.)

Die verkochten ze voor meer dan een tientje, dus ik dacht, 'Hey, dat kan ik zelf maken. Oh wacht, dat zou ik nog beter kunnen maken met arduino!'

Toen had ik het daarover met wat medestudenten, en realizeerde ik dat het toch niet zo'n interessant idee was. Maar, toen kwam ik bij het idee voor Digital Dice!

Dus, mijn idee:

Digital Dice voor D&D (of andere Tabletop Roleplaying Games die verschillende soorten dice gebruiken)

Dit wil ik doen door een 16x2 lcd scherm te gebruiken en 2 knoppen. Een waarmee je naar de Volgende dice kan gaan, en een waarmee je op ‘rollen’ kan klikken. Dan wordt er een random nummer gegenereerd tussen 1 & het maximum van de gewenste dobbelsteen. 

Als er een critical success (hoogst mogelijke cijfer) wordt gerold, dan speelt gaat er een groen lampje branden en speelt er een positief deuntje met een buzzer. Als er een critical fail (1) wordt gerold, dan gaat er een rood lampje branden, en speelt er een verdrietig deuntje. 

De dice die ik in mijn programma wil hebben zijn de D4, D6, D8, D10, D12, D20 en D100. 

Ik speel zelf al een aantal jaar D&D, dus vandaar ook dit idee!

Supplies

Elektronische componenten

  • 1x Arduino Uno
  • 1x 16x2 I2C LCD scherm
  • 1x Breadboard voor het testen
  • 2x Pushbutton met cap
  • 2x 10kOhm weerstand
  • 2x LED (1x rood, 1x groen)
  • 2x 330Ohm resistor
  • 1x Piezo buzzer
  • Wires

Gereedschap

  • Schuurpapier
  • Soldeerbout
  • Soldeer Tin
  • Soldeer Flux
  • Soldeer snoertjes
  • 3D printer
  • Duct tape

Circuit Bedenken & Uitvoeren

IMG_20240623_163141.jpg
Stunning Albar(2).png

Voor dit project wist ik al welke componenten ik wou gebruiken. Ik wou een 16x2 LCD scherm gebruiken waarop je kon zien welke soort dobbelsteen je aan het rollen bent, en wat het resultaat daarvan is.

Daarvoor heb ik eerst de code geschreven. Ik heb ervoor gezorgd dat het scherm simpelweg aangaf 'De dice is een d[nummer van huidige dobbelsteen]', en elke keer als je op knop A klikte, dan ging hij naar de volgende dobbelsteen.

Daarna heb ik met een random(1,max); ervoor gezorgd dat je daadwerkelijk de dobbelsteen kan 'rollen'.

Dat was eigenlijk het minimum van wat ik wou hebben, maar daarna heb ik nog wat dingen toegevoegd voor extra flair.

Toen wou ik ook dat er een geluidje afspeelde als je een critical succes (het hoogst mogelijke nummer op de dobbelsteen) of een critical fail (een 1) rolt op je dobbelsteen.

En ik wou dat er een groen lampje ging branden bij de critical succes en een rood lampje bij de critical fail.

De Arduino IDE Code

Ik vond het schrijven van de code eigenlijk best leuk!


Er waren een paar dingen waar ik tegenaan liep. Zo had ik bijvoorbeeld in mijn diceSelector() functie eerst een hele rij aan if statements die niet werkte, dus toen heb ik de variabele whichDice gebruikt om een range van 0-6 te maken die in de array dice[] kijkt naar welke dobbelsteen er gerold moet worden.


In mijn code gebeuren er een aantal dingen.

Eerst hebben we de 'next' button, deze heet 'button' in mijn script. Als deze wordt ingedrukt, gebeurt de functie 'diceSelector'. Deze zorgt ervoor dat de volgende dobbelsteen wordt geselecteerd. Dit gebeurt door de int whichDice +1 te doen, en als deze groter wordt dan 6, gaat die weer terug naar 0. whichDice wordt in de array dice[] gebruikt om te bepalen welke waarde binnen de array gebruikt moet worden.

Dan hebben we de 'roll' button, deze heet 'rollButton' in mijn script. Als deze wordt ingedrukt, gebeurt de functie 'diceRoller'. Deze functie zorgt ervoor dat er een dobbelsteen 'gerold' wordt, oftewel; er wordt een random nummer gegenereerd tussen 1 en het maximum van de huidig geselecteerde dobbelsteen.

Dan wordt er ook nog een soort rolling animatie afgespeeld, waarbij er een hele hoop random mogelijke nummers worden afgebeeld.

Daarna komt het daadwerkelijke resultaat op het scherm.

Als dit een critical roll is, gebeurt er ook nog wat.

Bij een crit failure (het laagste dat er gerold kan worden, dus altijd een 1) gaat er een rood lampje aan en wordt de gebruiker gerickrolled. Dit is een meme op het internet.

Bij een crit succes (het hoogste dat er op de dobbelsteen gerold kan worden) gaat er een groen lampje branden en speelt er een blij deuntje.


#include "Wire.h" // Library for I2C communication
#include "LiquidCrystal_I2C.h" // Library for LCD
#include <ezButton.h>
#include <ezBuzzer.h>
#include "pitches.h"


// Wiring: SDA pin is connected to A4 and SCL pin to A5. Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
const int BUZZER_PIN = 5;
const int REDLIGHT_PIN = 7;
const int GREENLIGHT_PIN = 8;


ezButton button(2);  // create ezButton object that attach to pin 7;
ezButton rollButton(3);  // create ezButton object that attach to pin 7;
ezBuzzer buzzer(BUZZER_PIN);


// variables
int buttonState = 0;  // variable for reading the pushbutton status
int whichDice = 0; // houdt bij welke dice het is
int dice[] = {4,6,8,10,12,20,100}; //de dice opties
int diceThrow;


// notes in the melody for when you WINNNNNNN:
int melodyWin[] = {NOTE_A5, NOTE_B5, NOTE_C5, NOTE_B5, NOTE_A5};
int noteDurationsWin[] = {4, 8, 4, 4, 2};


// notes in the melody for when you LOSEEEEEE:
int melodyLose[] = {NOTE_G4, NOTE_A4, NOTE_C5, NOTE_A4, NOTE_E5, NOTE_E5, REST, NOTE_D5};
int noteDurationsLose[] = {8, 8, 8, 8, 2, 12, 8, 2};


void setup() {
  lcd.init();   // Initiate the LCD
  lcd.backlight(); //zet de backlight aan
  Serial.begin(9600);
  button.setDebounceTime(50); // set debounce time to 50 milliseconds


  pinMode(REDLIGHT_PIN, OUTPUT);
  pinMode(GREENLIGHT_PIN, OUTPUT);


  Serial.println("Start!"); //check of de code start
}


void loop() {
  button.loop(); // MUST call the loop() function first
  rollButton.loop(); // MUST call the loop() function first
  buzzer.loop(); // MUST call the buzzer.loop() function in loop()


  lcd.setCursor(0, 0); // Set the cursor on the third column and first row.
  lcd.print("Dice is een d");
  lcd.print(dice[whichDice]);


  //if (buttonState == HIGH) {
  if(button.isPressed()){
    diceSelector();
  }
 
  if(rollButton.isPressed()){
    diceRoller();
  }
}


void diceSelector(){
  lcd.clear();
    Serial.println("Je klikt op knopje yay");
    whichDice ++;


    if(whichDice>6){
      whichDice = 0;
    }
}


void diceRoller(){
    lcd.clear();
    diceThrow = random(1, dice[whichDice]+1);


    rolling();


    lcd.clear();
    lcd.setCursor(7, 1);
    lcd.print(diceThrow);


    int whatLight;


    //crit success
    if (diceThrow == dice[whichDice]){  //kijkt of het gerolde nummer gelijk is aan het maximum
      int whatLight = GREENLIGHT_PIN;


        if (buzzer.getState() == BUZZER_IDLE) {
        int length = sizeof(noteDurationsWin) / sizeof(int);
        buzzer.playMelody(melodyWin, noteDurationsWin, length); // playing
      }
      lightsAndDisplay(whatLight);
    }


    //crit fail
    if (diceThrow == 1){    //kijkt of het gerolde nummer 1 is (het laagste nummer)
      int whatLight = REDLIGHT_PIN;


      if (buzzer.getState() == BUZZER_IDLE) {
        int length = sizeof(noteDurationsLose) / sizeof(int);
        buzzer.playMelody(melodyLose, noteDurationsLose, length); // playing
      }
      lightsAndDisplay(whatLight);
    }
}


void rolling(){
  int howManyTimesRolling = random(7,13);
  for (int i = 0; i <= howManyTimesRolling; i++) {
    lcd.setCursor(7, 1);
    lcd.print(random(1, dice[whichDice]+1));
    delay(100);
    lcd.clear();
  }
  delay(150);
}


void lightsAndDisplay(int whatLight){
        digitalWrite(whatLight, HIGH);  // turn the LED on (HIGH is the voltage level)
        lcd.display();
        delay(300);


        digitalWrite(whatLight, LOW);  // turn the LED on (HIGH is the voltage level)
        delay(100);


        digitalWrite(whatLight, HIGH);  // turn the LED on (HIGH is the voltage level)
        lcd.noDisplay();
        delay(150);


        digitalWrite(whatLight, LOW);  // turn the LED on (HIGH is the voltage level)
        delay(200);


        digitalWrite(whatLight, HIGH);  // turn the LED on (HIGH is the voltage level)
        lcd.display();
        delay(100);


        digitalWrite(whatLight, LOW);  // turn the LED on (HIGH is the voltage level)
}

Downloads

Behuizing Ontwerpen

dice box 3.png
dice box 2.png
dice box 1.png

Ik heb de behuizing ontworpen in Tinkercad. Daar heb ik de afmetingen van de bestaande 3d objecten van de onderdelen gebruikt om de goede afmetingen van de behuizing te kunnen maken.

Solderen

IMG_20240624_200520.jpg
IMG_20240624_200940.jpg
IMG_20240624_202025.jpg
IMG_20240624_203817.jpg
IMG_20240624_212019.jpg
IMG_20240624_213448.jpg
IMG_20240624_214622.jpg

Het solderen ging 500x beter dan dat ik had verwacht. Aangezien een van mijn klasgenoten het beschreef als iets dat als marteltechniek gebruikt zou kunnen worden, waren mijn verwachtingen niet erg hoog. Maar gelukkig had mijn vader veel goede tips voor me die ik kon gebruiken, en ook hulpmiddelen, zoals soldeerflux.

Ik ben er een lange avond mee bezig geweest, en de volgende ochtend was het tijd voor het moment van de waarheid. En tot mijn grote verbazing, werkte 99% van het circuit gewoon. Er was 1 probleem, en dat was dat wanneer ik 1 van mijn knopjes indrukte, dat allebei de acties werden uitgevoerd. (dit staat ook in de video met extra documentatie) ((die heb ik apart geupload omdat Instructable een file limit heeft van 25mb en dat is soms lastig met videos...)) Gelukkig was dit makkelijk te fixen door gewoon 1 connector door te knippen, aangezien daar kortsluiting was ontstaan. En daarna werkte het allemaal zoals ik in gedachten had.

Wel heb ik na het solderen een paar van de aansluitingspunten veranderd, dus hieronder staat de code die ik heb gebruikt na het solderen.

De Behuizing 3D Printen

rn_image_picker_lib_temp_864ad3e9-2551-486c-9a15-5685533fe1d6.jpg
IMG_20240627_071307.jpg
IMG_20240627_071326.jpg
rn_image_picker_lib_temp_66f38d59-37c5-4c02-8261-75be10432fe2.jpg

Tijdens het 3d printen is het een aantal keer wel een klein beetje fout gegaan. Eerst had ik alleen de bovenkant geprint, en dit ging helaas niet goed door een probleem met onze printer. Maar eigenlijk was het wel een goede test-run, want ik kwam er toen ook achter dat de gaten eigenlijk allemaal iets te klein waren. Hierna heb ik opnieuw de printer aangezet, en toen ging het wel goed.

Nadat ik de rest van de behuizing had ge3dprint, kwam ik erachter dat de afmetingen niet helemaal klopte. Dit kwam doordat het filament een beetje uitzet/meer ruimte inneemt dan dat TinkerCad aangaf.

Constructie

IMG_20240627_072316.jpg
IMG_20240627_090136.jpg

De constructie liep helaas niet zo soepel als ik had gehoopt! De 3d prints paste niet goed op elkaar, waardoor het een beetje wiebelig was. Maar ondanks dat vond ik het erg leuk om te doen, ookal heb ik er veel ducttape voor gebruikt.

Conclusie

Ik heb van dit project veel geleerd! DIt was de eerste keer dat ik heb gesoldeerd, en nu weet ik best goed hoe dat moet! Verder heb ik voor het eerst echt met Arduino gewerkt, en snap nu toch wel iets beter hoe dat werkt. Ook heb ik geleerd hoe de 3d printer werkt, en ik kijk ernaar uit om deze ook vaker te gaan gebruiken!


Bedankt voor het lezen van mijn documentatie! Ik vond dit een leuk project om aan te werken!


Youtube Link voor uiteindelijke werkende project: https://youtu.be/gn_RKEGanZY

Youtube Link voor aanvullende videos als documentatie: https://youtu.be/ED_WNIvEcJc