繁体   English   中英

如何检测安装有加速度计的Android设备的左右倾斜?

[英]How to detect left and right tilt of an android device mounted with an accelerometer?

假设您在所有3个维度(即X,Y和Z)中都有加速度读数。您如何使用读数来推断手机是向左还是向右倾斜? 读数每20ms生成一次。

我实际上想要从读数推断出倾斜的逻辑。 倾斜需要平稳。

可以通过某种不同的方式检测倾斜。 您可以考虑1轴,2轴或3轴。 取决于你想要它的准确程度,以及你对数学的斗争感觉。

如果只使用一个轴,则非常简单。 认为移动设备是完全水平的,你可以像这样移动它:

在此输入图像描述

使用一个轴,比如x轴,就足够了,因为你可以准确地检测到该轴位置的变化,因为即使任何小的运动都会对轴进行改变。 但是,如果您的应用程序仅读取该轴,并且用户使手机几乎垂直,那么即使将手机旋转大角度,x轴的差异也会非常小。 无论如何,对于仅需要粗分辨率的应用,可以使用单轴。

参考基本三角学, 重力矢量在x轴上的投影产生的输出加速度等于加速度计x轴和地平线之间的角度的正弦 这意味着具有轴的值(这些是加速度值),您可以计算设备的角度。

在此输入图像描述

这意味着传感器给你的值是=到角度的9,8 *正弦,所以做数学就可以得到实际的角度。

但不要担心,你甚至不必这样做。 由于这些值或多或少是成比例的,如下表所示,您可以直接使用传感器的值,而不必过多关注角度代表什么,如果您不需要它准确得多,因为该值的变化意味着角度的比例变化,所以通过一些测试,您将发现变化应该有多大才能与您相关。

在此输入图像描述

因此,如果你在一段时间内取值,并相互比较,你就可以计算出旋转的大小。 为了这,

  1. 你只考虑一个轴。 这将是X轴。
  2. 编写一个函数来获得一个函数调用和下一个函数调用之间该轴的传感器值的差异
  3. 确定最大时间和最小传感器差异,您将考虑有效运动(例如,大旋转是好的,但只有当它足够快时,只有当角度的差异足够大时,快速运动才是好的)
  4. 如果您检测到两个完成这些条件的测量,您会注意到半倾斜(例如,在布尔值中),并再次开始测量,但现在,新参考值是被认为是半倾斜的值。
  5. 如果最后一个差异为正,那么现在你需要一个负差异,如果最后一个差异是负数,那么现在你需要一个正差异; 这就是回来。 因此,开始将新参考值与来自传感器的新值进行比较,并查看是否完成了您在第3点中的决定。
  6. 如果找到有效值(完成值差和时间条件),则表示您有倾斜。 但是如果你没有得到一个好的值并消耗时间,你就重置一切:让你的参考值成为最后一个,重置定时器,将half-tilt-done布尔值重置为false,并继续测量。

我希望这对你来说已经足够了。 当然,您可以找到一些库或代码片段来帮助您解决这个问题,但我认为,如果您知道从读数中推断出倾斜的逻辑,我认为这很好。

这些照片是从这篇文章中拍摄的,如果你想要提高精度并考虑2 o 3轴倾斜,我建议阅读

commonsware Sensor Monitor应用程序可以很好地完成这项工作。 它将传感器读数转换为每个传感器读数上的X,Y,Z值,因此可以很容易地确定设备的移动方式。

https://github.com/commonsguy/cw-omnibus/tree/master/Sensor/Monitor

值得注意的另一个项目(来自Commonsware书 ):

有四个标准延迟周期,在SensorManager类中定义为常量:

  1. SENSOR_DELAY_NORMAL,这是大多数应用程序用于广泛更改的内容,例如检测从纵向旋转到横向的屏幕
  2. SENSOR_DELAY_UI,适用于您希望根据传感器读数连续更新UI的非游戏案例
  3. SENSOR_DELAY_GAME比SENSOR_DELAY_UI更快(延迟更少),试图提高帧速率
  4. SENSOR_DELAY_FASTEST,这是传感器读数的“消防”,没有延迟

您可以使用加速度计和磁场传感器来实现此目的。 您可以在OnSensorChanged方法中调用此方法来检测手机是否向上倾斜。 目前仅在手机水平握持时才有效。 查看实际的博客文章,获取更完整的解决方案。

http://www.ahotbrew.com/how-to-detect-forward-and-backward-tilt/

public boolean isTiltUpward()
{
    if (mGravity != null && mGeomagnetic != null) 
    {
          float R[] = new float[9];
          float I[] = new float[9];

          boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);

          if (success) 
          {
            float orientation[] = new float[3];
            SensorManager.getOrientation(R, orientation);               

            /*
             * If the roll is positive, you're in reverse landscape (landscape right), and if the roll is negative you're in landscape (landscape left)
             * 
             * Similarly, you can use the pitch to differentiate between portrait and reverse portrait. 
             * If the pitch is positive, you're in reverse portrait, and if the pitch is negative you're in portrait.
             * 
             * orientation -> azimut, pitch and roll
             * 
             *
             */

            pitch = orientation[1];
            roll = orientation[2];              

            inclineGravity = mGravity.clone();

            double norm_Of_g = Math.sqrt(inclineGravity[0] * inclineGravity[0] + inclineGravity[1] * inclineGravity[1] + inclineGravity[2] * inclineGravity[2]);

            // Normalize the accelerometer vector
            inclineGravity[0] = (float) (inclineGravity[0] / norm_Of_g);
            inclineGravity[1] = (float) (inclineGravity[1] / norm_Of_g);
            inclineGravity[2] = (float) (inclineGravity[2] / norm_Of_g);

            //Checks if device is flat on ground or not
            int inclination = (int) Math.round(Math.toDegrees(Math.acos(inclineGravity[2])));                     

            /*
             *   Float obj1 = new Float("10.2");
             *   Float obj2 = new Float("10.20");
             *   int retval =  obj1.compareTo(obj2);
             *   
             *   if(retval > 0) {
             *      System.out.println("obj1 is greater than obj2");
             *   }
             *   else if(retval < 0) {
             *      System.out.println("obj1 is less than obj2");
             *   }
             *   else {
             *      System.out.println("obj1 is equal to obj2");
             *   }
             */
            Float objPitch = new Float(pitch);
            Float objZero = new Float(0.0);
            Float objZeroPointTwo = new Float(0.2);
            Float objZeroPointTwoNegative = new Float(-0.2);

            int objPitchZeroResult = objPitch.compareTo(objZero);
            int objPitchZeroPointTwoResult = objZeroPointTwo.compareTo(objPitch);
            int objPitchZeroPointTwoNegativeResult = objPitch.compareTo(objZeroPointTwoNegative);

            if (roll < 0 && ((objPitchZeroResult > 0 && objPitchZeroPointTwoResult > 0) || (objPitchZeroResult < 0 &&  objPitchZeroPointTwoNegativeResult > 0)) && (inclination > 30 && inclination < 40))
            {
                return true;
            }
            else
            {
                return false;
            }               
        }
    }

    return false;
}

这是你在找什么?

public class AccelerometerHandler implements SensorEventListener
{
    float accelX;
    float accelY;
    float accelZ;

    public AccelerometerHandler(Context paramContext)
    {
        SensorManager localSensorManager = (SensorManager)paramContext.getSystemService("sensor");

        if (localSensorManager.getSensorList(1).size() != 0)
            localSensorManager.registerListener(this, (Sensor)localSensorManager.getSensorList(1).get(0), 1);
    }

    public float getAccelX()
    {
        return this.accelX;
    }

    public float getAccelY()
    {
        return this.accelY;
    }

    public float getAccelZ()
    {
        return this.accelZ;
    }

    public void onAccuracyChanged(Sensor paramSensor, int paramInt)
    {
    }

    public void onSensorChanged(SensorEvent paramSensorEvent)
    {
        this.accelX = paramSensorEvent.values[0];
        this.accelY = paramSensorEvent.values[1];
        this.accelZ = paramSensorEvent.values[2];
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM