【问题标题】:Android: Problems calculating the Orientation of the DeviceAndroid:计算设备方向的问题
【发布时间】:2013-01-22 08:15:29
【问题描述】:

我正在尝试构建一个简单的增强现实应用程序,因此我开始使用传感器数据。

根据此线程 (Android compass example) 和示例 (http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html),使用 Sensor.TYPE_ACCELEROMETERSensor.TYPE_MAGNETIC_FIELD 计算方向不会'真的不合适。

所以我无法获得“好的”价值。方位角值根本没有任何意义,所以如果我只是将手机向上移动,值就会发生极大的变化。即使我只是旋转手机,这些值也不代表手机的方向。

有没有人有想法,根据给定的例子,谁来提高价值质量?

【问题讨论】:

    标签: android orientation augmented-reality sensors compass-geolocation


    【解决方案1】:

    您以何种方式使用此示例应用程序?从所写的是这段代码,唯一支持的方向是纵向或平放在桌子上,这取决于设备。 “好”是什么意思?

    旋转设备时值不是“好”是正常的,设备坐标系应该是纵向工作,或者我不知道是平坦的(Y轴垂直于屏幕向上,Z轴从屏幕中心指向屏幕外,X 轴垂直于 Y 轴,沿屏幕向右)。有了这个,旋转设备不会旋转设备坐标系,你必须重新映射它。

    但是,如果您希望设备的标题是纵向的,这里有一段对我有用的代码:

    @Override
    public void onSensorChanged(SensorEvent event)
    {
        // It is good practice to check that we received the proper sensor event
        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
        {
            // Convert the rotation-vector to a 4x4 matrix.
            SensorManager.getRotationMatrixFromVector(mRotationMatrix,
                    event.values);
            SensorManager
                    .remapCoordinateSystem(mRotationMatrix,
                            SensorManager.AXIS_X, SensorManager.AXIS_Z,
                            mRotationMatrix);
            SensorManager.getOrientation(mRotationMatrix, orientationVals);
    
            // Optionally convert the result from radians to degrees
            orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
            orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
            orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);
    
            tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
                    + orientationVals[1] + "\n Roll (not used): "
                    + orientationVals[2]);
    
        }
    }
    

    您将在以下位置获得航向(或方位角):

    orientationVals[0]
    

    【讨论】:

    • 作为记录,我用 3x3 矩阵尝试了这段代码,但它只适用于 4x4(又名 float[16])
    【解决方案2】:

    Tíbó 的回答很好,但如果您记录滚动值,您会看到不规则的数字。 (滚动对 AR 浏览器很重要)

    这是由于

    SensorManager.remapCoordinateSystem(mRotationMatrix,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        mRotationMatrix);
    

    您必须使用不同的矩阵进出重映射。以下代码适用于我的正确滚动值:

    @Override
    public void onSensorChanged(SensorEvent event)
    {
        // It is good practice to check that we received the proper sensor event
        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
        {
            // Convert the rotation-vector to a 4x4 matrix.
            SensorManager.getRotationMatrixFromVector(mRotationMatrixFromVector, event.values);
            SensorManager.remapCoordinateSystem(mRotationMatrixFromVector,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        mRotationMatrix);
            SensorManager.getOrientation(mRotationMatrix, orientationVals);
    
            // Optionally convert the result from radians to degrees
            orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
            orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
            orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);
    
            tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
                    + orientationVals[1] + "\n Roll (not used): "
                    + orientationVals[2]);
    
        }
    }
    

    【讨论】:

    • 是的,您可以查看源代码: public static boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) * @param outR * 转换后的旋转矩阵。 inR 和 outR 不应该是同一个 * 数组。
    【解决方案3】:

    聚会可能迟到了。无论如何,这就是我如何获得方位角

    private final int sensorType =  Sensor.TYPE_ROTATION_VECTOR;
    float[] rotMat = new float[9];
    float[] vals = new float[3];
    
    @Override
    public void onSensorChanged(SensorEvent event) {
        sensorHasChanged = false;
        if (event.sensor.getType() == sensorType){
            SensorManager.getRotationMatrixFromVector(rotMat,
                    event.values);
            SensorManager
                    .remapCoordinateSystem(rotMat,
                            SensorManager.AXIS_X, SensorManager.AXIS_Y,
                            rotMat);
            SensorManager.getOrientation(rotMat, vals);
            azimuth = deg(vals[0]); // in degrees [-180, +180]
            pitch = deg(vals[1]);
            roll = deg(vals[2]);
            sensorHasChanged = true;
        }
    }
    

    希望对你有帮助

    【讨论】:

    • remapCoordinateSystem 调用只是身份转换,所以它是多余的。更糟糕的是,它使用rotMat 进行输入和输出,文档明确指出您不应该这样做。
    【解决方案4】:

    您是否尝试过组合(传感器融合)类型 Sensor.TYPE_ROTATION_VECTOR。这可能会产生更好的结果: 转到https://developer.android.com/reference/android/hardware/SensorEvent.html 并搜索“rotation_vector”。

    【讨论】:

    • 好的,有什么例子可以使用这个传感器吗?我得到 xsin(θ/2)、ysin(θ/2) 和 z*sin(θ/2) 的值。但是我如何获得价值,我需要建立我的指南针。我应该再次使用 getRotationMatrix 吗?感谢您的帮助。
    • "X定义为向量积YZ(在设备当前位置与地面相切,大致指向东)。Y在设备当前位置与地面相切,指向磁北。Z指向天空,垂直于地面。掸掉你的几何课书上的灰尘,或者用谷歌搜索一下:),你应该能弄明白的。
    【解决方案5】:

    这是一个包含所有必要矩阵的 Kotlin 方法(由于某种原因,前面的答案忽略了数组大小,这很重要)

    // This is determined from the deprecated Sensor.TYPE_ORIENTATION
    var lastOrientation: FloatArray = FloatArray(3)
    var lastHeading: Float = 0f
    var currentHeading: Float = 0f
    
    // This is from the non deprecated Sensor.TYPE_ROTATION_VECTOR
    var lastVectorOrientation: FloatArray = FloatArray(5)
    var lastVectorHeading: Float = 0f
    var currentVectorHeading: Float = 0f
    
    override fun onSensorChanged(event: SensorEvent) {
        when(event.sensor?.type) {
            null -> return
            Sensor.TYPE_ORIENTATION -> {
                lastOrientation = event.values
                lastHeading = currentHeading
                currentHeading = abs(event.values[0].roundToInt().toFloat())
            }
            Sensor.TYPE_ROTATION_VECTOR -> {
                lastVectorOrientation = event.values
                lastVectorHeading = currentVectorHeading
    
                val tempRotationMatrix = FloatArray(9)
                val tempOrientationMatrix = FloatArray(3)
                getRotationMatrixFromVector(tempRotationMatrix, event.values)
                remapCoordinateSystem(tempRotationMatrix, AXIS_X, AXIS_Z, tempRotationMatrix)
                getOrientation(tempRotationMatrix, tempOrientationMatrix)
                currentVectorHeading = Math.toDegrees(tempOrientationMatrix[0].toDouble()).toFloat()
                
                if(currentVectorHeading < 0) {
                    currentVectorHeading += 360f//heading = 360 - abs(neg heading), which is really 360 + (-heading)
                }
            }
            else -> return
        }
    }
    

    我还包含了已弃用的 Sensor.TYPE_ORIENTATION 供任何想了解这两种方法之间差异的人使用。使用不推荐使用的方法与使用更新的方法时存在几个程度的差异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      • 2011-06-23
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      相关资源
      最近更新 更多