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 ?
Related
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
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.
I've found this code, Its function is to do something when the device is shaken strong enough, but I haven't fully understood it . Anyone please help me
public class ShakeActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
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;
}
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 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];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta; // perform low-cut filter
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onStop() {
mSensorManager.unregisterListener(mSensorListener);
super.onStop();
}
}
please help me to understand this two lines
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));//I guess this is for computing the value of the acceleration
and this line I don't understand
mAccel = mAccel * 0.9f + delta;
thanks in advance.
The sensor will return three values, for acceleration along the three axis directions; these are placed in x, y and z in your code sample. Imagine three masses on springs all at right angles to each other; as you move the device around and the springs stretch and contract, x, y and z contain their lengths.
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
This is computing the magnitude of the acceleration. Imagine if, instead of the three masses on springs, you had just one, always pointing exactly in the direction the device is being accelerated in. It's actually possible to work out what that system would look like from the values we have, and that's what's being done here: mAccelCurrent is how much such a spring would get stretched. This is the calculation being performed.
mAccel = mAccel * 0.9f + delta;
This is a high pass filter on the input. Here it has the effect of making sudden changes in acceleration give bigger values. It's not clear from just the code you've posted why this is being done; I am guessing it is to make the code elsewhere that ultimately checks mAccel more sensitive to the forces at the extremes of each shake when the device is being shaken.
I am developing an application where I would require to retrieve the angle between the device and the vertical axis (the axis pointing to the center of the Earth).
So far, all the documentations and tutorials I found were not very conclusive.
Could you please explain me how can I do this or provide me with a link to a clear tutorial to help me find a solution to this problem?
First, I created a SensorEventListener implementation
private SensorEventListener sensorEventListener =
new SensorEventListener() {
/** The side that is currently up */
//private Side currentSide = null;
//private Side oldSide = null;
private float azimuth;
private float pitch;
private float roll;
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event) {
azimuth = event.values[0]; // azimuth
pitch = event.values[1]; // pitch
roll = event.values[2]; // roll
//code to deal with orientation changes;
//pitch is the angle between the vertical axis and the device's y axis (the one from the center of the device to its top)
}
};
Then, I register this listener to an Orientation Sensor
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
Sensor sensor;
List<Sensor> sensors = sensorManager.getSensorList(
Sensor.TYPE_ORIENTATION);
if (sensors.size() > 0) {
sensor = sensors.get(0);
sensorManager.registerListener(
sensorEventListener, sensor,
SensorManager.SENSOR_DELAY_NORMAL);
} else {
//notify the user that there's no orientation sensor
}
This may be an easy question, but I'm stuck. I am trying to implement the "shake to erase" feature in a drawing program (simple paint app). I can't get it to work. Here's my code:
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];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta; // perform low-cut filter
if (mAccel > 2) {
mView.onDraw(mCanvas);
mCanvas.drawBitmap(cache, 0, 0, new Paint(Paint.DITHER_FLAG));
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
The SensorEventListener is based off of this example. I make it into the if statement, but the canvas won't reset until after I've touched the screen (a new touch event).
I'd like the canvas to reset/erase during the shake event, without any further prompts from the user necessary.
Any help would be wonderful, thank you!
You might have to call invalidate on the graphics object to get it to redraw.
Hope that helps!
http://developer.android.com/guide/topics/graphics/index.html