Reputation: 93559
I'm trying to get the direction of the camera in Android. I have code that's working perfectly in portrait (I test it by slowly turning in a circle and looking at updates 1s apart), but it isn't working at all in landscape- The numbers seem to change randomly. It also gets totally out of whack after switching from portrait to landscape. Here's my code
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accelerometerValues = event.values.clone();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
geomagneticMatrix = event.values.clone();
break;
default:
break;
}
if (geomagneticMatrix != null && accelerometerValues != null) {
float[] R = new float[16];
float[] I = new float[16];
float[] outR = new float[16];
//Get the rotation matrix, then remap it from camera surface to world coordinates
SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix);
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
float values[] = new float[4];
SensorManager.getOrientation(outR,values);
float direction = normalizeDegrees((float) Math.toDegrees(values[0]));
float pitch = normalizeDegrees((float) Math.toDegrees(values[1]));
float roll = normalizeDegrees((float) Math.toDegrees(values[2]));
if((int)direction != (int)lastDirection){
lastDirection = direction;
for(CompassListener listener: listeners){
listener.onDirectionChanged(lastDirection, pitch, roll);
}
}
}
}
Any ideas what I'm doing wrong? I freely admit I don't 100% understand this. I also don't know why Google deprecated the orientation sensor- it seems like a common enough desire.
Upvotes: 0
Views: 668
Reputation: 93559
I seemed to have solved it, or at least improved it to the point where I know what was the problem. I put in a filter such that instead of delivering a single sensor reading, I'm remembering the last reading and applying a delta to it. Each new sensor point is allowed to add a maximum of 5 degrees. This completely filters out the weird hops, and forces it to converge to a value. I sill see an occasional odd jump, but I figure what I need is a more sophisticated filter. New code:
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
return;
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accelerometerValues = event.values.clone();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
geomagneticMatrix = event.values.clone();
break;
}
if (geomagneticMatrix != null && accelerometerValues != null) {
float[] R = new float[16];
float[] I = new float[16];
float[] outR = new float[16];
//Get the rotation matrix, then remap it from camera surface to world coordinates
SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix);
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
float values[] = new float[4];
SensorManager.getOrientation(outR,values);
int direction = filterChange(normalizeDegrees(Math.toDegrees(values[0])));
int pitch = normalizeDegrees(Math.toDegrees(values[1]));
int roll = normalizeDegrees(Math.toDegrees(values[2]));
if((int)direction != (int)lastDirection){
lastDirection = (int)direction;
lastPitch = (int)pitch;
lastRoll = (int)roll;
for(CompassListener listener: listeners){
listener.onDirectionChanged(lastDirection, pitch, roll);
}
}
}
}
//Normalize a degree from 0 to 360 instead of -180 to 180
private int normalizeDegrees(double rads){
return (int)((rads+360)%360);
}
//We want to ignore large bumps in individual readings. So we're going to cap the number of degrees we can change per report
private int filterChange(int newDir){
int change = newDir - lastDirection;
int circularChange = newDir-(lastDirection+360);
int smallestChange;
if(Math.abs(change) < Math.abs(circularChange)){
smallestChange = change;
}
else{
smallestChange = circularChange;
}
smallestChange = Math.max(Math.min(change,5),-5);
return lastDirection+smallestChange;
}
Upvotes: 0
Reputation: 6141
Did you consider, that when you change from portrait to landscape, accelerometer axes change ? Like Y-axis becomes Z-axis and so on. This might be one source of strange behavior.
Upvotes: 1