有两种方法可以获得3个旋转值(方位角,俯仰,滚动)。
一个是注册TYPE_ORIENTATION类型的监听器。这是最简单的方法,我从每次轮换中得到正确的值范围,如文档所述: 方位角:[0,359] 音高:[ - 180,180] roll:[ - 90,90]
另一个,第一次看到它时最精确,最复杂。 Android推荐它,所以我想使用它,但我得到不同的值。
方位角:[ - 180,180]。 -180 / 180是S,0 i N,90 E和-90 W. 音高:[ - 90,90]。 90是90,-90是-90,0是0但是-180/180(屏幕向下躺着)是0 roll:[ - 180,180]。我应该得到相同的值但是带小数,对吧?
我有以下代码:
aValues = new float[3];
mValues = new float[3];
sensorListener = new SensorEventListener (){
public void onSensorChanged (SensorEvent event){
switch (event.sensor.getType ()){
case Sensor.TYPE_ACCELEROMETER:
aValues = event.values.clone ();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
mValues = event.values.clone ();
break;
}
float[] R = new float[16];
float[] orientationValues = new float[3];
SensorManager.getRotationMatrix (R, null, aValues, mValues);
SensorManager.getOrientation (R, orientationValues);
orientationValues[0] = (float)Math.toDegrees (orientationValues[0]);
orientationValues[1] = (float)Math.toDegrees (orientationValues[1]);
orientationValues[2] = (float)Math.toDegrees (orientationValues[2]);
azimuthText.setText ("azimuth: " + orientationValues[0]);
pitchText.setText ("pitch: " + orientationValues[1]);
rollText.setText ("roll: " + orientationValues[2]);
}
public void onAccuracyChanged (Sensor sensor, int accuracy){}
};
请帮忙。这非常令人沮丧。
我是否必须对待这些价值观或者我做错了什么?
感谢。
答案 0 :(得分:21)
我知道我在这里玩线程死灵法师,但我最近一直在研究这些东西,所以我想我会投入2美分。
该设备不包含指南针或倾角仪,因此它不直接测量方位角,俯仰或滚动。 (我们称之为欧拉角,BTW)。相反,它使用加速度计和磁力计,两者都产生3空间XYZ矢量。这些用于计算方位角等值。
向量位于设备坐标空间中:
世界坐标Y朝北,X朝东,Z朝上:
因此,设备的“中性”方向平放在桌子背面,设备顶部朝北。
加速度计在“向上”方向上产生矢量。磁力计在“北”方向上产生矢量。 (请注意,在北半球,由于magnetic dip,这往往指向下方。)
加速度计矢量和磁力计矢量可以通过SensorManager.getRotationMatrix()进行数学组合,它返回一个3x3矩阵,它将设备坐标中的矢量映射到世界坐标,反之亦然。对于处于中性位置的设备,此函数将返回单位矩阵。
此矩阵不随屏幕方向而变化。这意味着您的应用程序需要了解方向并相应地进行补偿。
SensorManager.getOrientation()采用变换矩阵并计算方位角,俯仰和滚动值。这些是相对于处于中立位置的设备。
我不知道调用此函数和使用TYPE_ORIENTATION传感器之间的区别是什么,除了该函数允许您首先操作矩阵。
如果设备向上倾斜90°或接近它,则欧拉角的使用会分开。这是数学上的退化情况。在这个领域,如果你正在改变方位角或滚动,设备应该如何知道?
SensorManager.remapCoordinateSystem()函数可用于操纵变换矩阵,以补偿您可能了解的有关设备方向的信息。但是,我的实验表明,这并不包括所有情况,甚至不包括一些常见情况。例如,如果要重新映射直立设备(例如拍摄照片),您可能希望将变换矩阵乘以此矩阵:
1 0 0
0 0 1
0 1 0
在调用getOrientation()之前,这不是remapCoordinateSystem()支持的方向重映射之一[如果我在这里错过了某些内容请有人纠正我。]
好的,所以这一直是一种冗长的说法,如果你使用方向,无论是从TYPE_ORIENTATION传感器还是从getOrientation(),你可能做错了。您实际想要欧拉角的唯一时间是以用户友好的形式显示方向信息,注释照片,驾驶飞行仪表显示或类似的东西。
如果你想进行与设备方向相关的计算,你几乎肯定会更好地使用变换矩阵并使用XYZ矢量。
作为一名顾问,每当有人向我提出涉及欧拉角度的问题时,我都会备份并询问他们真正尝试做什么,然后找到一种方法来做而是用矢量代替。
回顾你原来的问题,getOrientation()应该在[-180 180] [-90 90]和[-180 180](从弧度转换后)中返回三个值。在实践中,我们将方位角视为[0 360]中的数字,因此您只需将360添加到您收到的任何负数。您的代码看起来是正确的。如果我确切地知道你期待什么结果以及你得到了什么,那将会有所帮助。
编辑补充:更多想法。 Android的现代版本使用称为“传感器融合”的东西,这基本上意味着所有可用的输入 - 加速器,磁力计,陀螺仪 - 在数学黑盒子中组合在一起(通常是卡尔曼滤波器,但取决于供应商)。所有不同的传感器 - 加速度,磁场,陀螺仪,重力,线性加速度和方向 - 都被视为黑匣子的输出。
只要有可能,您应该使用TYPE_GRAVITY而不是TYPE_ACCELEROMETER作为getRotationMatrix()的输入。
答案 1 :(得分:7)
我可能会在黑暗中拍摄,但如果我理解你的问题,你会想知道为什么得到[-179..179]
而不是[0..360]
?
请注意,-180
与+180
相同,与180 + N*360
相同,其中N
是整数(整数)。
换句话说,如果您想获得与方向传感器相同的数字,您可以这样做:
// x = orientationValues[0];
// y = orientationValues[1];
// z = orientationValues[2];
x = (x + 360.0) % 360.0;
y = (y + 360.0) % 360.0;
z = (z + 360.0) % 360.0;
这将为您提供[0..360]
范围内的值。
答案 2 :(得分:1)
您在计算中缺少一个关键计算 remapCoordinateSystem调用你做 getRotationMatrix 。
将其添加到您的代码中,一切都会好的 您可以阅读更多相关信息 here 。