将加速度计的数据从设备坐标转换为真实世界坐标

时间:2011-03-28 20:45:44

标签: android coordinates device accelerometer

如果这是一个非常基本的问题,我真的很抱歉,但我没有选择,只能问:如何将加速度计数据从设备坐标转换为真实世界坐标?

我的意思是,假设加速度计让我感觉像(Ax,Ay,Az) - in device's coordinates - ,我应该应用什么转换来将值转换为(Ax',Ay',Az') - in real world's coordinates - ,所以我可以使用真实世界坐标中的加速度矢量来计算设备是在加速北,东,西南等?

过去几天我一直在解决这个问题。起初我认为这很难,但在搜索了几十页后,我还没有提出任何功能。

顺便说一下,到目前为止,这里有一些我已实现的代码:

    private SensorEventListener mSensorEventListener = new SensorEventListener() {

    public void onAccuracyChanged(Sensor sensor, int accuracy){
}

    public void onSensorChanged(SensorEvent event) {
        switch(event.sensor.getType()){
        case Sensor.TYPE_ACCELEROMETER:
            accelerometervalues = event.values.clone();
            AX.setText(accelerometervalues[0]+"");
            AY.setText(accelerometervalues[1]+"");
            AZ.setText(accelerometervalues[2]+"");
            break;
        case Sensor.TYPE_ORIENTATION:
            orientationvalues = event.values.clone();
            azimuth.setText(orientationvalues[0]+"");
            pitch.setText(orientationvalues[1]+"");
            roll.setText(orientationvalues[2]+"");
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomagneticmatrix =event.values.clone();
            TAX.setText(geomagneticmatrix[0]+"");
            TAY.setText(geomagneticmatrix[1]+"");
            TAZ.setText(geomagneticmatrix[2]+"");
            break;
        }
        if (geomagneticmatrix != null && accelerometervalues != null) {
            float[] R = new float[16];
            float[] I = new float[16];
            SensorManager.getRotationMatrix(R, I, accelerometervalues, geomagneticmatrix);
            //What should I do here to transform the components of accelerometervalues into real world acceleration components??
        }
   }
};

我有:

accelerometervalues中原生坐标中的加速度矢量。

geomagneticmatrix中的磁场值矢量。

orientationvalues中的方位角,俯仰和滚动。

旋转矩阵R。 倾角矩阵I

我认为所有必要的信息都在那里,方位角,俯仰和滚动应该描述设备坐标系相对于真实世界坐标系的位移。另外,我相信R /甚至可以用作设备坐标内的真北向量。

在我看来,在现实世界中获得加速度值只是远离那些数据的数学变换。我只是想不出来。

提前致谢。

编辑:

我尝试直接将accelerometervalues的组件与旋转矩阵R(trueaccel = accel * R)相乘,但它不起作用。

                    trueacceleration[0]= accelerometervalues[0]*R[0]+accelerometervalues[1]*R[1]+accelerometervalues[2]*R[2];
                trueacceleration[1]= accelerometervalues[0]*R[1]+accelerometervalues[1]*R[4]+accelerometervalues[2]*R[7];
                trueacceleration[2]= accelerometervalues[0]*R[2]+accelerometervalues[1]*R[5]+accelerometervalues[2]*R[8];

我还尝试将accelerometervalues与倾斜矩阵I相乘。同时乘以R和I(trueaccel = accel * R * I)并且也不起作用。也没有呼叫remapcoordinates()然后乘以任何以前的形式。

有没有人知道我做错了什么?

5 个答案:

答案 0 :(得分:6)

Oki,我已经用数学方法解决了这个问题,所以请耐心等待。

如果您想将加速度矢量accelerationvalues转换为以真实世界坐标表示的加速度矢量trueacceleration,一旦您将方位角,俯仰和滚动存储在orientationvalues矢量中,执行以下操作:

                trueacceleration[0] =(float) (accelerometervalues[0]*(Math.cos(orientationvalues[2])*Math.cos(orientationvalues[0])+Math.sin(orientationvalues[2])*Math.sin(orientationvalues[1])*Math.sin(orientationvalues[0])) + accelerometervalues[1]*(Math.cos(orientationvalues[1])*Math.sin(orientationvalues[0])) + accelerometervalues[2]*(-Math.sin(orientationvalues[2])*Math.cos(orientationvalues[0])+Math.cos(orientationvalues[2])*Math.sin(orientationvalues[1])*Math.sin(orientationvalues[0])));
            trueacceleration[1] = (float) (accelerometervalues[0]*(-Math.cos(orientationvalues[2])*Math.sin(orientationvalues[0])+Math.sin(orientationvalues[2])*Math.sin(orientationvalues[1])*Math.cos(orientationvalues[0])) + accelerometervalues[1]*(Math.cos(orientationvalues[1])*Math.cos(orientationvalues[0])) + accelerometervalues[2]*(Math.sin(orientationvalues[2])*Math.sin(orientationvalues[0])+ Math.cos(orientationvalues[2])*Math.sin(orientationvalues[1])*Math.cos(orientationvalues[0])));
            trueacceleration[2] = (float) (accelerometervalues[0]*(Math.sin(orientationvalues[2])*Math.cos(orientationvalues[1])) + accelerometervalues[1]*(-Math.sin(orientationvalues[1])) + accelerometervalues[2]*(Math.cos(orientationvalues[2])*Math.cos(orientationvalues[1])));

答案 1 :(得分:1)

您需要能够知道参考坐标系,它还可以在“真实”世界坐标中为您提供设备的方向。如果没有这些信息,就无法将数据转换为有用的数据。

例如,您的设备是否有一种“定向”传感器可以帮助理解加速度计数据(例如陀螺仪和指南针?)

答案 2 :(得分:1)

我正在处理同样的问题。你可以做的是,因为你有R []矩阵乘以你的加速度矢量和voilá。

float resultVec[] = new float[4];
Matrix.multiplyMV(trueacceleration, 0, R, 0, accelerometervalues, 0);

PS:accelerometervalues必须是4场矢量,只需将0添加到最后一个场。

答案 3 :(得分:1)

试试这个,它为我工作

private float[] gravityValues = null;
    private float[] magneticValues = null;
    private SensorManager mSensorManager = null;  
private void registerSensorListener(Context context) {
        mSensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_FASTEST);

        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
                SensorManager.SENSOR_DELAY_FASTEST);

        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                SensorManager.SENSOR_DELAY_FASTEST);

        mSensorManager.registerListener(this,
                mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
                SensorManager.SENSOR_DELAY_FASTEST);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if ((gravityValues != null) && (magneticValues != null)
                && (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {

            float[] deviceRelativeAcceleration = new float[4];
            deviceRelativeAcceleration[0] = event.values[0];
            deviceRelativeAcceleration[1] = event.values[1];
            deviceRelativeAcceleration[2] = event.values[2];
            deviceRelativeAcceleration[3] = 0;

            Log.d("Raw Acceleration::","Values: (" + event.values[0] + ", " + event.values[1] + ", " + event.values[2] + ")");

            // Change the device relative acceleration values to earth relative values
            // X axis -> East
            // Y axis -> North Pole
            // Z axis -> Sky

            float[] R = new float[16], I = new float[16], earthAcc = new float[16];

            SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);

            float[] inv = new float[16];

            android.opengl.Matrix.invertM(inv, 0, R, 0);
            android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);
            Log.d("Earth Acceleration", "Values: (" + earthAcc[0] + ", " + earthAcc[1] + ", " + earthAcc[2] + ")");

        } else if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
            gravityValues = event.values;
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magneticValues = event.values;
        }
    }

答案 4 :(得分:0)

这是我用于将accelrometer数据从本地(Mobile)参考框架映射到地球参考框架,以摆脱依赖的方向。由于在地球框架中Z轴指向天空并且必须显示值〜= 9.81m / sec ^ 2。我无法理解的一个现象是,当我将电话放在旋转椅上任何方向并以恒定速度旋转时,XEarth和YEarth值显示90度相移的旋转并且像我认为的sin /余弦波一样振荡北轴和东轴。

public void onSensorChanged(SensorEvent event) {

        switch(event.sensor.getType()){

           case Sensor.TYPE_ACCELEROMETER:
                 System.arraycopy(event.values, 0, accel, 0, 3);
                     //To get Quternion representation of Accelrometer data              
                     SensorManager.getQuaternionFromVector(quatA , event.values);
             q1.w = quatA[0]; q1.x = quatA[1]; q1.y = quatA[2]; q1.z = quatA[3];
           break;

           case Sensor.TYPE_ROTATION_VECTOR:
                SensorManager.getRotationMatrixFromVector(rotationMatrix1,event.values);
                System.arraycopy(event.values, 0, rotationVector, 0, 3);
                SensorManager.getQuaternionFromVector(quat , event.values);
                q2.w = quat[0]; q2.x = quat[1]; q2.y = quat[2]; q2.z = quat[3];
                rotationMatrix2 = getRotationMatrixFromQuaternion(q2);
                rotationResult =  matrixMultiplication(accel,rotationMatrix2);
                //You can  use rotationMatrix1 or rotationMatrix2  

             break;
//Accel Data rotated as per earth frame of reference 
//rotationResult[0]; 
//rotationResult[1];
//rotationResult[2];

        }

    private float[] getRotationMatrixFromQuaternion(Quaternion q22) {
        // TODO Auto-generated method stub
        float [] q = new float[4];
        float [] result = new float[9];
        q[0] = q22.w;
        q[1] = q22.x;
        q[2] = q22.y;
        q[3] = q22.z;

        result[0] = q[0]*q[0] + q[1]*q[1] - q[2]*q[2] -q[3]*q[3];
            result[1] = 2 * (q[1]*q[2] - q[0]*q[3]);
            result[2] = 2 * (q[1]*q[3] + q[0]*q[2]);

            result[3] = 2 * (q[1]*q[2] + q[0]*q[3]);
            result[4] = q[0]*q[0] - q[1]*q[1] + q[2]*q[2] - q[3]*q[3];
            result[5] = 2 * (q[2]*q[3] - q[0]*q[1]);

            result[7] = 2 * (q[2]*q[3] + q[0]*q[1]);
            result[6] = 2 * (q[1]*q[3] - q[0]*q[2]);
        result[8] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];

        return result;
    }

 private float[] matrixMultiplication(float[] A, float[] B) {
        float[] result = new float[3];

        result[0] = A[0] * B[0] + A[1] * B[1] + A[2] * B[2];
        result[1] = A[0] * B[3] + A[1] * B[4] + A[2] * B[5];
        result[2] = A[0] * B[6] + A[1] * B[7] + A[2] * B[8];

        return result;
    }