8

I am implementing a demo TIMER, with Vibration ( at a particular condition ), When I press start my timer starts running.. and when I stop it using stop button, it simply stops.

Now I have to integrate a functionality, when the person shifts the device (while the Timer is running), it should reset the timer. It is working pretty good, but the accelerometer functionality is not working absolutely accurate. It needs a fast jerk to reset the timer.

Suggest me a good solution for the same.

Here is my code

public class SensorAccelerometer implements SensorEventListener {

    private Context context;
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private TextView timelabel;
    private Handler mHandler;
    Runnable run;

    private float mLastX, mLastY, mLastZ;
    private final float NOISE = (float) 3.0;

    public SensorAccelerometer(Context context) {

    }


    public SensorAccelerometer(Context context,TextView timelabel, Handler mHandler2, Runnable mUpdateTimeTask) {
        // TODO Auto-generated constructor stub

        this.context = context;
        this.timelabel = timelabel;
        this.mHandler = mHandler2;
        this.run = mUpdateTimeTask;

        initialiseSensor();
    }


    public void initialiseSensor(){
        sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
        sensorManager.registerListener(this, accelerometer,SensorManager.SENSOR_DELAY_NORMAL);
    }

    public void unregisterSensor(){
        sensorManager.unregisterListener(this);
        Toast.makeText(context, "Sensor Stopped..", Toast.LENGTH_SHORT).show();
    }


    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    public void onSensorChanged(SensorEvent event) {
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    mAccelLast=mAccelCurrent;

    mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
    float delta = mAccelCurrent - mAccelLast;
    mAccel = mAccel * 0.9f + delta;

    if(mAccel>0.5){
        TimerActivity.mStartTime = SystemClock.uptimeMillis();
        mHandler.removeCallbacks(run);
        mHandler.postDelayed(run, 100);
    }

}

Timer Activity

public class TimerActivity extends Activity {

    public static long mStartTime = 0L;
    private TextView mTimerLabel;

    private Handler mHandler = new Handler();

    String timerStop1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mTimerLabel = (TextView) findViewById(R.id.textTimer);

        Button timerStartButton = (Button) findViewById(R.id.btnTimer);       
        timerStartButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){

                if(mStartTime == 0L){
                    mStartTime = SystemClock.uptimeMillis();
                    mHandler.removeCallbacks(mUpdateTimeTask);
                    mHandler.postDelayed(mUpdateTimeTask, 100);

                    //activating the sensor and the acclerometer
                    SensorAccelerometer acc = new SensorAccelerometer(view.getContext(), mTimerLabel,mHandler,mUpdateTimeTask);
                }                                   
            }
        }); 

        Button timerStopButton = (Button) findViewById(R.id.btnTimerStop);       
        timerStopButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){

                mHandler.removeCallbacks(mUpdateTimeTask);
                mTimerLabel.setText(timerStop1);
                mStartTime = 0L;

                SensorAccelerometer scc = new SensorAccelerometer(view.getContext(),mTimerLabel,mHandler,mUpdateTimeTask);
                scc.unregisterSensor();
            }
        }); 

    } 


    private Runnable mUpdateTimeTask = new Runnable(){

        public void run() {

            final long start = mStartTime;
            long millis = SystemClock.uptimeMillis()- start;

            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            mTimerLabel.setText("" + minutes + ":"
                                  + String.format("%02d", seconds));                    

            timerStop1 = minutes + ":"
                      + String.format("%02d", seconds);

            mHandler.postDelayed(this, 200);            

        }   
    }; 

    protected void onPause() {
        super.onPause();
        SensorAccelerometer scc = new SensorAccelerometer(this,mTimerLabel,mHandler,mUpdateTimeTask);
        scc.unregisterSensor();
    };

} 
Gaurav Arora
  • 8,282
  • 21
  • 88
  • 143

3 Answers3

6

I think the next stage in the development of your app is to look at values of acceleration that are produced in a spreadsheet. I use Excel for this, but any tool that can produce graphs will do. So alter onSensorChanged() to something like

public void onSensorChanged(SensorEvent event) {
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    float mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
    float mAccel = mAccel * 0.9f + mAccelCurrent * 0.1f;
    Log.d("onSensorChanged",System.currentTimeMillis()+","+mAccelCurrent +","+mAccel);

}

and then you can capture the currentTime, mAccelCurrent and mAccel into the Android logging mechanism. Alternatively, create your own text file, write the values there, and open the file in a tool that can produce graphs. From the graphs, you can then decide what values to use for your trigger.

Stochastically
  • 7,616
  • 5
  • 30
  • 58
  • My simple question is how to check the tilt data, ( when the device is tilted ) and I want to perform a set of code on it. do you have any solution regarding the above code.. – Deepak Sharma May 16 '13 at 08:52
  • @stochastically. Mine question is same as above – Gaurav Arora May 16 '13 at 08:56
  • I thought that you wanted to use the accelerometer data to detect motion. To do that, you need to understand the the data, hence the need to log it and look at it. If you just want to check when the device is tilted that's a lot easier. For example, see my answser [link](http://stackoverflow.com/questions/16571798/android-device-angle-on-vertical-axis-while-device-stays-still/16572641#16572641). The pitch angle is probably what you're looking for. – Stochastically May 16 '13 at 09:55
2

Two suggestions, and one thought:

  1. For consistent behaviour, you should look at the length of the event.values vector, i.e. Math.sqrt(x*x+y*y+z*z), rather than the individual values. Mathematically, it's Math.sqrt(x*x+y*y+z*z) that's independent of your co-ordinate system, i.e. how the device is oriented relative to the ground etc, whereas the individual numbers x, y, z aren't.
  2. Your current app looks for changes in acceleration. Instead, I think you should just look for high acceleration, i.e. large values of Math.sqrt(x*x+y*y+z*z).
  3. I recently wrote this answer about using accelerometers for a pedometer, and I think you might find it interesting.
Community
  • 1
  • 1
Stochastically
  • 7,616
  • 5
  • 30
  • 58
  • You have provided a very good answer, but I am not able to understand what should I do, to check the motion of the device.? Where should I change my code.. so that If a person changes the position of the device a little, I should get it. – Gaurav Arora May 16 '13 at 04:32
  • My comments 1 and 2 both relate to your implementation of `onSensorChanged(SensorEvent event)`. Your first 3 lines are fine, where you set up x, y, and z, but then you need to (1) get `len=Math.sqrt(x*x+y*y+z*z)`. and (2) determine whether `len` is much bigger than usual etc. – Stochastically May 16 '13 at 07:13
  • 3
    I don't think editing the question like that is a good idea, because my answer and our conversation now make less sense to others. Also, your edit is incomplete because variables like mAccel aren't declared anywhere. You should start a new question if you're still having problems. That said, it looks like you're trying to make `mAccel` a smoothed value of `mAccelCurrent` in a rather strange way. Instead I suggest `mAccel = mAccel * 0.9f + mAccelCurrent * 0.1f`. beyond that, I think you should log mAccel and mAccelCurrent to a file, examine the results, and decide what to do from that. – Stochastically May 16 '13 at 07:43
  • I am not clear about what you are saying. Can u please reply via an answer ( in the form of code ) if you have understood what I want ?? – Gaurav Arora May 16 '13 at 07:52
  • @Stochastically can u discuss mathematical solution how to calculate distance using accelerometer i have done calculation till yet sqrt((x*x)+(y*y)+(z*z)) then now how can i calulate distance travelled by user i just need short interval distance – Erum Oct 17 '14 at 06:24
  • @ErumHannan calculating distance using the accelerometer is very hard, and I haven't heard of anyone doing that successfully. One problem is that acceleration is the 2nd derivative of distance, so in doing the integration, the initial condition (i.e. the starting velocity) is uncertain. – Stochastically Oct 17 '14 at 11:51
  • @Stochastically i need to calculate distance only from one door to another door inside home or offices what option should i use i want to calculate how much distance user has covered if it has covered around 10 to 15 metres distance then i wl stop sensor.what other options should i use if i prefer to use sensor values then remove noise from filter values and then sqrt(x*x+y*y+z*z) and then compare that value from threshold i m not getting what value will i set for threshold – Erum Oct 17 '14 at 11:58
  • @ErumHannan I think the best results are obtained using "Sensor fusion", i.e. using all the relevant sensors to correct each other to get the best estimates. For example, a lot of devices have a gyroscope as well as an acceleromter. But this is a very hard problem and I've never tried. I can't help you any more, but try googling "Sensor fusion". Good luck. – Stochastically Oct 17 '14 at 12:01
1

To find linear acceleration in a particular direction you can use this code too:

    @Override
public void onSensorChanged(SensorEvent event) {
// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate

final float alpha = 0.8f;

gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
}  

after calculating the linear acceleration you can simply use an 'if' statement to check whether you jerk was powerful or not! [Higher value= more powerful jerk]