Ritme Trainer Met Arduino UNO

by BenRosenmoller in Circuits > Arduino

199 Views, 0 Favorites, 0 Comments

Ritme Trainer Met Arduino UNO

PXL_20230505_110256980.PORTRAIT.jpg
PXL_20230505_120433326.jpg

Dit project is een speelse manier om te oefenen met het vast houden van een tempo. De interface bestaat uit 1 knop, 5 lampjes (2 rode, 1 gele en 2 groene) en een buzzer.

Supplies

Elektronische Componenten:

  • 1 x Arduino Uno

User Interface

  • 1 x Push Button (liefst een iets grotere)
  • 1 x Simple Active Buzzer
  • 2 x Rode LED
  • 1 x Gele LED
  • 2 x Groene LED

Kabels

  • 12 x Jumper Wire male-male (ongeveer 20 cm)
  • 5 x 330 Ω weerstand
  • 1 x 10 kΩ weerstand
  • 1 x 1 kΩ weerstand
  • 8 x krimpkousen (optioneel)
  • 3 x tiewrap (optioneel)


Behuizing:

  • Doosje ongeveer 13 x 13 x 6 cm (Ik heb de mijne bij de Action kunnen halen)
  • Hobbylijm
  • Kleine schroeven
  • Iets om je knop aan te bevestigen (in mijn geval zijkant van een oud rolgordijn)
  • Losse stukjes hout voor ophogen van de Arduino (en in mijn geval voor het rechttrekken van de deksel)

Gereedschap:

  • Houtzaag
  • Soldeerbout (+ Soldeertin)
  • Schroevendraaier of handboor
  • Striptang
  • tang

Het Eindproduct

Je start het spel door 1 keer op de knop te drukken. Dan gaat een buzzer op een willekeurig gekozen bpm 2 maten van 4 noten spelen. Hierna moet jij ditzelfde ritme nog 2 maten vasthouden door op de goede momenten op de knop te drukken. Het systeem berekend dan hoeveel je er gemiddeld naast zat en geeft je op basis hiervan een score. Deze score is te zien aan de lampjes die lopen van slecht (het meest linker rode lampje) tot zeer goed (het meest rechter groene lampje).

Het Elektronische Schema

Screenshot 2023-05-05 125716.png

Het elektronische schema is eigenlijk best wel simpel, want elk stukje van het ontwerp kun je direct verbinden met de Arduino.

Het systeem bestaat uit 3 delen:

  1. De lampjes
  • Elke lampje zit met zijn anode via een 330 Ω weerstand vast aan een eigen Digital pin op de Arduino (in dit schema pin 3 tot en met 7).
  • De Kathode van elk lampje zit via een draadje aan elkaar vast gesoldeerd en gaat dan samen naar één van de drie GND (Ground) ingangen van de Arduino.
  • Opmerking: In deze visualisatie zitten de LED's in een breadboard, maar dat is niet zo bij de constructie.

2. De knop

  • De ene kant van de knop zit via een 10 kΩ weerstand vast aan een andere GND (Ground) pin.
  • Aan dezelfde kant zit ook een draadje dat naar een Digital pin van de Arduino gaat, in dit geval pin 8.
  • Aan de andere kant gaat een draadje naar de 3.3 V power pin van de Arduino.

3. De Buzzer

  • Aan de min kant zit de buzzer via een 1 kΩ weerstand vast aan de derde GND (Ground) pin van de Arduino.
  • Aan de plus kant zit de buzzer direct vast aan een Digital pin van de Arduino (in dit geval pin 9).

De Code

De Code is opgedeeld in meerdere bestanden om de leesbaarheid te verbeteren. De applicatie start vanuit de RythmGame.ino file, maar die stuurt voornamelijk de GameLoop.h file aan waar de Arduino via verschillende states bepaalde code wel of niet uitvoert. De Button.h file is voor het opvangen van de button input plus spamfilter en de Notes.h is voor het definiëren van muziek noten en het win en verlies muziekje.


Deze code kun je zo gebruiken in je project en alles is voorzien van comments.


Helaas weigert Intstructables.com het uploaden van mijn GameLoop.h file, dus met gebrek aan een betere optie zet ik die dan maar hier neer

#include "Notes.h"
#include "Button.h"


// Set the correct pins
const byte LED_PIN_1 = 3;
const byte LED_PIN_2 = 4;
const byte LED_PIN_3 = 5;
const byte LED_PIN_4 = 6;
const byte LED_PIN_5 = 7;


// Make shift enum to keep track of the different game states
const byte IDLE = 0;
const byte PLAYING = 1;
const byte LISTENING = 2;


// Current game states determines which code should be executed in the loop function
byte currentGameState;


// Duration of the tempo notes played by the buzzer
int noteDuration = 50;
// Delay between the notes effectifly determining the bpm of the current attempt. Is set at the end of the IDLE state
int noteDelay;


// Counter that keeps track of how many notes the buzzer has already played (resets at 8)
int playedNotesCounter;


// Time from the millis() function from which the Arduino started listening for the user pressed inputs. Needs to be a long to prevent breaking after 32767 milliseconds
long startListeningTime;


// Sum of all the deviations between the correct time and the actual time pressed by the player
long sumOfDeviations;
// Index of the notes clicked by the player
int currentListenIndex;


// State where device is waiting for a game to start
void IdleState()
{
  if (buttonActiveThisCycle)
  {
    delay(500); // Delay to make sure the player hears the first note
    noteDelay = random(400, 1000); // Generate the noteDelay for this round
    playedNotesCounter = 0; // Reset the variable
    currentGameState = PLAYING; // Change the state to the Playing state
  }
}


// State where the device plays notes in a tempo
void PlayingState()
{
  playedNotesCounter++; // Increase the playedNotesCounter counter
  tone(BUZZER_PIN, 440, noteDuration); // Play the tone

  // if the counter is still under 8 delay the program for the length of one note to get the correct note distances
  if (playedNotesCounter < 8)
  {
    delay(noteDelay);
  }
  // End playing state
  else
  {
    startListeningTime = millis(); // Set the startListeningTime to the current run time of the program in milliseconds
    sumOfDeviations = 0; // Reset the variable
    currentListenIndex = 1; // Reset the variable
    currentGameState = LISTENING; // Switch state to listening
  }
}


void EndSequence()
{
  // Called called the average by deviding the sum by the amount
  double averageDeviation = sumOfDeviations / 8.0;
  bool playWinMusic = false;


  // Set the correct pin based on how precise the player was
  // Best when have a averageDeviation lower than 50 millieseconds and worst when having one of more than 1000.
  if (averageDeviation < 50)
  {
    digitalWrite(LED_PIN_5, HIGH);
    playWinMusic = true;
  }
  else if (averageDeviation < 150)
  {
    digitalWrite(LED_PIN_4, HIGH);
    playWinMusic = true;
  }
  else if (averageDeviation < 500)
  {
    digitalWrite(LED_PIN_3, HIGH);
    playWinMusic = true;
  }
  else if (averageDeviation < 1000)
  {
    digitalWrite(LED_PIN_2, HIGH);
  }
  else
  {
    digitalWrite(LED_PIN_1, HIGH);
  }


  // Play win music if the result was good enough other wise play lose music
  if (playWinMusic)
  {
    winMusic.Play();
  }
  else
  {
    loseMusic.Play();
  }


  // Delay the Arduino to allow seeing your score and taking a break
  delay(3000);


  // Reset the LED's
  digitalWrite(LED_PIN_1, LOW);
  digitalWrite(LED_PIN_2, LOW);
  digitalWrite(LED_PIN_3, LOW);
  digitalWrite(LED_PIN_4, LOW);
  digitalWrite(LED_PIN_5, LOW);


  // Restart the game by going back to the IDLE state
  currentGameState = IDLE;
}


// State where the device listens for button presses from the player and calculatates the deviation from the correct time
void ListeningState()
{
  if (buttonActiveThisCycle)
  {
    // Calculate current deviation from the correct timing and add it to the sumOfDeviations. currentlistenIndex * notedelay is the timing of this note.
    long currentDeviation = (currentListenIndex * noteDelay) - (millis() - startListeningTime);
    sumOfDeviations += abs(currentDeviation);
   
    // Increase the currentListenIndex to represent the amount of presses the player has already performed
    currentListenIndex++;


    // If the player played 8 notes start the endsequence
    if (currentListenIndex > 8)
    {
      EndSequence();
    }
  }
}

Behuizing

PXL_20230503_152140472.jpg
PXL_20230503_154403926.jpg
PXL_20230503_154406973.jpg
PXL_20230503_162036965.jpg
PXL_20230503_162058546.jpg
PXL_20230503_162112621.jpg
PXL_20230503_180817160.jpg
PXL_20230503_185352948.jpg
PXL_20230503_185359501.jpg
PXL_20230503_193208308.jpg
PXL_20230503_194413893.jpg
PXL_20230505_120433326.jpg

De behuizing van de ritme game is een houten doosje van 13 x 13 x 6 cm. Hier volgt een stap-voor-stapuitleg over hoe je de behuizing kunt maken.

  1. Boor vijf kleine gaten voor de LED's in de bovenkant van de doos. Zorg ervoor dat de gaten niet te groot zijn, zodat de LED's er strak in kunnen worden gelijmd.
  2. Boor een gat aan de zijkant van de doos ter grootte van de buzzer, zodat de buzzer daar strak in kan worden geklemd. Zorg ervoor dat je de buzzer niet te strak klemt, anders zal het geluid gedempt worden.
  3. Zaag een blokje weg aan de zijkant van de onderste helft van de doos waar de kabel doorheen kan. Houd er rekening mee dat de Arduino uiteindelijk op die hoogte zal worden geplaatst.
  4. Bevestig de knop. Dit kan op verschillende manieren, maar ik heb de knop vastgeschroefd aan de zijkant van een oud rolgordijn, zodat deze rechtop staat. Boor een gat in de deksel op de hoogte van de knop, zodat er een houten staafje doorheen kan steken. Bevestig het houten staafje aan een stukje hard plastic, zodat de knop omhoog blijft. Het lipje drukt vervolgens op de knop aan de onderkant van de doos.
  5. Kies een stukje hout dat ongeveer dezelfde hoogte heeft als het uitgezaagde blokje aan de zijkant van de doos, zodat de aansluitingen van de Arduino precies voor het gat zitten. Bevestig de Arduino op dit stukje hout met schroeven, en bevestig vervolgens het hout aan de onderkant van de doos.
  6. Ten slotte moet je de elektronica aansluiten. Voor de LED's is het het beste om de 330 Ω weerstand direct aan de anode te solderen en deze vervolgens aan het ene uiteinde van een male-male jumperwire met een krimpkous eromheen te bevestigen. De kathodes van de LED's kun je samenvoegen en solderen aan een andere jumperwire die vervolgens in een GND pin van de Arduino kan worden gezet.
  7. Doe hetzelfde voor de buzzer en de knop. Soldeer een jumper wire aan de buzzer en de knop en voeg indien nodig een weerstand toe. Sluit de draden aan op de juiste pinnen op de Arduino volgens het elektronische schema van de ritme game.


Dit is de laatste ontwerp stap en de constructie nu afgrond.

Reflectie

PXL_20230502_133132071.jpg

Mijn eerste idee voor dit project was het maken van een kaart van nederland met rode lampjes op de steden om aan te geven waar er storingen van de NS zitten. Voor dit project zou ik dan een ESP8266 wifi module verbinden aan mijn Arduino UNO en dan daarmee http calls doen naar de NS API. Dit bleek uiteindelijk wel een heel ambitieus plan voor iemand zonder Arduino ervaringen. Dus na 3 dagen de hele dag proberen de wifimodule te gebruiken heb ik uiteindelijk mijn plan moeten veranderen.

Hier uit neem ik mee dat ik betere tijdsinschattingen moet maken van mijn projecten, zeker ook reken houdend met de andere projecten die ook in dezelfde tijd af moeten. Verder moet ik ook eerder in het project de moeilijkste onderdelen van mijn idee testen, zodat ik genoeg tijd heb mogelijk hulp te vragen aan docenten, wat voor mij nu lastig was.


Het proces van mijn uiteindelijke product ging eigenlijk relatief soepel. Ik heb eerst geëxperimenteerd met het aansluiten van alle verschillende onderdelen (zie foto). Dan met het afspelen van tonen op de buzzer en dan met het uitlezen van intervallen tussen knop in drukken.

Daarna heb ik verschillende opties overwogen voor het ontwerp van spel. Zoals wanneer de tonen beginnen te spelen op welke manier je een indicatie krijgt over wanneer je moet spelen en hoe je het spel start. Ook over dingen zoals hoe ik de score wil laten zien en wat daarin het logischt aan voelt. Ik heb dingen overwogen zoals een aantal keren knipperen van een lampje, bepaalde toontjes op de buzzer en een hele rij van 20 lichtjes die als een soort levensbalk je correctheid aangeven. Maar ik denk dat mijn uiteindelijke ontwerp het meest intuïtief is, alle testers snapte na een korte uitleg over wat het was heel snel hoe ze het moesten gebruiken.

Een van de dingen waar ik wel over struikelde was het feit dat de Arduino programmeertaal andere limieten heeft voor de datatypes, dus waar een int in c++ een bereik heeft van -2147483648 tot 2147483647 heeft de Arduino int maar een bereik van -32768 tot 32767. Dus ik had een hele tijd waar mijn Arduino gewoon stopte met werken op een schijnbaar willekeurig moment tot ik er uiteindelijk achterkwam dat hij altijd na 32767 milliseconden stopte met werken en dat ik voor tijd berekeningen een long in plaats van een int moest gaan gebruiken.


Ik heb veel geleerd van dit project en hoewel het eerst heel lastig ging, ben ik uiteindelijk best wel blij over het eindresultaat.