Gyroscope absolute value - android

I have the following code for using the Gyroscope sensor, but it doesn't fit my needs, because it only gives me the xyz changes in a specific time. Is there a way to get the absolute xyz-rotation coordinates. Like if my smartphone is laying on the ground it has x = 0° and when it is tilted it has something like e.g. 34°
SensorManager sensorManager =
(SensorManager) getSystemService(SENSOR_SERVICE);
Sensor gyroscopeSensor =
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
SensorEventListener gyroscopeSensorListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float dx = sensorEvent.values[0];
float dy = sensorEvent.values[1];
float dz = sensorEvent.values[2];
Log.e("COORD",dx + " " + dy + " " + dz);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
};
sensorManager.registerListener(gyroscopeSensorListener,
gyroscopeSensor, SensorManager.SENSOR_DELAY_FASTEST);

Related

Accelerometer values to degrees

I wrote the following code,where the values of the accelerometer are shown in x,y,z during rotation.
public class MainActivity extends AppCompatActivity implements SensorEventListener {
private TextView xText,yText,zText;
private Sensor mySensor;
private SensorManager SM;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Creating the Sensor Manager
SM = (SensorManager)getSystemService(SENSOR_SERVICE);
// Accelerometer Sensor
mySensor = SM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// Register sensor Listener
SM.registerListener(this, mySensor, SensorManager.SENSOR_DELAY_NORMAL);
// Assign TextView
xText = (TextView)findViewById(R.id.xText);
yText = (TextView)findViewById(R.id.yText);
zText = (TextView)findViewById(R.id.zText);
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
xText.setText("X: " + sensorEvent.values[0]);
yText.setText("Y: " + sensorEvent.values[1]);
zText.setText("Z: " + sensorEvent.values[2]);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
}
Now I want to convert the values I get from the SensorEvents to degrees. I looked at various questions here,but I got confused.
double x = sensorEvent.values[0];
double y = sensorEvent.values[1];
double z = sensorEvent.values[2];
There should be a formula that takes the above values and convert them in degrees.
Any ideas?
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
//xText.setText("X: " + sensorEvent.values[0]);
//yText.setText("Y: " + sensorEvent.values[1]);
//zText.setText("Z: " + sensorEvent.values[2]);
double x = sensorEvent.values[0];
double y = sensorEvent.values[1];
double z = sensorEvent.values[2];
double pitch = Math.atan(x/Math.sqrt(Math.pow(y,2) + Math.pow(z,2)));
double roll = Math.atan(y/Math.sqrt(Math.pow(x,2) + Math.pow(z,2)));
//convert radians into degrees
pitch = pitch * (180.0/3.14);
roll = roll * (180.0/3.14) ;
yText.setText(String.valueOf(pitch));
zText.setText(String.valueOf(roll));
}
Now I want to convert the values I get from the SensorEvents to degrees
The unit of the value you get from TYPE_ACCELEROMETER is m/s^2, thus trying to convert to degree does not make sense.
Your pitch and roll calculations do not seem right. For the correct calculation see the method processSensorData(DProcessedSensorEvent.DProcessedSensorEventBuilder builder) in the DSensorEventProcessor class at https://github.com/hoananguyen/dsensor/blob/master/dsensor/src/main/java/com/hoan/dsensor_master/DSensorEventProcessor.java
To convert pitch and roll to degrees use Math.toDegrees(valueToConvert)
Youll need to register for the TYPE_ACCELEROMETER, but also for TYPE_MAGNETIC_FIELD and than you can leverage SensorManager built-in method for your help:
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geomagnetic = event.values;
if (mGravity != null && geomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity, geomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
myAzimut = orientation[0]; // myAzimut is The geomagnetic inclination angle in radians.
}
}
}
You can learn all additional information by reading SensorManagersource code comments.
your code seem right. use Math.PI in (180.0/3.14) to get more accurate results.

Android accelerometer reading 0 on z axys without change

I'm creating an app that makes use of accelerometer data to calculate device roll and pitch.
This is what I have for now, still haven't coded the roll/pitch calculations.
Just checking to see which sensors are present and listing them in logcat, checking if device has accelerometer, and implementing a simple output GUI (4 textviews, corresponding to the 3 axes and max sensor range).
X and Y read correctly with phone stationary and rotating along one axys at a time, and go from 0 to around 9.5 (which would correspond to the normal 9.8m/s2 corresponding to earth's gravity force). Shaking the device results in values going over the 9.8 threshold, as expected.
Z acceleration (sensorEvent.values[2]), however, is stationary at around 0.032 (lets call it a zero). Shaking, rotating, everything short of throwing it against a wall produces absolutely no change... Which renders any of my attempts to calculate roll and pitch pretty much useless...
Is there anything wrong with this code, or should I assume something is wrong with this particular phone (tested it with my wife's phone which is exactly the same model: same results).
Accelerometer is a KXTJ2-1009 3-axis Accelerometer (its the phones
only physical sensor)
Phone is a chinese-made HTM phone (suppose its a HTC clone)
(http://www.everbuying.com/product555984.html)
public class MainActivity extends ActionBarActivity implements SensorEventListener {
private TextView raw_x, raw_y, raw_z, acc_max;
private boolean hasAccelerometer;
private SensorManager senSensorManager;
private Sensor senAccelerometer;
private long lastUpdate = 0;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 700;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sMgr = (SensorManager) this.getSystemService(SENSOR_SERVICE);
List<Sensor> list = sMgr.getSensorList(Sensor.TYPE_ALL);
String data = new String();
for (Sensor sensor : list) {
data += (sensor.getName() + "\n");
data += (sensor.getVendor() + "\n");
data += (sensor.getVersion() + "\n");
}
Log.d(TAG, data);
PackageManager manager = getPackageManager();
hasAccelerometer = manager.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER);
if(hasAccelerometer) {
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
}
Log.d(TAG,Float.toString(senAccelerometer.getMaximumRange()));
initGui();
}
#Override
protected void onResume() {
super.onResume();
senSensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Sensor mySensor = sensorEvent.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
float x = (float) sensorEvent.values[0];
float y = (float) sensorEvent.values[1];
float z = (float) sensorEvent.values[2];
if ((curTime - lastUpdate) > 100) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000;
if (speed > SHAKE_THRESHOLD) {
//doSomething()
}
if(raw_x!=null){
raw_x.setText(Float.toString(x));
raw_y.setText(Float.toString(y));
raw_z.setText(Float.toString(z));
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private void initGui() {
setContentView(R.layout.activity_main);
raw_x = (TextView) findViewById(R.id.lbl_raw_x);
raw_y = (TextView) findViewById(R.id.lbl_raw_y);
raw_z = (TextView) findViewById(R.id.lbl_raw_z);
acc_max = (TextView) findViewById(R.id.lbl_max);
acc_max.setText(Float.toString(senAccelerometer.getMaximumRange()));
}
}
Apparently this is normal, since Z-axis depends on magnetic orientation. Without a gyroscope, magnetometer or compass the z-value will most likely always be 0. Or at least remain unchanged.
Since this phone of mine has none of those, that clears it up.

Get device angle by using getOrientation() function

I was using Sensor.TYPE_ORIENTATION to determine current angle of device but TYPE_ORIENTATION is deprecated on API version 8. In SensorManager manual it refers to getOrientation() function in order to use TYPE_ORIENTATION.
Here is the manual
Here is my old code :
public void onSensorChanged(SensorEvent event) {
Log.d("debug","Sensor Changed");
if (event.sensor.getType()==Sensor.TYPE_ORIENTATION) {
Log.d("debug",Float.toString(event.values[0]));
float mAzimuth = event.values[0];
float mPitch = event.values[1];
float mRoll = event.values[2];
Log.d("debug","mAzimuth :"+Float.toString(mAzimuth));
Log.d("debug","mPitch :"+Float.toString(mPitch));
Log.d("debug","mRoll :"+Float.toString(mRoll));
}
}
I'm really confused about using getOrientation() function, can anyone please show me an example how to get the angles?
You now use two sensors (ACCELEROMETER and MAGNETIC_FIELD) to get that information. See blog post for more detail.
public class CompassActivity extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
Sensor accelerometer;
Sensor magnetometer;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(mCustomDrawableView); // Register the sensor listeners
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0]; // orientation contains: azimut, pitch and roll
}
}
}
}
Permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Regarding your second question. When you are registering your sensor listeners, change your code to read:
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
}
Google has a great demo app for orientation in their google-developer-training series called TiltSpot. Because it has an Apache license, I've taken the liberty of turning it into a small library called johnnylambada-orientation that makes getting orientation as simple adding this to your activity:
getLifecycle().addObserver(new OrientationReporter(this, (a, p, r) -> {
Log.i("orientation","a="+a+" p="+p+" r="+r);
}));
My Answer is for those who getting jumping values of heading. For further instruction let me know in the comment.
Sensor accelerometer;
Sensor magnetometer;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float[] Rv = new float[9];
private float[] I = new float[9];
class MapsActivity
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, SensorEventListener{
onSensorChanged(SensorEvent event)
#Override
public void onSensorChanged(SensorEvent event) {
synchronized (this) {
float INITIAL_ALPHA = 0.97f;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = INITIAL_ALPHA * mGravity[0] + (1 - INITIAL_ALPHA)
* event.values[0];
mGravity[1] = INITIAL_ALPHA * mGravity[1] + (1 - INITIAL_ALPHA)
* event.values[1];
mGravity[2] = INITIAL_ALPHA * mGravity[2] + (1 - INITIAL_ALPHA)
* event.values[2];
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mGeomagnetic[0] = INITIAL_ALPHA * mGeomagnetic[0] + (1 - INITIAL_ALPHA)
* event.values[0];
mGeomagnetic[1] = INITIAL_ALPHA * mGeomagnetic[1] + (1 - INITIAL_ALPHA)
* event.values[1];
mGeomagnetic[2] = INITIAL_ALPHA * mGeomagnetic[2] + (1 - INITIAL_ALPHA)
* event.values[2];
if (Math.abs(mGeomagnetic[2]) > Math.abs(mGeomagnetic[1])) {
magStrength = Math.round(Math.abs(mGeomagnetic[2]));
} else {
magStrength = Math.round(Math.abs(mGeomagnetic[1]));
}
}
boolean success = SensorManager.getRotationMatrix(Rv, I, mGravity, mGeomagnetic);
if (success) {
float[] orientation = new float[3];
SensorManager.getOrientation(Rv, orientation);
azimuth = (float) Math.toDegrees(orientation[0]);
azimuth = (azimuth + 360) % 360;
// Log.d(TAG, "azimuth (deg): " + azimuth);
float degree = Math.round(azimuth);
// create a rotation animation (reverse turn degree degrees)
RotateAnimation ra = new RotateAnimation(
currentDegree,
-degree,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF,
0.5f);
ra.setDuration(500);
ra.setFillAfter(true);
ra.setRepeatCount(0);
binding.compassImage.startAnimation(ra);
showDirection(degree);
currentDegree = -degree;
}
}
}
onAccuracyChanged
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
onResume()
#Override
protected void onResume() {
super.onResume();
if (mSensorManager == null) {
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
mSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this, magnetometer,
SensorManager.SENSOR_DELAY_UI);
}
onPause()
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(MapsActivity.this);
}

how can we measure distance between object and android phone camera

I want to calculate the distance between the camera and the recognized object.For this I tried a lot of methods, I tried to find the angle between the object and the camera using accelerometer and then use
d = h * tan a
h is height of from from the base generally which is 1.4
and i tried to calculate the angle by using get orientation method. Kindly let me know where am I doing wrong. Its been more than 2 days I have been struggling with this requirement. We have looked into various Camera applications which are available on Android Store and have tried to understand the functionality of the same but nothing has been fruitful.
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetSensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values;
if (gravity != null && geoMagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity,
geoMagnetic);
if (success) {
/* Orientation has azimuth, pitch and roll */
float orientation[] = new float[3];
//SensorManager.remapCoordinateSystem(R, 1, 3, orientation);
SensorManager.getOrientation(R, orientation);
azimut = 57.29578F * orientation[0];
pitch = 57.29578F * orientation[1];
roll = 57.29578F * orientation[2];
}
}
}
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
double d = (Math.tan(Math.toRadians(Math.abs(pitch))) * sensorHeight);
Toast.makeText(
getApplicationContext(),
"Distance = "
+ String.valueOf(d)
+ "m Angle = "
+ String.valueOf(Math.toRadians(Math.abs(pitch))),
Toast.LENGTH_LONG).show();
}
});
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accSensor,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
Your getRotationMatrix is probably returning false! You should copy the values to your own vectors so they don't get mixed up! Use the clone() method to do so!
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values.clone();
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values.clone();
Using your code plus this change I was able to get the azimuth/pitch/roll values, without this change the success flag returns false:
Log.d("a", "orientation values: " + azimut + " / " + pitch + " / " + roll);
05-21 16:07:55.743: D/a(29429): orientation values: 77.71578 / 43.352722 / -152.39603
05-21 16:07:55.883: D/a(29429): orientation values: 175.26134 / 23.031355 / -148.72844
05-21 16:07:56.793: D/a(29429): orientation values: -146.3089 / 4.1098075 / -14.46417
You should use the PITCH value if you are holding the phone in portrait mode, if you are holding the phone in landscape mode you should use the ROLL value.
If you are holding the phone at a 1.4 height then you will have:
float dist = Math.abs((float) (1.4f * Math.tan(pitch * Math.PI / 180)));
Please note that you should use RADIANS and not DEGREES on the Math.tan function.
I tested here and the values seem to be valid!
The final code is
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetSensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
gravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
geoMagnetic = event.values;
if (gravity != null && geoMagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, gravity,
geoMagnetic);
if (success) {
/* Orientation has azimuth, pitch and roll */
float orientation[] = new float[3];
//SensorManager.remapCoordinateSystem(R, 1, 3, orientation);
SensorManager.getOrientation(R, orientation);
azimut = 57.29578F * orientation[0];
pitch = 57.29578F * orientation[1];
roll = 57.29578F * orientation[2];
}
}
}
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
float d = Math.abs((float) (1.4f * Math.tan(pitch * Math.PI / 180)));
Toast.makeText(
getApplicationContext(),
"Distance = "
+ String.valueOf(d)
+ "m Angle = "
+ String.valueOf(Math.toRadians(Math.abs(pitch))),
Toast.LENGTH_LONG).show();
}
});
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, accSensor,
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}

How to detect movement of an android device?

I need suggestion about how to detect the amount of movement of an android device. Suppose I have put the phone on a table or bed and then if somebody taps the table or sits or laydown on the bed then I want to detect the movement of the android device.
Actually I know that android has motion sensors APIs but I don't know which sensor to use and what sensor type is best for this type of movement detection.
I would be glad if someone can share some basic demo code.
Definitely work with the accelerometer:
// Start with some variables
private SensorManager sensorMan;
private Sensor accelerometer;
private float[] mGravity;
private float mAccel;
private float mAccelCurrent;
private float mAccelLast;
// In onCreate method
sensorMan = (SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
// And these:
#Override
public void onResume() {
super.onResume();
sensorMan.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
}
#Override
protected void onPause() {
super.onPause();
sensorMan.unregisterListener(this);
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
mGravity = event.values.clone();
// Shake detection
float x = mGravity[0];
float y = mGravity[1];
float z = mGravity[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = FloatMath.sqrt(x*x + y*y + z*z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
// Make this higher or lower according to how much
// motion you want to detect
if(mAccel > 3){
// do something
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// required method
}
I used the following class:
public class MovementDetector implements SensorEventListener {
protected final String TAG = getClass().getSimpleName();
private SensorManager sensorMan;
private Sensor accelerometer;
private MovementDetector() {
}
private static MovementDetector mInstance;
public static MovementDetector getInstance() {
if (mInstance == null) {
mInstance = new MovementDetector();
mInstance.init();
}
return mInstance;
}
//////////////////////
private HashSet<Listener> mListeners = new HashSet<MovementDetector.Listener>();
private void init() {
sensorMan = (SensorManager) GlobalData.getInstance().getContext().getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
}
public void start() {
sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
public void stop() {
sensorMan.unregisterListener(this);
}
public void addListener(Listener listener) {
mListeners.add(listener);
}
/* (non-Javadoc)
* #see android.hardware.SensorEventListener#onSensorChanged(android.hardware.SensorEvent)
*/
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
float diff = (float) Math.sqrt(x * x + y * y + z * z);
if (diff > 0.5) // 0.5 is a threshold, you can test it and change it
Log.d(TAG,"Device motion detected!!!!");
for (Listener listener : mListeners) {
listener.onMotionDetected(event, diff);
}
}
}
/* (non-Javadoc)
* #see android.hardware.SensorEventListener#onAccuracyChanged(android.hardware.Sensor, int)
*/
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
public interface Listener {
void onMotionDetected(SensorEvent event, float acceleration);
}
}
Usage:
On my activity onCrate():
MovementDetector.getInstance().addListener(new MovementDetector.Listener() {
#Override
public void onMotionDetected(SensorEvent event, float acceleration) {
mMotionDetectionTextView.setText("Acceleration: ["+String.format("%.3f",event.values[0])+","+String.format("%.3f",event.values[1])+","+String.format("%.3f",event.values[2])+"] "+String.format("%.3f", acceleration));
if (acceleration > SettingsHelper.getInstance().getMotionDetectionThreshold()){
mMotionDetectionTextView.setTextColor(Color.RED);
} else {
mMotionDetectionTextView.setTextColor(Color.WHITE);
}
}
});
On my activity onResume():
MovementDetector.getInstance().start();
On my activity onPause():
MovementDetector.getInstance().stop();
This code is for walking detection (Modified from #anthropomo code)
to get smoother value.
// initialize
private SensorManager sensorMan;
private Sensor accelerometer;
private float[] mGravity;
private double mAccel;
private double mAccelCurrent;
private double mAccelLast;
private boolean sensorRegistered = false;
// onCreate
sensorMan = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
sensorMan.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
sensorRegistered = true;
// onSensorChanged
private int hitCount = 0;
private double hitSum = 0;
private double hitResult = 0;
private final int SAMPLE_SIZE = 50; // change this sample size as you want, higher is more precise but slow measure.
private final double THRESHOLD = 0.2; // change this threshold as you want, higher is more spike movement
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = event.values.clone();
// Shake detection
double x = mGravity[0];
double y = mGravity[1];
double z = mGravity[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = Math.sqrt(x * x + y * y + z * z);
double delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
if (hitCount <= SAMPLE_SIZE) {
hitCount++;
hitSum += Math.abs(mAccel);
} else {
hitResult = hitSum / SAMPLE_SIZE;
Log.d(TAG, String.valueOf(hitResult));
if (hitResult > THRESHOLD) {
Log.d(TAG, "Walking");
} else {
Log.d(TAG, "Stop Walking");
}
hitCount = 0;
hitSum = 0;
hitResult = 0;
}
}
}
I have been working with a similar idea to measure the displacement of the phone. I have found that the LINEAR ACCELERATION (and ACCELERATION) are not accurate enough to correctly measure the displacement.
This code should work a little better:
(ititialize)
private SensorManager sensorManager;
private Sensor accelerometer;
double[] maxAccelerations = new double[3];
double[] position = new double[3];
long[] times = new long[3];
// time combined with maxAcceleration can approximate the change in position,
// with the formula Δpos = (maxAcceleration * time ^ 2) / 6
long currentTime;
(onCreate)
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION) != null) {
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
sensorManager.registerListener(this, accelerometer, sensorManager.SENSOR_DELAY_FASTEST);
}
currentTime = System.currentTimeMillis();
for(int i=0;i<3;i++){
times[i]=currentTime;
}
else{
throw "Error";
//Which will throw an error, if not the error that is expected. 😉
}
(onSensorChanged and onAccuracyChanged)
#Override
public void onAccuracyChanged(Sensor ignore, int thisFunction) {
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
for(int i=0;i<3;i++){
if(Math.abs(event.values[i])<0.01){
// Note: this is to try to prevent accelerating time from being counted when the phone is stationary. 0.01 should be
// changed to an appropriate sensitivity level that can be calculated by finding an average noise level when the phone is stationary.
times[i]=System.currentTimeMillis();
}
if(event.values[i]>maxAccelerations[i] && maxAccelerations[i]>=0){
maxAccelerations[i]=event.values[i];
}
else if(event.values[i]<maxAccelerations[i] && maxAccelerations[i]<=0){
maxAccelerations[i]=event.values[i];
}
else if(event.values[i]>0 && maxAccelerations[i]<0){
currentTime = System.currentTimeMillis();
position[i]+=maxAccelerations[i] * (times[i]-currentTime)*(times[i]-currentTime) / 6;
times[i]=currentTime;
maxAccelerations[i]=event.values[i];
}
else if(event.values[i]<0 && maxAccelerations[i]>0){
currentTime = System.currentTimeMillis();
position[i]+=maxAccelerations[i] * (times[i]-currentTime)*(times[i]-currentTime) / 6;
times[i]=currentTime;
maxAccelerations[i]=event.values[i];
}
}
}
}
While I don't have demo code (since you aren't specific enough), a good start is here: http://developer.android.com/guide/topics/sensors/sensors_motion.html (and other items on the left).
if you are trying to find the displacement of your phone, you need to find the
Linear acceleration acting on your phone rather than the acceleration due to gravity
android has a built in converter to find the LINEAR ACCELERATION acting on your mobile phone
https://github.com/yuvaramsingh94/AndroidSensorTestCode/tree/master
this is a code where you can see how to get the raw value of LINEAR ACCELERATION

Categories

Resources