2

Sensortag CC2541を使用しています(Nexus 電話に接続)

このセンサーの磁力計を使って簡単なコンパスを作っています。次の式を使用して、北、南、西、東を見つけています。

Direction (y>0) = 90 - [arcTAN(x/y)]*180/pi

Direction (y<0) = 270 - [arcTAN(x/y)]*180/pi

Direction (y=0, x<0) = 180.0

Direction (y=0, x>0) = 0.0

updateMagnetometer メソッドで使用しているコードは次のとおりです

    @Override
    public void onUpdateMagnetometer(SensorTagManager mgr, Point3D b) {
        super.onUpdateMagnetometer(mgr, b);

        double m=0;

        if(b.x < 0.0 && (b.y < 0.01 && b.y > 0.0))
            m = 180;
        else if(b.x > 0.0 && (b.y < 0.01 && b.y > 0.0))
            m = 0;
        else if(b.y > 0.0)
            m = 90 - (Math.atan(b.x/b.y))*(180/Math.PI);
        else if(b.y < 0.0)
            m = 270 - (Math.atan(b.x/b.y))*(180/Math.PI);

        final float rot = (float) m;

        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                pointer.setRotation(-rot); //pointer is the image of my compass
            }
        });
    }

しかし、実行すると、どれだけ移動、回転、またはセンサーの位置を変更しても、コンパスは常に北と西の間で動かなくなります。

私がやっているかもしれない間違いはありますか?

また、コンパスのヘルプを作成するためにインターネットでよく調べました。しかし、何も見つかりません。磁力計、加速度計、および/またはジャイロスコープを使用してコンパスを作成するためのコーディングのヒント、疑似コード、またはヒント???


追加情報

これは私のメインクラスです。これらのメソッドはx、測定値を更新するために毎秒呼び出されます。PS: 私のセンサーには 2 つのボタン (左右) があります。

    mStManager.enableSensor(Sensor.MAGNETOMETER,MAGNETOMETER_UPDATE_PERIOD);
    mStManager.enableSensor(Sensor.ACCELEROMETER,MAGNETOMETER_UPDATE_PERIOD);    

    @Override
    public void onUpdateAmbientTemperature(SensorTagManager mgr, double temp) {
        super.onUpdateAmbientTemperature(mgr, temp);
    }

    @Override
    public void onUpdateAccelerometer(SensorTagManager mgr, Point3D acc) {
        super.onUpdateAccelerometer(mgr, acc);

    }

    @Override
    public void onUpdateBarometer(SensorTagManager mgr, double pressure, double height) {
        super.onUpdateBarometer(mgr, pressure, height);
    }

    @Override
    public void onUpdateGyroscope(SensorTagManager mgr, Point3D ang) {
        super.onUpdateGyroscope(mgr, ang);
    }

    @Override
    public void onUpdateHumidity(SensorTagManager mgr, double rh) {
        super.onUpdateHumidity(mgr, rh);
    }

    @Override
    public void onUpdateInfraredTemperature(SensorTagManager mgr, double temp) {
        super.onUpdateInfraredTemperature(mgr, temp);
    }

    @Override
    public void onUpdateKeys(SensorTagManager mgr, boolean left, boolean right) {
        super.onUpdateKeys(mgr, left, right);

        if (right) {
            mgr.calibrateMagnetometer();
        }
    }

    @Override
    public void onUpdateMagnetometer(SensorTagManager mgr, Point3D b) {
        super.onUpdateMagnetometer(mgr, b);
    }

}

したがって、基本的にonUpdateMagnetometerメソッドにはb、私の読みが含まれています。Point3D以下に示すクラスです

public class Point3D {
public double x, y, z;

public Point3D(double x, double y, double z) {
    this.x = x;
    this.y = y;
    this.z = z;
}

public double norm() {
    return Math.sqrt(x*x + y*y + z*z);
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(x);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(y);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(z);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Point3D other = (Point3D) obj;
    if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
        return false;
    if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
        return false;
    if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
        return false;
    return true;
}

public String toString() {
    return "[" + this.x + ", " + this.y + ", " + this.z + "]";
}

}
4

1 に答える 1

3

問題の 1 つは、3D 磁力計を 2D センサーとして扱っていることです。そうではありません。

これを行う 1 つの方法は、磁力計と加速度計の両方からのデータを使用することです。

  1. 両方のセンサーから読み取り値を取得し、これらの値をSensorManager.getRotationMatrixで実行して、初期回転マトリックスを取得します。(ドキュメントでは、行列の説明では単位行列と回転行列が入れ替わっていることに注意してください。)
  2. 結果をSensorManager.getOrientationに渡して、3D 空間でのデバイスの向きを取得します。
  3. 方向配列の最初の値をコンパス方向として使用します

その最終的な値は、地球の中心に向けられたベクトルを中心としたデバイスの回転を表します。これはまさにコンパスに必要なものです。その値を使用して、西、東、南の位置を計算できます。

コードは次のようになります: (センサーの設定は無視します)

// globals
private float[] gravityData = new float[3];
private float[] geomagneticData  = new float[3];
private boolean hasGravityData = false;
private boolean hasGeomagneticData = false;
private double rotationInDegrees;


@Override
public void onSensorChanged(SensorEvent event) {
    switch (event.sensor.getType()){
        case Sensor.TYPE_ACCELEROMETER:
            System.arraycopy(event.values, 0, gravityData, 0, 3);
            hasGravityData = true;
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            System.arraycopy(event.values, 0, geomagneticData, 0, 3);
            hasGeomagneticData = true;
            break;
        default:
            return;
    }

    if (hasGravityData && hasGeomagneticData) {
        float identityMatrix[] = new float[9];
        float rotationMatrix[] = new float[9];
        boolean success = SensorManager.getRotationMatrix(rotationMatrix, identityMatrix,
            gravityData, geomagneticData);

        if (success) {
            float orientationMatrix[] = new float[3];
            SensorManager.getOrientation(rotationMatrix, orientationMatrix);
            float rotationInRadians = orientationMatrix[0];
            rotationInDegrees = Math.toDegrees(rotationInRadians);

            // do something with the rotation in degrees
        }
    }
}

それが役立つことを願っています!

于 2014-11-18T23:17:37.247 に答える