5

I've tried to detect shaking event using accelerometer. I've found that when I give a contiuous shake to the phone, the value difference of the acceleration is quite stable. But when I rotate the phone, there's always a big change on the value( the value is usually bigger than "shaking without rotation"). I want to focus on the shaking event, not the rotation event. Is there a way to solve the problem?

here's my code for shaing detection

public void onSensorChanged(SensorEvent event)
    {
        if (event.sensor.getType() == SensorManager.SENSOR_ACCELEROMETER)
        {
            nowTime = System.currentTimeMillis();

            float x = event.values[SensorManager.DATA_X];
            float y = event.values[SensorManager.DATA_Y];
            float z = event.values[SensorManager.DATA_Z];
            nowAcc = Math.sqrt(x*x+y*y+z*z);
            accDiff = Math.abs(nowAcc - preAcc);
            timeDiff = (nowTime - preTime);
                        //  try to get the sum of 10 samplings of accDiff
            tempAccDiff10 = tempAccDiff9;
            tempAccDiff9 = tempAccDiff8;
            tempAccDiff8 = tempAccDiff7;
            tempAccDiff7 = tempAccDiff6;
            tempAccDiff6 = tempAccDiff5;
            tempAccDiff5 = tempAccDiff4;
            tempAccDiff4 = tempAccDiff3;
            tempAccDiff3 = tempAccDiff2;
            tempAccDiff2 = tempAccDiff1;
            tempAccDiff1 = accDiff;
            sumAcc = tempAccDiff10+tempAccDiff9+tempAccDiff8+tempAccDiff7+tempAccDiff6+
                     tempAccDiff5+tempAccDiff4+tempAccDiff3+tempAccDiff2+tempAccDiff1;
            Log.i("SSSS",String.valueOf(sumAcc));
                        //when I give the phone a big & continuous "shake", it returns
                        //a value about 30~40, but when I give the phone a small
                        //"rotation", it returns a value of 80~120
            preAcc = nowAcc;
            preTime = nowTime;
            if (sumAcc>100)
            {
                SM.unregisterListener(sensorListener, sensor);
            }

            //123
        }


    }//end of onSensorChanged();

is it possible to neglect the rotation event using accelerometer? Or should I try to get the orientation change and do some computations on the sumAcc?

Jim31837
  • 1,599
  • 3
  • 12
  • 11

2 Answers2

3

You should use a filter to eliminate the influence of the gravity, there is some sort of tutorial on the docs to do so. I did something similar, in my case I was also trying to detect other movements, so your task seems a bit simpler. I can post the code next monday (If I remember).

Good luck!


I'm editing the answer to add you can use a Sensor TYPE_LINEAR_ACCELERATION if you're on Android 2.3 or higher. That is a normal acceleration sensor which discards the effect of gravity, which you definetely don't need to detect a shake event.

regards


Edit 13/06 -> I promised to post my code to detect shaking, but instead, I think it is a better idea to post this link, which gives sample pieces of code in a variety of responses. My code is very similar to one of those posted there.

Good luck!

Community
  • 1
  • 1
mdelolmo
  • 6,277
  • 3
  • 38
  • 58
  • Thanks for your advice! I'm expecting for the code. I hope I can solve this problem soon! – Jim31837 Jun 11 '11 at 16:32
  • I've tried to change the alpha(high pass filter constant), but still small rotating event result in a bigger value than big shaking. Actually I'm using android 2.2.... I'll try linear acceleration meter if I have a chance to use 2.3 devices – Jim31837 Jun 11 '11 at 17:48
0

From the code point of view, you need to implement the SensorListener:

public class ShakeActivity extends Activity implements SensorListener

You will need to acquire a SensorManager:

sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);

And register this sensor with desired flags:

ensorMgr.registerListener(this,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_GAME);

In your onSensorChange() method, you determine whether it’s a shake or not:

public void onSensorChanged(int sensor, float[] values) {
  if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
    long curTime = System.currentTimeMillis();
    // only allow one update every 100ms.
    if ((curTime - lastUpdate) > 100) {
      long diffTime = (curTime - lastUpdate);
      lastUpdate = curTime;

      x = values[SensorManager.DATA_X];
      y = values[SensorManager.DATA_Y];
      z = values[SensorManager.DATA_Z];

      float speed = Math.abs(x+y+z – last_x – last_y – last_z) / diffTime * 10000;

      if (speed > SHAKE_THRESHOLD) {
        Log.d("sensor", "shake detected w/ speed: " + speed);
        Toast.makeText(this, "shake detected w/ speed: " + speed, Toast.LENGTH_SHORT).show();
      }
      last_x = x;
      last_y = y;
      last_z = z;
    }
  }
}

The shake threshold is defined as:

private static final int SHAKE_THRESHOLD = 800;

There are some other methods too, to detect shake motion. look at this link.(If that link does not work or link is dead, look at this web archive.).

Thanks.

Harshal Doshi Jain
  • 2,379
  • 1
  • 16
  • 15