我尝试使用 SensorEvent.values 中的 Z 轴数据,但它没有检测到我的手机在 XY 平面上的旋转,即。围绕 Z 轴。
我将其用作坐标轴的参考。这是对的吗?
如何使用加速度计值测量该运动?
这些游戏做类似的事情:极限滑板,涂鸦跳跃。
PS:我的手机方向是横向的。
我尝试使用 SensorEvent.values 中的 Z 轴数据,但它没有检测到我的手机在 XY 平面上的旋转,即。围绕 Z 轴。
我将其用作坐标轴的参考。这是对的吗?
如何使用加速度计值测量该运动?
这些游戏做类似的事情:极限滑板,涂鸦跳跃。
PS:我的手机方向是横向的。
本质上,这里有两种情况:设备平放而不是平放。这里的平面是指设备屏幕表面与世界 xy 平面之间的角度(我称之为倾角)小于 25 度或大于 155 度。想象一下手机平放或从桌子上稍微倾斜一点。
首先,您需要标准化加速度计矢量。
也就是说,如果g是加速度计传感器事件值返回的向量。在代码中
float[] g = new float[3];
g = event.values.clone();
double norm_Of_g = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
// Normalize the accelerometer vector
g[0] = g[0] / norm_Of_g
g[1] = g[1] / norm_Of_g
g[2] = g[2] / norm_Of_g
那么倾角可以计算为
int inclination = (int) Math.round(Math.toDegrees(Math.acos(g[2])));
因此
if (inclination < 25 || inclination > 155)
{
// device is flat
}
else
{
// device is not flat
}
对于平放的情况,您必须使用指南针查看设备从起始位置旋转了多少。
对于不平坦的情况,旋转(倾斜)计算如下
int rotation = (int) Math.round(Math.toDegrees(Math.atan2(g[0], g[1])));
现在旋转 = 0 表示设备处于正常位置。对于大多数手机来说,这是没有任何倾斜的纵向,对于平板电脑来说可能是横向。因此,如果您像上图那样握住手机并开始旋转,旋转会改变,当手机处于横向时,旋转将是 90 或 -90,具体取决于旋转方向。
加速度计足以检查手机是否平坦,正如 Hoan 很好地展示的那样。
对于到达这里的人来说,不仅要检查手机是否平整,还要检查手机的旋转情况,可以通过旋转矢量运动传感器来实现。
private double pitch, tilt, azimuth;
@Override
public void onSensorChanged(SensorEvent event) {
//Get Rotation Vector Sensor Values
double[] g = convertFloatsToDoubles(event.values.clone());
//Normalise
double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]);
g[0] /= norm;
g[1] /= norm;
g[2] /= norm;
g[3] /= norm;
//Set values to commonly known quaternion letter representatives
double x = g[0];
double y = g[1];
double z = g[2];
double w = g[3];
//Calculate Pitch in degrees (-180 to 180)
double sinP = 2.0 * (w * x + y * z);
double cosP = 1.0 - 2.0 * (x * x + y * y);
pitch = Math.atan2(sinP, cosP) * (180 / Math.PI);
//Calculate Tilt in degrees (-90 to 90)
double sinT = 2.0 * (w * y - z * x);
if (Math.abs(sinT) >= 1)
tilt = Math.copySign(Math.PI / 2, sinT) * (180 / Math.PI);
else
tilt = Math.asin(sinT) * (180 / Math.PI);
//Calculate Azimuth in degrees (0 to 360; 0 = North, 90 = East, 180 = South, 270 = West)
double sinA = 2.0 * (w * z + x * y);
double cosA = 1.0 - 2.0 * (y * y + z * z);
azimuth = Math.atan2(sinA, cosA) * (180 / Math.PI);
}
private double[] convertFloatsToDoubles(float[] input)
{
if (input == null)
return null;
double[] output = new double[input.length];
for (int i = 0; i < input.length; i++)
output[i] = input[i];
return output;
}
然后要检查手机是否平坦,您只需将tilt
和pitch
值与容差值进行比较。例如
public boolean flatEnough(double degreeTolerance) {
return tilt <= degreeTolerance && tilt >= -degreeTolerance && pitch <= degreeTolerance && pitch >= -degreeTolerance;
}
这样做的好处是您可以检查手机是否处于任何特定的旋转状态。
值得注意的是,应用程序的方向不会影响俯仰、倾斜和方位角的值。
@Dan 的完美回应
他错过了@davy307 指出的一点点信息。
初始化 mAccelerometer 时,必须将其定义为Sensor.TYPE_ROTATION_VECTOR否则,它将没有第 3 个旋转向量并抛出 ArrayIndexOutOfBounds 异常。
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
否则,这是一个完美的解决方案......赞赏!