in my app, i use the AccelerationSensor.accelerationchanged(xAccel, yAccel, zAccel) API
the problem is the method is called every o.oooo1 change in any axis, so the app becomes very slow, some times even becomes "non-responding"
Is there a way to check if the integer part has changed and let away any decimal change?
This is what I am doing, in my onStartCommand() of my service
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
This is the function I am handling my data, it is pretty light weight but it should give you an idea using a threshold. In my case I really just need to know the device a bit, in my case it turned out the differenceValue neeeded to be about 1.75G but it might be different for you.
#Override
public void onSensorChanged(SensorEvent event) {
if(last[0] == 0.0f &&
last[1] == 0.0f &&
last[2] == 0.0f){
last[0] = event.values[0];
last[1] = event.values[1];
last[2] = event.values[2];
return;
}
float diff = 0f;
if(Math.abs(last[0] - event.values[0]) > differenceValue ||
Math.abs(last[1] - event.values[1]) > differenceValue ||
Math.abs(last[2] - event.values[2]) > differenceValue){
Log.d(TAG,"G values are "+event.values[0]+" "+event.values[1]+" "+event.values[2]);
Log.d(TAG,"Last G values are "+last[0]+" "+last[1]+" "+last[2]);
diff = Math.abs(last[0] - event.values[0]);
if(diff < Math.abs(last[1] - event.values[1])){
diff = Math.abs(last[1] - event.values[1]);
}
if(diff < Math.abs(last[2] - event.values[2])){
diff = Math.abs(last[2] - event.values[2]);
}
Log.d(TAG,"Sensor difference: "+diff);
//Do what ever processing you need here
}
last[0] = event.values[0];
last[1] = event.values[1];
last[2] = event.values[2];
}
When you register a listener for a sensor it allows you to set a frequency. Use a slower frequency.
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 was in a car accident on Tuesday evening, and am hoping someone here might be able to help.
I am wondering if it’s possible to gather position or accelerometer data from my phone to help pinpoint the time of impact, which might possibly be used in concert with traffic-light data or video from nearby cameras or other data.
Apologies for the slightly off-topic request. Posting here was recommended by some developer friends of mine.
from your question, yes it can be done by
get accelerometer to get it's value from time to time, since when your vehicle is going to crash, the force will give the very high result
from my point of view, you need to use compass sensor to help it to calculate properly, (plus GPS sensor, it world be a great help to calculate your current speed)
last one, you need to research about how the vehicle crash, when it hit force will go to forth and back, so alot of experiment or good research would be your great help
for starting of accelerometer, (not much of mobile device have this sensor)
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// to get accelerometer censor
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Sensor mySensor = sensorEvent.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
long curTime = System.currentTimeMillis();
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 > MIGHT_BE_CRASHING_THRESHOLD) {
// do something
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
im getting linear acceleration from my phone and have a problem.
I wanted to get i=i+1 if acceleration is higher than 10m/s but only add 1 ONCE not all the time readings are above 10 m/s. So thinking about getting the moment when values are getting down again below 10 and than adding +1 to i. Can Anyone help me?
For now im doing it like this but that works bad.
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
//odczytWyswX.setText(Float.toString(x));
//odczytWyswY.setText(Float.toString(y));
// odczytWyswZ.setText(Float.toString(z));
if (event.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
gravSensorVals = lowPass(event.values.clone(), gravSensorVals);
grav[0] = event.values[0];
grav[1] = event.values[1];
grav[2] = event.values[2];
}
odczytWyswZ.setText(Float.toString(grav[2]));
wychwytywanieGornegoTapniecia();
}
void wychwytywanieGornegoTapniecia(){
if(grav[2]>10){ i++
}
Try using a simple boolean in your logic.
private boolean updateValue; // A field on the Class
if (grav[2] > 10 && updateValue) {
i++;
updateValue = false;
}
if (grav[2] < 10) {
updateValue = true;
}
I want to perform some activity when the user lifts the phone from a flat surface. The method I am using right now is detect shake motion using phone's Accelerometer using the following code:
sensorMan = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMan.registerListener(this, accelerometer, SensorManager.SENSOR_STATUS_ACCURACY_HIGH);
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;
if (mAccel > 0.9) {
//Perform certain tasks.
}
}
The issue I am facing with this code is the 0.9f threshold is reached sometimes even if the phone is still on the flat surface. I tried logging the mAccel value and found it to be rannging from 9.0 to 0.4 even when the phone is not even touched. Is there any guaranteed way to detect the phone's lift movement?
Solved the issue. All I wanted to do was to check for the "Y" value stated in the question and check if the value was greater than 1.0.
Note that, if the phone is kept in vertical position the Y is always around 9.8 but in such cases you can check for X instead. In my case user had to lift the phone and somewhen he will tilt the phone so I put a check for if(y >= 1.0 && y <= 2.0);
EDIT : UPDATED CODE
#Override
public void onSensorChanged(SensorEvent event) {
try {
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];
float yAbs = Math.abs(mGravity[1]);
mAccelLast = mAccelCurrent;
mAccelCurrent = FloatMath.sqrt(x * x + y * y + z * z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
if (yAbs > 2.0 && yAbs < 4.0 && !isAlerted() && !isCallActive()) {
alert();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I would add the Gyroscope into the detection routine too.
The Phone gets Accelerated AND gets up from x=0 y=0 z=0 to, lets say y=120, that's the Trigger.
Look here
for Infos how to using it.
Another Sensor for lifting detection would be the Proximity Sensor, when the Phone lays flat on the Desk dinstance would be 0, if its picked up that value would raise quickly
I'm making a game which uses the device's accelerometer to fill a progress bar.
On my Note 2 it takes me about 20 seconds shaking the phone up and down to fill the bar, however I tried on a ZTE Blade and it took me 4 seconds.
Is there any way to calibrate the accelerometers within my code? This is what I'm doing:
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
if (!mInitialized) {
mLastX = x;
mLastY = y;
mLastZ = z;
mInitialized = true;
} else {
float deltaX = Math.abs(mLastX - x);
float deltaY = Math.abs(mLastY - y);
float deltaZ = Math.abs(mLastZ - z);
if (deltaX < NOISE) deltaX = (float)0.0;
if (deltaY < NOISE) deltaY = (float)0.0;
if (deltaZ < NOISE) deltaZ = (float)0.0;
mLastX = x;
mLastY = y;
mLastZ = z;
if(deltaY == 0){
return;
}
sProgress += deltaY;
pb.setProgress(sProgress);
}
}
Issue may be with frequency of Accelerometer.Dont use below android constants while registering.
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
these valuse are different for different device.
int SENSOR_DELAY_FASTEST get sensor data as fast as possible
int SENSOR_DELAY_GAME rate suitable for games
int SENSOR_DELAY_NORMAL rate (default) suitable for screen orientation changes
int SENSOR_DELAY_UI rate suitable for the user interface
Use Hard coded values in microseconds like for frequency 1 Hz
mSensorManager.registerListener(this, mAccelerometer,1000000);
Hope it solves.
Another solution to making the frequency equal is something like the following solution.
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
if(sensorEventTooQuick(sensorEvent.timestamp)) {
return;
}
mLastSensorEventTime = sensorEvent.timestamp;
// process sensor
}
private boolean sensorEventTooQuick(long sensorTime) {
long diff = sensorTime - mLastSensorEventTime;
return diff < MINIMUM_SENSOR_EVENT_GAP;
}
Things to consider:
You want to make sure you choose MINIMUM_SENSOR_EVENT_GAP to be small enough as to not lose information. The accelerometer is very quick so this is usually not a problem, but could be an issue for other sensors depending on the application.
Make sure to test different values across different devices.
I do this since it guarantees that you will not receive events faster than your limit.