I’ve completed a simple tap tempo that works great with a momentary button utilizing the ATTiny85. I have it averaging the last three readings to smooth things out a little and I’ve been pleased with it.
My next challenge was to create a version for my drummer that would allow a reed switch to attach to his drum kit and sense a magnet passing the switch in place of the button I’ve used previously.
The issue I encounter is that for each cycle the magnet passes the reed switch twice, once going down and again going up. I only want it to count the downward stroke, as the upstroke might not be in time and provide innacurate readings. I’ve tried a few variations but I’m just not savvy enough to figure it out. I’m also not exactly sure what terms I should be searching to find the appropriate operators for this. I’m sure it’s something super simple and obvious, but I just don’t know the correct terms to start with. Any assistance would be greatly appreciated.
The moving average code is handy, but not absolutely necessary, especially if it interferes with my intended goal for the reed switch setup.
Here’s a diagram showing how the magnet interacts with the reed switch for each cycle. I only want it to count one of the two passes:
Here is the code I originally used for the momentary switch and it works great for that use case.
//Working copy of ATTiny85 beatbug with TM1637 display.
//Includes the moving average library to display agerage of last three beats.
// One side of button goes to GPIO2 (pin 7) and the other goes to ground.
//
// ATMEL ATTINY85
//
// +-\/-+
// A0 (D 5) PB5 1| |8 Vcc
// A3/ DIO (D 3) PB3 2| |7 PB2 (D 2) A1/SCL
// CLK(D 4) PB4 3| |6 PB1 (D 1)
// GND 4| |5 PB0 (D 0) SDA
// +----+
#include <TM1637Display.h>
#include <math.h>
#include <Bounce2.h>
#include <movingAvg.h>
// Instantiate a button object
Bounce2::Button button = Bounce2::Button();
// Module connection pins (Digital Pins)
#define CLK 4 //pin 3
#define DIO 3 // pin 2
#define BUTTON_PIN 2
// Variables, button state, and debounce
int buttonState = 0;
int lastButtonState = HIGH;
int reading;
long lastBeat;
// Set up display library
TM1637Display display(CLK, DIO);
// Names the moving average. Number in () sets the number of values to evaluate
movingAvg bpmavg(3);
int calculateBPM(long thisTime, long lastTime) {
long elapsed = thisTime - lastTime;
double bpm = round(1000. / elapsed * 60.);
return (int)bpm;
}
void setup() {
// BUTTON SETUP
// SELECT ONE OF THE FOLLOWING :
// 1) IF YOUR BUTTON HAS AN INTERNAL PULL-UP
button.attach( BUTTON_PIN , INPUT_PULLUP ); // USE INTERNAL PULL-UP
// 2) IF YOUR BUTTON USES AN EXTERNAL PULL-UP
// button.attach( BUTTON_PIN, INPUT ); // USE EXTERNAL PULL-UP
// DEBOUNCE INTERVAL IN MILLISECONDS
button.interval(5);
// INDICATE THAT THE HIGH STATE CORRESPONDS TO PHYSICALLY PRESSING THE BUTTON
button.setPressedState(HIGH);
// Begins the averaging
bpmavg.begin();
// Set display brightness
display.setBrightness(0x02);
// Record first hit as now
lastBeat = millis();
}
void loop() {
// UPDATE THE BUTTON
// YOU MUST CALL THIS EVERY LOOP
button.update();
if ( button.pressed() )
{
// Calculate bpm and display average result
long thisBeat = millis();
int bpm = calculateBPM(thisBeat, lastBeat);
int avg= bpmavg.reading(bpm);
display.showNumberDec(avg);
// thisBeat is now lastBeat for the next button press
lastBeat = thisBeat;
}
}
Thanks for that info! I never thought of using two reed switches. I think I can manage to fit two of them in that space with enough travel to trigger both. I’ll just have to redesign my 3D enclosure and make a new PCB.
Side note- That website you linked looks pretty awesome. I’ll definitely be exploring that more. I never even knew something like that existed. Sort of like the Falstad simulator. I like it!
I’ll see if I can figure out how to integrate that workflow into my current sketch.
Before I looked closer, I thought it would be simple but as you previously or subsequently stated, you need the order. A bit trickier.
And a large constant. I haven't worked with reed switches much, and I'd want to do a back of the envelop calculation about how fast the magnet moves across the gap… this may be that rare case where interrupts are useful.
I threw in the towel, so to speak, when I made my dual beam cat detector which way was he going, in to or out of that other cat's territory, not that I was ever able to do anything about it… which brings up another way to see the event.
Instead of hearing, could you reliable detect by sound that the pedal did its thing? That would put you back where the original solution for the momentary switch might work.
You might be interested in using a leaky integrator, it may do a better job as well as being less expensive.
Here’s how the code works with the pushbutton. I’m posting it as my source of truth for those that might be curious about it.
I’m using this as a musician and the BPM will seldom go above 300, so I’m thinking a reed switch should be up to the task. Realistically it will probably hover in the 120-180 range most of the time. It’s a handy little tool to use when playing in a big band because it lets me keep track of the tempo and I can pinpoint exactly when things start to fall apart. The trumpets like to blame the rhythm section and it’s stopped a few moments of “intense fellowship” in their tracks before things got going.
Use a bar shaped magnet an orient it parallel to the long axis of the reed switch. The steel pins of the reed switch conduct the magnetic field to the moving end inside the glass enclosure and force the switch ends to close. there is only a few thousands of an inch opening between the switch ends. If you don’t make the magnetic field parallel to the switch, the timing will vary based on the orientation of the magnetic field each time the drum stick is moved.
I don’t have enough space for a bar magnet. I’ve already got the mechanical bits down. I’ve also already built the first prototype with the reed switch and it works great (mechanically), I just need it to record half as much as it does right now. If you look at the bottom of a hi-hat stand, the magnet will go on the chain and the reed switch enclosure will attach to the square metal framing on the bottom. This is the most effective place to put the magnet.
I previously made a similar device that used a piezo (attached to the bottom of the two cymbals) with a potentiometer to adjust the sensitivity. It worked pretty well, but i wanted something more accurate than a piezo disk that still contained parts that did not require a power source for that portion of the device.
I was flipping an easy-over egg when it occurred to me that all you might need to do is ignore every second rising edge, no matter which direction the pedal is going.
My tablet won't let me attach the picture I drew. But think about it.
Using one sensor that picks up both directions, the time between two forward triggers is the same as the time between two reverse triggers.
That would mean no changes to the hardware, and probably simple software charges.
If you are going to be missing events, you'll be screwing up. Maybe you are saying you need something that won't.
A bit of filtering for missed events might be needed in any solution, perhaps not processing a measurement that is obviously too much of a change.
Both ideas recover, again something that just decides not to act on data that seems unrealistic might work.
I see the code also publishes the BPM on every added measurement. Any system might work better if the output rate was not coupled directly to the measured activity.
In higher frequency circumstances, an interrupt might count events, and at some unrelated rate the main process would do some calculations based on the time between reports and the number of events during the reporting period. This has an advantage of automatically averaging the frequency. I don't think that would work here, as one would prolly want to see BPM sooner than a few bars between updates.
In the rock and pop world lots of guys will use a commercial device similar to this (which has since gone out of business after he retired) on the snare. I haven’t heard of many using the kick, but I bet lots of guys do.
In the jazz world, time is most consistently kept with the hi-hat and the string bass player (that’s me). The bass player provides a constant pulse and the hi-hat is usually on beats 2 and 4 to emphasize that swing feel. All the other pieces of the drum kit (kick, snare, toms, and cymbals) are just flavor and spice to bring it all together.
@alto777 and @Brazilino great thoughts and I agree it would be nice to keep my current setup.
Since marking tempo is such a dynamic endeavor and literally changes beat to beat I wouldn’t be too terribly worried about the occasional missed beat. I’m actually counting on that happening from time to time as there is no guarantee the mechanical action will travel the entire distance every time (human component either by accident or by design).
This device is something designed to give ballpark accuracy. Even if the math is dead on, it’s still controlled through human action and live music ebbs and flows over the course of a tune. The only reason I used the moving average of the last three reading on the switched version was to smooth out the numbers a little. That average was only good for about 3 seconds and honestly I could probably delete it and be just fine with it. In use I don’t think I ever noticed a practical difference.
I do like the idea of looking at the rising edge. I’ll see if I can figure out the right terms to use so I can make that work. That emulator will definitely make this much simpler than flashing my ATTiny85 over and over.
I would use an optical "slot" sensor with an opaque "flag" on the pedal that would block the sensor when the pedal was pressed down, no mechanical switch bounce.
Your code already finds edges. Here's you sim modified to skip every other edge. IDK and IDC if it's rising edges or falling edges.
I also added, with the help of AI, a synthetic drummer, who can press the button at a rate under control of a slide fader.
This should make testing this, and any other approach, somewhat easier.
If you want to use the button, just delete the white wire, which is the only connection between the synthetic drummer's output and the input to your process.
I should have made a few hard numbers into constants, but it is easy enough to go back to looking at every edge. Or just run the original simulation.
I'll fix that when I am back from in the lab.
Possible because the sketch is light on resource usage and has no blocking code.
Note: I don't use comments, much. So the AI comments, well let's just say I only now noticed they are a bit out of sync with the changes for the double rate… one reason I hate comments is that they tend to go wrong, fail to be maintained or are inherently gratuitous to begin with.
I described the synthetic drummer concept in a few lines of prose, showed the AI your sketch and it said it understood perfectly, evidence for which is the only mistake it made, even though I told it about the GPIO pins it had available, was to use one already working with the display.
That’s a pretty cool sketch! Thanks for sharing it. I always forget that AI can do these things for us. I made a few wiring changes just to test it out.
I added a switch so I could easily swap between the synthetic drummer and the tap tempo.
Moved the LED wire to the switch so it would light up for either setup. When testing I noticed the LED would flash with the fader and not the tap tempo, which might be distracting.
I think I might try to implement this change and test it out. I’ve got tons of little 9mm potentiometers and that’s easy to add to my enclosure.