ADXL335 Accelerometer, sense motion frm any angle?

I have a Duemilanove, an ADXL335 and a dream, LOL.

The overall project is a lightsaber controller based on Arduino. It will control, via PWM 3 or 4 LED's (RGB or RGB+Amber, ~10 watts) and use an accelerometer to sense motion and trigger sound playback in synch with some basic events.

Right now, I've been doing pretty well hacking together some RGB/RGBA control routines and have moved on to get a basic handle on some Aceelerometer action.

I'm looking for some help getting my head around some of the math involved.

Since I don't really care what the absolute acceleration is, only "is not moving" / "is moving" / "is moving lots" / "Oppss.. we just hit something" (well, that would be perfect... but a clash sensor can provide hit data, and just is/is not moving would be a great start.)

I get the running averages to "smooth out" the signal, but since the starting orientation is unknown I think maybe I will have to keep 2 sets of averages running?

A "long" (IE.. 1 second or so.) one to keep track of where it "was". Then a shorter (50-60 millis?) average to smooth out transients and compare to the "long average".

As in if longAverage != (within 30) of shortAverage then trigger swingOne

Am I missing something?

Does anyone know of a site or project looking to sense motion in a similar manner? I've found lots on Accelerometers and will continue searching/reading but if someone has a suggestion I'd appreciate it.

"is not moving" / "is moving" / "is moving lots"

Don't forget, you could be "moving lots" at 1000kph, and not experiencing any acceleration (apart form gravity)! ;D

True... motion != acceleration, LOL. But, from the perspective of the project I wouldn't want it to constantly "swing" while in the car.. LOL.

How about Static/ !Static / REALLY !Static.. LOL.

We looked at this on a PIC based project a while ago and some people had all kinds of "Delta V" math that I really didn't understand in trying to get it to work.. I think they may have been dealing with some faulty host code on the chip, and/or over complicating things.... it never did... ummm, "swing" LOL.

I'll have to code up the longAverage /shortAverage idea and just see what it gives me.

I think a longAverage (Where it's settled to) compared to a shortAverage (Or even one read, if it works) and looking at the difference between the two should let us know if it's changed by a little or a lot, and cancel out "bias" from the effects of gravity.... I think?

Here’s the code I have so far… next step is to add in the sensing math and try it out. One step at a time… although it feels like I’m still learning to crawl, LOL.

int axisZpin = 0;     // Z Axis connected to analog pin 0 using 3.3v External ref
int axisYpin = 1;     // Y Axis connected to analog pin 1 using 3.3v External ref
int axisXpin = 2;     // X Axis connected to analog pin 2 using 3.3v External ref
long analogMillis = 0;      // Store millis to keep track of the last time XYZ was updated
int analogInterval = 500;    // How often to update the XYZ values. The long value just for testing to slow things down
// Setup variables for smoothing filter
const int axisAverageFilter = 10; //How many readings to average
int axisXread[axisAverageFilter];           // variable to store the value read from X
int axisYread[axisAverageFilter];           // variable to store the value read from Y
int axisZread[axisAverageFilter];          // variable to store the value read from Z
int axisXtotal = 0;                         // Variable to store the total for X
int axisYtotal = 0;                         // Variable to store the total for Y
int axisZtotal = 0;                         // Variable to store the total for Z
int axisXaverage = 0;                       // Variable to store the average of the X readings
int axisYaverage = 0;                       // Variable to store the average of the X readings
int axisZaverage = 0;                       // Variable to store the average of the X readings
int axisIndex = 0;                  // the index of the current reading

void setup()
{
  Serial.begin(9600);          //  setup serial
  analogReference (EXTERNAL);  // Set up to use Aref
  
  // I'd prefer to fill it with analogRead data so it doesn't count up from zero as the registers fill up
  // analogRead (axis_pin) not working, so commented it out as a reminder to fix later
  for (int thisReading = 0; thisReading < axisAverageFilter; thisReading++){
    // axisXread[thisReading] = analogRead(axisXpin);
    // axisYread[thisReading] = analogRead(axisYpin); 
    // axisZread[thisReading] = analogRead(axisZpin);
    axisXread[thisReading] = 0;
    axisYread[thisReading] = 0; 
    axisZread[thisReading] = 0;  

  }
}

void loop()
{

  if (millis() - analogMillis >= analogInterval){
    analogMillis = millis ();

    // subtract the last reading:
    axisXtotal= axisXtotal - axisXread[axisIndex];
    axisYtotal= axisYtotal - axisYread[axisIndex];
    axisZtotal= axisZtotal - axisZread[axisIndex];
    // read from the sensor:  
    axisXread[axisIndex] = analogRead(axisXpin); 
    axisYread[axisIndex] = analogRead(axisYpin); 
    axisZread[axisIndex] = analogRead(axisZpin); 
    // add the reading to the total:
    axisXtotal= axisXtotal + axisXread[axisIndex];
    axisYtotal= axisYtotal + axisYread[axisIndex];   
    axisZtotal= axisZtotal + axisZread[axisIndex];      
    // advance to the next position in the array:  
    axisIndex = axisIndex + 1;                    

    // if we're at the end of the array...
    if (axisIndex >= axisAverageFilter)              
      // ...wrap around to the beginning: 
      axisIndex = 0;                           

    // calculate the average:
    axisXaverage = axisXtotal / axisAverageFilter;    
    axisYaverage = axisYtotal / axisAverageFilter;    
    axisZaverage = axisZtotal / axisAverageFilter;       
    // send it to the computer (as ASCII digits)
    Serial.print("X average is: ");
    Serial.print(axisXaverage, DEC);
    Serial.print("    Y average is: ");
    Serial.print(axisYaverage, DEC);
    Serial.print("    Z average is: ");
    Serial.println(axisZaverage, DEC);
  }
}

Can I suggest you factor your code a bit more? This bit of code :

    axisXtotal= axisXtotal - axisXread[axisIndex];
.. 
   // read from the sensor:
    axisXread[axisIndex] = analogRead(axisXpin);
..
    // add the reading to the total:
    axisXtotal= axisXtotal + axisXread[axisIndex];
..
    // calculate the average:
    axisXaverage = axisXtotal / axisAverageFilter;

is effectively the same for each axis. With a few arrays and some simple indices, you'd shorten your sketch and make it easier to read and debug.

Hmmm, do you mean to store the X, Y and Z reads in a single 30 place array, then read them by say using the index and adding +10 to it for Y and +20 for Z?

I’m not sure what “Factoring the code” really means, I’ll use that big 'ols “Search” button to see what I can find, LOL.

I saw some code in an other post about using “bitwise” math or some such. I really liked the whoooshing sound it made as it flew over my head. ;D

unsigned long filteredADC0 = 0;
...
filteredADC0 = (filteredADC0 - (filteredADC0 >> 6)) + ((unsigned long) analogRead(0) << 10);

But since it made no sense to me I was afraid to use it, LOL.

Ohhh yeah, and another thought... I probably won't want to actually execute all these reads in a row, as I will be using it with a WaveShield, (And later a mini-waveshield) which I understand is "touchy" about things holding up the works too long.

So, to "break it up" and allow some more breathing room I'll probably do something like:

read/calculate the X average use millis to have it bypass a handfull of cycles read/calculate the Y average use millis to have it bypass a handfull of cycles read/calculate the Z average use millis to have it bypass a handfull of cycles

Hmmm, do you mean to store the X, Y and Z reads in a single 30 place array, then read them by say using the index and adding +10 to it for Y and +20 for Z?

Well, that's the way the compiler is going to do it for you, but there's no need for you to think of it as anything so complicated. A two-dimensional array of 3 rows of ten is much simpler.

int axisRead[3][axisAverageFilter];

As to factoring, it's a little like algebra where: 4x + 4 is more succinctly expressed as 4 (x + 1) so you collect all the bits that look the same.

It doesn't stop you adding in some "breathing space"

Ahhhh.. OK, I see.

"Two dimensional array"... another term for that "Search thingy" above. (I'm sure it's been covered before... half the battle at the beginning is knowing what terms to look for.)

OT explanation:

filteredADC0 = (filteredADC0 - (filteredADC0 >> 6)) + ((unsigned long) analogRead(0) << 10);

The shift operators << and >> act as binary (think “powers of two”) multipliers and dividers respectively.
The value four shifted right (>>) one place divides by two.
It’s easier to see in binary:
00000100 >> 1 = 00000010
So 4 >> 1 is 2.
Or, 4 / 21 = 2
Shifting right by 6 (filteredADC0 >> 6) is the same as dividing by 26 or 64.

Shifting left (<<) multiplies by powers of two.
So “analogRead(0) << 10” is the same as multiplying by 210 = 1024.

Analysing the whole thing

filteredADC0 = (filteredADC0 - (filteredADC0 / 64)) + ((unsigned long) analogRead(0) * 1024);