Существует ли алгоритм преобразования вращений кватернионов в повороты на угол Эйлера?

StackOverflow https://stackoverflow.com/questions/1031005

Вопрос

Существует ли существующий алгоритм преобразования кватернионного представления поворота в представление угла Эйлера?Порядок вращения для представления Эйлера известен и может быть любой из шести перестановок (т. е.xyz, xzy, yxz, yzx, zxy, zyx).Я видел алгоритмы для фиксированного порядка вращения (обычно соглашение NASA о курсе, крене), но не для произвольного порядка вращения.

Кроме того, поскольку существует несколько представлений угла Эйлера с одной ориентацией, этот результат будет неоднозначным.Это приемлемо (потому что ориентация по-прежнему действительный, это просто может быть не тот, который пользователь ожидает увидеть), однако было бы еще лучше, если бы существовал алгоритм, который принимал ограничения на вращение (т.Е.количество степеней свободы и ограничения на каждую степень свободы) с учетом и получением "наиболее разумного" представления Эйлера с учетом этих ограничений.

У меня есть предчувствие, что эта проблема (или что-то подобное) может существовать в областях IK или динамики твердого тела.


Решаемая: Я просто понял, что, возможно, не совсем ясно, что я решил эту проблему, следуя алгоритмам Кена Шумейка из Graphics Gems.В то время я сам ответил на свой вопрос, но мне пришло в голову, что, возможно, было неясно, что я это сделал.Смотрите ответ ниже для получения более подробной информации.


Просто чтобы уточнить - я знаю, как преобразовать кватернион в так называемый 'Тейт-Брайан"представительство - то, что я называл конвенцией "НАСА".Это порядок вращения (при условии, что ось "Z" направлена вверх) zxy.Мне нужен алгоритм для ВСЕ приказы о ротации.

Возможно, решение, таким образом, состоит в том, чтобы взять преобразование порядка zxy и вывести из него пять других преобразований для других порядков вращения.Наверное, я надеялся, что существует более "всеобъемлющее" решение.В любом случае, я удивлен, что мне не удалось найти там существующих решений.

Кроме того, и это, возможно, должно быть вообще отдельным вопросом, любое преобразование (при условии, конечно, известного порядка вращения) будет выбирать один Представление Эйлера, но на самом деле их много.Например, при заданном порядке вращения yxz два представления (0,0,180) и (180,180,0) эквивалентны (и дали бы один и тот же кватернион).Есть ли способ ограничить решение, используя ограничения на степени свободы?Как вы занимаетесь ИК и динамикой твердого тела?т. е.в приведенном выше примере, если бы существовала только одна степень свободы относительно оси Z, то вторым представлением можно было бы пренебречь.


Я отыскал одну статью, которая могла бы быть алгоритмом в этот pdf-файл но я должен признаться, что нахожу логику и математику немного трудновыполнимыми.Наверняка есть и другие решения?Действительно ли произвольный порядок вращения так редок?Несомненно, каждый крупный 3D-пакет, который допускает скелетную анимацию вместе с интерполяцией кватернионов (т. е.Maya, Max, Blender и т.д.), Должно быть, решили именно эту проблему?

Это было полезно?

Решение

Это похоже на классический случай, когда упускают из виду старую технологию - мне удалось откопать копию Graphics Gems IV из гаража, и похоже, что у Кена Шумейка есть не только алгоритм преобразования из углов Эйлера произвольный порядок ротации, но также отвечает на большинство других моих вопросов по этому вопросу.Ура книгам!Если бы только я мог проголосовать за мистераОтветьте Сапожнику и наградите его очками репутации.

Я предполагаю, что всем, кто работает с Euler angles, следует получить копию Graphics Gems IV из своей локальной библиотеки и прочитать раздел, начинающийся со страницы 222.Это должно быть самое ясное и краткое объяснение проблемы, которое я когда-либо читал.


Вот полезная ссылка, которую я нашел с тех пор - http://www.cgafaq.info/wiki/Euler_angles_from_matrix - Это происходит по той же системе, что и изготовление обуви;24 различных перестановки порядка поворота кодируются как четыре отдельных параметра - внутренняя ось, четность, повторение и кадр, - что затем позволяет сократить алгоритм с 24 случаев до 2.Вообще, это могла бы быть полезная вики-страница - я раньше с ней не сталкивался.

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

Другие советы

В правой декартовой системе координат с осью Z, направленной вверх, сделайте следующее:

struct Quaternion
{
    double w, x, y, z;
};

void GetEulerAngles(Quaternion q, double& yaw, double& pitch, double& roll)
{
    const double w2 = q.w*q.w;
    const double x2 = q.x*q.x;
    const double y2 = q.y*q.y;
    const double z2 = q.z*q.z;
    const double unitLength = w2 + x2 + y2 + z2;    // Normalised == 1, otherwise correction divisor.
    const double abcd = q.w*q.x + q.y*q.z;
    const double eps = 1e-7;    // TODO: pick from your math lib instead of hardcoding.
    const double pi = 3.14159265358979323846;   // TODO: pick from your math lib instead of hardcoding.
    if (abcd > (0.5-eps)*unitLength)
    {
        yaw = 2 * atan2(q.y, q.w);
        pitch = pi;
        roll = 0;
    }
    else if (abcd < (-0.5+eps)*unitLength)
    {
        yaw = -2 * ::atan2(q.y, q.w);
        pitch = -pi;
        roll = 0;
    }
    else
    {
        const double adbc = q.w*q.z - q.x*q.y;
        const double acbd = q.w*q.y - q.x*q.z;
        yaw = ::atan2(2*adbc, 1 - 2*(z2+x2));
        pitch = ::asin(2*abcd/unitLength);
        roll = ::atan2(2*acbd, 1 - 2*(y2+x2));
    }
}

Я несколько дней искал похожее решение, и наконец наткнулся на этот веб-сайт, на котором есть алгоритм преобразования кватернионов в произвольные вращения Эйлера и Тейта-Брайана!

Вот ссылка: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

И вот этот код:

///////////////////////////////
// Quaternion to Euler
///////////////////////////////
enum RotSeq{zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx};

void twoaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r11, r12 );
  res[1] = acos ( r21 );
  res[2] = atan2( r31, r32 );
}

void threeaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r31, r32 );
  res[1] = asin ( r21 );
  res[2] = atan2( r11, r12 );
}

void quaternion2Euler(const Quaternion& q, double res[], RotSeq rotSeq)
{
    switch(rotSeq){
    case zyx:
      threeaxisrot( 2*(q.x*q.y + q.w*q.z),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    -2*(q.x*q.z - q.w*q.y),
                     2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                     res);
      break;

    case zyz:
      twoaxisrot( 2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.z + q.w*q.y),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.z - q.w*q.y),
                  res);
      break;

    case zxy:
      threeaxisrot( -2*(q.x*q.y - q.w*q.z),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      2*(q.y*q.z + q.w*q.x),
                     -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                      res);
      break;

    case zxz:
      twoaxisrot( 2*(q.x*q.z + q.w*q.y),
                  -2*(q.y*q.z - q.w*q.x),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.x*q.z - q.w*q.y),
                   2*(q.y*q.z + q.w*q.x),
                   res);
      break;

    case yxz:
      threeaxisrot( 2*(q.x*q.z + q.w*q.y),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    -2*(q.y*q.z - q.w*q.x),
                     2*(q.x*q.y + q.w*q.z),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                     res);
      break;

    case yxy:
      twoaxisrot( 2*(q.x*q.y - q.w*q.z),
                   2*(q.y*q.z + q.w*q.x),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.x*q.y + q.w*q.z),
                  -2*(q.y*q.z - q.w*q.x),
                  res);
      break;

    case yzx:
      threeaxisrot( -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                      2*(q.x*q.y + q.w*q.z),
                     -2*(q.y*q.z - q.w*q.x),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      res);
      break;

    case yzy:
      twoaxisrot( 2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.y - q.w*q.z),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.y + q.w*q.z),
                   res);
      break;

    case xyz:
      threeaxisrot( -2*(q.y*q.z - q.w*q.x),
                    q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    2*(q.x*q.z + q.w*q.y),
                   -2*(q.x*q.y - q.w*q.z),
                    q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    res);
      break;

    case xyx:
      twoaxisrot( 2*(q.x*q.y + q.w*q.z),
                  -2*(q.x*q.z - q.w*q.y),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.y - q.w*q.z),
                   2*(q.x*q.z + q.w*q.y),
                   res);
      break;

    case xzy:
      threeaxisrot( 2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                    -2*(q.x*q.y - q.w*q.z),
                     2*(q.x*q.z + q.w*q.y),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                     res);
      break;

    case xzx:
      twoaxisrot( 2*(q.x*q.z - q.w*q.y),
                   2*(q.x*q.y + q.w*q.z),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.z + q.w*q.y),
                  -2*(q.x*q.y - q.w*q.z),
                  res);
      break;
    default:
      std::cout << "Unknown rotation sequence" << std::endl;
      break;
   }
}

Я разместил свою статью под названием "Преобразование угла кватерниона в угол Эйлера для произвольной последовательности вращения с использованием геометрических методов" на своем веб-сайте по адресу noelhughes.net.У меня также есть алгоритмы для преобразования любого набора углов Эйлера в кватернион и кватернион в / из матрицы косинусов направления, которые я опубликую в эти выходные.Они также есть на веб-сайте Martin Bakers, хотя их немного сложно найти.Загуглите мое имя, Ноэль Хьюз, и кватернионы, и вы должны найти его.

Я решаю это таким образом:

шаг 1:Убедитесь, какое соглашение для вращения Эйлера вы хотите, скажем, зикс.

шаг 2:Вычислите аналитическую матрицу вращения для поворота.Например, если вы хотите, чтобы R(зикс),

**R***zyx* = **R***x*( фи ) * **Р***у*( тета ) * **R***z*( пси ), где элементы становятся

R11 =  cos(theta)*cos(psi)
R12 = -cos(theta)*sin(psi)
R13 =  sin(theta)
R21 =  sin(psi)*cos(phi) + sin(theta)*cos(psi)*sin(phi)
R22 =  cos(psi)*cos(phi) - sin(theta)*sin(psi)*sin(phi)
R23 = -cos(theta)*sin(phi)
R31 =  sin(psi)*sin(phi) - sin(theta)*cos(psi)*cos(phi)
R32 =  cos(psi)sin(phi) + sin(theta)*sin(psi)*cos(phi)
R33 =  cos(theta)*cos(phi) 

шаг 3:При осмотре вы можете найти синус или загар для трех углов, используя приведенные выше элементы.В этом примере,

tan(phi) = -R23/R33

sin(theta) = -R13

tan(psi) = -R12/R11

шаг 4:Вычислите матрицу вращения из вашего кватерниона (см. википедия), для элементов вам нужно вычислить углы, как показано в 3) выше.

Другие условные обозначения могут быть вычислены с использованием той же процедуры.

Вот статья, которую я написал о преобразовании кватерниона в углы Эйлера.

Ссылка 1

Я также разместил в этом месте ряд документов, в которых обсуждаются различные аспекты кватернионов, углов Эйлера и матриц вращения (DCM).

Ссылка 2

Для тех, кто наткнулся на эту страницу во время поиска в Google, я недавно нашел выводы для этих преобразований для всех 12 внутренних последовательностей вращения Тейта-Брайана (1-2-3, 3-2-1 и т.д.) и правильных последовательностей вращения Эйлера (1-2-1, 3-1-3 и т.д.) В следующих двух ссылках:

Благодаря фродо2975 что касается второй ссылки.

Википедия показывает, как можно использовать части кватерниона и вычислить углы Эйлера.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top