title: How to calculate running speed using accelerometer sensor in android
body: <p>I tried to calculate running speed sensor <code>TYPE_LINEAR_ACCELEROMETER</code> in Android, but the results I am getting is highly inaccurate. Calculated average acceleration is always positive value, so it keeps on increasing. Here is my procedure and code, please suggest me what is the correct way to calculate from 3-axis accelerometer data and where my code goes wrong.</p>
  
  <p>What I did is:</p>
  
  <p>I am getting acceleration values in <code>x</code>, <code>y</code>, <code>z</code> directions</p>
  
  <p>Resulting acceleration <code>a1 = sqrt(x*x + y*y + z*z)</code></p>
  
  <p>Average of <code>5</code> acceleration readings:</p>
  
  <pre><code>Avg(4) = `(a0 + a1 + a2 + a3 + a4) / 5`
  </code></pre>
  
  <p>Time delta:</p>
  
  <pre><code>Tdelta = (time of Avg(4)) - (time of Avg(0))
  </code></pre>
  
  <p>Initially <code>V(0)</code> is <code>0</code> and after that <code>V(0)</code> is the previously calculated velocity, hence:</p>
  
  <pre><code>V(1) = V(0) + at = 0 + Avg(1)
  V(2) = V(1) + at = V(1) + Avg(2)
  V(n) = V(n-1) + at = V(n-1) + Avg(n)
  </code></pre>
  
  <p>This is how I am getting the velocity value, but it is not the correct velocity. Please guide me.</p>
  
  <p>This is the code:</p>
  
  <pre><code>public class TestCalculateVelocityActivity extends Activity implements OnClickListener, SensorEventListener {
  
      final String TAG = getClass().getName().toString();
      SensorManager mSensorManager;
      Sensor mAccelerometer;
      TableLayout accTable;
      TextView accl, spd, spd_kmph;
      Button btnStart, btnStop, btnClear;
      Timer updateTimer;
      float []linearAcceleration = new float[3];
      Velocity velocity;
      Handler handler;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
  
          initSensor();
  
          accTable =(TableLayout)findViewById(R.id.country_table);
  
          //accl = (TextView)findViewById(R.id.accl);
          spd = (TextView)findViewById(R.id.spd);
          spd_kmph = (TextView)findViewById(R.id.spd_kmph);
  
          btnStart = (Button)findViewById(R.id.buttonStart);
          btnStart.setOnClickListener(this);
          btnStop = (Button)findViewById(R.id.buttonStop);
          btnStop.setOnClickListener(this);
          btnClear= (Button)findViewById(R.id.buttonClear);
          btnClear.setOnClickListener(this);
      }
  
      private void initSensor() {
          mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
          mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
          if(mAccelerometer == null) {
              Toast.makeText(this, "Accelerometer sensor not available", Toast.LENGTH_SHORT).show();
              finish();
          }
      }
  
      void fillTable(float values[]) {
  
          float[] val = values;
          TableRow row;
          TextView t1, t2, t3;
          //Converting to dip unit
          int dip = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                  (float) 1, getResources().getDisplayMetrics());
  
          //for (int current = 0; current &lt; CountriesList.abbreviations.length; current++) {
          row = new TableRow(this);
  
          t1 = new TextView(this);
          t1.setTextColor(Color.WHITE);
          t1.setBackgroundColor(Color.GRAY);
          t2 = new TextView(this);
          t2.setTextColor(Color.WHITE);
          t2.setBackgroundColor(Color.LTGRAY);
          t3 = new TextView(this);
          t3.setTextColor(Color.WHITE);
          t3.setBackgroundColor(Color.GRAY);
  
          t1.setText(""+val[0]);
          t2.setText(""+val[1]);
          t3.setText(""+val[2]);
  
          t1.setTypeface(null, 1);
          t2.setTypeface(null, 1);
          t3.setTypeface(null, 1);
  
          t1.setTextSize(15);
          t2.setTextSize(15);
          t3.setTextSize(15);
  
          t1.setWidth(150 * dip);
          t2.setWidth(150 * dip);
          t3.setWidth(150 * dip);
          t1.setPadding(20*dip, 0, 0, 0);
          row.addView(t1);
          row.addView(t2);
          row.addView(t3);
  
          accTable.addView(row, new TableLayout.LayoutParams(
                  LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  
      }
  
      public void onClick(View v) {
  
          if(v == btnStart) {
              mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
              velocity = new Velocity();
              updateTimer = new Timer("velocityUpdate");
              handler = new Handler();
              updateTimer.scheduleAtFixedRate(new TimerTask() {
                  public void run() {
                      calculateAndUpdate();
                  }
              }, 0, 1200);
          }else  if(v == btnStop) {
              mSensorManager.unregisterListener(this);
  
              displayVelocityValues();
              displayVelocityTable();
              velocity = null;
              handler = null;
              updateTimer.cancel();
  
  
          } else if(v == btnClear) {
              accTable.removeAllViews();
          }
      }
  
      private void displayVelocityTable() {
          try {
              accTable.removeAllViews();
              double[] vl = velocity.getVlArray();
              for(int i = 0; i&lt;vl.length; i++) {
                  /*Log.d(TAG, "v = " + vl[i] + "mps, "+(vl[i] * 3.6)+ " kmph");*/
  
  
                  //float[] val = values;
                  TableRow row;
                  TextView t1, t2;
                  //Converting to dip unit
                  int dip = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                          (float) 1, getResources().getDisplayMetrics());
  
                  //for (int current = 0; current &lt; CountriesList.abbreviations.length; current++) {
                  row = new TableRow(this);
  
                  t1 = new TextView(this);
                  t1.setTextColor(Color.WHITE);
                  t1.setBackgroundColor(Color.GRAY);
                  t2 = new TextView(this);
                  t2.setTextColor(Color.WHITE);
                  t2.setBackgroundColor(Color.LTGRAY);
  
  
                  t1.setText(""+vl[i]);
                  t2.setText(""+(vl[i] * 3.6));
  
  
                  t1.setTypeface(null, 1);
                  t2.setTypeface(null, 1);
  
  
                  t1.setTextSize(15);
                  t2.setTextSize(15);
  
                  t1.setWidth(200 * dip);
                  t2.setWidth(200 * dip);
  
                  t1.setPadding(20*dip, 0, 0, 0);
                  row.addView(t1);
                  row.addView(t2);
  
  
                  accTable.addView(row, new TableLayout.LayoutParams(
                          LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
              }
          } catch(NullPointerException e) {
              e.printStackTrace();
          }
      }
  
      public void displayVelocityValues() {
          try {
              double[] vl = velocity.getVlArray();
              for(int i = 0; i&lt;vl.length; i++) { 
                  Log.d(TAG, "v = " + vl[i] + "mps, "+(vl[i] * 3.6)+ " kmph");
              }
          } catch(NullPointerException e) {
              e.printStackTrace();
          }
      }
  
      private void calculateAndUpdate() {
  
          final double vel = velocity.getVelocity(linearAcceleration, System.currentTimeMillis());
          final double velKmph = vel * 3.6;
          //spd.setText("v = "+ velKmph + " kmph");
  
          handler.post(new Runnable() {
              public void run() {
  
                  //Log.d(getClass().getName().toString(), "Setting velocity = " + velKmph+ " kmph");
                  spd.setText("v = "+ vel + " mps");
                  spd_kmph.setText("v = "+ velKmph + " kmph");
              }
          });
      }
  
  
  
      @Override
      public void onAccuracyChanged(Sensor sensor, int accuracy) {
          // TODO Auto-generated method stub
  
      }
  
      @Override
      public void onSensorChanged(SensorEvent event) {
  
          linearAcceleration[0] = event.values[0];
          linearAcceleration[1] = event.values[1];
          linearAcceleration[2] = event.values[2];        
  
          fillTable(linearAcceleration);
      }
  }
  
  
  
  public class Velocity {
  
      private final String TAG = getClass().getName().toString();
      int sampleCounter = 0;
      final int totalSamples = 5;
      long time0, nAccel;
      static int i=0; 
      double aDelT0 = 0, v0 = 0, v = 0;
  
      final int totalVelocityValues = 1000;
      double []velocityValues = new double[totalVelocityValues];
  
      //float []linearAcceleration = new float[3];
  
      //final int totalAccl = 5;
      double []accel = new double[totalSamples];
  
      private double getAvg(double[] a) {
          double total = 0;
          for(int i = 0; i&lt;a.length; i++) 
              total = total + a[i];
          return (total / a.length);
      }
  
      private double getAcceleration(float[] linearAcceleration) {
          return Math.sqrt(Math.pow(linearAcceleration[0], 2) + Math.pow(linearAcceleration[0], 2) + Math.pow(linearAcceleration[0], 2));
      }
  
      public double getVelocity(float[] linearAcceleration, long time1) {
  
          //this.linearAcceleration = linearAcceleration;
  
          try {
              if(sampleCounter &lt; (totalSamples-1)) {
                  if(sampleCounter == 0) 
                      time0 = time1;
                  accel[sampleCounter] = getAcceleration(linearAcceleration);     
                  sampleCounter++;    
              } else if(sampleCounter == (totalSamples-1)) {
                  accel[sampleCounter] = getAcceleration(linearAcceleration);
  
                  double avgAccel = getAvg(accel);
                  long timeDelta = ((time1 - time0) / 1000);
                  double aDelT1 = (avgAccel * timeDelta);
                  Log.d(TAG, "aDelT1 = "+avgAccel +" * "+timeDelta + " = "+aDelT1 );
  
                  v = calculateVelovity(aDelT1);
                  if(i !=totalVelocityValues) {
                      velocityValues[i]=v;
                      i++;
                  } else {
                      for(int j=0;j&lt;(totalVelocityValues-1);j++)
                          velocityValues[j]=velocityValues[j+1];
                      velocityValues[totalVelocityValues -1]=v;
                  }
                  sampleCounter = 0;
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
          return v;
      }
  
      private double calculateVelovity(double aDelT1) {
          double v = v0 + (aDelT1 - aDelT0);
          Log.d(TAG, "v = "+v0+ "+ ("+aDelT1+" - "+aDelT0+") = "+v);
          v0 = v;
          aDelT0 = aDelT1;
          return v;
      }
  
  
  
      public double[] getVlArray() {
          return velocityValues;
      }
  </code></pre>
  
  <p>}</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" &gt;
  
  &lt;LinearLayout 
      android:layout_width="fill_parent"
       android:layout_height="wrap_content"
      android:orientation="vertical" &gt;
  
      &lt;TextView
          android:id="@+id/spd"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_marginBottom="5dip"
          android:layout_weight="1"
          android:background="@android:color/darker_gray"
          android:gravity="center_vertical|center_horizontal"
          android:text="speed (kmph)"
          android:textColor="@android:color/white"
          android:textSize="20dip"
          android:textStyle="bold"
          android:typeface="sans" /&gt;
  
      &lt;TextView
          android:id="@+id/spd_kmph"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_marginBottom="5dip"
          android:layout_weight="1"
          android:background="@android:color/darker_gray"
          android:gravity="center_vertical|center_horizontal"
          android:text="ooooo"
          android:textColor="@android:color/white"
          android:textSize="20dip"
          android:textStyle="bold"
          android:typeface="sans" /&gt;
  
  
      &lt;TextView  
          android:text="Acceleration Data"
              android:textColor="@android:color/white"
              android:gravity="center_vertical|center_horizontal"
              android:textSize="20dip"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:textStyle="bold"
              android:layout_marginBottom="5dip"
              android:typeface="sans"
              android:layout_weight="1"
              android:background="@android:color/darker_gray"/&gt;
  
  
  &lt;/LinearLayout&gt;
  
  &lt;LinearLayout android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:orientation="horizontal"&gt;
  
      &lt;Button android:id="@+id/buttonStart"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:layout_weight="1"
          android:text="Start" /&gt;
  
      &lt;Button android:id="@+id/buttonClear"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:layout_weight="1"
          android:text="Clear" /&gt;
  
       &lt;Button android:id="@+id/buttonStop"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:layout_weight="1"
          android:text="Stop" /&gt;
  
  &lt;/LinearLayout&gt;
  
  &lt;RelativeLayout android:id="@+id/rl_country_heading"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/darker_gray"&gt;
  
      &lt;TextView android:id="@+id/tv_11"
          android:layout_width="70dip"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:text="X"
          android:textStyle="normal|bold"
          android:textColor="@android:color/white"
          android:textSize="18dip"&gt;
      &lt;/TextView&gt;
  
      &lt;TextView android:id="@+id/tv_12"
          android:layout_width="150dip"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:text="Y"
          android:textStyle="normal|bold"
          android:textColor="@android:color/white"
          android:textSize="18dip"
          android:layout_toRightOf="@+id/tv_11"&gt;
      &lt;/TextView&gt;
  
      &lt;TextView android:id="@+id/tv_13"
          android:layout_width="150dip"
          android:layout_height="wrap_content"
          android:gravity="center"
          android:text="Z"
          android:textStyle="normal|bold"
          android:textColor="@android:color/white"
          android:textSize="18dip"
          android:layout_toRightOf="@+id/tv_12"&gt;
      &lt;/TextView&gt;
  &lt;/RelativeLayout&gt;
  
  &lt;LinearLayout android:id="@+id/ll_country"
      android:layout_height="fill_parent"
       android:layout_width="fill_parent"&gt;
  
      &lt;ScrollView android:id="@+id/ScrollView11"
          android:layout_width="fill_parent" 
          android:layout_height="fill_parent"
          android:fillViewport="true"&gt;
  
          &lt;LinearLayout android:layout_width="fill_parent"
              android:layout_height="wrap_content"
              android:layout_margin="5dip"&gt;
  
              &lt;TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="fill_parent" 
                  android:layout_height="fill_parent"
                  android:stretchColumns="0,1"
                  android:id="@+id/country_table"
                  android:background="@android:color/black"&gt;
              &lt;/TableLayout&gt;  
          &lt;/LinearLayout&gt;
      &lt;/ScrollView&gt;
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p></p>