I am trying to figure out how the accelerometer sensor work. I have a service which is started by my MainActivity and logs the sensor's data in the console. I followed the docs recommendation (eliminated the "force of gravity" in the sensor's readings). Now to the point, I am observing strange behaviour every time I move the device. Say it is laying on a table and I move it perpendicular with the top of the device facing up like that
and the readings go from all zero (XYZ) to that:
As you can see from the accelerometer's readings as soon as I hold my device to the up mentioned position steal the readings go back to zeros. Can somebody explain that behaviour to be please. Why the X, Y and Z value go back go zero (provided I hold the device steal).
This is my service code that logs the data:
#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 = (float) 0.8;
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];
double x = Math.abs(Math.round(linear_acceleration[0]));
double y = Math.abs(Math.round(linear_acceleration[1]));;
double z = Math.abs(Math.round(linear_acceleration[2]));
Log.d(TAG, "TimeStamp: " + event.timestamp + " X: " + x + " Y: " + y + " Z: " + z);
}
Related
I can't find the way of reaching the gravity value itself, only the x, y, z values that are not close to 9.8.
Probably I'm missing something.
I want to do something simple - display the gravity value in TextView.
in my main activity in onCreate() method I have:
gravityView = (TextView) findViewById(R.id.gravity);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
sensorGravity = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY).get(0);
mSensorManager.registerListener(this, sensorGravity, SensorManager.SENSOR_DELAY_GAME);
Then I override the onSensorChanged method:
#Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()){
case Sensor.TYPE_GRAVITY:
float alpha = 0.8f;
float x, y, z;
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];
x = event.values[0] - gravity[0];
y = event.values[1] - gravity[1];
z = event.values[2] - gravity[2];
double gravity = Math.sqrt( Math.pow(x,2) + Math.pow(y,2) + Math.pow(z, 2));
gravityView.setText("GRAVITY= " + gravity + "\n" + x + "\n " + y + "\n " + z );
break;
}
}
But the values in gravity, x, y and z are not close to 9.8.
Can somebody explain me what I'm missing?
Thanks
Have tried to adapt the android developer documentation for accelerator LPF but it does not seem to work with pressure
float pressure_value = 0.0f;
float height = 0.0f;
float height2 = (float) 964.98;
final float alpha = (float) 0.8;
if( Sensor.TYPE_PRESSURE == event.sensor.getType() ) {
pressure_value = event.values[0];
event.values[0] = alpha * event.values[0] + (1 - alpha) * event.values[0];
event.values[1] = alpha * event.values[1] + (1 - alpha) * event.values[1];
event.values[2] = alpha * event.values[2] + (1 - alpha) * event.values[2];
does anyone have some insight?
The pressure sensor only has one value i.e. event.values[0]. A simple low pass filter for that would look like:
pressure = alpha*event.values[0] + (1 - alpha)*pressure
Extremely oversimplified explanation:
For alpha=0.8, the 'new' pressure value is 80% of the actual current pressure supplied by the sensor + 20% of the value of the 'old' pressure. Increasing the alpha value will make it more responsive to pressure fluctuations, lower alpha values will make it less noisy (more filtered).
More explanatory code:
private float alpha = 0.8f;
private float filteredPressure = 0.0f;
#Override
public final void onSensorChanged(SensorEvent event) {
if (Sensor.TYPE_PRESSURE == event.sensor.getType()) {
float currentPressure = event.values[0];
filteredPressure = (alpha*currentPressure) + (1 - alpha)*filteredPressure;
}
}
I'm working with the Accelerometer Sensor from my Android, but I have a problem.
I need to get only gravity and i don't know how to do.
I read in the official documentation of Android the following method:
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.8;
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];
}
So I guess would be good if I take the gravity[] values.
I'm I right?
Sensor is: BMA250 3 axis accelerometer, documentation is in:
BMA250
I am trying to track the movement of the device only on the vertical direction, i.e. upward and downward movement. This should be irrespective of the orientation of the device. Things that i already know or have tried are these
Linear acceleration is given by sensor TYPE_LINEAR_ACCELERATION and the axes is the phone axes and hence tracking any particular axes does not make a difference.
I tried applying transpose or inverse of rotation vector( inverse or transpose for the rotation vector are same) and then tried tracking the z direction of the linear acceleration vector. Does not seem to help.
I am trying to do a dot product with gravity values (TYPE_GRAVITY) to get the direction of the acceleration but it seems to be error prone. Even when i move my device swiftly up, it says going down.
I will outline this method here
dotProduct = vectorA[0]*vectorB[0]+vectorA[1]*vectorB[1] + vectorA[2]*vectorB[2];
cosineVal = dotProduct/(|vectorA|*|vectorB|)
if(cosineVal > 0 ) down else Up.
What is the flaw with the method ? Please help, I have been stuck on this for some time now.
As I see it, in the 3rd method you trying to find the cos of angle between two vectors (gravity vector and acceleration vector). And the idea is if the angle is close to 180 degrees you have up movement, if angle is close to 0 degrees you have down movement. Cosine is function that has positive value when angle is from -90 to 90 degrees. So when your cosineVal value is positive it means phone is going down and even if cosineVal closer to 1 movement is straight down. So it is true vice versa. When cosine is negative ( from 90 degrees to 270) you have up movement.
Probably you can get vectors from Sensor.TYPE_ACCELEROMETER from https://developer.android.com/reference/android/hardware/SensorEvent.html#values there you have gravity vector and acceleration vector.
I made a code snippet below you can try.
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];
float scalarProduct = gravity[0] * linear_acceleration[0] +
gravity[1] * linear_acceleration[1] +
gravity[2] * linear_acceleration[2];
float gravityVectorLength = (float) Math.sqrt(gravity[0] * gravity[0] +
gravity[1] * gravity[1] + gravity[2] * gravity[2]);
float lianearAccVectorLength = (float) Math.sqrt(linear_acceleration[0] * linear_acceleration[0] +
linear_acceleration[1] * linear_acceleration[1] + linear_acceleration[2] * linear_acceleration[2]);
float cosVectorAngle = scalarProduct / (gravityVectorLength * lianearAccVectorLength);
TextView tv = (TextView) findViewById(R.id.tv);
if (lianearAccVectorLength > 2) {//increase to detect only bigger accelerations, decrease to make detection more sensitive but noisy
if (cosVectorAngle > 0.5) {
tv.setText("Down");
} else if (cosVectorAngle < -0.5) {
tv.setText("Up");
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
}
I came across this solution to remove gravity values from raw values of an acelerometer but I can't understand why alpha = 0.8 and not just 0.997.
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.8;
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];
}
As per the comment on your code: alpha = t / (t + dT), so alpha is just to be calculated according to your filter time lenght and the sampling rate of the accelerometer.
if your solution sets alpha = 0.8 it simply means that dT = 0,025 t or, on the other side, t = 40dt.
If you increase the sampling rate of the accelerometer, decreasing dT you'll have alpha pointing asyntotically to 1.