простой компас с использованием магнитометра - Android (Java)

Я использую 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 + "]";
}

}

person Matt    schedule 09.11.2014    source источник
comment
Я хотел бы помочь вам, но я действительно не понимаю, что пытается сделать ваш код. Во-первых, Direction (y=0, x>0) = 0.0 - это не уравнение, я даже не знаю, что это значит. Во-вторых, использование однобуквенных переменных - отличный способ заставить людей игнорировать ваш вопрос, поскольку их очень трудно читать. Что такое b? Есть ли там какие-то показания с магнитометра?   -  person Mike Ounsworth    schedule 12.11.2014
comment
Я получил Direction (y=0, x>0) = 0.0 с веб-сайта. Это в основном означает, что если y магнитометра равно 0, а его x больше 0, то указатель компаса должен быть на 0.0 (север). остальные похожи на его. Кроме того, b - это показание магнитометра. В аргументе b - это класс Point3D, в котором x, y, z - переменная магнитометра. Объект b также содержит такие методы, как norm(), _10 _... и т.д ... Но единственные и наиболее важные поля - это x,y,z.   -  person Matt    schedule 12.11.2014
comment
Хорошо, я вижу, что b - это Point3D, это в вашем коде. У меня вопрос: какие данные в нем? x,y,z описывают точку на единичном круге, какой-то кватернион, силу магнитного поля на каждой оси и т. д.? Вы не предоставили нам достаточно кода, чтобы узнать, откуда берется значение b.   -  person Mike Ounsworth    schedule 12.11.2014
comment
Думаю, я нашел сайт, на котором вы получили эти уравнения ... aerospace.honeywell.com/~/media/Images/ Очень странно, что у них есть арктан только в двух квадрантах. Это кажется неправильным.   -  person Mike Ounsworth    schedule 12.11.2014
comment
это действительно веб-сайт. И xyz задают вектор магнитной силы   -  person Matt    schedule 12.11.2014
comment
хорошо, тогда см. мой ответ ниже.   -  person Mike Ounsworth    schedule 12.11.2014
comment
Я скоро попробую   -  person Matt    schedule 12.11.2014


Ответы (1)


Одна из ваших проблем заключается в том, что вы используете 3D-магнитометр как 2D-датчик. Это не так.

Один из способов сделать это - использовать данные как магнитометра, так и акселерометра:

  1. Вы фиксируете показания с обоих датчиков, прогоняете эти значения через SensorManager.getRotationMatrix, чтобы получить исходную матрицу поворота. (Обратите внимание, что в документации в описании матриц переключены единичная матрица и матрица вращения.)
  2. Вы передаете результат через
person Chris    schedule 18.11.2014
comment
Я очень ценю, что вы нашли время. Однако я считаю, что в вашем объяснении и коде используются магнитометр и акселерометр устройства. Я использую отдельное устройство (Sensortag cc2541). Мне нужно получить магнитное поле и соотв. От этого устройства. А в устройстве есть следующее. И в магнитометре, и в акселерометре я могу получить x y и z. В вашем коде есть функции и методы, которых, вероятно, нет в моей библиотеке Sensor. Я обновил вопрос и добавил методы и функции, которые у меня есть для магнитометра и акселерометра - person Matt; 19.11.2014
comment
Кроме того, не требует ли этот метод калибровки? Я имею в виду, что из предоставленного вами кода он автоматически обнаружит Север ?. - person Matt; 19.11.2014
comment
Глядя на ваш обновленный вопрос, я не вижу причин, по которым вы не сможете использовать библиотеку датчиков Android. Единственное отличие состоит в том, что в моем примере используются массивы с тремя точками данных (именно так Android изначально предоставляет данные датчика), а не ваш Point3D. В качестве отправной точки вы могли бы реализовать это с помощью акселерометра / магнитометра устройства Nexus, поскольку этот пример действительно работает. После этого замените данные с внешнего устройства. - person Chris; 19.11.2014
comment
Для калибровки встроенного магнитометра телефона Nexus просто переместите телефон в виде восьмерки, чтобы Android мог его откалибровать. К сожалению, я не знаю, как это сделать с вашим внешним устройством. - person Chris; 19.11.2014