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
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
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.
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.
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.