0

我正在尝试在 Android 中获取相机的方向。我的代码在纵向上运行良好(我通过慢慢转一圈并查看相隔 1 秒的更新来测试它),但在横向上它根本不起作用——数字似乎随机变化。从纵向切换到横向后,它也完全失控。这是我的代码

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% 理解这一点。我也不知道为什么谷歌不推荐使用方向传感器——这似乎是一个足够普遍的愿望。

4

2 回答 2

1

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

于 2012-09-04T08:46:46.407 回答
0

我似乎已经解决了它,或者至少将它改进到我知道问题所在的地步。我放入了一个过滤器,这样我就不会提供单个传感器读数,而是记住最后一次读数并对其应用增量。每个新的传感器点最多允许增加 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;
}
于 2012-09-05T00:25:22.077 回答