如何使用 Android 中的加速度计测量手机在 XY 平面上的倾斜度

Posted

技术标签:

【中文标题】如何使用 Android 中的加速度计测量手机在 XY 平面上的倾斜度【英文标题】:How to measure the tilt of the phone in XY plane using accelerometer in Android 【发布时间】:2012-06-25 21:32:43 【问题描述】:

我尝试使用 SensorEvent.values 中的 Z 轴数据,但它没有检测到我的手机在 XY 平面上的旋转,即。围绕 Z 轴。

我使用它作为坐标轴的参考。对吗?

如何使用加速度计值测量该运动?

这些游戏做类似的事情:Extreme Skater, Doodle Jump。

PS:我的手机方向是横向的。

【问题讨论】:

【参考方案1】:

这里基本上有两种情况:设备平放和不平放。这里的平面是指设备屏幕表面与世界 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,具体取决于旋转方向。

【讨论】:

太棒了!通常人们建议为此任务也使用 Sensor.TYPE_MAGNETIC_FIELD,但是您简化了解决方案;顺便说一下,加速度计是唯一保证会出现在 android 上的传感器。 我能问你“acc 向量的归一化”背后的数学原理是什么吗?以及为什么要使用 atan(g[1]/g[0]) (或 atan(y/x) )来获得学位? ? @Hoan Nguyen @AndreaBaccega 据我了解,标准化需要降低 -1 到 1 范围内的值,这是Math.acos() 的可接受范围,对于超出此范围的数字,它会返回南。如果有人感兴趣,有一些链接:in.mathworks.com/help/matlab/ref/…mathopenref.com/arccos.html 谁能告诉,当“设备是平的位置”时如何找到角度?我要使用“TYPE_MAGNETIC_FIELD”吗? “TYPE_MAGNETIC_FIELD”在 Lollipop(moto e)中不起作用。我该怎么做? @savram 是的,z 加速度计组件的符号将告诉手机的朝向。正面表示正面朝上,负面表示正面朝下。【参考方案2】:

加速度计足以检查手机是否平坦,正如 Hoan 很好地演示的那样。

对于任何到达这里的人来说,不仅要检查手机是否平整,还要检查手机的旋转情况,可以通过Rotation Vector Motion Sensor 来实现。

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;

然后要检查手机是否平整,您只需将tiltpitch 值与容差值进行比较。例如

public boolean flatEnough(double degreeTolerance) 
    return tilt <= degreeTolerance && tilt >= -degreeTolerance && pitch <= degreeTolerance && pitch >= -degreeTolerance;

这样做的好处是您可以检查手机是否处于任何特定的旋转状态。

值得注意的是,应用程序的方向不会影响俯仰、倾斜和方位角的值。

【讨论】:

为什么倾斜在-90到90之间?如果我需要查找 / 倾斜 vs \ 倾斜怎么办? 当我尝试编译它时,它在 g[3] 上出现 ArrayIndexOutOfBounds 失败,因为长度为 3...我想出的解决方案是产生一个从 90(垂直向上)到 - 90(垂直向下),0 表示手机处于水平位置,正在替换 sinT 方程为 sinT = (g[1] - g[2] * g[0]).toDouble() 【参考方案3】:

利用@Dan 的完美回应

他错过了@davy307 指出的一点点信息。

在初始化mAccelerometer时,必须将其定义为Sensor.TYPE_ROTATION_VECTOR,否则将没有第3个旋转向量并抛出ArrayIndexOutOfBounds异常。

mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

否则,这是一个完美的解决方案...感谢!

【讨论】:

以上是关于如何使用 Android 中的加速度计测量手机在 XY 平面上的倾斜度的主要内容,如果未能解决你的问题,请参考以下文章

android 加速度传感器妙用与自定义View

手机加速度计精度

Android加速度计校准?

Android_(传感器)获取手机中的传感器

测量随机算法中的并行加速

如何在android中测量NFC RSSI?