Android:计算设备方向的问题
Posted
技术标签:
【中文标题】Android:计算设备方向的问题【英文标题】:Android: Problems calculating the Orientation of the Device 【发布时间】:2013-01-22 08:15:29 【问题描述】:我正在尝试构建一个简单的增强现实应用程序,因此我开始使用传感器数据。
根据此线程 (android compass example) 和示例 (http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html),使用 Sensor.TYPE_ACCELEROMETER 和 Sensor.TYPE_MAGNETIC_FIELD 计算方向不会'真的不合适。
所以我无法获得“好的”价值。方位角值根本没有任何意义,所以如果我只是将手机向上移动,值就会发生极大的变化。即使我只是旋转手机,这些值也不代表手机的方向。
有没有人有想法,根据给定的例子,谁来提高价值质量?
【问题讨论】:
【参考方案1】:您以何种方式使用此示例应用程序?从所写的是这段代码,唯一支持的方向是纵向或平放在桌子上,这取决于设备。 “好”是什么意思?
旋转设备时值不是“好”是正常的,设备坐标系应该是纵向工作,或者我不知道是平坦的(Y轴垂直于屏幕向上,Z轴从屏幕中心指向屏幕外,X 轴垂直于 Y 轴,沿屏幕向右)。有了这个,旋转设备不会旋转设备坐标系,你必须重新映射它。
但是,如果您希望设备的标题是纵向的,这里有一段对我有用的代码:
@Override
public void onSensorChanged(SensorEvent event)
// It is good practice to check that we received the proper sensor event
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
// Convert the rotation-vector to a 4x4 matrix.
SensorManager.getRotationMatrixFromVector(mRotationMatrix,
event.values);
SensorManager
.remapCoordinateSystem(mRotationMatrix,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
mRotationMatrix);
SensorManager.getOrientation(mRotationMatrix, orientationVals);
// Optionally convert the result from radians to degrees
orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);
tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
+ orientationVals[1] + "\n Roll (not used): "
+ orientationVals[2]);
您将在以下位置获得航向(或方位角):
orientationVals[0]
【讨论】:
作为记录,我用 3x3 矩阵尝试了这段代码,但它只适用于 4x4(又名 float[16])【参考方案2】:Tíbó 的回答很好,但如果您记录滚动值,您会看到不规则的数字。 (滚动对 AR 浏览器很重要)
这是由于
SensorManager.remapCoordinateSystem(mRotationMatrix,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
mRotationMatrix);
您必须使用不同的矩阵进出重映射。以下代码适用于我的正确滚动值:
@Override
public void onSensorChanged(SensorEvent event)
// It is good practice to check that we received the proper sensor event
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
// Convert the rotation-vector to a 4x4 matrix.
SensorManager.getRotationMatrixFromVector(mRotationMatrixFromVector, event.values);
SensorManager.remapCoordinateSystem(mRotationMatrixFromVector,
SensorManager.AXIS_X, SensorManager.AXIS_Z,
mRotationMatrix);
SensorManager.getOrientation(mRotationMatrix, orientationVals);
// Optionally convert the result from radians to degrees
orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);
tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
+ orientationVals[1] + "\n Roll (not used): "
+ orientationVals[2]);
【讨论】:
是的,您可以查看源代码: public static boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) * @param outR * 转换后的旋转矩阵。 inR 和 outR 不应该是同一个 * 数组。【参考方案3】:聚会可能迟到了。无论如何,这就是我如何获得方位角
private final int sensorType = Sensor.TYPE_ROTATION_VECTOR;
float[] rotMat = new float[9];
float[] vals = new float[3];
@Override
public void onSensorChanged(SensorEvent event)
sensorHasChanged = false;
if (event.sensor.getType() == sensorType)
SensorManager.getRotationMatrixFromVector(rotMat,
event.values);
SensorManager
.remapCoordinateSystem(rotMat,
SensorManager.AXIS_X, SensorManager.AXIS_Y,
rotMat);
SensorManager.getOrientation(rotMat, vals);
azimuth = deg(vals[0]); // in degrees [-180, +180]
pitch = deg(vals[1]);
roll = deg(vals[2]);
sensorHasChanged = true;
希望对你有帮助
【讨论】:
remapCoordinateSystem
调用只是身份转换,所以它是多余的。更糟糕的是,它使用rotMat
进行输入和输出,文档明确指出您不应该这样做。【参考方案4】:
您是否尝试过组合(传感器融合)类型 Sensor.TYPE_ROTATION_VECTOR。这可能会产生更好的结果: 转到https://developer.android.com/reference/android/hardware/SensorEvent.html 并搜索“rotation_vector”。
【讨论】:
好的,有什么例子可以使用这个传感器吗?我得到 xsin(θ/2)、ysin(θ/2) 和 z*sin(θ/2) 的值。但是我如何获得价值,我需要建立我的指南针。我应该再次使用 getRotationMatrix 吗?感谢您的帮助。 "X定义为向量积YZ(在设备当前位置与地面相切,大致指向东)。Y在设备当前位置与地面相切,指向磁北。Z指向天空,垂直于地面。掸掉你的几何课书上的灰尘,或者用谷歌搜索一下:),你应该能弄明白的。【参考方案5】:这是一个包含所有必要矩阵的 Kotlin 方法(由于某种原因,前面的答案忽略了数组大小,这很重要)
// This is determined from the deprecated Sensor.TYPE_ORIENTATION
var lastOrientation: FloatArray = FloatArray(3)
var lastHeading: Float = 0f
var currentHeading: Float = 0f
// This is from the non deprecated Sensor.TYPE_ROTATION_VECTOR
var lastVectorOrientation: FloatArray = FloatArray(5)
var lastVectorHeading: Float = 0f
var currentVectorHeading: Float = 0f
override fun onSensorChanged(event: SensorEvent)
when(event.sensor?.type)
null -> return
Sensor.TYPE_ORIENTATION ->
lastOrientation = event.values
lastHeading = currentHeading
currentHeading = abs(event.values[0].roundToInt().toFloat())
Sensor.TYPE_ROTATION_VECTOR ->
lastVectorOrientation = event.values
lastVectorHeading = currentVectorHeading
val tempRotationMatrix = FloatArray(9)
val tempOrientationMatrix = FloatArray(3)
getRotationMatrixFromVector(tempRotationMatrix, event.values)
remapCoordinateSystem(tempRotationMatrix, AXIS_X, AXIS_Z, tempRotationMatrix)
getOrientation(tempRotationMatrix, tempOrientationMatrix)
currentVectorHeading = Math.toDegrees(tempOrientationMatrix[0].toDouble()).toFloat()
if(currentVectorHeading < 0)
currentVectorHeading += 360f//heading = 360 - abs(neg heading), which is really 360 + (-heading)
else -> return
我还包含了已弃用的 Sensor.TYPE_ORIENTATION 供任何想了解这两种方法之间差异的人使用。使用不推荐使用的方法与使用更新的方法时存在几个程度的差异。
【讨论】:
以上是关于Android:计算设备方向的问题的主要内容,如果未能解决你的问题,请参考以下文章