Reputation: 11
Im making an android app with accelerometer sensor. My goal is when I move my smartphone to right, then send to server "RIGHT" and when I move my smartphone to left, then send to server "LEFT". To implement this function, I know that I have to detect the movement of my smartphone. Before implement this function, I just want to print "RIGHT" or "LEFT" at textview, So I searched some codes and I wrote codes like this,
package com.example.administrator.motiondetector;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MotionDetector extends AppCompatActivity implements SensorEventListener {
private TextView xText;
private TextView yText;
private SensorManager mSensorManager;
private Sensor mSensorAccelerometer;
private float xPastData;
private float yPastData;
private float zPastData;
private float Speed;
private float AccHistory[] = new float[3];
private float AccelData[] = new float[3];
String[] direction = {"NONE", "NONE"}
private long lastTime;
private static final int SHAKE_THRESHOLD = 800;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_motion_detector);
xText = (TextView) findViewById(R.id.xText);
yText = (TextView) findViewById(R.id.yText);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorAccelerometer = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
mSensorManager.registerListener(this, mSensorAccelerometer, SensorManager.SENSOR_DELAY_FASTEST);
}
public void onSensorChanged (SensorEvent event) {
if (event.sensor.getType() == mSensorAccelerometer.TYPE_ACCELEROMETER) {
long currentTime = System.currentTimeMillis();
long TimeInterval = currentTime - lastTime;
if (TimeInterval > 100) {
lastTime = currentTime;
AccelData[0] = event.values[0];
AccelData[1] = event.values[1];
AccelData[2] = event.values[2];
Speed = Math.abs(AccelData[0] + AccelData[1] + AccelData[2] - xPastData - yPastData - zPastData) / TimeInterval * 10000;
if (Speed > SHAKE_THRESHOLD) {
Log.i("roosh", "Speed : " + Speed + ". Higher than Threshold");
float xChange = AccHistory[0] - AccelData[0];
float yChange = AccHistory[1] - AccelData[1];
AccHistory[0] = event.values[0];
AccHistory[1] = event.values[1];
if (xChange > 3) {
Log.i("roosh", "AccHistory[0] : " + AccHistory[0]);
Log.i("roosh", "AccelData[0] : " + AccelData[0]);
Log.i("roosh", "xChange : " + xChange + ". Direction is LEFT");
direction[0] = "LEFT";
} else if (xChange < -3) {
Log.i("roosh", "AccHistory[0] : " + AccHistory[0]);
Log.i("roosh", "AccelData[0] : " + AccelData[0]);
Log.i("roosh", "xChange : " + xChange + ". Direction is RIGHT");
direction[0] = "RIGHT";
}
if (yChange > 3) {
Log.i("roosh", "AccHistory[1] : " + AccHistory[1]);
Log.i("roosh", "AccelData[1] : " + AccelData[1]);
Log.i("roosh", "xChange : " + xChange + ". Direction is DOWN");
direction[1] = "DOWN";
} else if (yChange < -3) {
Log.i("roosh", "AccHistory[1] : " + AccHistory[1]);
Log.i("roosh", "AccelData[1] : " + AccelData[1]);
Log.i("roosh", "xChange : " + xChange + ". Direction is UP");
direction[1] = "UP";
}
xText.setText("X : " + direction[0]);
yText.setText("Y : " + direction[1]);
}
Log.i("roosh", "Speed : " + Speed + ". Lower than Threshold");
xPastData = event.values[0];
yPastData = event.values[1];
zPastData = event.values[2];
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Not in use
}
}
The problem is this. This code sometimes works well. But sometimes there are many problems. That means the textview shows me "RIGHT" although I moved the smartphone right to left(textview must show me "LEFT"), and the textview shows me "LEFT" although I moved the smartphone left to right(textview muse show me "RIGHT").
I found some solutions in stackoverflow, but I failed.. Some of people says that I have to use not just accelerometer sensor, use more sensors such as gyroscope or magnetometer. But I can't understand how to fix these sensor(accelerometer, gyroscope, magnetometer) to detect movement of my smartphone.
I thought codes at "https://www.codeproject.com/Articles/729759/Android-Sensor-Fusion-Tutorial" can help me, but I can't understand this codes...
So, question is this. What is the problem of my codes? Is there any solutions at my codes? Or is there any sample codes? Or can somebody tell me how to understand the codes at "https://www.codeproject.com/Articles/729759/Android-Sensor-Fusion-Tutorial"?
Some people would say "Please search more at stackoverflow" but I already did.. I really want to make this program..
thank you for reading
Upvotes: 0
Views: 3813
Reputation: 4524
There is no good way to detect the absolute movement of your phone using an accelerometer, it only detects relative movement / shaking.
You can start moving your phone to the right slowly, then stop it abruptly, you will see a spike in your accelerometer readings.
But if you start moving your phone to the left rapidly, then slowly stop it, you will see an identical spike in accelerometer reading, in the same direction.
You can imagine an accelerometer as a small ball floating freely inside your phone. When you move your phone to the right, the ball hits the left side, and the phone detects movement. When you move your phone to the left, then stop it, the ball hits the same left side, and detects the same movement, the phone has no way of knowing that you have started to move it earlier.
And since an accelerometer is not a very precise sensor, it cannot detect slow movement at all, unless you are using Project Tango device.
The only reliable reading an accelerometer can give you is the direction to the center of the Earth, thanks to gravity.
Gyroscope is usually much more precise sensor, but it only detects relative rotation, not linear movement. It also has no way to of knowing if you started to rotate your phone earlier, but you can combine it with accelerometer, which gives you an absolute direction to the center of the Earth, and with compass, which gives you the direction to the magnetic North pole, although from my experience, the compass drifts wildly even on high-end phones.
To do that same thing for accelerometer, you have to combine it with GPS, and GPS is too imprecise for that.
Upvotes: 1
Reputation: 197
Did you read the Android Developers documentation?
There are few points that might interest you:
From Motion Sensors:
Accelerometers use the standard sensor coordinate system. In practice, this means that the following conditions apply when a device is laying flat on a table in its natural orientation:
If you push the device on the left side (so it moves to the right), the x acceleration value is positive.
If you push the device on the bottom (so it moves away from you), the y acceleration value is positive.
If you push the device toward the sky with an acceleration of A m/s2, the z acceleration value is equal to A + 9.81, which corresponds to the acceleration of the device (+A m/s2) minus the force of gravity (-9.81 m/s2).
The stationary device will have an acceleration value of +9.81, which corresponds to the acceleration of the device (0 m/s2 minus the force of gravity, which is -9.81 m/s2).
In which of this cases your application works?
Also you could check this information too about Sensor Coordinate System.
Upvotes: 0