Android 从设备坐标系到绝对坐标系的加速度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11578636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Acceleration from device's coordinate system into absolute coordinate system
提问by alex
From my Android device I can read an array of linear acceleration values (in the device's coordinate system) and an array of absolute orientation values (in Earth's coordinate system). What I need is to obtain the linear acceleration values in the latter coord. system.
从我的 Android 设备中,我可以读取一组线性加速度值(在设备坐标系中)和一组绝对方向值(在地球坐标系中)。我需要的是获得后一个坐标中的线性加速度值。系统。
How can I convert them?
我该如何转换它们?
EDITafter Ali's reply in comment:
在阿里回复评论后编辑:
All right, so if I understand correctly, when I measure the linear acceleration, the position of the phone completely does not matter, because the readings are given in Earth's coordinate system. right?
好吧,所以如果我理解正确的话,当我测量线性加速度时,手机的位置完全无关紧要,因为读数是在地球坐标系中给出的。对?
But I just did a test where I put the phone in different positions and got acceleration in different axes. There are 3 pairs of pictures - the first ones show how I put the device (sorry for my Paint "master skill") and the second ones show readings from data provided by the linear acc. sensor:
但我刚刚做了一个测试,我将手机放在不同的位置,并在不同的轴上获得加速度。有 3 对图片 - 第一张显示了我如何放置设备(对不起我的油漆“大师技能”),第二张显示了线性加速度计提供的数据的读数。传感器:
- device put on left side
- 设备放在左侧
- device lying on back
- 设备仰卧
- device standing
- 设备站立
And now - why in the third case the acceleration occurs along the Z axis (not Y) since the device position doesn't matter?
现在 - 为什么在第三种情况下加速度沿 Z 轴(而不是 Y)发生,因为设备位置无关紧要?
回答by alex
I finally managed to solve it! So to get acceleration vectorin Earth's coordinate systemyou need to:
我终于设法解决了!因此,要获得地球坐标系中的加速度矢量,您需要:
- get rotation matrix (
float[16]
so it could be used later byandroid.opengl.Matrix
class) fromSensorManager.getRotationMatrix()
(usingSENSOR.TYPE_GRAVITY
andSENSOR.TYPE_MAGNETIC_FIELD
sensors values as parameters), - use
android.opengl.Matrix.invertM()
on the rotation matrix to invert it (not transpose!), - use
Sensor.TYPE_LINEAR_ACCELERATION
sensor to get linear acceleration vector (in device's coord. sys.), - use
android.opengl.Matrix.multiplyMV()
to multiply the rotation matrix by linear acceleration vector.
- 从(使用和传感器值作为参数)获取旋转矩阵(
float[16]
以便以后可以由android.opengl.Matrix
类SensorManager.getRotationMatrix()
使用),SENSOR.TYPE_GRAVITY
SENSOR.TYPE_MAGNETIC_FIELD
- 使用
android.opengl.Matrix.invertM()
的旋转矩阵反转它(不转!) - 使用
Sensor.TYPE_LINEAR_ACCELERATION
传感器获得线性加速度矢量(在设备的坐标系中), - 用于
android.opengl.Matrix.multiplyMV()
将旋转矩阵乘以线性加速度向量。
And there you have it! I hope I will save some precious time for others.
你有它!我希望我能为别人节省一些宝贵的时间。
Thanks for Edward Falk and Ali for hints!!
感谢 Edward Falk 和 Ali 的提示!!
回答by orak
Based on @alex's answer, here is the code snippet:
根据@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;
}
}
回答by Ali
According to the documentationyou get the linear acceleration in the phone's coordinate system.
根据文档,您可以获得手机坐标系中的线性加速度。
You can transform any vector from the phone's coordinate system to the Earth's coordinate system by multiplying it with the rotation matrix. You can get the rotation matrix from getRotationMatrix().
您可以将任何向量从手机坐标系转换为地球坐标系,方法是将其乘以旋转矩阵。您可以从getRotationMatrix()获取旋转矩阵。
(Perhaps there already is a function doing this multiplication for you but I don't do Android programming and I am not familiar with its API.)
(也许已经有一个函数可以为你做这个乘法,但我不做 Android 编程,也不熟悉它的 API。)
A nice tutorial on the rotation matrix is the Direction Cosine Matrix IMU: Theorymanuscript. Good luck!
关于旋转矩阵的一个很好的教程是方向余弦矩阵 IMU:理论手稿。祝你好运!
回答by Edward Falk
OK, first of all, if you're trying to do actual inertial navigation on Android, you've got your work cut out for you. The cheap little sensor used in smart phones are just not precise enough. Although, there has been some interesting work done on intertial navigation over small distances, such as inside a building. There are probably papers on the subject you can dig up. Google "Motion Interface Developers Conference" and you might find something useful -- that's a conference that Invensense put on a couple months ago.
好的,首先,如果您想在 Android 上进行实际的惯性导航,那么您的工作就已经完成了。智能手机中使用的廉价小传感器不够精确。尽管如此,在小距离内(例如在建筑物内)的星际导航方面已经做了一些有趣的工作。可能有关于您可以挖掘的主题的论文。谷歌“运动界面开发者大会”,你可能会发现一些有用的东西——这是 Invensense 几个月前举办的一次会议。
Second, no, linear acceleration is in device coordinates, not world coordinates. You'll have to convert yourself, which means knowing the device's 3-d orientation.
其次,不,线性加速度在设备坐标中,而不是世界坐标中。您必须自行转换,这意味着要了解设备的 3-d 方向。
What you want to do is use a version of Android that supports the virtual sensors TYPE_GRAVITY and TYPE_LINEAR_ACCELERATION. You'll need a device with gyros to get reasonably accurate and precise readings.
您想要做的是使用支持虚拟传感器 TYPE_GRAVITY 和 TYPE_LINEAR_ACCELERATION 的 Android 版本。您需要一个带陀螺仪的设备来获得相当准确和精确的读数。
Internally, the system combines gyros, accelerometers, and magnetometers in order to come up with true values for the device orientation. This effectively splits the accelerometer device into its gravity and acceleration components.
在内部,该系统结合了陀螺仪、加速度计和磁力计,以便得出设备方向的真实值。这有效地将加速度计设备分为重力和加速度分量。
So what you want to do is to set up sensor listeners for TYPE_GRAVITY, TYPE_LINEAR_ACCELERATION, and TYPE_MAGNETOMETER. Use the gravity and magnetometer data as inputs to SensorManager. getRotationMatrix() in order to get the rotation matrix that will transform world coordinates into device coordinates or vice versa. In this case, you'll want the "versa" part. That is, convert the linear acceleration input to world coordinates by multiplying them by the transpose of the orientation matrix.
因此,您要做的是为 TYPE_GRAVITY、TYPE_LINEAR_ACCELERATION 和 TYPE_MAGNETOMETER 设置传感器侦听器。使用重力和磁力计数据作为 SensorManager 的输入。getRotationMatrix() 以获得将世界坐标转换为设备坐标的旋转矩阵,反之亦然。在这种情况下,您将需要“相反”部分。即,通过将线性加速度输入乘以方向矩阵的转置将它们转换为世界坐标。