如何获得引力方向

时间:2014-07-01 20:22:21

标签: java accelerometer sensor android-sensors gyroscope

我需要根据加速度计,陀螺仪和磁力计计算线性加速度。我发现了一个Android应用程序,它正是我想要实现的目标:

https://play.google.com/store/apps/details?id=com.kircherelectronics.fusedlinearaccelerationhttps://github.com/KEOpenSource/FusedLinearAcceleration

我试图将它移植到纯java。由于代码的某些元素基于虚拟传感器(重力传感器),我希望通过基于三个基本传感器的计算重力方法获得相同的结果。我读到可以使用低通滤波器(与Android< 4.0相同)计算重力,但这种方法不能给出非常准确的结果。

从android 4.0开始,使用传感器融合计算每个轴上的重力。我找到了负责这些测量的代码,但它写在CPP中:

https://github.com/android/platform_frameworks_base/blob/ics-mr1/services/sensorservice/GravitySensor.cpp

使用的方法称为" getRotationMatrix"。 SensorManager.java中的相同方法:https://gitorious.org/android-eeepc/base/source/9cb3e09ec49351401cf19b5ae5092dd9ca90a538:core/java/android/hardware/SensorManager.java#L1034

    public static boolean getRotationMatrix(float[] R, float[] I,
        float[] gravity, float[] geomagnetic) {
    // TODO: move this to native code for efficiency
    float Ax = gravity[0];
    float Ay = gravity[1];
    float Az = gravity[2];
    final float Ex = geomagnetic[0];
    final float Ey = geomagnetic[1];
    final float Ez = geomagnetic[2];
    float Hx = Ey*Az - Ez*Ay;
    float Hy = Ez*Ax - Ex*Az;
    float Hz = Ex*Ay - Ey*Ax;
    final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
    if (normH < 0.1f) {
        // device is close to free fall (or in space?), or close to
        // magnetic north pole. Typical values are  > 100.
        return false;
    }
    final float invH = 1.0f / normH;
    Hx *= invH;
    Hy *= invH;
    Hz *= invH;
    final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
    Ax *= invA;
    Ay *= invA;
    Az *= invA;
    final float Mx = Ay*Hz - Az*Hy;
    final float My = Az*Hx - Ax*Hz;
    final float Mz = Ax*Hy - Ay*Hx;
    if (R != null) {
        if (R.length == 9) {
            R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
            R[3] = Mx;     R[4] = My;     R[5] = Mz;
            R[6] = Ax;     R[7] = Ay;     R[8] = Az;
        } else if (R.length == 16) {
            R[0]  = Hx;    R[1]  = Hy;    R[2]  = Hz;   R[3]  = 0;
            R[4]  = Mx;    R[5]  = My;    R[6]  = Mz;   R[7]  = 0;
            R[8]  = Ax;    R[9]  = Ay;    R[10] = Az;   R[11] = 0;
            R[12] = 0;     R[13] = 0;     R[14] = 0;    R[15] = 1;
        }
    }
    if (I != null) {
        // compute the inclination matrix by projecting the geomagnetic
        // vector onto the Z (gravity) and X (horizontal component
        // of geomagnetic vector) axes.
        final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
        final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
        final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
        if (I.length == 9) {
            I[0] = 1;     I[1] = 0;     I[2] = 0;
            I[3] = 0;     I[4] = c;     I[5] = s;
            I[6] = 0;     I[7] =-s;     I[8] = c;
        } else if (I.length == 16) {
            I[0] = 1;     I[1] = 0;     I[2] = 0;
            I[4] = 0;     I[5] = c;     I[6] = s;
            I[8] = 0;     I[9] =-s;     I[10]= c;
            I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
            I[15] = 1;
        }
    }
    return true;
}

有四个参数:

float [] R, float [] I, float [] gravity, float [] Geomagnetic.

其中一个只是引力......我目前正在处理的代码类似于

https://github.com/KEOpenSource/FusedLinearAcceleration/blob/master/FusedLinearAcceleration/src/com/kircherelectronics/fusedlinearacceleration/sensor/LinearAccelerationSensor.java

,但引用SensorManager的方法除外。这些是从android源代码复制的:

https://gitorious.org/android-eeepc/base/source/9cb3e09ec49351401cf19b5ae5092dd9ca90a538:core/java/android/hardware/SensorManager.java

我没有找到任何关于如何在Java中实现它的例子。

所以我的问题是:如何实现方法(在java中),仅基于三个基本传感器,它返回重力方向(x,y,z)的数组,类似于Android一个,但不使用Android API

1 个答案:

答案 0 :(得分:1)

重力是加速度计信号(x,y和amp; z)中的稳定贡献。 因此,从逻辑上讲,为了将重力值与时间相关联,只需对3个加速度计信号进行低通滤波,例如频率为2Hz。 一个简单的FIR可以完成这项工作。

在此site 我计算了以下系数:

[0.000381, 0.001237, 0.002634, 0.004607, 0.007100, 0.009956, 0.012928, 
0.015711, 0.017987, 0.019480, 0.020000, 0.019480, 0.017987, 0.015711, 
0.012928, 0.009956, 0.007100, 0.004607, 0.002634, 0.001237, 0.000381]

基于这些特征: Fa = 0Hz,Fb = 1Hz,长度= 21Pts,Fs = 100Hz,Att = 60dB。

你将得到一个信号,它将是时间函数的三个重力值。

您可以找到here一些FIR解释和Java实现。