使用传感器的罗盘,与Google地图相比,性能较差

问题描述 投票:0回答:1

通过遵循android dev samples中的示例,我设法使用Sensor.TYPE_ACCELEROMETERSensor.TYPE_MAGNETIC_FIELD创建了一个不平滑的罗盘)。

使用一些幼稚的平滑技术(使用最后n个值的平均值),效果会更好。但是,旋转设备时,它与Google Maps应用程序所能完成的工作相差无几。

[使用内置的Google Maps应用程序时,指南针工作得很好,没有可察觉的延迟,无抖动和平滑的360度。

这是要使用的正确传感器/ API,它仅需要更复杂的平滑处理?如果是,android API是否对此有任何帮助?

android google-maps orientation android-sensors
1个回答
0
投票

出于不太精确的目的,例如根据方位在屏幕上旋转地图,您可以使用基于exponential smoothing传感器信号和阈值的方法(跳过小的变化并摆脱抖动),而无需任何其他API或库。通常它是这样的:

...
private static final ALPHA = 0.095;
private static final THRESHOLD = 0.75;
...   

// get current bearing value
SensorManager.getOrientation(rotationMatrix, mOrientationAngles);
float currentMeasuredBearing = (float) (Math.toDegrees(mOrientationAngles[0]));
// process 0 transition
if (currentMeasuredBearing < 0) {
    currentMeasuredBearing += 360;
}
// apply exponential smoothing (select trend of bearing)
currentMeasuredBearing = mLastMeasuredBearing + (float) ALPHA * (currentMeasuredBearing - mLastMeasuredBearing);
// apply threshold (skip values less THRESHOLD)
if (Math.abs(Math.toDegrees(mOrientationAngles[0]) - mLastMeasuredBearing) > THRESHOLD){
    // do what you need (e.g. rotate map) here
    updateCamera(currentMeasuredBearing);
}

您可以通过指数平滑的ALPHA参数和THRESHOLD的值来调节灵敏度。

或更详细:

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
    ...
    private static final SAMPLING_PERIOD = 250 * 1000;
    private static final ALPHA = 0.095;
    private static final THRESHOLD = 0.75;
    private GoogleMap mGoogleMap;
    private SensorManager mSensorManager;
    private Sensor mSensorAccelerometer;
    private Sensor mSensorMagneticField;
    private float[] mAccelerometer;
    private float[] mMagnetic;
    private float[] mOrientationAngles = new float[3];
    private float mLastMeasuredBearing;
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mSensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        ...
    }

        @Override
    protected void onStart() {
        super.onStart();
        startSensors();
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopSensors();
    }

    private void updateCamera(float bearing) {
        CameraPosition oldPos = mGoogleMap.getCameraPosition();

        CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing).build();
        mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
    }

    private void startSensors() {
        mLastMeasuredBearing = 0;

        if (mSensorAccelerometer != null) {
            mSensorManager.registerListener(mSensorEventListener,
                    mSensorAccelerometer, SAMPLING_PERIOD);
        }

        if (mSensorMagneticField != null) {
            mSensorManager.registerListener(mSensorEventListener,
                    mSensorMagneticField, SAMPLING_PERIOD);
        }
    }

    private void stopSensors() {
        if (mSensorAccelerometer != null && mSensorMagneticField != null) {
            mSensorManager.unregisterListener(mSensorEventListener);
        }
    }

    private SensorEventListener mSensorEventListener = new SensorEventListener() {

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }

        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                mAccelerometer = event.values.clone();
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                mMagnetic = event.values.clone();
            }

            if (mAccelerometer != null && mMagnetic != null) {
                float[] rotationMatrix = new float[9];
                if (SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometer, mMagnetic)) {

                    SensorManager.getOrientation(rotationMatrix, mOrientationAngles);
                    float currentMeasuredBearing = (float) (Math.toDegrees(mOrientationAngles[0]));
                    // process 0 transition
                    if (currentMeasuredBearing < 0) {
                        currentMeasuredBearing += 360;
                    }
                    // apply exponential smoothing (select trend of sensors data)
                    currentMeasuredBearing = mLastMeasuredBearing + (float) ALPHA * (currentMeasuredBearing - mLastMeasuredBearing);
                    // apply threshold (skip values less THRESHOLD)
                    if (Math.abs(Math.toDegrees(mOrientationAngles[0]) - mLastMeasuredBearing) > THRESHOLD){
                        updateCamera(currentMeasuredBearing);
                    }

                    mBearingTextView.setText(String.valueOf(Math.round(currentMeasuredBearing)));
                    mAxisXTextView.setText(String.valueOf(Math.round(Math.toDegrees(mOrientationAngles[0]))));
                    mAxisYTextView.setText(String.valueOf(Math.round(Math.toDegrees(mOrientationAngles[1]))));
                    mAxisZTextView.setText(String.valueOf(Math.round(Math.toDegrees(mOrientationAngles[2]))));

                    mLastMeasuredBearing = currentMeasuredBearing;

                }
            }
        }
    };
© www.soinside.com 2019 - 2024. All rights reserved.