Doodlebox! Portable Arduino Piano

by Spaghettibrot in Circuits > Arduino

1846 Views, 24 Favorites, 0 Comments

Doodlebox! Portable Arduino Piano

test1.jpg
Arduino Doodlebox

Take some wires, a breadboard and a button. Load the button example from the arduino ide and voilĂ , you just made your first project. With the introduction of the Arduino, tinkering with electronics has never been more accesible.

Now add a few more buttons and a piezo speaker and you have built a simple arduino piano. Recently I bought myself a Kalimba, I was amazed how it fits just into the palm of my hands and even though by default it had no semitones, I was able to easily play a variety of songs.

Inspired by this, I wanted to create a portable piano powered by an Arduino which:

  • is portable and powered by battery
  • is able to play at least one octave
  • has all of the notes accessible by at least one hand while also holding it

And that is how I came up with this design in the end. The best thing about it? I am going to teach you how to build one yourself.

This project consists of the following parts:

  1. A word about Tinkercad
  2. How to create the circuit
  3. How to create the code
  4. How to assemble it
  5. Lessons learned (optional)

Supplies

IMG_20230223_211604 - Kopie.jpg

In terms of tools the following will be necessary:

  • Soldering iron & some solder
  • Cutter knife
  • Flush cutter (for cutting and stripping the wires)
  • Screwdriver
  • 3D printer (for the case)

In terms of materials needed to assemble one unit:

Optional:

For the lcd and piezo it would be better to use the ones I mentioned, otherwise they might not fit into the printed case. Make sure that you buy a passive and not an active piezo buzzer. Also look out that the lcd is the one with the i2c controller, as this will save you a lot of work.

If you want to permanently use the arduino in this device, feel free to just solder wires to it. Otherwise consider using jumper wires.

Working With Tinkercad

For the circuit and code part of this project, I opted to use Tinkercad’s circuits feature. To get started with circuits, check out this well written guide on their page.

One of the main advantages I see with Arduino in general is, fast prototyping. You take your breadboard, place your componentes and wire them up with some jumper wires and upload your code. Tinkercad circuits takes it a step further and relieves you of the physical wiring part. Why would that be so important? Especially when prototyping in the early stages, designs are quick to change, being able to easily make modifications while also keeping track of your circuits wiring in an orderly fashion helps you avoid issues in the later stages and saves you a lot of time debugging. As an added bonus on top, Tinkercad creates a wiring diagram out of the circuit. The diagram is created on the go, while you drag and drop your components into the circuit.

With that in mind we can solely concentrate on creating the circuit itself, writing the code and even verifiying its functionality on a virtual Arduino inside of Tinkercad.

The Circuit

Doodlebox_breadboard.PNG
buttons.png

Do note, that Tinkercad circuits uses an Arduino Uno and I will be using an Arduino nano in the actual build. The actual wiring will differ from the one created in circuits.

The first step of the actual project involves creating the circuit. We can structure the parts connected to the arduino into three groups:

  1. Passive Piezo Buzzer
  2. 16x2 LCD (I2C)
  3. Buttons

For each of these it will be important to know, what properties these parts have (e.g. resistor values) and which pin they will they be connected to.

The piezo buzzer is an easy one. Since it is a passive buzzer, it will be driven by a pwm signal. All you have to do is make sure it is connected to a digital pin on the arduino, capable of driving a pwm signal. This is discernable by the ~ symbol next to the pin. To make sure the sound is not too loud, I added a 2.2k Ohms resistor in series. A different value might work better for you. Another option woul be going for a potentiometer with a range of up to 10k Ohms, tune it to your desired volume.

Thanks to using an lcd with integrated i2c controller, all we have to worry about is connecting the SDA, SCL, GND and VCC connection. SDA and SCL stand for the serial data line and serial clock line of the i2c bus. Just like with the pwm Signal, you will have to make sure to connect to the SDA / SCL capable pins. Those may vary between different arduino boards. Make sure to check the pinout in the documentation of your arduino. VCC will be connected to 5V on the arduino.

For last part we have to connect the switches/buttons. By default the pins in one row will be connected internally, when pressed, all pins will be connected. For this schematic the buttons are wired in a pull down configuration. If we refer to the wiring numbers of the second picture:

  • Pin 3 Button <->5V on Arduino
  • Pin 2 of Button <-> digital Pin on Arduino
  • Pin 2 of Button <-> 10k Ohms resistor <-> GND

When the switch is open, the resistor will pull the digital pin to GND, meaning a LOW state will be visible for the Arduino. Once we push the button, pin 2 and 3 will be connected. With that we will have the 5V that on the digital pin connected to pin 2 and as such the Arduino will see the digital pin as HIGH state.

The Code

lcd.PNG
buttons_press.PNG

For the code I used Tinkercads visual style of programming, using predefined codeblocks. You can drag and drop the code snippets and inspect the logic behind it in real time in the text editor. Unless more advanced programming features are needed, this might be a good way to concentrate on programming the logic of your code alone, without having to worry too much about the code syntax.

As with the circuit before, there will be 3 main components, we need to write code for. The piezo buzzer, the lcd and our buttons.

Piezo buzzer

Our main codeblock for the piezo is the tone() function, which is called a "play speaker on pin xx with note yy for zz duration" in codeblocks. What we need to know is, what input does this function expect for a certain note? As mentioned before, the piezo is driven by pwm signal with a varying duty cycle but with a set frequency. With a varying duty cycle (how long is the signal HIGH, how long is it LOW) the buzzer will see different RMS voltage values, which will result in different tones. Luckily the code block already takes care of that and we do not have to specify a certain duty cycle to get to our desired note. As such we only have to find which integer corresponds to the note that we want to play. For the start of our octave I went with the note C5, which corresponds to the int 60. To find out which note corresponds to which integer, change the editors view to "Blocks + Text". The corresponding note to each integer will be displayed in a comment next to your tone function.

LCD

The most important part for the lcd will be getting the adress right, for the configure block. The address of your actual physical lcd depends on whether the a0, a1 and a2 bridges were soldered or not. The easiest way to determine this is by hooking up your lcd to your arduino and then going under "examples -> wire -> i2c_scanner". Open the serial monitor on your Arduino and wait for the sketch to find the adress of your device. Once found add it to the corresponding field of your configure block. Now to actually display characters on your display, we do the following:

  1. Clear Screen, to delete previous display
  2. Set cursor to column 0 row 0, to tell lcd where to start writing
  3. Print your desired text
  4. Set cursor to column 0 row 1, to write the row below it
  5. Print your desired text

Note that it can only display a maximum of 16 characters at once. Feel free to play a little bit with the "on Display" block, as it offers a few more options, such as autoscroll if you want to display more than 16 characters in one row.

Buttons

Just like with the Kalimba, we want to press the button once and then have it play a note for a certain duration and not have it play the note for all the time while holding it. To do so we will need an edge detection, in this case we want the Arduino to look for the rising edge, when the button is pressed. In other words, for the Arduino to play the tone, the previous button state must have been 0 and the current one 1. That means at the end of every cycle, we will now have to store the last button state, before going into the next program cycle.

  1. Check current button state and save it
  2. Check whether previous cycle button state was 0 and current is 1
  3. Play your tune if true, otherwise do nothing
  4. Save the current button state as previous cycle value
  5. Cycle repeats from step 1.

This is a nifty little trick, that you will be able to use in a variety of projects. Apart from the use case mentioned above, you could also use it to count the times the button has been pressed in step 3. For a future feature this could mean, if there were a "play by notes" mode, it could count the amount of times you pressed a wrong note and play the song wrong.

Code verification

From here on out the simulation inside of tinkercad can be started with the "start simulation button" and you can simply interact with all the elements that you placed into your circuit.

  • Do the buttons play the specified note?
  • Does the lcd display the correct text?
  • Do the buttons work reliably with your chosen logic?

For reference, feel free to check out the tinkercad project. Note that this is still different code than the final one to be used. But this is already fully functional Arduino piano, that can be played in the Tinkercad virtual environment.

The Assembly

slice.PNG
IMG_20230226_163539 - Kopie.jpg
IMG_20230223_213037 - Kopie.jpg
IMG_20230223_213605 - Kopie.jpg
switch assembly.jpg

To simpify the assembly, I made three changes as opposed to the Tinkercad project:

  1. Arduino nano will be used instead of Arduino Uno, resulting in slightly different pinout for the lcd only! (SDA=A4, SCL=A5 ont the Arduino nano)
  2. Buttons will be used in a pull up instead of pull down configuration, resulting in inverted logic
  3. In pull up configuration, the digital pin is connected to 5V via an internal pull up resistor, meaning in the default button opened state, the digital pin will be at 5V
  4. When the button is pressed, the digital pin will be connected to GND over the bridged button connection and thus will be at a LOW state
  5. Built in internal pull up resistors are used, making the external 10k Ohms resistors redudant

QUICK Guide

  1. Flash the provided code onto the Arduino Nano
  2. Assemble the top parts of the build.
  3. Prepare 3 miniature switches to pcb (picture 3) + their caps + solder according to wiring diagram
  4. The power switch and its battery wiring
  5. Install the display and connect to Arduino (SDA=A4, SCL=A5)
  6. Mount the Arduino at the bottom left using the double sided tape
  7. Screw the piezo buzzer to the bottom part and solder one end to the Arduino pin 11 and the other to GND including your desired resistor or the 2.2k Ohms resistor
  8. Solder GND on all the switches to each other and from there connect it to one GND pin of the arduino
  9. Solder the digital pin connections to the switches according
  10. Check your solder connections visually and turn on the device, set your desired contrast on the lcd by turning the potentiometer
  11. If all is well works like in the simulation from Step 3, align the case using the 3 noses at the bottom of the case and screw it shut

To start off, you want to be printing the top and bottom case and three of the smd button caps. For the top casing at the very least I recommend using one of the less brittle materials, such as petg. I used 0.2mm layer height and anything from 15%-25% infill should work fine. Make sure to have to have supports connecting to build plate only activated. Set the prints with their face sides towards the build plate when slicing, as shown in the picutre. The prints took me about 10h and about 85g of material.

Once printed we want to solder in our three miniature buttons onto the universal pcb, so that those can be fitted to the top of our case. For the pcb with two buttons on it, make sure the switches have 2 pcb holes spacing in between them. Then use your cutter knife to mark the lines where you will be breaking off the pcb to its final size and break it off. Make the final fit using your flush cutters. Make sure to trim the side that will be touching the face side of the case, as indicated in the third picture using your flush cutters instead of the cutter knife. The other sides should have about 2 holes of distance. Sliding in the pcb now might be a little tight, so you might have to flex the pcb a little when trying to push in. Now solder pin 3 of the buttons to GND and pin 2 of each button to their respective digital pin on the Arduino as indicated in the wiring diagram.

Now make install the 9V battery and have + soldered to one end of the power switch and - of the Battery end to GND. The remaining side of the power switch is then connected to Vin. Install the Display next and connect SDA to A4 and SCL to A5 on the Arduino. VCC goes to 5V and GND to GND. Screw the piezo buzzer to the bottom part and solder it on the Arduino pin 11. Doing this step before installing all the switch connections should make this a little easier.

Once that is done, all there is left are the mechanical switches. As opposed to the miniature buttons, those only have 2 contacts, one side will be connected to their respective digital pin (picture 5) and for the other side, interconnect all the remaining pins of the switches, using one solid piece of wire. From there you can simply connect it to GND of the Arduino.

Lessons Learned

This was a fun little project to work on. Given how trivial this project seemed though, as it basically only reads button inputs and converts them into sound, quite some trial and error was involved. As such there are a few thing that I would do differently in the future:

  • M3 brass inserts to make the threads more durable
  • Slide open port for battery
  • Add external potentiometer to change volume
  • Replace top row miniature buttons (work much less reliably than their mechanical brothers)
  • Add a better mounting option for the Arduino and and external usb port
  • Better Power supply such as 4xAA batteries instead of 9V block, where 4V are dissipated at the voltage regulator
  • Add advanced LCD functionalities

In case this insipired you to make your very own Arduino music device, here are a few more ideas:

  • Slider potentiometer to modify the tones
  • Add a rotary encoder
  • Replace the passive piezo buzzer with Speaker + driver
  • Add a playback mode, to play back certain songs
  • Add a play along mode with stats at the end
  • Add a sequencer mode, where it records your notes and you can modify the sequence afterwards
  • Add midi compatibility, so you can use it to play notes on your computer