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

Android 在横向模式或翻转方向后无法从传感器获取方向,android,orientation,accelerometer,sensors,Android,Orientation,Accelerometer,Sensors,我想用安卓系统来确定摄像机的方向。我的代码在纵向上运行得很好(我通过慢慢地转一圈,间隔1秒看更新来测试),但在横向上根本不起作用——数字似乎是随机变化的。在从肖像画切换到风景画之后,它也变得完全不正常。这是我的密码 public void onSensorChanged(SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: accelerome

我想用安卓系统来确定摄像机的方向。我的代码在纵向上运行得很好(我通过慢慢地转一圈,间隔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%理解这一点。我也不知道为什么谷歌不喜欢定向传感器——这似乎是一个共同的愿望。

< P>你有没有想过,当你从肖像变成风景时,加速度轴会改变?就像Y轴变成Z轴一样。这可能是奇怪行为的一个来源。

我似乎已经解决了它,或者至少改进到了我知道问题所在的程度。我加入了一个过滤器,这样我就可以记住上一次的读数,并对其应用一个增量,而不是发送一个传感器读数。每个新传感器点最多可增加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;
}
传感器更改时的公共无效(传感器事件){ if(event.accurity==SensorManager.SENSOR\u状态\u不可靠) 返回; 开关(event.sensor.getType()){ 外壳传感器.U型加速计: accelerometerValues=event.values.clone(); 打破 外壳传感器。类型\u磁场: 地磁矩阵=event.values.clone(); 打破 } if(地磁矩阵!=null和加速度计值!=null){ 浮动[]R=新浮动[16]; 浮动[]I=新浮动[16]; 浮动[]输出=新浮动[16]; //获取旋转矩阵,然后将其从摄影机曲面重新映射到世界坐标 SensorManager.getRotationMatrix(R、I、加速度计值、地磁矩阵); SensorManager.remapCoordinationSystem(R,SensorManager.AXIS_X,SensorManager.AXIS_Z,outR); 浮动值[]=新浮动[4]; SensorManager.getOrientation(输出、值); int direction=filterChange(normalizedgrees(数学toDegrees(值[0])); int pitch=标准化程度(数学到度(值[1]); int roll=normalizedgrees(数学toDegrees(值[2]); 如果((int)方向!=(int)最后方向){ lastDirection=(int)方向; lastPitch=(int)音高; lastRoll=(int)roll; for(CompassListener:侦听器){ 方向改变(最后方向、音高、滚动); } } } } //将0到360度的角度规格化,而不是-180到180度 专用整数规格化灰度(双拉德){ 返回值(整数)((rads+360)%360); } //我们希望忽略单个读数中的大起伏。因此,我们将限制每个报告可以更改的度数 私有int filterChange(int newDir){ int change=newDir-lastDirection; int circularChange=newDir-(lastDirection+360); 最微小的变化; if(数学abs(变化)我已经想到了这一点。这里是y轴和x轴的切换(z始终通过屏幕显示)。但这似乎也不能正确移动-我已经将所有3个都转储到屏幕上,但没有一个移动正确。即使在工作时,方向也会像疯了一样跳跃——在转弯后每隔1s采集一次样本,可以得到180、320、280、220、180、300。。。当它应该是200ish时。快速评论-值3和-3似乎提供了相当好的反弹保护。