使用方向感应器 [英] Direction using sensor

查看:204
本文介绍了使用方向感应器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用我想显示设备的方向,如北,南,东,西。对于我使用加速计和磁传感器,并与下面code尝试。

In my app i wanted to show device direction such as north, south, east, west. For that i am using accelerometer and magnetic sensor and tried with following code.

public class MainActivity extends Activity implements SensorEventListener 
{

public static float swRoll;
public static float swPitch;
public static float swAzimuth;


public static SensorManager mSensorManager;
public static Sensor accelerometer;
public static Sensor magnetometer;

public static float[] mAccelerometer = null;
public static float[] mGeomagnetic = null;


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

@Override
public void onSensorChanged(SensorEvent event) 
{
    // onSensorChanged gets called for each sensor so we have to remember the values
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 
    {
        mAccelerometer = event.values;
    }

    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) 
    {
        mGeomagnetic = event.values;
    }

    if (mAccelerometer != null && mGeomagnetic != null) 
    {
        float R[] = new float[9];
        float I[] = new float[9];
        boolean success = SensorManager.getRotationMatrix(R, I, mAccelerometer, mGeomagnetic);

        if (success) 
        {
            float orientation[] = new float[3];
            SensorManager.getOrientation(R, orientation);
            // at this point, orientation contains the azimuth(direction), pitch and roll values.
            double azimuth = 180 * orientation[0] / Math.PI;
            //double pitch = 180 * orientation[1] / Math.PI;
            //double roll = 180 * orientation[2] / Math.PI;

            Toast.makeText(getApplicationContext(), "azimuth: "+azimuth, Toast.LENGTH_SHORT).show();
            //Toast.makeText(getApplicationContext(), "pitch: "+pitch, Toast.LENGTH_SHORT).show();
            //Toast.makeText(getApplicationContext(), "roll: "+roll, Toast.LENGTH_SHORT).show();
        }
    }
}



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
    accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}

@Override
protected void onResume() {
    super.onResume();

    mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
    mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME);
}

@Override
protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this, accelerometer);
    mSensorManager.unregisterListener(this, magnetometer);
}
}

我看了一些ARTICAL和来知道方位值是用于获得方向。但它没有显示应有的价值即它总是显示在任意方向的103至140的值。我使用的三星Galaxy S测试的目的。其中i出错。
任何帮助将AP preciated ...谢谢

I read some artical and come to know that azimuth value is use for getting direction. But it not shows proper value i.e it always shows value between 103 to 140 in any direction. I am using samsung galaxy s for test purpose. where i goes wrong. Any help will be appreciated...thank you

推荐答案

编辑:我要去,因为没有其他的答案在这里,但我的直觉在这个code再次寻找它是保持这个答案了可能不能很好地工作。使用您自己的风险,如果有谁给一个像样的答案,我会删除此

I'm going to keep this answer up because there are no other answers here, but my gut feeling looking at this code again is it probably doesn't work well. Use at your own risk, and if anyone ever gives a decent answer I'll delete this

下面是我写我自己用的指南针传感器。它的工作原理,有点。在现实中,它需要更好的filtering-来自传感器的结果非常嘈杂,我建立在它之上,以减缓更新一个过滤器,它改善了的东西,但它需要一个更好的过滤器,如果它是在生产中使用

Here's a compass sensor I wrote for my own use. It works, somewhat. In reality it needs better filtering- the results from the sensor are very noisy, I built a filter on top of it to slow the updates and it improved things, but it needs a much better filter if it was to be used in production

package com.gabesechan.android.reusable.sensor;

import java.lang.ref.WeakReference;
import java.util.HashSet;


import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Message;

public class CompassSensor {

SensorManager sm;
int lastDirection = -1;
int lastPitch;
int lastRoll;
boolean firstReading = true;
HashSet<CompassListener> listeners = new HashSet<CompassListener>();

static CompassSensor mInstance;

public static CompassSensor getInstance(Context ctx){
    if(mInstance == null){
        mInstance = new CompassSensor(ctx);
    }
    return mInstance;
}

private CompassSensor(Context ctx){
    sm = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE);
    onResume();
}

public void onResume(){
    sm.registerListener(sensorListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
    sm.registerListener(sensorListener, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
    firstReading = true;
    //Restart the timer only if we have listeners
    if(listeners.size()>0){
        handler.sendMessageDelayed(Message.obtain(handler, 1),1000);
    }
}

public void onPause(){
    sm.unregisterListener(sensorListener);
    handler.removeMessages(1);
}

private final SensorEventListener sensorListener = new SensorEventListener(){
    float accelerometerValues[] = null;
    float geomagneticMatrix[] = null;
    public void onSensorChanged(SensorEvent event) {
        if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
            return;

        switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            accelerometerValues = event.values.clone();

            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomagneticMatrix = event.values.clone();
            break;
        }   

        if (geomagneticMatrix != null && accelerometerValues != null && event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {

            float[] R = new float[16];
            float[] I = new float[16];
            float[] outR = new float[16];

            //Get the rotation matrix, then remap it from camera surface to world coordinates
            SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix);
            SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
            float values[] = new float[4];
            SensorManager.getOrientation(outR,values);

            int direction = normalizeDegrees(filterChange((int)Math.toDegrees(values[0])));
            int pitch = normalizeDegrees(Math.toDegrees(values[1]));
            int roll = normalizeDegrees(Math.toDegrees(values[2]));
            if((int)direction != (int)lastDirection){
                lastDirection = (int)direction;
                lastPitch = (int)pitch;
                lastRoll = (int)roll;
            }
        }
    }

    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
};


//Normalize a degree from 0 to 360 instead of -180 to 180
private int normalizeDegrees(double rads){
    return (int)((rads+360)%360);
}

//We want to ignore large bumps in individual readings.  So we're going to cap the number of degrees we can change per report
private static final int MAX_CHANGE = 3;
private int filterChange(int newDir){
    newDir = normalizeDegrees(newDir);
    //On the first reading, assume it's right.  Otherwise NW readings take forever to ramp up
    if(firstReading){
        firstReading = false;
        return newDir;
    }       

    //Figure out how many degrees to move
    int delta = newDir - lastDirection;
    int normalizedDelta = normalizeDegrees(delta);
    int change = Math.min(Math.abs(delta),MAX_CHANGE);

    //We always want to move in the direction of lower distance.  So if newDir is lower and delta is less than half a circle, lower lastDir
    // Same if newDir is higher but the delta is more than half a circle (you'd be faster in the other direction going lower).
    if( normalizedDelta > 180 ){
        change = -change;
    }

    return lastDirection+change;
}

public void addListener(CompassListener listener){
    if(listeners.size() == 0){
        //Start the timer on first listener
        handler.sendMessageDelayed(Message.obtain(handler, 1),1000);
    }
    listeners.add(listener);
}

public void removeListener(CompassListener listener){
    listeners.remove(listener);
    if(listeners.size() == 0){
        handler.removeMessages(1);
    }

}

public int getLastDirection(){
    return lastDirection;
}
public int getLastPitch(){
    return lastPitch;
}
public int getLastRoll(){
    return lastPitch;
}

private void callListeners(){
    for(CompassListener listener: listeners){
        listener.onDirectionChanged(lastDirection, lastPitch, lastRoll);
    }             

}

//This handler is run every 1s, and updates the listeners
//Static class because otherwise we leak, Eclipse told me so
static class IncomingHandler extends Handler {
    private final WeakReference<CompassSensor> compassSensor; 

    IncomingHandler(CompassSensor sensor) {
        compassSensor = new WeakReference<CompassSensor>(sensor);
    }
    @Override
    public void handleMessage(Message msg)
    {
        CompassSensor sensor = compassSensor.get();
         if (sensor != null) {
              sensor.callListeners();
         }
        sendMessageDelayed(Message.obtain(this, 1), 1000);
    }
}

IncomingHandler handler = new IncomingHandler(this);

public interface CompassListener {
    void onDirectionChanged(int direction, int pitch, int roll);
}

}

这篇关于使用方向感应器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆