在横向模式下或在翻转方向后无法从传感器获取方向

时间:2012-09-04 08:38:57

标签: android orientation accelerometer sensor

我正试图在Android中获取相机的方向。我的代码在肖像中完美运行(我通过慢慢转动圈子并相隔1s看更新来测试它),但它在风景中根本不起作用 - 数字似乎随机变化。从肖像切换到横向后,它也完全失控了。这是我的代码

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);
            }
        }
    }
}

任何想法我做错了什么?我坦率地承认我不会100%理解这一点。我也不知道谷歌为什么不赞成使用方向传感器 - 这似乎是一种常见的愿望。

2 个答案:

答案 0 :(得分:1)

您是否考虑过,当您从纵向更改为横向时,加速度计轴会发生变化?像Y轴一样变成Z轴等。这可能是奇怪行为的一个来源。

答案 1 :(得分:0)

我好像已经解决了它,或者至少将它改进到了解我的问题所在。我放入了一个过滤器,使得我不记得最后一个读数,而是应用了一个delta。每个新传感器点最多允许添加5度。这样可以完全滤除怪异的跳跃,并强制它收敛到一个值。我会偶尔看到一个奇怪的跳跃,但我认为我需要的是一个更复杂的过滤器。新代码:

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;
}