【问题标题】:Android getOrientation issue - mirrored values along axisAndroid getOrientation 问题 - 沿轴的镜像值
【发布时间】:2021-06-04 18:46:36
【问题描述】:

我在使用 getOrientation 时遇到了一些问题。我在横向模式下运行我的应用程序,但我遇到了一个轴的问题。代码中有更多解释,一些图片:

    valuesMagnet      = new float[3];
    valuesAccel       = new float[3];
    valuesOrientation = new float[3];
    rotationMatrix    = new float[9];
    rotationMatrixTemp= new float[9];

....


@Override
public void onSensorChanged(SensorEvent event) {


    switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            System.arraycopy(event.values, 0, valuesAccel, 0, 3);
            break;

        case Sensor.TYPE_MAGNETIC_FIELD:
            System.arraycopy(event.values, 0, valuesMagnet, 0, 3);
            break;
    }

    if (SensorManager.getRotationMatrix(rotationMatrixTemp, null, valuesAccel, valuesMagnet)) {
        //SensorManager.remapCoordinateSystem(rotationMatrixTemp, SensorManager.AXIS_X, SensorManager.AXIS_Z, rotationMatrix);
        SensorManager.getOrientation(rotationMatrix, valuesOrientation);

        for (int i = 0; i < valuesOrientation.length; i++) {
            valuesOrientation[i] /= Math.PI;
            valuesOrientation[i] *= 100;
            valuesOrientation[i] = (int)valuesOrientation[i];
            valuesOrientation[i] /= 100;
        }

        updateOrientationBuffer(valuesOrientation);

        quadcopter.onEvent(new Event(Event.Codes.ORIENTATION_CHANGED, calculateSmoothedOrientation()));
    }
    else {
        Log.d("App", "Matrix rotate error");
    }
}

我希望orientation[1] 轴在将手机旋转 180 度时给出 -1 和 1 之间的全谱值。此外,目标设备不是陀螺仪。

【问题讨论】:

  • 您能否发布更多代码以查看您是如何生成 valuesAccel 和 valuesMagnet 的?
  • @GilMoshayof,我已经编辑了我的帖子。
  • 你使用SensorManager获取方向传感器吗?还是您使用原始传感器数据?我不确定(我在文档中找到了不同的信息),但我认为第一个可能使用 radians,第二个可能使用 degrees。请检查是否不是这种情况。
  • 很难理解你的图片是什么意思。我在您的代码中注意到“qaudcopter”。我想你想用手机控制它,当手机放下时,四轴飞行器不动,当手机向左倾斜时,四轴飞行器向左移动。为此,您只需要加速度计的 x,y 轴。你宁愿不想知道你的手机是朝北还是朝东——这就是你得到的方向。

标签: java android orientation


【解决方案1】:
@Override
public void onSensorChanged(SensorEvent event) {
    switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            System.arraycopy(event.values, 0, valuesAccel, 0, 3);
            break;

        case Sensor.TYPE_MAGNETIC_FIELD:
            System.arraycopy(event.values, 0, valuesMagnet, 0, 3);
            break;

        case Sensor.TYPE_GRAVITY:
            System.arraycopy(event.values, 0, valuesGravity, 0, 3);
            break;

        default:
            break;
    }

    if (SensorManager.getRotationMatrix(rotationMatrixTemp, null, valuesAccel, valuesMagnet)) {
        SensorManager.getOrientation(rotationMatrixTemp, valuesOrientation);

        if(valuesGravity[2] < 0)                                     {
            if (valuesOrientation[1] > 0) {
                valuesOrientation[1] = (float) (Math.PI - valuesOrientation[1]);
            }
            else {
                valuesOrientation[1] = (float) (-Math.PI - valuesOrientation[1]);
            }
        }

        for (int i = 0; i < valuesOrientation.length; i++) {
            valuesOrientation[i] /= Math.PI;
            valuesOrientation[i] *= 100;
            valuesOrientation[i] = (int)valuesOrientation[i];
            valuesOrientation[i] /= 100;
        }


        updateOrientationBuffer(valuesOrientation);

        quadcopter.onEvent(new Event(Event.Codes.ORIENTATION_CHANGED, calculateSmoothedOrientation()));
    }
    else {
        Log.d("Quadcopter-SM", "Matrix rotate error");
    }
}

【讨论】:

    【解决方案2】:

    根据您面临的问题,我的理解是您主要关注两个轴,根据笛卡尔系统主要是 X 和 Y。

    在 Ans 中,我将 Orintation1 称为 X,将 Orientation2 称为 Y。

    因此,您需要 X 轴在 -90 到 90 度之间发生旋转时的值谱。

    我已经分析了问题和你的代码,下面是我对问题的解决方案。

    package com.example.stackoverflowquestion;
    
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Context;
    import android.util.Log;
    import android.view.Menu;
    import android.widget.Toast;
    
    public class MainActivity extends Activity implements SensorEventListener {
    
        private SensorManager mSensorManager;
        private Sensor accel, magnet;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
            accel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            magnet = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        }
    
        @Override
        protected void onPause() {
            // TODO Auto-generated method stub
            super.onPause();
            mSensorManager.unregisterListener(this);
        }
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
            if (accel != null) {
                mSensorManager.registerListener(this, accel,
                        SensorManager.SENSOR_DELAY_NORMAL);
            } else {
                Toast.makeText(this, "Accelerometer not available",
                        Toast.LENGTH_LONG).show();
            }
            if (magnet != null) {
                mSensorManager.registerListener(this, magnet,
                        SensorManager.SENSOR_DELAY_NORMAL);
            } else {
                Toast.makeText(this, "MagnetoMeter not available",
                        Toast.LENGTH_LONG).show();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public void onAccuracyChanged(Sensor arg0, int arg1) {
            // TODO Auto-generated method stub
    
        }
    
        float[] accelMat = new float[3];
        float[] magMat = new float[3];
        float[] rotmat = new float[9];
        float[] orientationMat = new float[3];
    
        @Override
        public void onSensorChanged(SensorEvent event) {
            // TODO Auto-generated method stub
            switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER:
                System.arraycopy(event.values, 0, accelMat, 0, 3);
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                System.arraycopy(event.values, 0, magMat, 0, 3);
                break;
            }
    
            if (SensorManager.getRotationMatrix(rotmat, null, accelMat, magMat)) {
                SensorManager.getOrientation(rotmat, orientationMat);
    
                for (int i = 0; i < orientationMat.length; i++) {
                    // convert from redians to degrees
                    orientationMat[i] = (float) (orientationMat[i] / Math.PI) * 180;
                }
                Log.d("yaw", ":" + orientationMat[0]);
                Log.d("pitch", ":" + orientationMat[1]);
                Log.d("roll", ":" + orientationMat[2]);
    
            }
    
        }
    }
    

    此代码打印度数中的日志,如果您想要在 redians 中,则需要简单的公式更改。

    注意:此代码也适用于没有陀螺仪的设备。我在 HTC Evo 4G 设备上进行了测试,结果符合预期。

    【讨论】:

    • 抱歉,您的解决方案中的音高介于 -90 和 90 之间,而不是滚动时的 -180 和 180 之间。仍然,例如。 -45 度意味着两个不同的俯仰旋转。我想我在这里的评论中找到了解决方案:stackoverflow.com/questions/17747823/…我正在测试它。
    • 好的。很好,你找到了解决方案,但是我们使用的公式会很有用。
    • 另外,在这种情况下,解决方案不够充分,我正在等待我的朋友发布代码。
    【解决方案3】:

    getOrientation 的文档声称它返回 -π 到 π 之间的间距。这不可能是真的,因为实现是values[1] = (float) Math.asin(-R[7]);asin 返回的值在 -π/2 和 π/2 之间)

    这是一个known issue,Google 不会修复。我基于Gregory G. Slabaugh's paper创建了自己的getOrientation函数

    // Based on pseudo code from http://www.close-range.com/docs/Computing_Euler_angles_from_a_rotation_matrix.pdf
    object EulerAngleHelper {
        private const val R11 = 0
        private const val R12 = 1
        private const val R13 = 2
        private const val R21 = 3
        private const val R22 = 4
        private const val R23 = 5
        private const val R31 = 6
        private const val R32 = 7
        private const val R33 = 8
        private const val AZIMUTH = 0
        private const val PITCH = 1
        private const val ROLL = 2
        private const val PHI_Z = AZIMUTH
        private const val PSI_X = PITCH
        private const val THETA_Y = ROLL
    
        fun getOrientation(r: DoubleArray, values: DoubleArray): DoubleArray {
            when {
                r[R31] < -0.98 -> {
                    values[PHI_Z] = 0.0 // Anything; can set to 0
                    values[THETA_Y] = Math.PI / 2
                    values[PSI_X] = values[PHI_Z] + atan2(r[R12], r[R13])
                }
                r[R31] > 0.98 -> {
                    values[PHI_Z] = 0.0 // Anything; can set to 0
                    values[THETA_Y] = -Math.PI / 2
                    values[PSI_X] = values[PHI_Z] + atan2(-r[R12], -r[R13])
                }
                else -> {
                    values[THETA_Y] = -asin(r[R31])
                    val cosTheta = cos(values[THETA_Y])
                    values[PSI_X] = atan2(r[R32] / cosTheta, r[R33] / cosTheta)
                    values[PHI_Z] = atan2(r[R21] / cosTheta, r[R11] / cosTheta)
                }
            }
            return values
        }
    }
    

    我只测试了俯仰和滚动。

    【讨论】:

      猜你喜欢
      • 2019-06-30
      • 2015-03-10
      • 2018-04-10
      • 1970-01-01
      • 2021-10-18
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多