How to properly calculate linear acceleration using AcceleroMeter in Android

To my utmost surprise, in Android 4.0+ they decided to remove LINEAR ACCELERATION sensor from available software sensors and put it inside a hardware sensor, the gyroscope that is rarely available in regular phones. I don't know why they did it, but imagine my surprise when I delivered the software that was tested on a cheap 2.3 phone, and on 2 months old phone it shows Unable to instantiate linear acceleration sensor. Why have they done it?

To save my skin, I checked if an Accelerometer is available in the phone, and it does. Based on this article, I should be able to calculate linear acceleration using the data from accelerometer. I checked the code and I see a variable that has no declaration available.

public void onSensorChanged(SensorEvent event){
  // In this example, alpha is calculated as t / (t + dT),
  // where t is the low-pass filter's time-constant and
  // dT is the event delivery rate.

  final float alpha = 0.8;
  float[] gravity=new float[]{0.0f,0.0f,0.0f}; //should it be here???

  // Isolate the force of gravity with the low-pass filter.
  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];

  // Remove the gravity contribution with the high-pass filter.
  linear_acceleration[0] = event.values[0] - gravity[0];
  linear_acceleration[1] = event.values[1] - gravity[1];
  linear_acceleration[2] = event.values[2] - gravity[2];
}

What does the gravity array contain in the first run? Should I add it like

float[] gravity=new float[]{0.0f,0.0f,0.0f};

?

Or should it contain real gravity data that is available via the Gravity sensor (also not available in regular devices)?

Does the calculation result proper linear acceleration data? Is it possible to calculate just by substracting a number from the incoming sensor data?


Actually what is done in that docs provided code snippet is that they take data from accelerometer(which contains both gravity and linear acceleration) and filter it. So how it basically works, we take raw data and assume that gravity vector is something constant and cannot change very quickly, opposite to linear acceleration, which changes really fast. So let's say if we take 80% of past counted gravity vector and add 20% of raw data we filter fast linear acceleration peaks and get gravity vector. If we remove gravity vector from raw data we get linear acceleration without gravity. Google for exponential filter for more information. Here you can play with it http://copterpilot.ru/custom-app/exponential/. So you can easily initialize your global gravity array of floats with zeros and wait a little for filtered data. Here is code snippet

public class MainActivity extends AppCompatActivity implements SensorEventListener {
private float[] gravity = new float[3];
private float[] linear_acceleration = new float[3];

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    Sensor mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}

@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];
}  
}

I don't have a cannonical answer, but what i know is that the actual initial readings of the acelerometer will hardly be (0,0,0), since it is not 0 when the device is not moving, because the value depends on the position of the 3 axis, and not in the movement (with the differences in the positions, we can infer the movements). So to get any relevant data you have to compare different readings. For that, i would prefer to read the acelerometer values at the beginning (in the first call to onsensorchanged ) and then start calculating what you need starting in the second call to the function

actually, when they talk about gravity, you dont need a gravity sensor, since the acelerometer is actually that. It is measuring the gravity value for each axis, from 0 to 1


You need to calculate gravity force vector. Basically your accelerometer measures total as gravity+acceleration so you need to remove gravity force out of it. In the same article you provided there is info on how to use Gravity sensor. So listen to that sensor and update your gravity vector global variable from it.

链接地址: http://www.djcxy.com/p/76670.html

上一篇: Sweave to R降价文件转换

下一篇: 如何在Android中使用AcceleroMeter正确计算线性加速度