This question has been asked in a few ways but there has been no conclusive answer to it.
I am trying to find out the maximum range of the accelerometer on Android phones.
Some forums claim +-2Gs and some +-3.5Gs.
The accelerometer hardware (of the LSM330 which is on the s4) has a higher range, up to 16Gs.
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/DM00059856.pdf
I wrote an application to practically find this range and loaded it onto an S4. The following picture shows the readings.
Clearly, the maximum range in each direction is 2Gs.
Is there a way to increase this range and if so, how?
Has anyone found a larger default range on other Android phones?
For those interested, here is the nb part of my code:
public class MainActivity extends Activity implements SensorEventListener{
Sensor accelerometer;
SensorManager sm;
TextView maxValue;
TextView realTimeValues;
TextView realTimeResultant;
TextView maxValues;
TextView maxResultant;
float x = 0;
float y = 0;
float z = 0;
float res = 0;
float xMax = 0;
float yMax = 0;
float zMax = 0;
float resMax = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sm = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
maxValue = (TextView)findViewById(R.id.MaxValue);
realTimeValues = (TextView)findViewById(R.id.RealTimeValues);
realTimeResultant = (TextView)findViewById(R.id.RealTimeResultant);
maxValues = (TextView)findViewById(R.id.maxValues);
maxResultant = (TextView)findViewById(R.id.maxResultant);
float max = accelerometer.getMaximumRange();
maxValue.setText("Max range: "+ max);
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
x = event.values[0];
y = event.values[1];
z = event.values[2];
res = (float) Math.sqrt( x*x + y*y + z*z);
realTimeValues.setText("X: " + x + "\nY: " + y + "\nZ: " + z);
realTimeResultant.setText(res + " m/s^2");
if (Math.abs(x) > Math.abs(xMax))
xMax = x;
if (Math.abs(y) > Math.abs(yMax))
yMax = y;
if (Math.abs(z) > Math.abs(zMax))
zMax = z;
if (res > resMax)
resMax = res;
maxValues.setText("X: " + xMax + "\nY: " + yMax + "\nZ: " + zMax);
maxResultant.setText(resMax + " m/s^2");
}
}
It seems impossible to do so.
It should also be noted that the Linear accelerometer is cannot essentially increase the range of accelerometer readings, even though its values go up to 3Gs (on some phones). The reason for this increase is only due to the way in which the linear acceleration is calculated (the use of a filter essentially) which sometimes results in values higher than 2Gs should the direction be switched quickly enough.
See here for calculation of linear accelerometer: http://developer.android.com/guide/topics/sensors/sensors_motion.html
Related
I would like to detect using accelerometer if phone is moving up or down and how many times direction was changed.
I am using this code:
lastY = 0;
lastYChange = 0;
initialized = false;
...
if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
...
#Override
public void onSensorChanged(SensorEvent event) {
float y = event.values[1];
if (!initialized) {
lastY = y;
initialized = true;
}
else {
float yChange = lastY - y;
float deltaY = Math.abs(yChange);
if (deltaY < 2) {
deltaY = 0;
}
else {
if (lastYChange < 0 && yChange > 0) {
counter += 1;
textViewDirection.setText("Direction: Top");
textViewCounter.setText("Counter: " + counter);
}
else if (lastYChange > 0 && yChange < 0) {
counter += 1;
textViewDirection.setText("Direction: Bottom");
textViewCounter.setText("Counter: " + counter);
}
lastYChange = yChange;
}
lastY = y;
textViewAcceleration.setText("Acceleration is: " + deltaY);
}
}
So if I move phone in only one direction, for example top direction, counter should be increased by only 1, and textViewDirection should have value of "Direction: Top".
Instead, with this code counter is increased multiple times and textViewDirection is switching from "Direction: Top" and "Direction: Down".
Does anyone know to fix this? So that, for example, if I move phone up, then down, then up, counter should have value of 3, and textViewDirection should have value "Direction: Top", "Direction: Down" and "Direction: Top", respectively.
This is a possible accelerometer result when you move the sensor Unfortunately, y accelerometer waveform is not as straightforward to behave as you thought in your code. It oscillates a lot, e.g. when you stop the device
I am programming an accelerometre in order to measure a distance. I already read that integrating twice the acceleration, the error is very consequent but I don't care about that, I have enough precision for what I want to do.
The problem is that my position in x axis is always negative and I don't know where it comes from because I move my phone in all directions and I still have negative values.
This is my code that I picked and arranged from internet:
#Override
public void onSensorChanged(SensorEvent event){
if(last_values != null){
float dt = (event.timestamp - last_timestamp) * NS2S;
acceleration[0]= event.values[0];
acceleration[1]= event.values[1];
acceleration[2]= event.values[2];
for(int index = 0 ; index < 3 ; ++index){
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += velocity[index] * dt;
}
}
else{
last_values = new float[3];
acceleration = new float[3];
velocity = new float[3];
position = new float[3];
velocity[0] = velocity[1] = velocity[2] = 0f;
position[0] = position[1] = position[2] = 0f;
}
xarr.add(position[0]);
yarr.add(position[1]);
zarr.add(position[2]);
tvX.setText(String.valueOf(position[0]));
tvY.setText(String.valueOf(position[1]));
tvZ.setText(String.valueOf(position[2]));
last_timestamp = event.timestamp;
}
And this are a few X axis values:
X axis
-0,001147982
-0,003418462
-0,006807898
-0,011325749
-0,01697435
-0,023762027
-0,031681452
-0,04072018
-0,050905682
-0,062279336
-0,07478787
-0,088445522
-0,103226766
-0,119143963
-0,136174649
-0,154338345
-0,17362912
-0,19407627
-0,215692967
Please help.
I am currently trying to write a fall detection algorithm on android. I have successfully detected free fall, however when the phone lands the resulting vector is always around 1G and I am not able to create an upper threshold. Here is my code for the method:
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
double totalAccel = Math.sqrt(Math.pow(x,2) + Math.pow(y,2) + Math.pow(z,2));
if(totalAccel < FALL_THRESHOLD && !isFalling){
isFalling = true;
}
if(isFalling && totalAccel > FALL_THRESHOLD){
isFalling = false;
TextView view = (TextView) findViewById(R.id.values);
view.setText("" + totalAccel);
}
I try to use the Vector Rotation sensor to find the event when the user turn over his device, as GS3 to stop music.
My code :
private SensorManager mSensorManager;
private final SensorEventListener mSensorListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
System.out.println("X Vector : " + x + " / Y Vector : " + y + " / Z Vector : " + z);
if(//condition){
//method1();
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR), SensorManager.SENSOR_DELAY_NORMAL);
}
I use System.out.println to see how the x, y and z variables change during my turn over, but I don't understand these values. When I let the device on the table and I start Activity, x, y and z are not always at 0. Then when I turn over it, all values change and still very close (values between -1 and 1).
My quastion is, how can I find the good axis, and what is the value which I have to put in my condition to detect the turn over ?
EDIT : Finally the code works fine using Y axe, but I can't use the values if landscape orientation is possible on the activity. Y axe values are corrects only if use portrait orientation only. Any idea to use with both ?
I am building an Android game and I want to figure out whether the user tilts the device to the left or the right (Similar to how Temple Run works when you move the man from side to side).
I have read many tutorials and examples and I made sample applications but the amount of data I get back from both the Gyroscope and the Accelerometer are overwhelming. Would I need both sets of hardware to work out whether the user tilts the device and in which direction?
My current application is detecting every slight movement and that is obviously not correct.
public class Main extends Activity {
private SensorManager mSensorManager;
private float mAccel; // acceleration apart from gravity
private float mAccelCurrent; // current acceleration including gravity
private float mAccelLast; // last acceleration including gravity
private RelativeLayout background;
private Boolean isleft = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.background = (RelativeLayout) findViewById(R.id.RelativeLayout1);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
/* float x1, x2, y1, y2;
String direction;
switch(event.getAction()) {
case(MotionEvent.ACTION_DOWN):
x1 = event.getX();
y1 = event.getY();
break;
case(MotionEvent.ACTION_UP) {
x2 = event.getX();
y2 = event.getY();
float dx = x2-x1;
float dy = y2-y1;
// Use dx and dy to determine the direction
if(Math.abs(dx) > Math.abs(dy)) {
if(dx>0) directiion = "right";
else direction = "left";
} else {
if(dy>0) direction = "down";
else direction = "up";
}
}
}*/
}
private final SensorEventListener mSensorListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
if((mAccelLast<mAccelCurrent)&&(isleft == true)){
background.setBackgroundResource(R.drawable.bg_right);
isleft = false;
}
if((mAccelLast>mAccelCurrent)&&(isleft == false)){
background.setBackgroundResource(R.drawable.bg_left);
isleft = true;
}
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = mAccelCurrent - mAccelLast;
Log.d("FB", "delta : "+delta);
mAccel = mAccel * 0.9f + delta; // perform low-cut filter
// Log.d("FB", "mAccel : "+mAccel);
}
Would I be better off using just the accelerometer, just the gyroscope or would I need both?
This post links to the differences between the two: Android accelerometer and gyroscope
http://diydrones.com/profiles/blogs/faq-whats-the-difference
http://answers.oreilly.com/topic/1751-mobile-accelerometers-and-gyroscopes-explained/
The documentation will also help: http://developer.android.com/guide/topics/sensors/sensors_motion.html
From my VERY limited experience, the gyro constantly measures the x, y, z rotation and keeps updating. Useful for steering a car/plane/character in a game. The accelerometer is a little more like a wii-mote, for swinging around or picking up a shake gesture.
From my experience with accelerometer using the gravity method, you can use it for x, y and z rotation. Just type in google "vector method accelerometer". I have used this method with a compass for correcting the coordinates due to tilt.