How many times have you heard a song - on the radio, during a movie, or at a concert - and thought "Man I wish I could play that"? Now you can! This project allows you to learn a song note by note on the piano by lighting up appropriate LED lights that correspond to each individual key on the piano. In fact, even if you don't have a piano but have a smaller electronic keyboard, you can customize it for that. Some electronic keyboards actually have light-up keys for just this purpose, but doing it on a real piano is so much more satisfying. Have fun, and learn some songs!
The three main components of this project (like many) are:
2) Hardware (non-electronic)
3) Electronics and Wiring
Although they're separate parts of the project, in reality you'll frequently be working on more than one at a time simply because how you decide to do one part affects how you'll do another. A good thing about doing them in parallel, however, is that you keep the big picture in mind and if you get tired of writing code, you can design your acrylic parts, and if you're tired of the computer altogether you can wire up some resistors and LEDs and have some fun with that. The parts are in a specific order in the Instructable, but how you do it is up to you.
The biggest question when I started out was "How the heck do you individually control 88 LEDs?!?!" Fortunately, after some research I found some chips designed to do just that and some Arduino tutorials and code that helped along the way. Aside from that question, everything else was fairly straightforward or at least only required me to pick from several options - what to make the strip out of, how to hold the LEDs in place, how to write the code to make it all run, and so forth. Let's talk about the big question in a little more depth so you have an idea of how it all works before you get started.
The chips I got are LED matrix (or 7 segment display) drivers, which means that as far as the chip is concerned, we have our LEDs wired as if they're in a square grid, with a certain number of rows and columns - the positive terminals are common in each column, and the negative terminals are common in each row. This allows 64 LEDs (in an 8x8 grid) to be controlled by each chip and only requires three (that's right THREE!!!) control inputs. No matter which or how many of the LEDs you want to turn on, the system can handle it.
But wait, if you want to turn on LEDs (1,1) and (2,2), wouldn't that also light up (1,2) and (2,1), because in order to achieve the original goal all of rows 1-2 and columns 1-2 would have to be on? This is where the clock inside the chip comes in - the LEDs aren't actually on continuously. Rather, they're blinking so fast that the human eye observes them as continuously on. This is how unwanted LEDs can remain off!
So although we see the strip as just a line of LEDs, they're wired as if they're in two square matrices - one 8x8 (first chip) and one 5x5 (second chip), which adds up to 89 keys (the final "row" of the 5x5 matrix only has 4 LEDs, so that brings us down to 88). Voila!
How do we tell the chip which LEDs to illuminate? That's all done using binary numbers. Using some code borrowed from developers online (see the code for the attribution), I created the program in such a way that all you have to do when translating a song is to call the command playKey(...). This plays the given numbered key, starting with 1 on the left and ending with 88 on the right. This command takes the key number and translates it so the chips can do their duty by doing the following: the key number is translated into a row and column number, which is then translated into a row number and a binary number that represents which LED should be on (read from the left, not the right). For example, if I call playKey(13), which is A, the functions translate that as row 2, column 5; then since 2^5 is 32, that would be the number that goes to the chip. Reading from the left, 32 is 00000100, which represents the state of the second row. The same concept applies when we're dealing with lighting up multiple LEDs - it's all about binary numbers! Check out the code for the exact functions and a little more explanation.
Finally, there's a potentiometer attached to it all to control tempo - something really, really important when you have no idea what you're doing...
NOTE: This was not an easy Instructable to write because of how complicated it was to put everything together and make it all work. Don't hesitate to let me know if something is confusing or unclear, or if you have specific questions!
Let's get going!
Add a Teacher Note to share how you incorporated it into your lesson.
Step 1: Get All the Components
There isn't one right way to make a strip of LEDs fit nicely and elegantly atop your piano keys, so definitely spend some time and see what cool spins you can put on the idea. Before settling on this design, I bounced around a number of other ideas, some of which would have been uglier and some of which could have been much prettier. My goal was to achieve balance: making something worth leaving on the piano all year long without spending too much time being a perfectionist. I was glad with that decision when I started messing with the electronics and software and realized (as expected) that most of the work up front would be focused on those two things. So see what you can design! Either way, the electronics and software should work regardless of what your strip looks like.
- Arduino (Uno from Adafruit, $30)
- 88 red LEDs (100 pack from Jameco, $10)
- 2 MAX7219 LED driver chips (Jameco, $16)
- 1 potentiometer (had)
- 2 100nF capacitors (had)
- 1 10uF capacitor (had)
- 2 18K resistors (had)
- PCB prototyping board (Jameco, $6)
-- Note - it's good to have a breadboard too, for prototyping and testing electronics
- 2 24 pin sockets (10 pack from Jameco, $2.40)
- spool(s) of wire (had)
- Arduino USB cable
- Arduino wall adapter (LEDs will draw a lot of current)
- small 8x8 LED matrix for debugging code if necessary - it was SO nice to be able to test this way instead of wiring up the entire strip before I knew the software was right. Only "debug" one thing at a time!
- black acrylic 7.5" x 13.5" (TAP Plastics, ~$7)
- acrylic glue (TAP, $7)
- solder (thinner is better)
- zip ties
- a piano!
- laser cutter
- soldering iron
- wire strippers
- wire cutters
- small needle-nosed pliers
- acrylic glue hypo applicator (TAP, $3.25)
Step 2: Measure the Piano & Design the Acrylic Parts
The first step in designing the acrylic pieces is to determine the size of laser cutter you have access to. The one I used is small - about 9x14" - so I had to design my parts accordingly. What this meant practically is that I had to divide my keyboard into more pieces than I would have had I had access to a larger cutter. I ended up splitting it into six pieces, though it could have been done with fewer. So know your cutter and your piano/keyboard before you launch your CAD program.
1) Measure the keyboard and keys
Fundamentally self-explanatory, but there are some things to watch out for:
- Compounding measurement errors. Even if you measure one octave and feel good about it, there might be some slight variations between octaves. I suggest measuring each octave, a few black keys, a few white keys, and the entire keyboard before launching the design program or starting to cut anything.
- Spaces in between keys. Don't just measure a key and multiply!
- The black keys are tapered, so be sure to measure the width near the white keys, not at the top of the black keys when you're figuring out how large the spaces in the strip need to be.
2) Design parts
Pick a program and go for it! I used AutoCAD and kept the design simple - no rounded edges, and no fancy etchings or designs (although a musical note etched here and there might be good....), etc. The image below is the from a pdf that I ended up with.
3) Make sure your scale is correct
I had some trouble with figuring out scaling with AutoCAD and the cutter I was using, so before you start cutting into your new piece of black acrylic, definitely make sure the scale is correct and the pieces will fit around or on the keys. A good way step to begin with is to laser cut some paper and make sure the slots line up with the keys correctly and the LEDs (or holders) fit in the holes.
Step 3: Cut the Acrylic
Before you cut all your pieces, I suggest you cut a test hole and insert some LEDs to see if it's the right fit. Because you're working with small diameters, the sides of LED encasements are not completely parallel (they're tapered inward toward the tip), and the actual cut hole diameter may vary from the diameter you assign in your CAD program, a couple attempts may be necessary to find the right fit. Because the acrylic isn't very thick, cracking is something to be aware of when figuring out the sizes - the first time I started shoving LEDs into too-small holes I cracked a piece or two and had to recut. If you avoid these problems, you've eliminated one of the biggest frustrations I had...
The laser I used needed more than one pass to cut all the way through the acrylic sheet - if this is the case for you make sure your part won't move AT ALL during cutting!
Step 4: Glue the Acrylic
When you're ready to join the pieces of acrylic, you have some options for how to do so - brackets, glue, etc. I used acrylic glue and found that despite the low surface area, it was sufficiently strong (if you handle it with reasonable care). Acrylic glue isn't just an adhesive; it chemically melts the plastics together like welding, so you've got a nice strong connection.
Make sure you have a large flat surface on which to work and also some extra pieces of acrylic to raise the pieces you're gluing off the table a bit - and make sure they're the SAME height off the table, obviously. Fortunately for me, I had some extra pieces that had been cut incorrectly or cracked...
Once you feel good about your setup, start gluing the pieces together! A neat trick for using the hypo needle for applying the cement is to squeeze the bottle while it's upright, then turn it upside down to apply the cement. This allows you to maintain a sort of negative pressure inside (by releasing the squeeze a little) until you're ready to apply, thereby ensuring you don't end up with acrylic cement in places you don't want it.
Step 5: Wire the PCB
This step and the LED wiring step are related, so maybe read both before you start either. Really, they both sort of depend on how the software works...so I'll just describe what I did and leave the rest up to you. One thing to keep in mind: it is better to have the PCB soldered and ready to go before you start wiring the LEDs because then, when you're doing that you can solder the wires exactly where they belong rather than having a clump of wires coming from the strip with nowhere to put them yet. Also, I soldered the LED wires before I added the potentiometer; if I were to do it again, I'd reverse these steps.
Step 1 - The chips. Because each chip can only control 64 LEDs, you need two. And because chips can get hurt by the heat of soldering, you should have a 24-pin socket for each too. Toss these on the board, solder them, and then insert the chips. You can leave a row or two between the sockets, but be aware that you need three rows for the potentiometer at one end. Remember that the "top" of the chips (and sockets) have semicircular grooves, and that pin 1 is just to the left and they're numbered increasing CCW from there.
Step 2 - Power connections. Connect pins 4 & 9 to Ground and pin 19 to Power on each chip. Also connect pin 18 to Power but instead of using a wire, use a resistor - I used an 18k for each. This resistor controls the amount of current flowing to each LED. Also connect the Power and Ground columns at the top or bottom; I like having Ground on the inside and Power on the outside. Solder in a long black wire and a long red wire to one side - these will eventually plug into the Arduino, delivering power to your system.
Step 3 - Capacitors. Attach a 10mF capacitor between power and ground on one side, and two 100nF capacitors across the chips, also between power and ground.
Step 4 - Potentiometer. Solder the pot onto the board using three empty rows. The way it's shown in the photo, the leftmost pin goes to ground, the rightmost to power, and the middle to the Arduino input pin of choice.
Step 5 - Control wires (white). Connect pin 12 on chip 1 to pin 12 on chip 2, then solder a long wire that will eventually go to output pin 3 on the Arduino. Do the same with pin 13 on each chip - this will eventually be connected to pin 4 on the Arduino. Finally, connect pin 24 on chip 1 to pin 1 on chip 2 - this is the communication wire between the chips.
Step 6 - LED wires. Now comes the "fun" part...onto the next step!
Step 6: Insert the LEDs Into Strip
The only decision you have to make before you start inserting LEDs is what orientation of each pair of leads will make your life easiest when the time comes to wire them all together. After some thought, I went for the orientation shown the close-up photo here, and it turned out to work really well.
Note in the zoomed-out photo the noticeable bending of the acrylic. This is because the holes ended up being slightly too small, so the slightly tapered LEDs introduced a stress causing the strip to take on a slightly concave shape when viewed from the front. I'm sure having LED holders or making the holes a tiny bit larger would solve the problem - but don't make the holes so big that the LEDs won't be held firmly if you're going sans holder!
Step 7: Wire and Solder the LEDs
The most detail-oriented aspect of the strip was wiring the LEDs. It requires a good amount of time, focused attention, and precise soldering, but as long as you work slowly and carefully, it's not especially difficult per se. Knowing which wire should be soldered to which LED connection was the most mentally demanding aspect, so do what you need to do to make that as painless as possible - draw it out on paper, make a table showing corresponding LED/chip pins, whatever will work.
Prepare the LEDs
Once you've inserted the LEDs into the acrylic strips, either directly or using LED holders, you need to organize the leads to simplify the soldering as much as possible. The first way I thought to try it was to bend the leads at 90 degree angles to interlock in some way (see photo 1). This may have worked, but even as I was doing it I found myself just bending the leads more directly to one another (see photos 2-5). Any way that works works! Just keep in mind you're going to have a lot of wires coming through, and the positive leads obviously need to not come in contact with the negative leads and vice versa.
To recap the explanation from the intro, we're wiring the LEDs as if they're in a square grid even though they're in one long row in reality. So imagine every 8 LEDs (for the first 64) or 5 LEDs (for the last 24) are a separate group - maybe even put a piece of masking tape or some other sort of divider between the groups to help you remember. LEDs within each group get their negative leads bent and soldered to one another (common ground). Then, the positive lead of the first LED in each group is wired to the positive lead of the first LED in every other group within each chip (i.e. only the first LEDs in the first 8 groups are wired together because that completes the 8x8 grid for the first chip. Then you wire the first LED in each group of 5 together for the remaining 5 groups.)
The first 8 LEDs are row 1, columns 1-8. The next 8 are row 2, etc. Once you get through 8 groupings of 8, start counting rows/groups by 5 (if you want to use a 5x5 grid like I did. You can certainly do another 8x8 one; it just won't be as full and you'll need to tweak the code). The negative (shorter) leads should be bent to connect to the adjacent LED - LEDs in the same row share a common "ground". The positive leads should remain upright because you'll be wiring each of them to the LED 8 spaces away (for the first 64) or 5 spaces away (for the last 24). To repeat, negative leads get connected to adjacent LEDs until a group of 8 is created, at which point you start a new grouping (row). Each positive lead will be connected to the positive lead 8 (or 5) LEDs away. I know I've said this in three different ways, but keeping all this straight was the most confusing aspect of the project.
Solder the LEDs and add the wires
Grab your coil of black wire and your coil of red wire and eat some bananas (they're supposed to help with brain function/focus, right?). Check out the two excel screenshots to see exactly which chip pins correspond to which column or row. I sorted one set by chip pins and the other set by column and row numbers. Use these when you're wiring up the LEDs to the PCB. Have wire cutters, strippers, and fine needle nose pliers on hand for this - you'll be cutting and stripping lots of wire and the pliers will help make small bends/hook in the wire ends for easier soldering.
For the first 64 LEDs, you'll run through all 8 rows and all 8 columns. For the last 24, you'll only use the chip pins that correspond to columns 1-5 and rows 1-5, with LED (5,5) absent.
LEDs are fairly sensitive to the heat of a soldering iron, so adding even a small heat sink can help avoid damaging them. While soldering, I threw an alligator clip in between the bulb and where I was soldering the lead - even just that much more metal mass can dissipate the heat before it gets to the bulb.
As you're soldering, be super careful to not accidentally melt through the insulation of wires you've already laid down and create a short/cross. The only hardware bug I had occurred because I did just this, meaning the states of columns 2 and 6 - the 2nd and 6th LED in each group/row of 8 were tied together. Once I found out the pattern, it only took a brief search to find where the wires were crossed.
When you've finished all the soldering, throw some zip ties around the bunch of wire every foot or so to keep it organized.
When you're completely finished putting all the wires where they need to go, everything should be hooked up as follows:
- Arduino output pin 2 - chip 1, pin 1
- Arduino output pin 3 - chip 1, pin 12
- Arduino output pin 4 - chip 1, pin 13
- Arduino input pin A0 - potentiometer middle pin
- chip 1, pin 24 - chip 2, pin 1
- both chips, pins 4 & 9 - Ground
- both chips, pin 18 - Power thru 18k resistor
- both chips, pin 19 - Power
- LED row/column wiring shown in attached tables and schematic (NOTE: the way I did it, the columns are mirrored right-left relative to the schematic. This was because I counted LEDs from the left of the piano, so reading the binary numbers from the left made sense in the context, so I swapped the columns in this way. Also note this schematic is easy to find online if you search for MAX7219 schematic.)
Step 8: Writing the Software
Here I'll describe what I did,(which is by no means the best way, and then you can peruse the code. In fact, I can confidently say the way I did it is nowhere near the best way. I chose a brute force method of lighting up individual keys, which makes translating songs into my program's language extremely time consuming. I'd be interested to hear if anyone has suggestions on how to modify or change the existing code to make songwriting easier/quicker. Experienced coders will no doubt find my program ugly.
Check out the code file to see exactly what I did. Some of the math in there is weird (explained elsewhere for the most part), but it all works.
I borrowed the code and the register declarations that relate directly to the MAX7219 chips but wrote the rest (see the attribution in the code file). What the MAX7219 code does is deals with the chips directly, so that any functions I wrote later on could easily tell them what to do to the LEDs in simple language.
The way the functions work, in a nutshell, is using binary numbers for each row. I send a command to the chips that contains the row number I want and a binary number whose 1's represent which LEDs in that row will be turned on. For example, if I say maxAll(1,51), then the LEDs in row 1 of both chips will turn on in such a way that they'll represent the number 48, but from left to right: 11001100.
When figuring out the software, it's good to have a small 8x8 LED matrix on hand - that way you can plug it into a breadboard and wire up the chips and Arduino and see what happens when testing the code.
For writing songs, I made a little key that helps translate musical bars into key numbers (one of the files below).
Step 9: The End!
In the video below, I chose to set the tempo to pretty slow.
Have fun, write some cool songs, improve my code and songwriting strategy, and let me know any thoughts you have!