POSTS
Piano Game
- 8 minutes read - 1616 wordsBased on prior work, I made a mini piano game like the arcade game Grand Piano Keys.
3d printing
For Black Friday 2023, I got a my first 3d printer, a Bambu X1 Carbon. I started using it by printing various items from MakerWorld and ThingVerse. The ease and quality of printing have been amazing, and I really appreciate how little maintenance there’s been.
I had a little experience creating 3d models in Blender, and this new printer was an opportunity to learn more about modeling. My first few models were tutorials like creating a phone stand, and small modifications to existing models, for example blunting an existing sharp point.
Next, I started making SVG extrusions. I learned how to make multicolored SVG extrusions by extruding separate bodies, which could be colored separately in Bambu Studio. The X1 hooks into an AMS (Automated Material System) that can switch filaments automatically (albeit with some waste).
Piano game
My latest and most complex project yet is a remix of a project called Mini Piano Arcade Game. This project interested me since I am a fan of the arcade game it’s based on called Grand Piano Keys.
There aren’t any wiring instructions for the project; however, it turned out to be straightforward. The code worked well too, and was simple to modify for my use case. When I first printed the components, I only had on-hand an Arduino Uno and a single 8x8 MAX7219 LED module from a hobbyist kit. Since the code was written to use 4 MAX7219s, I ordered more, and rewrote the code so I could use just one component.
There was a problem with the version of the components I used. When I inserted the rod meant to keep the keys in place, they pushed down the MX switches too much, activating them. It could be that the keys were designed for shorter MX switches. I am not sure how much variability MX switches have. I widened the rod hole on the keys as a temporary fix while waiting for more components.
While the display worked well, Grand Piano is a game about music, so I wanted to add some sound to the game. I had a piezo buzzer, and figured out how to output sound. As a player uses the keys, a note is played according to a few built-in songs.
3d modeling
Once I had everything working and the missing components arrived, it was time to make adjustments to the model. I’ve been using Fusion 360 for modeling because of its parametric editing capabilities, which is like git rebase for modeling.
For example, you may create 2d sketches to extrude 3d bodies. Later, you may edit that original sketch to change the shape of the body, and that change will carry through to the latest revisions if you create your model in a specific way that makes the relations between sketches and bodies and other bodies clear.
There were a few modifications I wanted to make.
- Fix the keys pressing down on the switches by either lowering the switch holders or raising the key ledges.
- Make the box larger to accommodate an Arduino Uno rather than the Arduino Micro that the model was originally designed for.
Making these modifications would require remodeling everything based on the original model. Fusion 360’s free version cannot convert an STL into a body that is easy to work with. This process of remodeling took several hours and required many test prints. I learned a lot of things along the way but I have some unanswered questions.
What I learned:
-
Print samples of a model by intersecting with a box and exporting the result. This is quicker and wastes less in the long run.
-
Double check the places where two bodies connect, and join those bodies if feasible to prevent floating regions.
-
Double check when exporting that you are at the appropriate place in the timeline. I had a wasted print because I was not at the end of the timeline when I printed.
-
While parametric editing is a godsend, there seem to be times when it doesn’t work. Going back and editing a body doesn’t carry it over to copies on the body. I’m still trying to figure out exactly what actions cause this.
Code
You can find my fork of the original code at https://github.com/jamiely/arduino-piano-game.
I made a few modifications to the original code including:
- Making the number of MAX7219s configurable
- Refactoring the code to improve readability
- Adding music
To implement music, I import a standard Arduino library, pitches.h
, that
defines pitch values by note and octave. I
define an array of pitches
to define each song. Chat GPT helped generate these arrays for
Ode to Joy and Twinkle, Twinkle, Little Star, but it repeatedly
hallucinated several
different songs I asked it to help me with such as Joy to the World
and When the Saints Go Marching In. I had to manually transcribe these songs.
#include "pitches.h"
int odeToJoyMelody[] = {
NOTE_E4, NOTE_E4, NOTE_F4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4,
NOTE_E4, NOTE_E4, NOTE_F4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_D4, NOTE_C4,
NOTE_D4, NOTE_E4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_C4, NOTE_C4, NOTE_D4, NOTE_C4, NOTE_B4, NOTE_C4
};
There are private class attributes:
melodyIndex
- the current song indexmelodyPosition
- the index of the current note
When a player presses the correct key, a tone is played based on
melodyPosition
, then melodyPosition
is incremented. Once melodyPosition
reaches the length of the melody, the next song is selected, and
melodyPosition
is reset.
tone(PIEZO_PIN, melody[melodyPosition], toneDuration);
melodyPosition = (melodyPosition + 1) % melodyLength;
if(melodyPosition == 0) {
switchSong();
}
Circuit
There are three major components.
- A set of switches for the piano keys
- A piezo buzzer to generate the tones
- A MAX7219 LED module that drives an LED matrix to display the keys that should be pressed.
The switches are brown cherry MX switches. I debated between brown and blue ones. Although I like the clickiness of the blue switches, I chose browns because pianos aren’t clicky. One pin from each switch is daisy chained to the next switch, and the last switch is connected to the Arduino’s ground pin. Each other pin on each switch is connected to one of the Arduino’s GPIO pins. I have them wired to 4, 5, 6, and 7.
I have 4 daisy-chained MAX7219 with 5 pins. VCC and GND are wired to the Arduino 5V and Ground, respectively. CS, DIN, and CLK are wired to 9, 11, and 13. The code is hardcoded to assume 4 matrices, but can be adjusted for more or less.
The piezo buzzer’s negative terminal is connected to Ground. The positive terminal is wired to a diode connected to both a 100 ohm resistor and cathode end of a diode. The resister is connected to a GPIO pin, in my case, 8. The diode’s anode is connected to ground to allow excess voltage to dissipate without damaging the Arduino.
This is not part of the main circuit, but I have a DC input plugged into the Arduino, wired with a battery holder and power switch to turn off the game. I’d like to add a port for the power switch into the next revision of the model.
Here are some pictures of the internals:
For this project, I used Wago connectors to connect wires together for quick prototyping. I plan to solder these together at some point.
I got a kit to make my own DuPont connectors and got some new experience crimping these connectors. I had some trouble with the vertical clearance of the project box and plugging these connectors in the Arduino headers. I ordered some right-angle pin headers from AliExpress while I debated desoldering the Arduino headers. I realized I could just bend the pins of my DuPont connectors. It worked well enough but one of the pins would unseat from the Arduino header, and I had to recrimp that connector.
What’s next?
- The arcade game’s keys light up as you press them. This seems like it would be relatively easy to do, although there might be changes to the model to shield each other key from the light, or to add a place to mount an LED to each key. Hot gluing an LED to the underside of each key might work well enough.
- Part of the fun of the arcade game is the huge keys. My print bed can fit a much larger key, but what would the enclosure look like? Would a cherry MX support the weight of a larger key? Or would I need something springy to support the key?
- The original game had a separate score display. I thought it seemed unnecessary for the game, but seeing the score update live is somewhat fun.
- I’d like to change the current interface for entering high scores.
- I’m not sure if high scores are supposed to display right now, but I don’t see them. I’d like them to display when the game is idle.
- Add a case opening for the power switch.
- Figure out a solution to add a battery holder to the case.