【问题标题】:Compass readings on SGS IIISGS III 上的指南针读数
【发布时间】:2013-01-01 18:27:58
【问题描述】:

我的应用需要使用指南针显示设备的当前方位。我正在使用的代码(如下)在我的 Galaxy Nexus 和 Galaxy One 上运行良好,但指南针在三星 Galaxy S III 上疯狂旋转。我已经尝试做一个图 8 来重新校准设备,但这并没有改变任何东西。奇怪的是,从 Google Play 下载的其他指南针应用程序在 SIII 上运行良好。这可能是什么问题?

float[] mGravity;
float[] mGeomagnetic;

public void onSensorChanged( SensorEvent event ) {
    float azimuth = 0f;
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        mGravity = event.values;
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
        mGeomagnetic = event.values;
    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);
            azimuth = orientation[0]; // orientation contains: azimut, pitch and roll
        }
     }

    //Discard 0.0-values
    if(azimuth == 0.0) { return; }

    //Convert the sensor value to degrees
    azimuth = (float) Math.toDegrees(azimuth); //same as azimuth = -azimuth*360/(2*3.14159f);


    //Smooth the sensor-output
    azimuth = smoothValues(azimuth);
}

//From http://stackoverflow.com/questions/4699417/android-compass-orientation-on-unreliable-low-pass-filter
//SmoothFactorCompass: The easing float that defines how smooth the movement will be (1 is no smoothing and 0 is never updating, my default is 0.5).
//SmoothThresholdCompass: The threshold in which the distance is big enough to turn immediately (0 is jump always, 360 is never jumping, my default is 30).
static final float SmoothFactorCompass = 0.5f;
static final float SmoothThresholdCompass = 30.0f;
float oldCompass = 0.0f;
private float smoothValues (float newCompass){
    if (Math.abs(newCompass - oldCompass) < 180) {
        if (Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
            oldCompass = newCompass;
        }
        else {
            oldCompass = oldCompass + SmoothFactorCompass * (newCompass - oldCompass);
        }
    }
    else {
        if (360.0 - Math.abs(newCompass - oldCompass) > SmoothThresholdCompass) {
            oldCompass = newCompass;
        }
        else {
            if (oldCompass > newCompass) {
                oldCompass = (oldCompass + SmoothFactorCompass * ((360 + newCompass - oldCompass) % 360) + 360) % 360;
            } 
            else {
                oldCompass = (oldCompass - SmoothFactorCompass * ((360 - newCompass + oldCompass) % 360) + 360) % 360;
            }
        }
    }
    return oldCompass;
}

【问题讨论】:

    标签: android galaxy android-sensors samsung-mobile digital-compass


    【解决方案1】:

    目前我正在研究 Android 上的指南针机制,我建议您从低通滤波器开始。 您需要做的是对 ACCELEROMETER 和 MAGNETIC_FIELD 传感器数据应用低通滤波器。 以下是我的实现方式:

    private float[] accel;
    private float[] geomagnetic;
    float R[] = new float[9];
    float I[] = new float[9];
    float orientation[] = new float[3];
    
    @Override
    public void onSensorChanged(SensorEvent event)
    {
        synchronized (this)
        {
            float azimuth = -1f;
    
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
                accel = lowPass( event.values.clone(), accel );
    
            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
                geomagnetic = lowPass(event.values.clone(), geomagnetic);
    
            if (accel != null && geomagnetic != null)
            {
    
                boolean success = SensorManager.getRotationMatrix(R, I,
                        accel, geomagnetic);
    
                SensorManager.remapCoordinateSystem(R,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z, R);
    
                if (success)
                {
                    SensorManager.getOrientation(R, orientation);
                    azimuth = orientation[0]; // orientation contains:
                                             // azimuth, pitch
                                             // and roll
                    float newHeading = azimuth * 360 / (2 * 3.14159f);
    
                    //do what you need to do with new heading
                } 
            }
        }
    }
    
    
    /*
     * time smoothing constant for low-pass filter 0 ≤ alpha ≤ 1 ; a smaller
     * value basically means more smoothing See:
     * http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization
     */
    static final float ALPHA = 0.15f;
    
    /**
     * @see http
     *      ://en.wikipedia.org/wiki/Low-pass_filter#Algorithmic_implementation
     * @see http
     *      ://developer.android.com/reference/android/hardware/SensorEvent.html
     *      #values
     */
    
    protected float[] lowPass(float[] input, float[] output)
    {
        if (output == null)
            return input;
    
        for (int i = 0; i < input.length; i++)
        {
            output[i] = output[i] + ALPHA * (input[i] - output[i]);
        }
        return output;
    }
    

    【讨论】:

    • 你如何计算 ALPHA = 0.15 从科学上讲,闭上眼睛并选择从 0 到 1 的随机值是无法做到这一点的。在这种情况下,谁能详细说明 ALPHA 的计算。我需要证明为什么我使用 ALPHA 的 X 值,而我的采样率为 100Hz。任何帮助
    • 为什么不呢?这就是我所做的 :) 这是“平滑度”系数,取决于您的偏好(更平滑的输出值 = 较小的 alpha)。所以首先,你需要想出如何衡量你的偏好(因为这只是这个方程中的变量),然后你才能创建一个计算 alpha 的公式:)
    【解决方案2】:

    也许你应该先克隆传感器读数中的值,如果这不起作用,然后低通滤波器,我知道 SONY XPeria 手机非常敏感,不像三星非常稳定。

    在我看来,在 android OS 4.3 下 S3 读取是相当不错的

    event.values.clone;
    

    我最近的经验夫妇数据反馈迫使我在装有 Invesense 传感器的索尼手机上应用旋转矢量逻辑,它似乎工作,虽然我仍然不喜欢波涛汹涌的响应,但我已经接受了索尼的这种响应安卓 4.3 操作系统。在我看来,任何加载了 invensense 传感器的手机都需要应用旋转矢量才能正常工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-25
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      • 2016-09-06
      • 1970-01-01
      相关资源
      最近更新 更多