My brother makes these cases himself, but for the inside he asked me if it would be difficult to do in an Arduino project. Hell no, I replied :)
In fact, it was really easy to do, and only took me a couple of hours (design, drawing it, putting it together, programming, testing/debugging, improving, ...). As I didn't really find any references that took te same approach as I did (with a short loop to get better responsiveness on the button press), I thought to share this with the world.
Not much special to say about that. RGB Led, two push buttons and a couple of resistors, that's it.
So, what's so different ? I only found approaches that set the interval the light needs to be on, and then off, and put that entire time interval in one loop call. I found this not workable (especially not in a live environment like a concert), as this means the press of the button is only checked right before the next cycle. So, if you have 60 BPM, there's a beat every second, and so only 60 moments it gets checked whether you pressed one of the buttons. So, a bit simplified: uno is at 16 Mhz (megaherz = 1.000.000 'ticks' per second), so has 16.000.000 ticks per second. Taking into account the normal length of a button press (especially done with the foot on a pedal during a concert) this means a significant portion of the time the button press is missed because it fell completely during a single call to loop().
In short: responsive buttons means trying to get the loop() execution time as low as possible, which in turn means not using the delay() function.
Another small problem (in my tests the error wasn't really noticable against an actual metronome) is that there is a small amount of time it takes to execute the code, and the delay() calls don't take that into account. So two delays (one for LED on, the other for LED off) of 250 (microseconds) should give a BPM of 2x250ms = 500ms = 0,5 sec ==> 2 BPsec ==> 120 BPM. However, let's say the execution of the rest of the code takes 10 ms, the time it takes to get to the next loop is not 500ms, but 510 ms. This would introduce a very small offset to your BPM setting (and no good way to correct it, as it's hard to determine exactly what the overhead is).
With these two arguments in mind, I've used a more robust manner, which starts of by using the internal timer (ticking in microseconds), and just looking based on the difference between the current timestamp and the baseline whether the light should be on or off (taking the BPM into account). This should be by far more accurate, and is more robust in terms of responsiveness and scalability (if you tweak the code to do more things - like storing or sending some values around, playing audio markers, read potentiometers, ... - the metronome will keep ticking away as close to the real BPM as possible, even for very long periods of time (not the case in the previous approach).
I'm well aware that it would be pretty easy to expand this to make it so it can handle any BPM, and you don't have to hardcode them, but that's not what my little brother wanted.
- Instead of using an arduino uno, I would like to go for something a lot smaller (and cheaper), I'll blog when that's done.
- For myself I would probably prefer a version with a potentiometer to set the BPM rate, and so also a small display to show what BPM we are at. So, one push button (the 'Next' one) replaced by a potentiometer and interaction with a screen.