I built an alarm clock powered by a Pro-Mini which has an accelerometer in it. I wanted the user to be able to shake the alarm clock in order to silence it. Everything worked great on a breadboard, but not so well when it was assembled. The problem is the vibrations from the speaker are getting picked up by the accelerometer. So the speaker is causing the alarm to be silenced instead of the user. If I increase the threshold so the sound doesn't silence the alarm, then the user can't shake it enough to silence the alarm. Maybe if they banged it on the table, but that's not what I'm going for.
Basically what I'm doing is taking two reading of the accelerometer axes. Then I see which of the three axes has the greatest change between the two readings. Than I compare that to the threshold I set. If the axis change is greater then the threshold I assume the alarm is moving and the alarm is silenced. I've got my code on Gitbub: http://bit.ly/Hvazq1
The function is: bool ClockAccel::isMoving(uint16_t threshold)
I'd like to be able to distinguish between user shaking and speaker vibrations, but I have no idea where to start. I'd appreciate any advice.
If I can't figure this out, my backup plan is to see if I can use a tilt switch instead of the accelerometer. But then I'd have to have a new PCB made up, so I'm hoping I can figure this out using the accelerometer.
There is a small part called a "shake switch" that is included in many cheap handheld game controllers. It should work much better than an accelerometer. If you don't have a game controller that you can dismantle, check the thrift or secondhand shops (or buy the switch online).
Here is a link describing one such device, with test circuit: http://www.electroons.com/blog/2013/08/sw18020p-vibration-switch-shake-switch-testing/
Should not be too hard filter out vibration, as they differ in 100x times or so, for example vibration -( manually ) a few Hertz, and small speaker > 100 Hz. Search for Low Pass Filter, I think arduino library posted somewhere. Even build -in IDE /Analog/ example "smoothing" may do a trick - just increase an averaging array to 100 samples or so. Little bit more complicated than switch, same time you may develop gesture recognition, when only special manipulation to alarm clock would stop a buzzer -);
Magician:
Should not be too hard filter out vibration, as they differ in 100x times or so, for example vibration -( manually ) a few Hertz, and small speaker > 100 Hz. Search for Low Pass Filter, I think arduino library posted somewhere. Even build -in IDE /Analog/ example "smoothing" may do a trick - just increase an averaging array to 100 samples or so. Little bit more complicated than switch, same time you may develop gesture recognition, when only special manipulation to alarm clock would stop a buzzer -);
I'll have to do a little test and see how long it takes the accelerometer to respond with updated data. I think it's kind of slow and it may not be practical to take a bunch of reading for a low pass filter and tie up my sketch on just the accelerometer. I've got PWM outputs that need to change and test for pushbutton inputs at the same time. But if it's fast this might do the trick.
I did order some vibration sensors (shake switch), but they're coming from China, so it could be a while.
I got my shake switch out of game controller that someone threw away.
The accelerometer takes about 1mS to update. For some reason I thought it was longer. So I put this Low Pass filter in:
bool ClockAccel::isMoving(uint16_t threshold)
{
int currentAccelVal[] = {0,0,0}; // Stores the 12-bit signed value
int filteredAccelVal[] = {0,0,0}; // filter accelerometer values
uint16_t maxAxisChange = 0; // value of the axis with the maximum accelerometer value
float filterVal = 0.9; // smooth the incomming data. O = no smoothing, 1 = infinite smoothing
for(int k = 0; k < 15; k++) // take 15 samples
{
readAccelData(currentAccelVal); // Read accelerometer values
// Filter the valuse. Numbers added to currentAccelVal try to normalize to zero when still
filteredAccelVal[0] = ( (currentAccelVal[0] + 48) * (1 - filterVal)) + (filteredAccelVal[0] * filterVal);
filteredAccelVal[1] = ( (currentAccelVal[1] - 15) * (1 - filterVal)) + (filteredAccelVal[1] * filterVal);
filteredAccelVal[2] = ( (currentAccelVal[2] - 1000) * (1 - filterVal)) + (filteredAccelVal[2] * filterVal);
}
// see which axis had the most change
for ( int i = 0; i < 3; i++ )
{
filteredAccelVal[i] = abs(filteredAccelVal[i]); // make everything positive
if ( filteredAccelVal[i] > maxAxisChange )
{ maxAxisChange = filteredAccelVal[i]; }
}
// If any axis was greater then the threshold then we're moving
if ( maxAxisChange > threshold )
{ return true; }
else
{ return false; }
}
This filter works very well. I use 300 for the threshold. The vibrations from the speaker usually are less then 100.