Search code examples
androidaccelerometer

Android: Using the accelerometer to detect a flick


I'm trying to develop an app where the user can hit an invisible drum using the motion of the phone. So that when the phone is flicked downwards a drum is sounded at the end of the flick.

I have managed to get 90% of this working, by detecting when a large, quick movement suddenly stops. But although the drum is being sounded after a flick (good) it's also being sounded at the end of a pull (not desirable).

By flick I mean the phone is being flicked forwards and downwards, as if you are striking a drum with it, and by pull I mean you are returning your arm back to the starting position.

Does anyone know an efficient way of determining when a flick occurs but not a push?

Any ideas will be gratefully received.

Thanks

EXISTING CODE:

package com.example.testaccelerometer;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity implements SensorEventListener{

    public static TextView results;

    public static TextView clickresults;

    StringBuilder builder = new StringBuilder();

      private float mAccelNoGrav;
      private float mAccelWithGrav;
      private float mLastAccelWithGrav;

    public static boolean shakeIsHappening;
    public static int beatnumber = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        results = (TextView) findViewById(R.id.results);
        clickresults = (TextView) findViewById(R.id.clickresults);

        SensorManager manager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        Sensor accelerometer = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        if(!manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST)){
            builder.append("Problem with Accelerometer - Shaking will not work");
        };


        mAccelNoGrav = 0.00f;
        mAccelWithGrav = SensorManager.GRAVITY_EARTH;
        mLastAccelWithGrav = SensorManager.GRAVITY_EARTH;



    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        builder.setLength(0);
        builder.append("X " + event.values[0] + "\nY " + event.values[1] + "\nZ " + event.values[2]);
    results.setText(builder.toString());


        float x = event.values[0];
          float y = event.values[1];
          float z = event.values[2];
          mLastAccelWithGrav = mAccelWithGrav;
          mAccelWithGrav = android.util.FloatMath.sqrt(x*x + y*y + z*z);
          float delta = mAccelWithGrav - mLastAccelWithGrav;
          mAccelNoGrav = mAccelNoGrav * 0.9f + delta;

    if (mAccelNoGrav >8.5) {
        shakeIsHappening = true;
        //clickresults.append(" click " + mAccel);
    }

    if (shakeIsHappening == true && mAccelNoGrav <2) {
        beatnumber++;
clickresults.append(" click number: " + beatnumber + "\n" + "PA: " + mLastAccelWithGrav + " CA:" + mAccelNoGrav + "\n ");
shakeIsHappening = false;
    }

    }


    @Override
    protected void onResume() {
      super.onResume();
    // YOU DO NEED TO TRY AND REREGISTER IT NOW
    }

    @Override
    protected void onPause() {
        // YOU DO NEED TO TRY AND UNREGISTER IT NOW
      super.onPause();
    }


}

Solution

  • You can use the geo-magnet sensor in conjunction with your accelerometer sensor to determine which edge of the device is facing toward the ground, and then exclude any acceleration events in the opposite direction

    http://developer.android.com/reference/android/hardware/SensorManager.html#getOrientation(float[], float[])