2

我在使用 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 之间的全谱值。此外,目标设备没有陀螺仪。

4

3 回答 3

2
@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");
    }
}
于 2013-10-18T12:55:08.720 回答
0

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

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

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

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

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 设备上进行了测试,并得到了预期的结果。

于 2013-10-18T05:09:32.187 回答
0

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

这是Google 不会解决的已知问题。getOrientation我根据Gregory G. Slabaugh 的论文创建了自己的函数

// 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
    }
}

我只测试了俯仰和滚动。

于 2021-06-04T10:46:36.137 回答