简体   繁体   English

Android-如何检测指南针度的变化(Java)

[英]Android - How to detect change in compass degree (Java)

I have the following code that perfectly works on my Nexus 5. 我有以下代码可以在Nexus 5上完美运行。

public void onSensorChanged(SensorEvent event) {
        float degree = Math.round(event.values[0]);
        displayMsg.setText(String.valueOf(degree));
}

degree contains the compass's direction. degree包含指南针的方向。 What I want to do is to detect change in direction. 我要做的是检测方向的变化。 So let's say if a person is walking north and then the turn 10 degrees to the right. 因此,假设某人向北走,然后向右转10度。 As soon as the person changes direction, I want to be able to notice. 人一旦改变方向,我就希望能够注意到。 Also, there are uncertainties. 此外,还有不确定性。 So for example when the person is walking North, the direction isn't constant 0 degrees. 因此,例如,当人向北走时,方向不是恒定的0度。 It will be fluctuating between 358 and 2-3 degrees. 它将在358至2-3度之间波动。

I thought of using Timer.schedule to store the degrees every 500 ms and then do a 我想到了使用Timer.schedule每500毫秒存储一次度,然后执行

if(Math.abs(degree - storedDegree) > 10)
   Toast.makeText(this,"Direction Changed",Toast.LENGTH_SHORT).show();

However this method runs out of memory due to the number of threads created I think. 但是,由于我认为创建的线程数量,此方法用完了内存。 Is there a smarter/better way of detecting change in direction? 有没有更聪明/更好的方法来检测方向变化?


UPDATE 更新

Here's the full code I'm doing. 这是我正在执行的完整代码。

I am counting steps and I want to keep the direction that the steps are taken. 我正在计算步骤,我想保持执行步骤的方向。 As soon as the direction is changed by say 10 degrees, the step counter should store the value it has (say in an array list) and then go to 0 and restart counting. 一旦方向改变了10度,步数计数器应存储它拥有的值(例如在数组列表中),然后转到0并重新开始计数。

boolean start = true;

@Override
public void onSensorChanged(SensorEvent event) {
    //------------------------------Compass--------------------------------------
    final float degree = Math.round(event.values[0]);
    displayMsg.setText(String.valueOf(degree));
    //---------------------------------------------------------------------------

    Sensor sensor = event.sensor;
    float[] values = event.values;
    int value = -1;
    int steps;

    if (values.length > 0) {
        value = (int) values[0];
    }

    if(mode.equals("Start"))
    {
        if (sensor.getType() == Sensor.TYPE_STEP_COUNTER) 
        {
            if(start)
            {
                count = value;
                start = false;
            }
            steps = value-count;
            stepCounter.setText("Step Counter Detected : " + steps);
        } 
    }
}

I would use a low pass filter, to eliminate the fluctuations. 我将使用低通滤波器来消除波动。

here's the code: 这是代码:

protected float[] lowPass(float[] input, float[] output) {
    if (output == null) return input;
    for (int i = 0; i < input.length; i++) {
        output[i] = output[i] + ALPHA * (input[i] - output[i]);
    }
    return output;
}

Where ALPHA is static final float ALPHA = 0.25f; 其中ALPHA是静态最终浮点ALPHA = 0.25f;

I'll also post code for getting the "direction". 我还将发布用于获取“方向”的代码。 Maybe it helps you: 也许它可以帮助您:

protected void onResume() {
    super.onResume();
    mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
    mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
}

protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this);
}


@Override
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
        mGravity = lowPass(event.values.clone(), mGravity);
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
        mGeomagnetic = lowPass(event.values.clone(), mGeomagnetic);
    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);
            azimut = orientation[0]; // orientation contains: azimut, pitch and roll
        }
    }

}

after this, use the azimut like this: 之后,使用如下方位角:

        if (azimut != null) {
            canvas.rotate(-azimut * 360 / (2 * 3.14159f), centerx, centery);

            if ((azimut > -0.2) && (azimut < 0.2)) current_direction = "North";
            if ((azimut > 1.3) && (azimut < 1.7)) current_direction = "East";
            if (((azimut < -2.8) && (azimut > -3.2)) || ((azimut < 3.2) && (azimut > 2.8))) current_direction = "South";
            if ((azimut > -1.7) && (azimut < -1.3)) current_direction = "West";
        }

I think your problem is more related to the sensors and not your logic. 我认为您的问题更多与传感器有关,而不是您的逻辑。 You can try this, but I am not really failure with the sensors. 您可以尝试一下,但是传感器并不是我真正的失败。 I know the location service can provide you with a device bearing (via gps), which might also be an option. 我知道定位服务可以为您提供设备定位(通过gps),这也可能是一种选择。

Can you check that the current degree has changed by more than your threshold, and then update the stored value with the new degree? 您可以检查当前学位的变化幅度是否超过阈值,然后用新学位更新储值吗?

one possible example would be something like this: The idea is that since onSensorChanged is called whenever a value is updated, you can check if the difference between the current degree and a stored value is more than some threshold. 一个可能的示例是这样的:想法是,由于onSensorChanged在值更新时都会被调用,因此您可以检查当前度和存储值之间的差是否大于某个阈值。 If it is take action and store the new degree, if not the change is simply ignored. 如果采取措施并存储新的度数,则不做任何更改。

private float storedDegree;

public void onSensorChanged(SensorEvent event) {
    if (sensor.getType() == Sensor.TYPE_ORIENTATION) {
        float degree = Math.round(event.values[0]);
        if(Math.abs(degree - storedDegree) > 10) {
            Toast.makeText(this,"Direction Changed",Toast.LENGTH_SHORT).show();
            displayMsg.setText(String.valueOf(degree));
            storedDegree = degree;
        }
    }
}

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

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