从设备的坐标系加速到绝对坐标系

时间:2012-07-20 11:41:20

标签: android vector accelerometer coordinate-systems coordinate-transformation

在我的Android设备上,我可以读取一系列线性加速度值(在设备的坐标系中)和一组绝对方向值(在地球坐标系中)。我需要的是获得后一个坐标系中的线性加速度值。系统

我如何转换它们?

在Ali回复评论后

编辑

好吧,如果我理解正确,当我测量线性加速度时,手机的位置完全无关紧要,因为读数是在地球坐标系中给出的。正确?

但是我只是做了一个测试,我把手机放在不同的位置,并在不同的轴上加速。有3对图片 - 第一部分显示我如何放置设备(对不起我的Paint“掌握技能”),第二部分显示线性acc提供的数据读数。传感器:

  1. 设备放在左侧
  2. first position first readings

    1. 背面的设备
    2. second position second readings

      1. 设备站立
      2. enter image description here enter image description here

        现在 - 为什么在第三种情况下加速沿Z轴(而不是Y)发生,因为器件位置无关紧要?

4 个答案:

答案 0 :(得分:42)

我终于设法解决了!因此,要在地球坐标系中获得加速度矢量,您需要:

  1. float[16]获取旋转矩阵(android.opengl.Matrix以便SensorManager.getRotationMatrix()类可以稍后使用)(使用SENSOR.TYPE_GRAVITYSENSOR.TYPE_MAGNETIC_FIELD传感器值作为参数) ,
  2. 在旋转矩阵上使用android.opengl.Matrix.invertM()来反转它(不是转置!),
  3. 使用Sensor.TYPE_LINEAR_ACCELERATION传感器获取线性加速度矢量(在设备的坐标系中。)
  4. 使用android.opengl.Matrix.multiplyMV()将旋转矩阵乘以线性加速度矢量。
  5. 你有它!我希望我能为别人节省一些宝贵的时间。

    感谢Edward Falk和Ali提示!!

答案 1 :(得分:15)

根据@ alex的回答,这是代码片段:

private float[] gravityValues = null;
private float[] magneticValues = null;

 @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;

            // 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("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;
        } 
   }

答案 2 :(得分:4)

According to the documentation你可以在手机的坐标系中获得线性加速度。

您可以将任意矢量从手机坐标系转换为地球坐标系,方法是将其与旋转矩阵相乘。您可以从getRotationMatrix()获取旋转矩阵。

(也许已经有一个函数为你做这个乘法,但我不做Android编程,我不熟悉它的API。)

关于旋转矩阵的一个很好的教程是Direction Cosine Matrix IMU: Theory手稿。祝你好运!

答案 3 :(得分:1)

好的,首先,如果您尝试在Android上进行实际的惯性导航,那么您的工作就已经完成了。智能手机中使用的廉价小传感器不够精确。尽管如此,有一些有趣的工作已经完成了对小距离的内部导航,例如在建筑物内部。你可以挖掘这个主题的论文。谷歌“运动界面开发者大会”,您可能会发现一些有用的东西 - 这是几个月前Invensense举办的会议。

第二,不,线性加速度在设备坐标中,而不是世界坐标。你必须转换自己,这意味着要知道设备的三维方向。

您要做的是使用支持虚拟传感器TYPE_GRAVITY和TYPE_LINEAR_ACCELERATION的Android版本。你需要一个带陀螺仪的设备来获得合理准确和精确的读数。

在内部,系统结合了陀螺仪,加速度计和磁力计,以便为设备方向提供真正的值。这有效地将加速度计装置分成重力和加速度分量。

所以你要做的是为TYPE_GRAVITY,TYPE_LINEAR_ACCELERATION和TYPE_MAGNETOMETER设置传感器监听器。使用重力和磁力计数据作为SensorManager的输入。 getRotationMatrix()以获得将世界坐标转换为设备坐标的旋转矩阵,反之亦然。在这种情况下,您将需要“反之”部分。也就是说,将线性加速度输入转换为世界坐标,方法是将它们乘以方向矩阵的转置。