Is there a way to "smooth" the input from an accelerometer connected to an analog input? The values jump erratically between just a couple of numbers. I want to use the accelerometer to control objects on a computer, but right now the objects are very shaky on the screen. I thought maybe a small capacitor connected to the accelerometer's output, or some way to smooth it in the programming might work.
You could use an RC filter on the output, or you could probably produce the same effect by taking a software average of readings over a certain time period.
- Ben
I like to use an 8 or 16 sample moving average. I'll create an array and keep looping through it; each time I take a sample, I subtract the current array value from a running total, and add the new sample. Then save the new sample into the array. This means the running total always has the total of the whole array, updated every sample. Then you divide the running total by the number of stored samples. The effect is similar to just taking 16 samples and averaging them, but you get an average every time you do an ADC sample instead of having to wait for 16 samples and then calculate. It's much more responsive while still smoothing the values.
If you want to do something mathematically similar to this but without using an array, you can use the following formulation:
avg = x * avg + (1 - x)* new sample
where x is between 0 and 1.
This is performing a weighted average between your new sample and your previous average. The effect is that older samples become increasingly less and less important as new samples are accumulated, and so the newer samples always dominate the current average. The rate at which older samples become less imporant is controlled by the value of x (the larger x is, the longer older samples impact the running average).
Note that you can do this calculation using integer math (so you can avoid using floats) by doing something like:
new avg = (99 * prev avg + new sample) / 100
which is the same as
new avg = 0.99 * prev avg + 0.01 * new sample
Just make sure that you avoid integer overflows if you go the integer-math route.
- Ben
Cool, the array thing worked great. Here is how the code turned out. I'm still pretty new to this (i've only been writing code for a couple monts, and i've had arduino less than two), but it works. As of right now, it moves a circle around on the screen. Useless, but still cool.
int xin = 1;
int yin = 2;
int xval;
int yval;
int xavg;
int yavg;
int ytotal;
int xtotal;
int xarray[16];
int yarray[16];
int i;
int count = 0;
void setup() {
Serial.begin(19200);
}
void loop(){
xval = analogRead(xin);
yval = analogRead(yin);
xarray[count] = xval;
yarray[count] = yval;
count ++;
if (count == 16){
count = 0;
}
xtotal = 0;
for (i = 0; i <= 15; i ++){
xtotal = xtotal + xarray*;*
- }*
- ytotal = 0;*
- for (i = 0; i <= 15; i ++){*
_ ytotal = ytotal + yarray*;_
_ }_
_ xavg = (xtotal / 16);_
_ yavg = (ytotal / 16); _
_ Serial.print(xavg);_
_ Serial.print(",");_
_ Serial.print(yavg);_
_ Serial.println();_
_}*_
Well...you're calculating the new average every time, which gives the same result as the method I described. However, it uses up more processor time. That may not be an issue if you have plenty of CPU to spare.
count ++;
if (count == 16){
count = 0;
Note that you can also replace this with the more efficient:
count = (count + 1) & 0x0F;
And if you make count an unsigned char it will run around twice as fast. I assume that probably will have no impact on the overall performance of this application, but it can still be good to consider such things in case you're ever writing a program that does have tight timing constraints.
- Ben
Did you see the Smoothing example: http://www.arduino.cc/en/Tutorial/Smoothing?
It's pretty similar to what you came up with.