I am getting the accelerometer values continuously (i.e) X and Y values in the run time. My question is that when the values of the accelerometer changes in mobile the corresponding values should be accumulated as per the change.
This is my code :
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private float accumulation_x = 0;
private float accumulation_y = 0;
private float accumulation_z = 0;
private TextView acessTextview, angleTextview;
private float value;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
int count = 1;
while(count!=0){
float x = (float) 0.9887777;
float y = (float) 0.187359372;
float z = (float) 0.0228636;
float X_axis = (float) (x + (0.02724095));
float Y_axis = (float) (y + (-0.027792556));
float Z_axis = (float) (z - (0.105689));
accumulation_x = accumulation_x + X_axis;
accumulation_y = accumulation_y + Y_axis;
accumulation_z = accumulation_z + Z_axis;
value = (y / z);
float angle = (float) Math.toDegrees(Math.atan(value));
angleTextview.setText("Angle:" + angle);
acessTextview.setText("accumulation_x :" + X_axis + "\n"
+ "accumulation_y :" + Y_axis + "\n"
+ "accumulation_z :" + Z_axis);
count++;
}
}
}
private void findViewById() {
// TODO Auto-generated method stub
acessTextview = (TextView) findViewById(R.id.accessTextview);
angleTextview = (TextView) findViewById(R.id.angleTextview);
}
}
Your code is correct, only minor changes are require, I have updated your code with an extra method called refreshValues(). This method will set the latest values of X,Y in to TextView. This method will get called from onSensorChanged() method.
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private float accumulation_x = 0;
private float accumulation_y = 0;
private float accumulation_z = 0;
private TextView acessTextview, angleTextview;
private float value;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
int count = 1;
while(count!=0){
float x = (float) 0.9887777;
float y = (float) 0.187359372;
float z = (float) 0.0228636;
float X_axis = (float) (x + (0.02724095));
float Y_axis = (float) (y + (-0.027792556));
float Z_axis = (float) (z - (0.105689));
accumulation_x = accumulation_x + X_axis;
accumulation_y = accumulation_y + Y_axis;
accumulation_z = accumulation_z + Z_axis;
value = (y / z);
float angle = (float) Math.toDegrees(Math.atan(value));
angleTextview.setText("Angle:" + angle);
acessTextview.setText("accumulation_x :" + X_axis + "\n"
+ "accumulation_y :" + Y_axis + "\n"
+ "accumulation_z :" + Z_axis);
count++;
}
}
refreshValues ( accumulation_x,accumulation_y );
}
private void findViewById() {
// TODO Auto-generated method stub
acessTextview = (TextView) findViewById(R.id.accessTextview);
angleTextview = (TextView) findViewById(R.id.angleTextview);
}
private void refreshValues ( float x, float y )
{
acessTextview.setText ( String.valueOf(x) );
angleTextview.setText( ( String.valueOf(y)));
}
}
Related
Due to the power consuming GPS data, I would like to calculate the device speed with only the accelerometer x,y and z data. I have read a lot of questions about this topic and I tried many set-ups to find a satisfactory solution to calculate the speed when my device is in my car.
It seems so simple but nothing works, which drives me crazy.
Been trying the Sensor.TYPE_LINEAR_ACCELERATION and the Sensor.TYPE_ACCELEROMETER with removed gravity. Tried a Low Pass Filter on the Linear acceleration data. Unfortunately all with no succes.
Looks like the calculated speed is correct but testing in my car the calculated speed doesn't get higher then about 2 m/s.
below a code snip
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
public void onSensorChanged(SensorEvent event) {
if (event.sensor == mAccelerometer) {
if (timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
lax = event.values[0];
lay = event.values[1];
laz = event.values[2];
vx = vxo + lax * dT ;
vy = vyo + lay * dT ;
vz = vzo + laz * dT ;
speed = (float) (Math.sqrt(vx*vx + vy*vy + vz*vz)) ;
if (speed < 0.01) {speed = 0 ; }
tv_speed.setText(String.valueOf(speed));
}
timestamp = event.timestamp;
}
}
Hope someone can help, thanks a lot.
It's possible to compute distance and speed using only accelerometer, but with three conditions:
1. Linear movement - trajectory must be straight.
2. Slope of the road must be constant.
3. You must perform calibration procedure before start.
Where can you use this method with such restrictions - it's up to you... Now, how to do it:
We need something, implementing SensorEventListener interface. For the future use, let's add following abstract class:
public abstract class Accelerometer implements SensorEventListener {
protected float lastX;
protected float lastY;
protected float lastZ;
public abstract Point getPoint();
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
}
and this will be our SensorEventListener:
public class XYZAccelerometer extends Accelerometer {
private static final int BUFFER_SIZE = 500;
// calibration
private float dX = 0;
private float dY = 0;
private float dZ = 0;
// buffer variables
private float X;
private float Y;
private float Z;
private int cnt = 0;
// returns last SenorEvent parameters
public Point getLastPoint(){
return new Point(lastX, lastY, lastZ, 1);
}
// returrns parameters, using buffer: average acceleration
// since last call of getPoint().
public Point getPoint(){
if (cnt == 0){
return new Point(lastX, lastY, lastZ, 1);
}
Point p = new Point(X, Y, Z, cnt);
reset();
return p;
}
// resets buffer
public void reset(){
cnt = 0;
X = 0;
Y = 0;
Z = 0;
}
public void onSensorChanged(SensorEvent se) {
float x = se.values[SensorManager.DATA_X] + dX;
float y = se.values[SensorManager.DATA_Y] + dY;
float z = se.values[SensorManager.DATA_Z] + dZ;
lastX = x;
lastY = y;
lastZ = z;
X+= x;
Y+= y;
Z+= z;
if (cnt < BUFFER_SIZE-1) {
cnt++;
} else
{
reset();
}
}
public int getCnt(){
return cnt;
}
public void setdX(float dX) {
this.dX = dX;
}
public void setdY(float dY) {
this.dY = dY;
}
public void setdZ(float dZ) {
this.dZ = dZ;
}
}
Calibrating accelerometer must be called before each experiment. Phone orientation must not be changed while measuring.
To calibrate accelerometer, i use this class:
public class Calibrator {
final static int UPDATE_INTERVAL = 400;
final static int ITERATIONS = 5;
Handler hRefresh;
XYZAccelerometer acc;
int eventNumber;
private LinkedList calData;
public Calibrator(Handler hRefresh, XYZAccelerometer acc, int eventNumber) {
this.hRefresh = hRefresh;
this.acc = acc;
this.eventNumber = eventNumber;
}
public void calibrate() {
final Timer calTimer = new Timer();
calData = new LinkedList();
acc.setdX(0);
acc.setdY(0);
acc.setdZ(0);
calTimer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
addCalData(calData);
if (calData.size() > ITERATIONS) {
calTimer.cancel();
try {
calSensor(calData);
} catch (Exception ex) {
try {
throw ex;
} catch (Exception ex1) {
hRefresh.sendEmptyMessage(5);
}
}
hRefresh.sendEmptyMessage(eventNumber);
}
}
},
0,
UPDATE_INTERVAL);
}
private void addCalData(LinkedList cD) {
Point p = acc.getPoint();
cD.add(p);
acc.reset();
}
private void calSensor(LinkedList cD) throws Exception {
if (cD.size() < ITERATIONS-1) {
throw new Exception("not enough data to calibrate");
}
float x = 0;
float y = 0;
float z = 0;
// Don't use first measure
for (int i = 1; i < cD.size(); ++i) {
x += cD.get(i).getX();
y += cD.get(i).getY();
z += cD.get(i).getZ();
}
x = x / (cD.size() - 1);
y = y / (cD.size() - 1);
z = z / (cD.size() - 1);
acc.setdX(-x);
acc.setdY(-y);
acc.setdZ(-z);
}
}
maintenance class to keep data of one measure
public class Point {
private float x = 0;
private float y = 0;
private float z = 0;
private int cnt = 1;
public float getX() {
return x/(float)cnt;
}
public float getY() {
return y/(float)cnt;
}
public float getZ() {
return z/(float)cnt;
}
public Point(float x, float y, float z, int cnt) {
this.x = x;
this.y = y;
this.z = z;
this.cnt = cnt;
}
public float getForce(){
return getX()*getX()+getY()*getY()+getZ()*getZ();
}
}
And class to process data of measure
public class MeasurePoint {
private float x;
private float y;
private float z;
private float speedBefore;
private float speedAfter;
private float distance;
private float acceleration;
private long interval;
private Point averagePoint;
public MeasurePoint(float x, float y, float z, float speedBefore, long interval, Point averagePoint) {
this.x = x;
this.y = y;
this.z = z;
this.speedBefore = speedBefore;
this.interval = interval;
this.averagePoint = averagePoint;
speedAfter = 0;
calc();
}
private void calc(){
//Acceleration as projection of current vector on average
acceleration = this.x*averagePoint.getX() +
this.y*averagePoint.getY() +
this.z*averagePoint.getZ();
acceleration = acceleration / ((float)Math.sqrt(averagePoint.getForce()));
float t = ((float)interval / 1000f);
speedAfter = speedBefore + acceleration * t;
distance = speedBefore*t + acceleration*t*t/2;
}
public String getStoreString(){
String s = "write here whatever you want";
return s;
}
// add getters
}
This one - to store and save data array
public class MeasureData {
// points from accelerometr
private LinkedList accData;
private LinkedList data;
// timer interval of generating points
private long interval;
public MeasureData(long interval) {
this.interval = interval;
accData = new LinkedList ();
data = new LinkedList ();
}
public void addPoint(Point p){
accData.add(p);
}
public void process(){
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
float speed = 0;
if(i > 0){
speed = data.get(i-1).getSpeedAfter();
}
data.add(new MeasurePoint(p.getX(), p.getY(), p.getZ(), speed, interval, getAveragePoint()));
}
}
public boolean saveExt(Context con, String fname) throws Throwable {
try {
File file = new File(con.getExternalFilesDir(null), fname);
FileOutputStream os = new FileOutputStream(file);
OutputStreamWriter out = new OutputStreamWriter(os);
for (int i = 0; i < data.size(); ++i) {
MeasurePoint m = data.get(i);
out.write(m.getStoreString());
}
out.close();
} catch (Throwable t) {
throw (t);
}
return true;
}
private Point getAveragePoint() {
float x = 0;
float y = 0;
float z = 0;
for(int i = 0; i < accData.size(); ++i){
Point p = accData.get(i);
x += p.getX();
y += p.getY();
z += p.getZ();
}
return new Point(x, y, z, 1);
}
public float getLastSpeed(){
return data.getLast().getSpeedAfter();
}
public float getLastSpeedKm(){
float ms = getLastSpeed();
return ms*3.6f;
}
}
And, finally, how to use all this in your activity(I cleaned it up a lot, sorry if it will not complie - fill free to write it in comments:
public class TestActivity extends Activity {
static final int TIMER_DONE = 2;
static final int START = 3;
static final int CAL_TIMER_DONE = 4;
static final int ERROR = 5;
private StartCatcher mStartListener;
private XYZAccelerometer xyzAcc;
private SensorManager mSensorManager;
private static final long UPDATE_INTERVAL = 500;
private static final long MEASURE_TIMES = 20;
private Timer timer;
private TextView tv;
private Button testBtn;
int counter;
private MeasureData mdXYZ;
/** handler for async events*/
Handler hRefresh = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TIMER_DONE:
onMeasureDone();
String es1 = Float.toString(Math.round(mdXYZ.getLastSpeedKm()*100)/100f);
tv.append(" END SPEED " + es1 + " " + es2 + " \n");
enableButtons();
break;
case START:
tv.append(" START");
timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
dumpSensor();
}
},
0,
UPDATE_INTERVAL);
break;
case ERROR:
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
break;
}
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.txt);
testBtn = (Button) findViewById(R.id.btn);
}
#Override
protected void onResume() {
super.onResume();
tv.append("\n ..");
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
setAccelerometer();
setStartCatcher();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(xyzAcc);
super.onPause();
}
public void onButtonTest(View v) {
disableButtons();
mdXYZ = new MeasureData(UPDATE_INTERVAL);
counter = 0;
tv.setText("");
tv.append("Calibrating");
Calibrator cal = new Calibrator(hRefresh, xyzAcc, START);
cal.calibrate();
}
void dumpSensor() {
++counter;
mdXYZ.addPoint(xyzAcc.getPoint());
hRefresh.sendEmptyMessage(TICK);
if (counter > MEASURE_TIMES) {
timer.cancel();
hRefresh.sendEmptyMessage(TIMER_DONE);
}
}
private void enableButtons() {
testBtn.setEnabled(true);
}
private void setAccelerometer() {
xyzAcc = new XYZAccelerometer();
mSensorManager.registerListener(xyzAcc,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
}
private void disableButtons() {
testBtn.setEnabled(false);
}
private void onMeasureDone() {
try {
mdXYZ.process();
long now = System.currentTimeMillis();
mdXYZ.saveExt(this, Long.toString(now) + ".csv");
} catch (Throwable ex) {
Toast.makeText(this, ex.getMessage().toString(), Toast.LENGTH_SHORT);
}
}
}
<serviceLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<serviceButton
android:id="#+id/btn"
android:text="TEST"
android:layout_width="300px"
android:layout_height="200px"
android:onClick="onButtonTest" />
<serviceTextView
android:id = "#+id/txt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=":"
/>
<service/LinearLayout>
Although at the developer.android.com site it is stated clearly that
you could use the linear accelerometer to see how fast your car is going"
But I did not find anything (in testing or in examples or code) that showed this is really true.
Now, unfortunately, I am convinced that it is not possible to calculate the speed of a car with the linear accelerometer.
Please see the below code to get the velocity using accelerometer
public class SensorTestActivity extends Activity implements SensorEventListener {
double calibration = Double.NaN;
private SensorManager sensorManager;
private boolean color = false;
private TextView view;
private long lastUpdate;
float appliedAcceleration = 0;
float currentAcceleration = 0;
float velocity = 0;
Date lastUpdatedate;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
view = findViewById(R.id.textView);
// view.setBackgroundColor(Color.GREEN);
lastUpdatedate = new Date(System.currentTimeMillis());
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
lastUpdate = System.currentTimeMillis();
}
#Override
public void onSensorChanged(SensorEvent event) {
// if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// getAccelerometer(event);
// }
double x = event.values[0];
double y = event.values[1];
double z = event.values[2];
double a = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
if (calibration == Double.NaN)
calibration = a;
else {
updateVelocity();
currentAcceleration = (float)a;
}
}
private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
long actualTime = event.timestamp;
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
// Toast.makeText(this, "Device was shuffed", Toast.LENGTH_SHORT)
// .show();
if (color) {
view.setBackgroundColor(Color.GREEN);
} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
view.setText("SPEEDDDDD=== "+accelationSquareRoot);
// Log.i("SensorTestActivity","SPEEDDDDD=== "+accelationSquareRoot+" ");
}
}
private void updateVelocity() {
// Calculate how long this acceleration has been applied.
Date timeNow = new Date(System.currentTimeMillis());
long timeDelta = timeNow.getTime()-lastUpdatedate.getTime();
lastUpdatedate.setTime(timeNow.getTime());
// Calculate the change in velocity at the
// current acceleration since the last update.
float deltaVelocity = appliedAcceleration * (timeDelta/1000);
appliedAcceleration = currentAcceleration;
// Add the velocity change to the current velocity.
velocity += deltaVelocity;
final double mph = (Math.round(100*velocity / 1.6 * 3.6))/100;
Log.i("SensorTestActivity","SPEEDDDDD=== "+mph+" "+velocity);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
// unregister listener
super.onPause();
sensorManager.unregisterListener(this);
}
}
For my Android app I need to get more or less accurately the step count. I say "more or less" because what I need to do is to know if the steps taken in 2 seconds are more or less than the previous ones.
I have tried the following two algorithms, and none of them worked effectively. Also I have tested requesting the step count to Google Fit, but it sometimes returns 215, and then 155, so I can't rely on that.
My solutions were as follows:
private SensorEventListener sensorEventListener = new SensorEventListener() {
//Listens for change in acceleration, displays and computes the steps
#Override
public void onSensorChanged(SensorEvent event) {
//Gather the values from accelerometer
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
//Fetch the current y
currentY = y;
//Measure if a step was taken
if(Math.abs(currentY - previousY) > threshold) {
numSteps++;
textViewSteps.setText(String.valueOf(numSteps));
//Vibramos
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(200);
}
//Display the values
//textViewX.setText(String.valueOf(x));
//textViewY.setText(String.valueOf(y));
//textViewZ.setText(String.valueOf(z));
//Store the previous y
previousY = y;
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
private SensorEventListener sensorEventListener = new SensorEventListener()
{
private final static String TAG = "StepDetector";
private float mLimit = 10;
private float mLastValues[] = new float[3*2];
private float mScale[] = new float[2];
private float mYOffset;
private float mLastDirections[] = new float[3*2];
private float mLastExtremes[][] = { new float[3*2], new float[3*2] };
private float mLastDiff[] = new float[3*2];
private int mLastMatch = -1;
//Como no podemos crear un constructor en una clase anónima, uso un inicializador de instancia (instance initializer)
{
int h = 480;
mYOffset = h * 0.5f;
mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
}
public void setSensitivity(float sensitivity) {
mLimit = sensitivity; // 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62
}
//public void onSensorChanged(int sensor, float[] values) {
public void onSensorChanged(SensorEvent event) {
if(calculateKmhtime == 0)
calculateKmhtime = System.currentTimeMillis();
Sensor sensor = event.sensor;
synchronized (this) {
if (sensor.getType() == Sensor.TYPE_ORIENTATION) {
}
else {
int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
if (j == 1) {
float vSum = 0;
for (int i=0 ; i<3 ; i++) {
final float v = mYOffset + event.values[i] * mScale[j];
vSum += v;
}
int k = 0;
float v = vSum / 3;
float direction = (v > mLastValues[k] ? 1 : (v < mLastValues[k] ? -1 : 0));
if (direction == - mLastDirections[k]) {
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType][k] = mLastValues[k];
float diff = Math.abs(mLastExtremes[extType][k] - mLastExtremes[1 - extType][k]);
if (diff > mLimit) {
boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k]*2/3);
boolean isPreviousLargeEnough = mLastDiff[k] > (diff/3);
boolean isNotContra = (mLastMatch != 1 - extType);
if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
Log.i(TAG, "step");
//Hemos detectado un paso. Aumentamos el número de pasos
numSteps++;
textViewSteps.setText(String.valueOf(numSteps));
mLastMatch = extType;
long currentTime = System.currentTimeMillis();
//Vibramos
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(200);
if(currentTime - calculateKmhtime >= CALCULATE_KMH_DELAY) {
calculateKmh(stepsInSpecifiedSeconds, (currentTime - calculateKmhtime) / 1000);
calculateKmhtime = System.currentTimeMillis();
stepsInSpecifiedSeconds = 0;
}else{
stepsInSpecifiedSeconds++;
}
}
else {
mLastMatch = -1;
}
}
mLastDiff[k] = diff;
}
mLastDirections[k] = direction;
mLastValues[k] = v;
}
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
How can it be improved?
Thank you
I am a beginner in android programming. Below is the program which is updating current position of the object using accelerometer and gyroscope readings.My objective is to update the object's position on the screen. Currently the output of the program is it just displays the object and it doesn't update it's position. Can you please suggest me where i am going wrong.
Mainactivity.java
public class MainActivity extends Activity implements SensorEventListener {
CustomDrawableView mCustomDrawableView = null;
ShapeDrawable mDrawable = new ShapeDrawable();
int UPDATE_THRESHOLD=20;
Sensor accelerometer,gyroscope;
SensorManager sm,sm1;
TextView acceleration,rotation,c_x,c_y;
long mLastUpdate;
public static int x;
public static int y;
double GRAVITY_THRESH = 12;
double one_step_freeze = 0;
double SENSOR_INTERVAL = 0.02;
double STEP_INTERVAL_THRESH = 0.4;
double init_x = 1;
double init_y = 0;
double init_theta = 0;
static int ACCE_FILTER_DATA_MIN_TIME = 20; // 1000ms
long lastSaved = System.currentTimeMillis();
double step_counter = 0;
double current_x,current_y;
double one_step_happend = 0;
double accumulated_rad = 0;
double trace_x = init_x;
double trace_x_particle = init_x;
double trace_y = init_y;
double trace_y_particle = init_y;
double last_x = init_x;
double last_y = init_y;
double last_theta = init_theta;
double z_gy;
float acc_z,acc_x,acc_y;
SensorEventListener mSensorListenerAcc,mSensorListenerGyro;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
sm=(SensorManager)getSystemService(SENSOR_SERVICE);
sm1=(SensorManager)getSystemService(SENSOR_SERVICE);
mCustomDrawableView = new CustomDrawableView(this);
setContentView(mCustomDrawableView);
accelerometer=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
gyroscope=sm1.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL );
sm1.registerListener(this,gyroscope,SensorManager.SENSOR_DELAY_NORMAL);
//acceleration=(TextView)findViewById(R.id.acceleration);
//rotation=(TextView)findViewById(R.id.rotation);
// c_x=(TextView)findViewById(R.id.c_x);
//c_y=(TextView)findViewById(R.id.c_y);
}
/*#Override
protected void onResume()
{
super.onResume();
//sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
sm.registerListener(mSensorListenerAcc, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
sm1.registerListener(mSensorListenerGyro, gyroscope,SensorManager.SENSOR_DELAY_FASTEST);
//mLastUpdate=System.currentTimeMillis();
}
#Override
protected void onPause()
{
sm.unregisterListener(this);
}*/
#Override
public void onSensorChanged(SensorEvent event) {
/* long actualTime = System.currentTimeMillis();
if(actualTime-mLastUpdate > UPDATE_THRESHOLD){
mLastUpdate=actualTime;
}*/
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
/*rotation.setText("Xg: " + event.values[0] +
"\nYg: " + event.values[1] +
"\nZg: " + event.values[2]);*/
z_gy= event.values[2];
}
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
/* acceleration.setText("X: " + event.values[0] +
"\nY: " + event.values[1] +
"\nZ: " + event.values[2]);*/
acc_x=event.values[1];
acc_y=event.values[2];
acc_z = event.values[2];
System.out.println("acc_z:" + Float.toString(acc_z));
if (acc_z > GRAVITY_THRESH && one_step_freeze == 0) {
System.out.println("entering1oop1");
one_step_happend = 1;
step_counter = step_counter + 1;
System.out.println("stepcounter: " + Double.toString(step_counter) + "==========================");
one_step_freeze = STEP_INTERVAL_THRESH / SENSOR_INTERVAL;
/*System.out.println("onestepfreeze_in_firstloop_aft_div: " + Double.toString(one_step_freeze));
System.out.println("exitingloop1");*/
}
if (one_step_freeze > 0) {
System.out.println("stepcounterin 2 loop: " + Double.toString(step_counter) + "==========================");
if ((System.currentTimeMillis() - lastSaved) > ACCE_FILTER_DATA_MIN_TIME) {
lastSaved = System.currentTimeMillis();
one_step_freeze = one_step_freeze - 1;
/* System.out.println("onestepfreeze2:" + Double.toString(one_step_freeze));
System.out.println("exitin 2loop");*/
}
}
if(one_step_happend==1){
// System.out.println("entered 3 loop:");
last_theta=accumulated_rad+last_theta;
// System.out.println("last_theta value: "+last_theta);
current_x=last_x+STRIDE_LENGTH*Math.cos(last_theta);
System.out.println("current_x value: " + current_x);
current_y=last_y+STRIDE_LENGTH*Math.sin(last_theta);
//System.out.println("current_y value: " + current_y);
// System.out.println("processing c_x");
//c_x.setText("c_x:" + current_x);
// System.out.println("processing c_y");
//c_y.setText("c_y:" + current_y);
last_x = current_x;
// System.out.println("last_x value: " + last_x);
last_y = current_y;
// System.out.println("last_y value: "+last_y);
accumulated_rad = 0;
one_step_happend = 0;
}else{
accumulated_rad= accumulated_rad + z_gy * SENSOR_INTERVAL;
System.out.println("accumulatedrad: "+accumulated_rad);
}
}
/*if ((acc_z > GRAVITY_THRESH) && (one_step_freeze == 0)) {
one_step_happend = 1;
step_counter = step_counter + 1;
System.out.println("stepcounter: " + Double.toString(step_counter) + "==========================");
one_step_freeze = STEP_INTERVAL_THRESH / SENSOR_INTERVAL;
//System.out.println("onestepfreeze2:"+Double.toString(one_step_freeze)+"==========================");
/*spcounter.setText((int) step_counter);
}*/
/*if (one_step_freeze > 0) {
if ((System.currentTimeMillis() - lastSaved) > ACCE_FILTER_DATA_MIN_TIME) {
lastSaved = System.currentTimeMillis();
one_step_freeze = one_step_freeze - 1;
System.out.println("onestepfreeze2:" + Double.toString(one_step_freeze));
}
}
if (one_step_happend == 1) {
last_theta = accumulated_rad + last_theta;
double current_x = last_x + STRIDE_LENGTH * Math.cos(last_theta);
double current_y = last_y + STRIDE_LENGTH * Math.sin(last_theta);
c_x.setText((int) current_x);
c_y.setText((int)current_y);
/*trace_x = [trace_x current_x];
trace_y = [trace_y current_y];
last_x = current_x;
//System.out.println("last_x"+last_x);
last_y = current_y;
//System.out.println("last_y"+last_y);
accumulated_rad = 0;
one_step_happend = 0;
} *//*else {
accumulated_rad = accumulated_rad + z_gy * SENSOR_INTERVAL;
//System.out.println(accumulated_rad);
/* calculate(accumulated_rad);
}
}
*/
}
#Override
protected void onResume()
{
super.onResume();
// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm1.registerListener(this, sm1.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onStop()
{
// Unregister the listener
sm.unregisterListener(this);
super.onStop();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public class CustomDrawableView extends View
{
static final int width = 50;
static final int height = 50;
public CustomDrawableView(Context context)
{
super(context);
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds((int) current_x, (int) current_y, (int) current_x + width, (int) current_y + height);
//mDrawable.setBounds((int)acc_x, (int)acc_y, (int)acc_x + width,(int) acc_y + height);
}
protected void onDraw(Canvas canvas)
{
/* x= (int)current_x;
y= (int)current_y;*/
RectF oval = new RectF(MainActivity.x, MainActivity.y, MainActivity.x + width, MainActivity.y
+ height); // set bounds of rectangle
Paint p = new Paint(); // set some paint options
p.setColor(Color.BLUE);
canvas.drawOval(oval, p);
invalidate();
}
}
}
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
I want to listen to a shake and then stop the accelerometer completely and move to another activity. Sadly I didn't find any way to do this.
Even if I count up a variable and check with a simple 'if' it loads always the new activity again every time a shake is detected.
Please help me with my lack of understanding.
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(mSensorListener);
super.onPause();
}
#Override
protected void onStop() {
mSensorManager.unregisterListener(mSensorListener);
super.onStop();
}
private SensorManager mSensorManager;
private final SensorEventListener mSensorListener = new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
float[] value = event.values;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = value[0];
float y = value[1];
float z = value[2];
//in G Umrechnung
float gX = x / gravityEarth;
float gY = y / gravityEarth;
float gZ = z / gravityEarth;
//G-Force will be 1 when there is no movement. (gravity)
gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);
double gForce2 = Math.round(gForce * 100) / 100.0;
String g = String.format("" + gForce2 + " G");
TextViewG.setTextColor(0xffff0000);
TextViewG.setTextSize(35);
TextViewG.setText(g);
}
Intent nextScreen = new Intent(getApplicationContext(), Send.class);
if (gForce > shakeThresholdInGForce ){
final long now = System.currentTimeMillis();
// ignore shake events too close to each other (500ms)
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now ) {
mShakeTimestamp = now;
mSensorManager.unregisterListener(mSensorListener);
onStop();
startActivity(nextScreen);
}
}