- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我正在尝试在我的 Android 手机 (Nexus 4) 上制作一个应用程序,该应用程序将用于模型船。我添加了低通滤波器来过滤掉传感器中的 gitter。
但是,指南针只有在手机平放时才能稳定。如果我将它向上倾斜(例如翻一页书),那么指南针的航向就会偏离 - 多达 50*。
我已经用 Sensor.TYPE_MAGNETIC_FIELD 和 Sensor.TYPE_GRAVITY 和 Sensor.TYPE_ACCELEROMETER 尝试过这个,效果是一样的。
我使用了提到的解决方案 here ,以及许多其他地方。我的数学不是很好,但这一定是一个常见问题,我发现没有 API 可以处理它,这让我很沮丧。
我已经解决这个问题 3 天了,仍然没有找到任何解决方案,但是当我使用 Compass from Catch 时,无论手机倾斜多少,它们都保持稳定。所以我知道这一定是可能的。
我要做的就是创建一个指南针,如果手机指向北方,那么指南针将读取北方,并且当手机通过任何其他轴(滚动或俯仰)移动时不会跳来跳去。
在我不得不放弃我的项目之前,谁能帮忙。
谢谢,亚当
最佳答案
巧合的是,我已经考虑这个问题好几个星期了,因为
我已经把我正在使用的数学 here on math.stackexchange.com ,并且我已经粘贴了我在下面使用的代码。该代码根据原始 TYPE_GRAVITY
和 TYPE_MAGNETIC_FIELD
传感器数据计算方位角和俯仰角,无需任何 API 调用,例如SensorManager.getRotationMatrix(...)
或 SensorManager.getOrientation(...)
。代码可能会得到改进,例如如果输入有点不稳定,则使用低通滤波器。请注意,代码通过 onAccuracyChanged(Sensor sensor, int accuracy)
方法记录传感器的精度,因此如果方位角看起来不稳定,另一件要检查的是每个传感器的精度。在任何情况下,所有计算都在此代码中明确可见,如果存在不稳定性问题(当传感器精度合理时),则可以通过查看输入或方向向量中的不稳定性来解决这些问题 m_NormGravityVector[ ]
、m_NormEastVector[]
或 m_NormNorthVector[]
。
我会对任何人对这种方法的任何反馈都非常感兴趣。我发现它在我自己的应用程序中就像做梦一样,只要设备是平面朝上、垂直或介于两者之间的。但是,正如我在 math.stackexchange.com 文章中提到的那样,当设备接近倒置时会出现一些问题。在这种情况下,需要仔细定义自己想要的行为。
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.Surface;
public static class OrientationSensor implements SensorEventListener {
public final static int SENSOR_UNAVAILABLE = -1;
// references to other objects
SensorManager m_sm;
SensorEventListener m_parent; // non-null if this class should call its parent after onSensorChanged(...) and onAccuracyChanged(...) notifications
Activity m_activity; // current activity for call to getWindowManager().getDefaultDisplay().getRotation()
// raw inputs from Android sensors
float m_Norm_Gravity; // length of raw gravity vector received in onSensorChanged(...). NB: should be about 10
float[] m_NormGravityVector; // Normalised gravity vector, (i.e. length of this vector is 1), which points straight up into space
float m_Norm_MagField; // length of raw magnetic field vector received in onSensorChanged(...).
float[] m_NormMagFieldValues; // Normalised magnetic field vector, (i.e. length of this vector is 1)
// accuracy specifications. SENSOR_UNAVAILABLE if unknown, otherwise SensorManager.SENSOR_STATUS_UNRELIABLE, SENSOR_STATUS_ACCURACY_LOW, SENSOR_STATUS_ACCURACY_MEDIUM or SENSOR_STATUS_ACCURACY_HIGH
int m_GravityAccuracy; // accuracy of gravity sensor
int m_MagneticFieldAccuracy; // accuracy of magnetic field sensor
// values calculated once gravity and magnetic field vectors are available
float[] m_NormEastVector; // normalised cross product of raw gravity vector with magnetic field values, points east
float[] m_NormNorthVector; // Normalised vector pointing to magnetic north
boolean m_OrientationOK; // set true if m_azimuth_radians and m_pitch_radians have successfully been calculated following a call to onSensorChanged(...)
float m_azimuth_radians; // angle of the device from magnetic north
float m_pitch_radians; // tilt angle of the device from the horizontal. m_pitch_radians = 0 if the device if flat, m_pitch_radians = Math.PI/2 means the device is upright.
float m_pitch_axis_radians; // angle which defines the axis for the rotation m_pitch_radians
public OrientationSensor(SensorManager sm, SensorEventListener parent) {
m_sm = sm;
m_parent = parent;
m_activity = null;
m_NormGravityVector = m_NormMagFieldValues = null;
m_NormEastVector = new float[3];
m_NormNorthVector = new float[3];
m_OrientationOK = false;
}
public int Register(Activity activity, int sensorSpeed) {
m_activity = activity; // current activity required for call to getWindowManager().getDefaultDisplay().getRotation()
m_NormGravityVector = new float[3];
m_NormMagFieldValues = new float[3];
m_OrientationOK = false;
int count = 0;
Sensor SensorGravity = m_sm.getDefaultSensor(Sensor.TYPE_GRAVITY);
if (SensorGravity != null) {
m_sm.registerListener(this, SensorGravity, sensorSpeed);
m_GravityAccuracy = SensorManager.SENSOR_STATUS_ACCURACY_HIGH;
count++;
} else {
m_GravityAccuracy = SENSOR_UNAVAILABLE;
}
Sensor SensorMagField = m_sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (SensorMagField != null) {
m_sm.registerListener(this, SensorMagField, sensorSpeed);
m_MagneticFieldAccuracy = SensorManager.SENSOR_STATUS_ACCURACY_HIGH;
count++;
} else {
m_MagneticFieldAccuracy = SENSOR_UNAVAILABLE;
}
return count;
}
public void Unregister() {
m_activity = null;
m_NormGravityVector = m_NormMagFieldValues = null;
m_OrientationOK = false;
m_sm.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent evnt) {
int SensorType = evnt.sensor.getType();
switch(SensorType) {
case Sensor.TYPE_GRAVITY:
if (m_NormGravityVector == null) m_NormGravityVector = new float[3];
System.arraycopy(evnt.values, 0, m_NormGravityVector, 0, m_NormGravityVector.length);
m_Norm_Gravity = (float)Math.sqrt(m_NormGravityVector[0]*m_NormGravityVector[0] + m_NormGravityVector[1]*m_NormGravityVector[1] + m_NormGravityVector[2]*m_NormGravityVector[2]);
for(int i=0; i < m_NormGravityVector.length; i++) m_NormGravityVector[i] /= m_Norm_Gravity;
break;
case Sensor.TYPE_MAGNETIC_FIELD:
if (m_NormMagFieldValues == null) m_NormMagFieldValues = new float[3];
System.arraycopy(evnt.values, 0, m_NormMagFieldValues, 0, m_NormMagFieldValues.length);
m_Norm_MagField = (float)Math.sqrt(m_NormMagFieldValues[0]*m_NormMagFieldValues[0] + m_NormMagFieldValues[1]*m_NormMagFieldValues[1] + m_NormMagFieldValues[2]*m_NormMagFieldValues[2]);
for(int i=0; i < m_NormMagFieldValues.length; i++) m_NormMagFieldValues[i] /= m_Norm_MagField;
break;
}
if (m_NormGravityVector != null && m_NormMagFieldValues != null) {
// first calculate the horizontal vector that points due east
float East_x = m_NormMagFieldValues[1]*m_NormGravityVector[2] - m_NormMagFieldValues[2]*m_NormGravityVector[1];
float East_y = m_NormMagFieldValues[2]*m_NormGravityVector[0] - m_NormMagFieldValues[0]*m_NormGravityVector[2];
float East_z = m_NormMagFieldValues[0]*m_NormGravityVector[1] - m_NormMagFieldValues[1]*m_NormGravityVector[0];
float norm_East = (float)Math.sqrt(East_x * East_x + East_y * East_y + East_z * East_z);
if (m_Norm_Gravity * m_Norm_MagField * norm_East < 0.1f) { // Typical values are > 100.
m_OrientationOK = false; // device is close to free fall (or in space?), or close to magnetic north pole.
} else {
m_NormEastVector[0] = East_x / norm_East; m_NormEastVector[1] = East_y / norm_East; m_NormEastVector[2] = East_z / norm_East;
// next calculate the horizontal vector that points due north
float M_dot_G = (m_NormGravityVector[0] *m_NormMagFieldValues[0] + m_NormGravityVector[1]*m_NormMagFieldValues[1] + m_NormGravityVector[2]*m_NormMagFieldValues[2]);
float North_x = m_NormMagFieldValues[0] - m_NormGravityVector[0] * M_dot_G;
float North_y = m_NormMagFieldValues[1] - m_NormGravityVector[1] * M_dot_G;
float North_z = m_NormMagFieldValues[2] - m_NormGravityVector[2] * M_dot_G;
float norm_North = (float)Math.sqrt(North_x * North_x + North_y * North_y + North_z * North_z);
m_NormNorthVector[0] = North_x / norm_North; m_NormNorthVector[1] = North_y / norm_North; m_NormNorthVector[2] = North_z / norm_North;
// take account of screen rotation away from its natural rotation
int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
float screen_adjustment = 0;
switch(rotation) {
case Surface.ROTATION_0: screen_adjustment = 0; break;
case Surface.ROTATION_90: screen_adjustment = (float)Math.PI/2; break;
case Surface.ROTATION_180: screen_adjustment = (float)Math.PI; break;
case Surface.ROTATION_270: screen_adjustment = 3*(float)Math.PI/2; break;
}
// NB: the rotation matrix has now effectively been calculated. It consists of the three vectors m_NormEastVector[], m_NormNorthVector[] and m_NormGravityVector[]
// calculate all the required angles from the rotation matrix
// NB: see https://math.stackexchange.com/questions/381649/whats-the-best-3d-angular-co-ordinate-system-for-working-with-smartfone-apps
float sin = m_NormEastVector[1] - m_NormNorthVector[0], cos = m_NormEastVector[0] + m_NormNorthVector[1];
m_azimuth_radians = (float) (sin != 0 && cos != 0 ? Math.atan2(sin, cos) : 0);
m_pitch_radians = (float) Math.acos(m_NormGravityVector[2]);
sin = -m_NormEastVector[1] - m_NormNorthVector[0]; cos = m_NormEastVector[0] - m_NormNorthVector[1];
float aximuth_plus_two_pitch_axis_radians = (float)(sin != 0 && cos != 0 ? Math.atan2(sin, cos) : 0);
m_pitch_axis_radians = (float)(aximuth_plus_two_pitch_axis_radians - m_azimuth_radians) / 2;
m_azimuth_radians += screen_adjustment;
m_pitch_axis_radians += screen_adjustment;
m_OrientationOK = true;
}
}
if (m_parent != null) m_parent.onSensorChanged(evnt);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
int SensorType = sensor.getType();
switch(SensorType) {
case Sensor.TYPE_GRAVITY: m_GravityAccuracy = accuracy; break;
case Sensor.TYPE_MAGNETIC_FIELD: m_MagneticFieldAccuracy = accuracy; break;
}
if (m_parent != null) m_parent.onAccuracyChanged(sensor, accuracy);
}
}
关于可以补偿倾斜和俯仰的 Android 指南针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16317599/
我是初学者,我正在做一些练习来熟悉 CALayer ... 我只是想知道如何“倾斜”(或倾斜)CALayer 45° 角? 谢谢。 最佳答案 CALayers 有一个属性 affineTransfor
无法理解如何制作this trick或 this与CSS。我的意思是标题和标志。这条线不直。它们是倾斜的/倾斜的边界。能否请您举个例子或只是举例说明这是可行的? 最佳答案 看看https://jsfi
如何倾斜图像?例如,每个角都有一个 CGPoint,其坐标为 - p1、p2、p3、p4。然后,我需要设置 - p4.x+=50,p4.y+=30。因此这个角 (p4) 应该在 2D 透视中拉伸(st
我想弄清楚如何通过仅使用 css 来实现元素底部的跟随边框,并使其尽可能对跨浏览器友好 示例代码,带有标准边框 .object { width: 200px; height: 45p
我正在尝试使用 CSS transform 来倾斜 Bootstrap 导航 li,我可以做到这一点,但是当我尝试扭转内部链接上的倾斜时,li 倾斜也会反转回来。我不知道为什么。我试着做这里接受的答案
这个问题在这里已经有了答案: CSS: Set a background color which is 50% of the width of the window (14 个答案) 关闭 7 年前
我已经创建了一个预定的 div 来与我的导航栏一起使用,但是它弄乱了网站的其余格式。导航栏位于右上角,倾斜的 div 位于其下方,但它弄乱了网页上的所有其他内容。我一直在尝试一切都无济于事。 http
你好,我想像这里的附图一样对步骤菜单进行风格化。我该如何风格化这个?主要问题是菜单右侧的边框。 检查我的 JSFiddle URL https://jsfiddle.net/hcx1pv8x/ , 不
我正在尝试使用 HTML5 在 javascript 中倾斜 svg 元素,例如: 中的矩形元素是倾斜的,但 rect 元素也向右移动(不需要),我尝试手动设置位置使用 transform
目前我对应该倾斜的容器使用clip-path。 .box { height: 150px; line-height: 150px; text-align: center; backgr
我有一个相机从上方指向禅宗花园。然而,相机固定在侧面而不是直接在板的上方。结果,图像看起来像这样(注意矩形的倾斜形状): 有没有办法处理图像,使沙子区域看起来或多或少像一个完美的正方形? cap =
我正在尝试使用倾斜 350 度的 UIScrollview,我首先想到的是使用变换属性,滚动上的倾斜起作用了,但现在滚动上的所有内容看起来都不对,当我谈论所有内容时,我指的是位置和这个卷轴的所有 ch
我需要将我的应用程序升级到 Rails 3.2.16,当时我做了 bundle update rails它给了我以下错误。 Bundler could not find compatible vers
我正在尝试运行 rake db:migrate在本地,但我收到以下错误: Gem::LoadError: You have already activated rake 10.2.2, but you
很难用语言表达我想要完成的事情,所以请查看这张照片作为示例: 如您所见,我希望创建一个带有图案背景的倾斜 div(简单),但另一部分,即倾斜被半遮住的部分,也必须有背景图像。我想到了很多不同的想法,并
假设,我想将两个二维数组添加到第三个二维数组中。 我正在使用以下代码: cudaMallocPitch((void**)&device_a, &pitch, 2*sizeof(int),2); cud
很难用语言表达我想要完成的事情,所以请查看这张照片作为示例: 如您所见,我希望创建一个带有图案背景的倾斜 div(简单),但另一部分,即倾斜被半遮住的部分,也必须有背景图像。我想到了很多不同的想法,并
我刚刚遇到了这种附加字符串的变体,其中包含存储在变量中的值,这是我以前从未见过的。谁能帮我解释一下这是怎么回事? 这是我遇到的情况: var fruit = "banana"; $main = $('
假设,我想将两个二维数组添加到第三个二维数组中。 我正在使用以下代码: cudaMallocPitch((void**)&device_a, &pitch, 2*sizeof(int),2); cud
我正在尝试分析在 Windows 上运行的 Java UI 应用程序的 CPU 使用率。我将它连接到 VisualVM,但看起来 CPU 使用率最高的是 sum.rmi.transport.tcp.T
我是一名优秀的程序员,十分优秀!