syntax for shakeControl with accelerometer

Hi there,
I'm building a controlDevice as multiple-purpose-interface with some sensors in it.
The beginning is the LIS3LV02DQ 3-axis Acc from ST-Electronics, which comunicates via I2C to the Arduino.

After connecting the Acc like shown in this tutorial:
[I can't include links in my first post.... On the next post you'll see the links.]
I got the values between -2048..+2048 for +-2g.

Here's my syntax problem:
I want to have something like the shake-control in the iPhone.
That means:
Shake the device on the right and turn on the led on the right side.
Shake the device on the left and turn on the led on the left side.

First I detected the peaks of a shake.
I decided to set the threshold > 1g.

My not correct working loop to detect a shake:
if(x_val >= 1024){ // threshold >= 1g

  • digitalWrite(ledPin_x1,HIGH); // led to show the right-shake*
  • digitalWrite(ledPin_x2,LOW); // led to show the left-shake*
  • delay(500); // light the led for a half second*
  • } else{digitalWrite(ledPin_x1,LOW);} // else: take the led low*
    if(x_val <= -1024){
  • digitalWrite(ledPin_x2,HIGH);*
  • digitalWrite(ledPin_x1,LOW);*
  • delay(500);*
  • } else{digitalWrite(ledPin_x2,LOW);}*

The two leds light up rather randomly, because there are two peaks on each movement.
One at the beginning of the motion and one at the end of the shaking-motion.
--> The signal is not clear.
Sometimes the first peak triggers the motion and sometimes the "end of shaking motion" triggers the action.

==> Does anyone have a idea how I can fix that problem?!?
I'm not a great coder and maybe my brain is not flexible enough to get the right lines of code written.... :-/

So I would be very thankful for some help!
Regards from Germany,
bitreacter

Here are the missing links:

After connecting the Acc like shown in this tutorial:
www.nearfuturelaboratory.com/2006/09/22/arduino-and-the-lis3lv02dq-triple-axis-accelerometer

Here's a little diagram of the peaks I recieved in x-direction with one smooth shake:
http://picasaweb.google.de/lh/photo/udx1D6RDfzKPqzco5_sGuw

Cheers,
There's two ways you could solve the problem, I believe.
First, you could set a somewhat lower threshold and always detect the pair of peaks.
Second, you could use a variable to keep the time when the last peak occurred, and ignore further peaks until X milliseconds have passed.
Also, you probably shouldn't lock the data acquiring in the delay to light the led.
I'd try something like this:

long lastpeaktime=0;   //time of last peak, in ms
int timethresold=300;  //time to ignore peaks, in ms
int ledontime=500;      //time the led is left turned on, in ms

// loop:
{
long currenttime=millis();
if (currenttime>lastpeaktime+timethresold)
   {
   if(x_val >= 1024)
      {
      digitalWrite(ledPin_x1,HIGH);
      lastpeaktime=currenttime;
      }

    if(x_val <= 1024)
      {
      digitalWrite(ledPin_x2,HIGH);
      lastpeaktime=currenttime;
      }
   }
if (currenttime>lastpeaktime+timeonled)
   {
   digitalWrite(ledPin_x1,LOW);
   digitalWrite(ledPin_x2,LOW);
   }
}
//end loop

Messy code.... hope it works:P
You'll need to obtain a good timethresold value empirically :wink:

Are you sure the second peak is not the result of the sensor shortly shaking when you start/stop the motion?

Hi and thanks for your replies!!
@fdufnews:
Exactly! I start a smooth swing to the right side.
--> there's a peak at the beginning and one at the end.
the strength depends on your violence.

@dsc:
I tried your solution with the time, but it is hard for me to get the connection between codeflow and time.
It was easier to send data via serial.
I recorded the data after each loop with hyperterminal and plotted a little excel-table.
==> If there's a fast movement, the g-values move very fast after each loop.
Here's my solution:

  • I store the last value
  • I read the new value
  • If value is greater than the threshold
  • Substract the new value from the old
  • If the difference is great enough, there was a fast movement
  • --> light up the led for one side.

Rather simple, but works really good for detecting a jiggle.

Here's the loop as code:

last_x_val = x_val;
x_val = xVal();[hr]// get the sensor value from the xVal function
///////// ugly method to get out the sensors offset...
x_val = map(x_val,-2048,2048,-2048 - offset, 2048 - offset);


delta_x = last_x_val - x_val;      // if delta_x > 0 --> the values rise up
Serial.print(delta_x);            // if delta_x < 0 --> the values go down
Serial.print("\t");

if(x_val > 1000){
 if(delta_x < -1500){
  digitalWrite(ledPin_x1,HIGH);
  digitalWrite(ledPin_x2,LOW);
  delay(500);[hr]// delay is just for degugging...
 }
  else{digitalWrite(ledPin_x1,LOW);}
}  else{digitalWrite(ledPin_x1,LOW);}

if(x_val < -1000){
 if(delta_x > 1500){
  digitalWrite(ledPin_x1,LOW);
  digitalWrite(ledPin_x2,HIGH);
  delay(500);
 }
  else{digitalWrite(ledPin_x2,LOW);}
} else{digitalWrite(ledPin_x2,LOW);}

It is normal you are measuring acceleration (the derivative of speed).
Listen for a simple example (a translation along one axis):
At the beginning your sensor is static so you get 0g
You start moving, speed changes from 0 to some positive value giving a positive acceleration.
The movement continue at constant speed so giving 0g (no acceleration at constant speed)
You stop moving, speed changes from some positive speed to 0 giving a negative acceleration.

Here's a graph of the movement.

  • The purple curve is the measured value for acceleration
  • The blue curve is the differential between last value and value

http://picasaweb.google.de/lh/photo/wJvPrIsUySmsr684Z7a6Ug

My code works rather well, I just hope there will be no complications.
I just use the actual value and the last value.
If the derivate is strong enough at the right time it works good.
Maybe I should also measure the time, as mentioned by DSC to verify the effect.

If I stop the serial-stream, the Arduino runs faster through the loops and maybe measures more often.

I'll try to modify the code for a more reliable output.

Thanks a lot for your suggestions!

Hello bitreacter,
what you are doing looks interesting, can you share your code?
cheers!

As mentioned above, you will have to debounce the "trigger" condition, or it will keep triggering. You also can't really expect someone to "bump left" or "bump right" with any degree of dexterity.

Just use shaking as a general nondirectional command, and maybe check the overall tilt after the shake subsides to decide which direction your user intended to indicate.

My similar code is here:

http://www.arduino.cc/playground/Main/ADXL330

It watches the force of shaking to adjust the "mood" of an RGB LED, sleeping, upset, calming, etc.