Pergunta

Existe um algoritmo existente para converter uma representação quaternion de uma rotação para uma representação ângulo de Euler? A ordem de rotação para a representação de Euler é conhecido e pode ser qualquer um dos seis permutações (isto é xyz, xzy, YXZ, YZX, ZXY, ZYX). Eu vi algoritmos para uma ordem de rotação fixo (normalmente o título NASA, banco, convenção rolo), mas não para a ordem de rotação arbitrária.

Além disso, porque há múltiplas representações ângulo Euler de uma única orientação, este resultado vai ser ambíguo. Isto é aceitável (porque a orientação ainda é válido , ele só pode não ser o que o usuário está esperando para ver), no entanto, seria ainda melhor se houvesse um algoritmo que teve limites de rotação (ou seja, o número de graus de liberdade e os limites de cada grau de liberdade) em conta e que produziu o 'sensível mais' representação Euler dado essas limitações.

Tenho a sensação este problema (ou algo similar) podem existir nos domínios IK ou dinâmica de corpo rígido.


Resolvido: Eu só percebi que ele pode não ser claro que eu resolver esse problema seguindo os algoritmos do Ken shoemake a partir de gráficos Gems. Eu não respondeu minha pergunta no momento, mas ocorre-me que pode não ser claro que eu fiz isso. Veja a resposta, abaixo, para mais detalhes.


Só para esclarecer - Eu sei como converter de um quaternion para o chamado ' Tait- Bryan ' representação - o que eu estava chamando a "convenção da NASA. Esta é uma ordem de rotação (assumindo a convenção de que o eixo 'Z' é acima) de ZXY. Eu preciso de um algoritmo para todas ordens de rotação.

Possivelmente, a solução, então, é fazer a conversão fim ZXY e dela derivam cinco outras conversões para as outras ordens de rotação. Eu acho que eu estava esperando que houvesse uma solução mais 'overarching'. Em qualquer caso, eu estou surpreso que eu não tenha sido capaz de encontrar soluções existentes lá fora.

Além disso, e este talvez deve ser uma questão em separado completamente, qualquer conversão (assumindo uma ordem de rotação conhecido, é claro) vai selecionar um representação Euler, mas há de fato muitos. Por exemplo, dada uma ordem de rotação YXZ, as duas representações (0,0,180) e (180,180,0) são equivalentes (e iria produzir o mesmo Quatérnion). Existe uma maneira para restringir a solução usando limites sobre os graus de liberdade? Assim como você faz em IK e dinâmica de corpo rígido? isto é, no exemplo acima, se houvesse apenas um grau de liberdade sobre o eixo Z, em seguida, a segunda representação pode ser ignorada.


Eu rastreou um papel que poderia ser um algoritmo em este pdf mas devo confessar que eu encontrar a lógica e matemática um pouco difícil de seguir. Certamente existem outras soluções lá fora? É ordem de rotação arbitrária realmente tão raro? Certamente cada grande pacote 3D que permite animação esquelética em conjunto com interpolação quaternion (ou seja, Maya, Max, Blender, etc) deve ter resolvido exatamente este problema?

Foi útil?

Solução

Isto parece um caso clássico de estar velha tecnologia esquecido - eu consegui desenterrar uma cópia do Gráficos Gems IV da garagem e parece que Ken Shoemake não só tem um algoritmo para conversão de ângulos de Euler de arbitrária ordem de rotação, mas também responde a maioria das minhas outras perguntas sobre o assunto. Hooray para os livros. Se eu pudesse votar-se a resposta do Sr. Shoemake e recompensá-lo com pontos de reputação.

Eu acho que uma recomendação que o trabalho qualquer pessoa com ângulos de Euler deve obter uma cópia do Gráficos Gems IV a partir de sua biblioteca local e ler a seção a partir da página 222 terá que fazer. Tem que ser o mais claro e mais explicação concisa do problema Eu li ainda.


Aqui está um link útil que eu encontrei uma vez - http://www.cgafaq.info/wiki/Euler_angles_from_matrix - Isso segue o mesmo sistema que Shoemake; os 24 diferentes permutações de ordem de rotação são codificados como quatro parâmetros separados - eixo interior, paridade, repetição e quadro - que, em seguida, permite reduzir o algoritmo de 24 casos a 2. Poderia ser um wiki útil em geral - eu não tivesse vindo através dele antes.

Para ligação de idade forneceu parece estar quebrado aqui é uma outra cópia de "Computing ângulos de Euler de uma matriz de rotação ".

Outras dicas

Em um sistema destro de coordenadas cartesianas com eixo Z apontando para cima, faça o seguinte:

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));
    }
}

Eu estive procurando por vários dias para uma solução semelhante, e eu finalmente correu por este site que tem um algoritmo para converter quaternions para arbitrárias Euler e Tait-Bryan rotações!

Aqui está o link: http://bediyap.com/programming/convert -quaternion-to-Euler-rotações /

E aqui está o código:

///////////////////////////////
// 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;
   }
}

Tenho postado meu artigo intitulado "Quaternion a conversão Ângulo de Euler para a rotação arbitrária Seqüência Usando métodos geométricos" no meu site em noelhughes.net. Eu também tenho algoritmos para a conversão de qualquer conjunto de ângulos de Euler a um quaternion e quaternion de / para a matriz de co-seno direção que eu vou postar este fim de semana. Estes também estão no site Martin Bakers, embora um pouco difícil de encontrar. Google meu nome, Noel Hughes, e quaternions e você deve encontrá-lo.

Eu resolvê-lo desta maneira:

etapa 1 : Certifique-se de que convenção para rotação Euler quiser, digamos, zyx .

etapa 2 : Compute a matriz de rotação analítica para a rotação. Por exemplo, se você quer R ( zyx ),

** R *** zyx * = ** R *** x * ( phi ) * ** R *** y * ( theta ) * ** R *** z * ( psi ), onde os elementos se tornam

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) 

etapa 3 : Por inspeção, você pode encontrar o pecado ou tan para os três ângulos usando os elementos acima referidos. Neste exemplo,

tan(phi) = -R23/R33

sin(theta) = -R13

tan(psi) = -R12/R11

etapa 4 : Compute a matriz de rotação do seu quaternion (veja wikipedia ), para os elementos que você precisa para calcular os ângulos como em 3) acima.

Outras convenções pode ser calculado usando o mesmo procedimento.

Aqui está um artigo que escrevi sobre a conversão de um quaternion para ângulos de Euler.

Link 1

Eu também colocar um número de documentos neste local discutindo vários aspectos da quaternions, ângulos de Euler e matrizes de rotação (DCM).

Link 2

Para aqueles que tropeçar em cima desta página enquanto Googling, eu encontrei recentemente derivações para essas conversões para todos os 12 intrínseca Tait-Bryan (1-2-3, 3-2-1, etc.) e Euler adequada (1-2 -1, 3-1-3, etc) sequências de rotação nas duas referências seguintes:

Graças à frodo2975 para o segundo link.

Wikipédia mostra como você pode usar as partes do quaternion e calcular os ângulos de Euler.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top