Получение вектора направления в Android

Как я могу получить вектор направления, представляющий направление задней части устройства относительно земных координат?

Например, если поместить его на стол (экраном вверх), он должен читать [0,0, -1], а если держать вертикально лицом к северу, он должен читать [1,0,0] и т. Д.

Я знаю, как рассчитать его по курсу, тангажу и крену, если они относятся к земным координатам. Чтобы быть ясным здесь, я не ищу угловую скорость, но фактический текущий угол относительно плоскости, касательной к земле. Поэтому, если устройство удерживается вертикально и направлено на север, угол «альфа» следует читать 0 или 360, угол «бета» должен читать 90, и "гамма" должен читать 0. Я также не могу понять, как получить эти значения.

Я читал API весь день и до сих пор не могу найти, как получить что-то из этого.

public void onSensorChanged(SensorEvent event) {
    // ?    
}

Спасибо за любые идеи.

Ответы на вопрос(2)

Прочитайте эту страницу:http://developer.android.com/reference/android/hardware/Sensor.html

В API 8 и выше есть «виртуальный» датчики, которые генерируются путем объединения входов всех доступных датчиков и соответствующих фильтров. & Quot; TYPE_ORIENTATION & quot; Датчик дает вам полную ориентацию вашего устройства, но этот интерфейс устарел из-за состояний отказа в определенных ориентациях. Новый датчик - TYPE_ROTATION_VECTOR (API 9 и выше), который определяет ориентацию вашего устройства в виде кватерниона. Это действительно лучший датчик для использования, но математика немного сложнее.

В противном случае вы вызываете SensorManager.getRotationMatrix (), передавая последние данные гравитации и магнитометра. Это вернет матрицу вращения, которую можно использовать для преобразования вектора из координат устройства в мировые координаты или наоборот (просто транспонируйте матрицу, чтобы инвертировать ее).

Функция getOrientation () может давать вам направление, угол наклона и крен, но они имеют те же состояния отказа, что и датчик TYPE_ORIENTATION.

Examples:

  Device flat on a table, top facing north:
    1  0  0
    0  1  0
    0  0  1

  Tilted up 30 degrees (rotated about X axis)
    1   0      0
    0   0.86  -0.5
    0   0.5    0.86

  Device vertical (rotated about X axis), facing north:
    1  0  0
    0  0 -1
    0  1  0

  Device flat on a table, top facing west:
    0 -1  0
    1  0  0
    0  0  1

  Device rotated about its Y axis, onto its left side, top
  facing north:
    0  0 -1
    0  1  0
    1  0  0

Вот пример кода, который вы можете найти полезным:

public void onSensorChanged(SensorEvent event) {
    long now = event.timestamp;     // ns

    switch( event.sensor.getType() ) {
      case Sensor.TYPE_ACCELEROMETER:
        gData[0] = event.values[0];
        gData[1] = event.values[1];
        gData[2] = event.values[2];
        break;
      case Sensor.TYPE_MAGNETIC_FIELD:
        mData[0] = event.values[0];
        mData[1] = event.values[1];
        mData[2] = event.values[2];
        haveData = true;
        break;
    }

    if( haveData ) {
        double dt = (now - last_time) * .000000001;

        SensorManager.getRotationMatrix(R1, Imat, gData, mData);
        getOrientation(R1, orientation);
        pfdView.newOrientation(orientation[2], (float)dt);


        Log.d(TAG, "yaw: " + (int)(orientation[0]*DEG));
        Log.d(TAG, "pitch: " + (int)(orientation[1]*DEG));
        Log.d(TAG, "roll: " + (int)(orientation[2]*DEG));

        acft.compass = orientation[0];

        last_time = now;
    }
}
 Joey17 июн. 2012 г., 07:09
Спасибо за ваш ответ - у меня есть только два вопроса, если я использую TYPE_ROTATION_VECTOR, квантион выражается в мировых координатах? Это уже интегрировано, или я должен интегрировать его, чтобы получить текущий вектор?
 17 июн. 2012 г., 19:26
Мировые координаты устройства, я считаю. Уже преобразуется в единицу кватерниона, и иногда термин w опускается. Честно говоря, я никогда не использовал это сам. Код, который я показываю выше, взят из приложения для навигации по полету, которое я написал для 1.5, до появления новых типов датчиков.
Решение Вопроса

SensorManager.getRotationMatrix() делает то, что описано ниже, написано до того, как я узнал об этом. Я оставлю добавленное объяснение, потому что, если вы хотите исправить разницу между магнитным и истинным севером, оно вам все равно понадобится.

Грубый алгоритм, чтобы получить матрицу вращения, умножить вектор[0,0,-1] затем настройте его в соответствии с вашей системой координат. Зачем? Документы Android дают системы координат для устройства и мира

deviceworld

Заметка[0,0,-1] в устройстве Android координаты точек перпендикулярны назад от экрана. Если вы умножите матрицу вращения R на этот вектор, вы получите[0,0,-1] в мировых координатах, когда устройство находится на столе, как вам нужно. Когда он направлен вертикально на север, вы получите[0,-1,0], который указывает, что вы выбрали систему координат, гдеx а такжеy меняются относительно системы Android, но это просто изменение соглашений.

ЗаметкаR * [0,0,-1]^T это просто третий столбецR отрицается. Из этого я получаю псевдокод:

getRotationMatrix(R);
Let v = first three elements of third column of R.
swap v[0] and v[1]

Это должно получить то, что вы хотите.

Дополнительная информация о том, чтоgetRotationMatrix() делает следующее.

Вам нужны данные обоих акселерометров, чтобы установить направление "вниз" и данные магнитометра для определения направления "север". Вы должны будете предположить, что акселерометры воспринимают только гравитацию (устройство неподвижно или движется с постоянной скоростью). Затем вам нужно спроецировать вектор магнитометра на плоскость, перпендикулярную вектору гравитации (поскольку магнитное поле обычно не касается поверхности Земли). Это дает вам две оси. Третий является ортогональным, поэтому может быть вычислен по перекрестному произведению. Это дает вам векторы координат земли в системе устройств. Похоже, вы хотите обратное: координаты устройства в земных координатах. Для этого достаточно построить матрицу направляющих косинусов и инвертировать.

Добавлю, что в приведенном выше обсуждении предполагается, что вектор магнитометра направлен на север. Я думаю (из науки средней школы!), Что это на самом деле к магнитному югу, но у меня нет под рукой какого-либо устройства, поэтому я не могу его попробовать. Конечно, магнитный север / юг отличается от истинного на ноль на 180 градусов, в зависимости от того, где вы находитесь на земле. Вы можете получить координаты GPS и вычислить фактическое смещение.

Если вы не знакомы с математикой, необходимой для этого, я могу объяснить дальше, но это будет позже.

 Joey17 июн. 2012 г., 12:15
Я получил это, используя ваше объяснение. Оказывается, я передаю значения, возвращенные датчиком силы тяжести и датчиком магнитного поля, прямо в getRotationMatrix (), и все работает. Затем просто умножьте эту матрицу на [0,0, -1] и получите dv.
 Joey17 июн. 2012 г., 07:03
Большое спасибо, это действительно полезно. Вы оба дали такие хорошие ответы, я хотел бы, чтобы был способ выбрать их обоих. Похоже, я могу получить вектор гравитации с помощью только Sensor.TYPE_GRAVITY - они сделали эту работу для меня. Хотелось бы, чтобы так же легко было получить "север" вектор.

Ваш ответ на вопрос