I want to detect whether device is moving or device is stationary. I have a situation where i want to execute task when device is not moving.
Right now i have implemented something like this using sensor but i'm not getting device is moving when i try to move device on plain surface like table.
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
double alpha = 0.6;
double[] gravity = new double[3];
gravity[0] = 0;
gravity[1] = 0;
gravity[2] = 0;
gravity[0] = alpha * gravity[0] + (1 - alpha) * sensorEvent.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * sensorEvent.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * sensorEvent.values[2];
double[] linear_acceleration = new double[3];
linear_acceleration[0] = sensorEvent.values[0] - gravity[0];
linear_acceleration[1] = sensorEvent.values[1] - gravity[1];
linear_acceleration[2] = sensorEvent.values[2] - gravity[2];
float magnitude = 0.0f;
magnitude = (float)Math.sqrt(linear_acceleration[0]*linear_acceleration[0]+linear_acceleration[1]*linear_acceleration[1]+linear_acceleration[2]*linear_acceleration[2]);
magnitude = Math.abs(magnitude);
Log.e("Magnitude",magnitude+"");
if(magnitude>0.2){
Log.e("walking","Yes");
}else{
Log.e("walking","No");
}
}
If you are looking for an example there is one below
This code is for walking detection
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;
}
}
}
Related
I am new in android developing, I developed this code based on previous code related to Mr.liwatiz to find orientation from sensor fusion, I added writeCSV file to store data, The application work and the file created but there is no data store! So please what is the problem. my code clear below
public class MainActivity extends Activity implements SensorEventListener, RadioGroup.OnCheckedChangeListener{
private SensorManager mSensorManager = null;
// angular speeds from gyro
private float[] gyro = new float[3];
// rotation matrix from gyro data
private float[] gyroMatrix = new float[9];
// orientation angles from gyro matrix
private float[] gyroOrientation = new float[3];
// magnetic field vector
private float[] magnet = new float[3];
// accelerometer vector
private float[] accel = new float[3];
// orientation angles from accel and magnet
private float[] accMagOrientation = new float[3];
// final orientation angles from sensor fusion
private float[] fusedOrientation = new float[3];
// accelerometer and magnetometer based rotation matrix
private float[] rotationMatrix = new float[9];
public static final float EPSILON = 0.000000001f;
private static final float NS2S = 1.0f / 1000000.0f;
private int timestamp;
private boolean initState = true;
public static final int TIME_CONSTANT = 30;
public static final float FILTER_COEFFICIENT = 0.98f;
private Timer fuseTimer = new Timer();
// The following members are only for displaying the sensor output.
public Handler mHandler;
private RadioGroup mRadioGroup;
private TextView mAzimuthView;
private TextView mPitchView;
private TextView mRollView;
private int radioSelection;
DecimalFormat d = new DecimalFormat("#.##");
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gyroOrientation[0] = 0.0f;
gyroOrientation[1] = 0.0f;
gyroOrientation[2] = 0.0f;
// initialise gyroMatrix with identity matrix
gyroMatrix[0] = 1.0f; gyroMatrix[1] = 0.0f; gyroMatrix[2] = 0.0f;
gyroMatrix[3] = 0.0f; gyroMatrix[4] = 1.0f; gyroMatrix[5] = 0.0f;
gyroMatrix[6] = 0.0f; gyroMatrix[7] = 0.0f; gyroMatrix[8] = 1.0f;
// get sensorManager and initialise sensor listeners
mSensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
initListeners();
// wait for one second until gyroscope and magnetometer/accelerometer
// data is initialised then scedule the complementary filter task
fuseTimer.scheduleAtFixedRate(new calculateFusedOrientationTask(),
1000, TIME_CONSTANT);
// GUI stuff
mHandler = new Handler();
radioSelection = 0;
d.setRoundingMode(RoundingMode.HALF_UP);
d.setMaximumFractionDigits(3);
d.setMinimumFractionDigits(3);
mRadioGroup = (RadioGroup)findViewById(R.id.radioGroup1);
mAzimuthView = (TextView)findViewById(R.id.textView4);
mPitchView = (TextView)findViewById(R.id.textView5);
mRollView = (TextView)findViewById(R.id.textView6);
mRadioGroup.setOnCheckedChangeListener(this);
}
#Override
public void onStop() {
super.onStop();
// unregister sensor listeners to prevent the activity from draining the device's battery.
mSensorManager.unregisterListener(this);
}
#Override
protected void onPause() {
super.onPause();
// unregister sensor listeners to prevent the activity from draining the device's battery.
mSensorManager.unregisterListener(this);
}
#Override
public void onResume() {
super.onResume();
// restore the sensor listeners when user resumes the application.
initListeners();
}
// This function registers sensor listeners for the accelerometer, magnetometer and gyroscope.
public void initListeners(){
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
public void writeToCsvGy(String x,String y,String z) throws IOException {
Calendar c = Calendar.getInstance();
File folder = new File(Environment.getExternalStorageDirectory() + "/TollCulator");
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (success) {
// Do something on success
String csv = "/storage/sdcard0/project/GyroscopeValue.csv";
FileWriter file_writer = new FileWriter(csv,true);
String s= c.get(Calendar.YEAR)+","+c.get(Calendar.MONTH)+","+c.get(Calendar.DATE)+","+c.get(Calendar.HOUR)+","+c.get(Calendar.MINUTE)+","+c.get(Calendar.SECOND)+","+ c.get(Calendar.MILLISECOND)+","+x + ","+y+","+z+"\n";
file_writer.append(s);
file_writer.close();
}
}
#Override
public void onSensorChanged(SensorEvent event) {
switch(event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
// copy new accelerometer data into accel array and calculate orientation
System.arraycopy(event.values, 0, accel, 0, 3);
calculateAccMagOrientation();
break;
case Sensor.TYPE_GYROSCOPE:
// process gyro data
gyroFunction(event);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
// copy new magnetometer data into magnet array
System.arraycopy(event.values, 0, magnet, 0, 3);
break;
}
}
// calculates orientation angles from accelerometer and magnetometer output
public void calculateAccMagOrientation() {
if(SensorManager.getRotationMatrix(rotationMatrix, null, accel, magnet)) {
SensorManager.getOrientation(rotationMatrix, accMagOrientation);
}
}
// This function is borrowed from the Android reference
// at http://developer.android.com/reference/android/hardware/SensorEvent.html#values
// It calculates a rotation vector from the gyroscope angular speed values.
private void getRotationVectorFromGyro(float[] gyroValues,
float[] deltaRotationVector,
float timeFactor)
{
float[] normValues = new float[3];
// Calculate the angular speed of the sample
float omegaMagnitude =
(float)Math.sqrt(gyroValues[0] * gyroValues[0] +
gyroValues[1] * gyroValues[1] +
gyroValues[2] * gyroValues[2]);
// Normalize the rotation vector if it's big enough to get the axis
if(omegaMagnitude > EPSILON) {
normValues[0] = gyroValues[0] / omegaMagnitude;
normValues[1] = gyroValues[1] / omegaMagnitude;
normValues[2] = gyroValues[2] / omegaMagnitude;
}
// Integrate around this axis with the angular speed by the timestep
// in order to get a delta rotation from this sample over the timestep
// We will convert this axis-angle representation of the delta rotation
// into a quaternion before turning it into the rotation matrix.
float thetaOverTwo = omegaMagnitude * timeFactor;
float sinThetaOverTwo = (float)Math.sin(thetaOverTwo);
float cosThetaOverTwo = (float)Math.cos(thetaOverTwo);
deltaRotationVector[0] = sinThetaOverTwo * normValues[0];
deltaRotationVector[1] = sinThetaOverTwo * normValues[1];
deltaRotationVector[2] = sinThetaOverTwo * normValues[2];
deltaRotationVector[3] = cosThetaOverTwo;
}
// This function performs the integration of the gyroscope data.
// It writes the gyroscope based orientation into gyroOrientation.
public void gyroFunction(SensorEvent event) {
// don't start until first accelerometer/magnetometer orientation has been acquired
if (accMagOrientation == null)
return;
// initialisation of the gyroscope based rotation matrix
if(initState) {
float[] initMatrix = new float[9];
initMatrix = getRotationMatrixFromOrientation(accMagOrientation);
float[] test = new float[3];
SensorManager.getOrientation(initMatrix, test);
gyroMatrix = matrixMultiplication(gyroMatrix, initMatrix);
initState = false;
}
// copy the new gyro values into the gyro array
// convert the raw gyro data into a rotation vector
float[] deltaVector = new float[4];
if(timestamp != 0) {
final float dT = (event.timestamp - timestamp) * NS2S;
System.arraycopy(event.values, 0, gyro, 0, 3);
getRotationVectorFromGyro(gyro, deltaVector, dT / 2.0f);
}
// measurement done, save current time for next interval
switch ( timestamp = (int) event.timestamp ) {
}
// convert rotation vector into rotation matrix
float[] deltaMatrix = new float[9];
SensorManager.getRotationMatrixFromVector(deltaMatrix, deltaVector);
// apply the new rotation interval on the gyroscope based rotation matrix
gyroMatrix = matrixMultiplication(gyroMatrix, deltaMatrix);
// get the gyroscope based orientation from the rotation matrix
SensorManager.getOrientation(gyroMatrix, gyroOrientation);
}
private float[] getRotationMatrixFromOrientation(float[] o) {
float[] xM = new float[9];
float[] yM = new float[9];
float[] zM = new float[9];
float sinX = (float)Math.sin(o[1]);
float cosX = (float)Math.cos(o[1]);
float sinY = (float)Math.sin(o[2]);
float cosY = (float)Math.cos(o[2]);
float sinZ = (float)Math.sin(o[0]);
float cosZ = (float)Math.cos(o[0]);
// rotation about x-axis (pitch)
xM[0] = 1.0f; xM[1] = 0.0f; xM[2] = 0.0f;
xM[3] = 0.0f; xM[4] = cosX; xM[5] = sinX;
xM[6] = 0.0f; xM[7] = -sinX; xM[8] = cosX;
// rotation about y-axis (roll)
yM[0] = cosY; yM[1] = 0.0f; yM[2] = sinY;
yM[3] = 0.0f; yM[4] = 1.0f; yM[5] = 0.0f;
yM[6] = -sinY; yM[7] = 0.0f; yM[8] = cosY;
// rotation about z-axis (azimuth)
zM[0] = cosZ; zM[1] = sinZ; zM[2] = 0.0f;
zM[3] = -sinZ; zM[4] = cosZ; zM[5] = 0.0f;
zM[6] = 0.0f; zM[7] = 0.0f; zM[8] = 1.0f;
// rotation order is y, x, z (roll, pitch, azimuth)
float[] resultMatrix = matrixMultiplication(xM, yM);
resultMatrix = matrixMultiplication(zM, resultMatrix);
return resultMatrix;
}
private float[] matrixMultiplication(float[] A, float[] B) {
float[] result = new float[9];
result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6];
result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7];
result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8];
result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6];
result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7];
result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8];
result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6];
result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7];
result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8];
return result;
}
class calculateFusedOrientationTask extends TimerTask {
public void run() {
float oneMinusCoeff = 1.0f - FILTER_COEFFICIENT;
/*
* Fix for 179? <--> -179? transition problem:
* Check whether one of the two orientation angles (gyro or accMag) is negative while the other one is positive.
* If so, add 360? (2 * math.PI) to the negative value, perform the sensor fusion, and remove the 360? from the result
* if it is greater than 180?. This stabilizes the output in positive-to-negative-transition cases.
*/
// azimuth
if (gyroOrientation[0] < -0.5 * Math.PI && accMagOrientation[0] > 0.0) {
fusedOrientation[0] = (float) (FILTER_COEFFICIENT * (gyroOrientation[0] + 2.0 * Math.PI) + oneMinusCoeff * accMagOrientation[0]);
fusedOrientation[0] -= (fusedOrientation[0] > Math.PI) ? 2.0 * Math.PI : 0;
}
else if (accMagOrientation[0] < -0.5 * Math.PI && gyroOrientation[0] > 0.0) {
fusedOrientation[0] = (float) (FILTER_COEFFICIENT * gyroOrientation[0] + oneMinusCoeff * (accMagOrientation[0] + 2.0 * Math.PI));
fusedOrientation[0] -= (fusedOrientation[0] > Math.PI)? 2.0 * Math.PI : 0;
}
else {
fusedOrientation[0] = FILTER_COEFFICIENT * gyroOrientation[0] + oneMinusCoeff * accMagOrientation[0];
}
// pitch
if (gyroOrientation[1] < -0.5 * Math.PI && accMagOrientation[1] > 0.0) {
fusedOrientation[1] = (float) (FILTER_COEFFICIENT * (gyroOrientation[1] + 2.0 * Math.PI) + oneMinusCoeff * accMagOrientation[1]);
fusedOrientation[1] -= (fusedOrientation[1] > Math.PI) ? 2.0 * Math.PI : 0;
}
else if (accMagOrientation[1] < -0.5 * Math.PI && gyroOrientation[1] > 0.0) {
fusedOrientation[1] = (float) (FILTER_COEFFICIENT * gyroOrientation[1] + oneMinusCoeff * (accMagOrientation[1] + 2.0 * Math.PI));
fusedOrientation[1] -= (fusedOrientation[1] > Math.PI)? 2.0 * Math.PI : 0;
}
else {
fusedOrientation[1] = FILTER_COEFFICIENT * gyroOrientation[1] + oneMinusCoeff * accMagOrientation[1];
}
// roll
if (gyroOrientation[2] < -0.5 * Math.PI && accMagOrientation[2] > 0.0) {
fusedOrientation[2] = (float) (FILTER_COEFFICIENT * (gyroOrientation[2] + 2.0 * Math.PI) + oneMinusCoeff * accMagOrientation[2]);
fusedOrientation[2] -= (fusedOrientation[2] > Math.PI) ? 2.0 * Math.PI : 0;
}
else if (accMagOrientation[2] < -0.5 * Math.PI && gyroOrientation[2] > 0.0) {
fusedOrientation[2] = (float) (FILTER_COEFFICIENT * gyroOrientation[2] + oneMinusCoeff * (accMagOrientation[2] + 2.0 * Math.PI));
fusedOrientation[2] -= (fusedOrientation[2] > Math.PI)? 2.0 * Math.PI : 0;
}
else {
fusedOrientation[2] = FILTER_COEFFICIENT * gyroOrientation[2] + oneMinusCoeff * accMagOrientation[2];
}
// overwrite gyro matrix and orientation with fused orientation
// to comensate gyro drift
gyroMatrix = getRotationMatrixFromOrientation(fusedOrientation);
System.arraycopy(fusedOrientation, 0, gyroOrientation, 0, 3);
// update sensor output in GUI
mHandler.post(updateOreintationDisplayTask);
}
}
// **************************** GUI FUNCTIONS *********************************
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch(checkedId) {
case R.id.radio0:
radioSelection = 0;
break;
case R.id.radio1:
radioSelection = 1;
break;
case R.id.radio2:
radioSelection = 2;
break;
}
}
public void updateOreintationDisplay() {
switch(radioSelection) {
case 0:
mAzimuthView.setText(d.format(accMagOrientation[0] * 180/Math.PI) + '?');
mPitchView.setText(d.format(accMagOrientation[1] * 180/Math.PI) + '?');
mRollView.setText(d.format(accMagOrientation[2] * 180/Math.PI) + '?');
try {
writeToCsv((d.format(accMagOrientation[0] * 180/Math.PI) + '?'),(d.format(accMagOrientation[1] * 180/Math.PI)+ '?'),(d.format(accMagOrientation[2] * 180/Math.PI) + '?'));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case 1:
mAzimuthView.setText(d.format(gyroOrientation[0] * 180/Math.PI) + '?');
mPitchView.setText(d.format(gyroOrientation[1] * 180/Math.PI) + '?');
mRollView.setText(d.format(gyroOrientation[2] * 180/Math.PI) + '?');
try {
writeToCsv((d.format(gyroOrientation[0] * 180/Math.PI) + '?'),(d.format(gyroOrientation[1] * 180/Math.PI)+ '?'),(d.format(gyroOrientation[2] * 180/Math.PI) + '?'));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case 2:
mAzimuthView.setText(d.format(fusedOrientation[0] * 180/Math.PI) + '?');
mPitchView.setText(d.format(fusedOrientation[1] * 180/Math.PI) + '?');
mRollView.setText(d.format(fusedOrientation[2] * 180/Math.PI) + '?');
try {
writeToCsv((d.format(fusedOrientation[0] * 180/Math.PI) + '?'),(d.format(fusedOrientation[1] * 180/Math.PI) + '?'),(d.format(fusedOrientation[2] * 180/Math.PI) + '?'));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
private void writeToCsv(String x, String y, String z) throws IOException {
Calendar c = Calendar.getInstance();
// File path = getFilesDir();
File folder = new File(getFilesDir() + "/TollCulator");
boolean success = true;
if (! folder.exists()) {
success = folder.mkdir();
}
if (success) {
// Do something on success
String csv = "data.csv";
FileWriter file_writer = new FileWriter(csv,true);
String s= c.get(Calendar.YEAR)+","+c.get(Calendar.MONTH)+","+c.get(Calendar.DATE)+","+c.get(Calendar.HOUR)+","+c.get(Calendar.MINUTE)+","+c.get(Calendar.SECOND)+","+ c.get(Calendar.MILLISECOND)+","+x + ","+y+","+z+"\n";
file_writer.append(s);
file_writer.close();
}
}
private Runnable updateOreintationDisplayTask = new Runnable() {
public void run() {
updateOreintationDisplay();
}
};
}
Try with below code to create csv file and save data into csv.
Reference : https://sourceforge.net/projects/opencsv/files/opencsv/
For more : Look into this
String csv = (Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyCsvFile.csv"); // Here csv file name is MyCsvFile.csv
//by Hiting button csv will create inside phone storage.
buttonAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CSVWriter writer = null;
try {
writer = new CSVWriter(new FileWriter(csv));
List<String[]> data = new ArrayList<String[]>();
data.add(new String[]{"Country", "Capital"});
data.add(new String[]{"India", "New Delhi"});
data.add(new String[]{"United States", "Washington D.C"});
data.add(new String[]{"Germany", "Berlin"});
writer.writeAll(data); // data is adding to csv
writer.close();
callRead();
} catch (IOException e) {
e.printStackTrace();
}
}
});
I want to show the west direction in my app using compass. No matter where my user are my compass will always navigate to west direction. I am confused about it that how can i achieve and rotate my image in only one direction . Below is my code -
public class Compass implements SensorEventListener {
private static final String TAG = "Compass";
private SensorManager sensorManager;
private Sensor gsensor;
private Sensor msensor;
private float[] mGravity = new float[3];
private float[] mGeomagnetic = new float[3];
private float azimuth = 0f;
private float currectAzimuth = 0;
private Context context ;
PackageManager packageManager ;
// compass arrow to rotate
public ImageView arrowView = null;
public Compass(Context context) {
this.context = context;
sensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
gsensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
msensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
packageManager = context.getPackageManager();
}
public void start() {
if(packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)){
sensorManager.registerListener(this, gsensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(this, msensor,
SensorManager.SENSOR_DELAY_GAME);
}
else{
Toast.makeText(context,"No Compass Sensor !", Toast.LENGTH_SHORT).show();
}
}
public void stop() {
sensorManager.unregisterListener(this);
}
private void adjustArrow() {
if (arrowView == null) {
Log.i(TAG, "arrow view is not set");
return;
}
Log.i(TAG, "will set rotation from " + currectAzimuth + " to "
+ azimuth);
Animation an = new RotateAnimation(-currectAzimuth, -azimuth,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
currectAzimuth = azimuth;
an.setDuration(500);
an.setRepeatCount(0);
an.setFillAfter(true);
arrowView.startAnimation(an);
}
#Override
public void onSensorChanged(SensorEvent event) {
final float alpha = 0.97f;
synchronized (this) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity[0] = alpha * mGravity[0] + (1 - alpha)
* event.values[0];
mGravity[1] = alpha * mGravity[1] + (1 - alpha)
* event.values[1];
mGravity[2] = alpha * mGravity[2] + (1 - alpha)
* event.values[2];
// mGravity = event.values;
// Log.e(TAG, Float.toString(mGravity[0]));
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
// mGeomagnetic = event.values;
mGeomagnetic[0] = alpha * mGeomagnetic[0] + (1 - alpha)
* event.values[0];
mGeomagnetic[1] = alpha * mGeomagnetic[1] + (1 - alpha)
* event.values[1];
mGeomagnetic[2] = alpha * mGeomagnetic[2] + (1 - alpha)
* event.values[2];
// Log.e(TAG, Float.toString(event.values[0]));
}
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);
Log.d(TAG, "azimuth (rad): " + azimuth);
azimuth = (float) Math.toDegrees(orientation[0]); // orientation
azimuth = (azimuth + 360) % 360;
Log.d(TAG, "azimuth (deg): " + azimuth);
adjustArrow();
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Why don't you use trigonometry to calculate the correct angle for the image based on north being at 0 degrees.
If north is 0 degrees, west would be -90 degrees or 270 degrees in comparison. So simply set the rotation of the image to north + 270 degrees?
#
i want to try counting shake on android and show it on textview, but keep crashing after i try shaking.
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 > 10) {
max = 100;
for (i=1; i<=max;) {
i=i+1;
TextView angka = (TextView) findViewById(R.id.angka);
angka.setText(i);
}
}
}
I have this app in which the screen orientation is fixed on portrait and instead of doing a full screen rotation, and having to re-build the activity, I have decided to use the accelerometer instead.
The following code works fine on all the devices I test until I came across this one device (One+ running 6.0), in which I was unable to get the geomagnetic field in order to calculate the orientation.
Is this a problem from the hardware? am I missing some permissions?
I have looked into it and I didn't find any documentation saying I need to ask for permissions during runtime for an accelerometer.
Here is the code of the onSensor:
public void onSensorChanged(SensorEvent event) {
boolean isOrientationEnabled;
try {
isOrientationEnabled = Settings.System.getInt(getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION) == 1;
} catch (Settings.SettingNotFoundException e) {
isOrientationEnabled = false;
}
if (!isOrientationEnabled){
if(this.Orientation!= ORIENTATION_PORTRAIT)rotateViews(ORIENTATION_PORTRAIT);
this.Orientation = ORIENTATION_PORTRAIT;
return;
}
if(allow_rotation) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
//mGeomagnetic is null
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);
// orientation contains: azimut, pitch and roll
float pitch = (float) Math.toDegrees(orientation[1]);
if (pitch < -45 && pitch > -135) {
// if device is laid flat on a surface
if(this.Orientation!= ORIENTATION_PORTRAIT) rotateViews(ORIENTATION_PORTRAIT);
this.Orientation = ORIENTATION_PORTRAIT;
return;
}
float roll = (float) Math.abs(Math.toDegrees(orientation[2]));
if ((roll > 60 && roll < 135)) {
// The device is closer to landscape orientation. Enable fullscreen
int landscape_mode;//0 = right, 2 = left
if (Math.toDegrees(orientation[2]) > 0) landscape_mode = ORIENTATION_LANDSCAPE_RIGHT;
else landscape_mode = ORIENTATION_LANDSCAPE_LEFT;
if(this.Orientation!=landscape_mode) rotateViews(landscape_mode);
this.Orientation = landscape_mode;
} else if (roll < 45 && roll > 135) {
// The device is closer to portrait orientation. Disable fullscreen
if(this.Orientation!=1)rotateViews(ORIENTATION_PORTRAIT);
this.Orientation = ORIENTATION_PORTRAIT;
}
}
}
}
}
You do not need Magnetic sensor for pitch and roll. Just low pass filter accelerometer to get gravity.
private static final float ALPHA = 0.8;
private float[] mGravity;
public void onSensorChanged(SensorEvent event) {
mGravity[0] = ALPHA * mGravity[0] + (1 - ALPHA) * event.values[0];
mGravity[1] = ALPHA * mGravity[1] + (1 - ALPHA) * event.values[1];
mGravity[2] = ALPHA * mGravity[2] + (1 - ALPHA) * event.values[2];
double gravityNorm = Math.sqrt(mGravity[0] * mGravity[0] + mGravity[1] * mGravity[1] + mGravity[2] * mGravity[2]);
pitch = (float) Math.asin(-mGravity[1] / gravityNorm);
roll = (float) Math.atan2(-mGravity[0] / gravityNorm, mGravity[2] / gravityNorm);
}
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