Domanda

Esiste un algoritmo esistente per convertire una rappresentazione quaternione di una rotazione in una rappresentazione dell'angolo di Eulero? L'ordine di rotazione per la rappresentazione di Eulero è noto e può essere una qualsiasi delle sei permutazioni (cioè xyz, xzy, yxz, yzx, zxy, zyx). Ho visto algoritmi per un ordine di rotazione fisso (di solito l'intestazione della NASA, la banca, la convenzione di lancio) ma non per l'ordine di rotazione arbitrario.

Inoltre, poiché esistono più rappresentazioni dell'angolo di Eulero di un singolo orientamento, questo risultato sarà ambiguo. Questo è accettabile (poiché l'orientamento è ancora valido , potrebbe non essere quello che l'utente si aspetta di vedere), tuttavia sarebbe ancora meglio se esistesse un algoritmo che ha preso limiti di rotazione (es. il numero di gradi di libertà e i limiti di ciascun grado di libertà) in considerazione e ha prodotto la rappresentazione di Eulero "più sensata" dati questi vincoli.

Ho la sensazione che questo problema (o qualcosa di simile) possa esistere nei domini IK o delle dinamiche del corpo rigido.


Risolto: Ho appena realizzato che potrebbe non essere chiaro che ho risolto questo problema seguendo gli algoritmi di Ken Shoemake di Graphics Gems. Ho risposto alla mia domanda in quel momento, ma mi viene in mente che potrebbe non essere chiaro che l'ho fatto. Vedi la risposta, di seguito, per maggiori dettagli.


Giusto per chiarire: so come convertire da quaternione al cosiddetto ' Tait- Bryan "rappresentanza - quella che stavo chiamando la convenzione" NASA ". Questo è un ordine di rotazione (supponendo che l'asse 'Z' sia in alto) di zxy. Ho bisogno di un algoritmo per tutti ordini di rotazione.

Probabilmente la soluzione, quindi, è quella di prendere la conversione dell'ordine zxy e ricavarne altre cinque conversioni per gli altri ordini di rotazione. Immagino che sperassi ci fosse una soluzione più "generale". In ogni caso, sono sorpreso di non essere stato in grado di trovare soluzioni esistenti là fuori.

Inoltre, e questa forse dovrebbe essere una domanda separata, qualsiasi conversione (presupponendo un ordine di rotazione noto, ovviamente) selezionerà una rappresentazione di Eulero, ma in realtà ce ne sono molte. Ad esempio, dato un ordine di rotazione di yxz, le due rappresentazioni (0,0,180) e (180,180,0) sono equivalenti (e produrrebbe lo stesso quaternione). Esiste un modo per vincolare la soluzione usando limiti sui gradi di libertà? Come fai in IK e dinamiche del corpo rigido? vale a dire nell'esempio sopra se ci fosse un solo grado di libertà attorno all'asse Z, la seconda rappresentazione può essere ignorata.


Ho rintracciato un documento che potrebbe essere un algoritmo in questo pdf ma devo confessare che trovo la logica e la matematica un po 'difficili da seguire. Sicuramente ci sono altre soluzioni là fuori? L'ordine di rotazione arbitraria è davvero così raro? Sicuramente ogni importante pacchetto 3D che consente l'animazione scheletrica insieme all'interpolazione di quaternioni (cioè Maya, Max, Blender, ecc.) Deve aver risolto esattamente questo problema?

È stato utile?

Soluzione

Sembra un classico caso di vecchia tecnologia trascurata: sono riuscito a estrarre una copia di Graphics Gems IV dal garage e sembra che Ken Shoemake non abbia solo un algoritmo per la conversione da angoli di Eulero di arbitrario ordine di rotazione, ma risponde anche alla maggior parte delle mie altre domande sull'argomento. Evviva per i libri. Se solo potessi votare la risposta del signor Shoemake e premiarlo con punti reputazione.

Immagino che chiunque lavori con gli angoli di Eulero dovrebbe ottenere una copia di Graphics Gems IV dalla propria biblioteca locale e leggere la sezione che inizia a pagina 222. Deve essere la spiegazione più chiara e concisa del problema che ho letto ancora.


Ecco un link utile che ho trovato da - http://www.cgafaq.info/wiki/Euler_angles_from_matrix - Questo segue lo stesso sistema di Shoemake; le 24 diverse permutazioni dell'ordine di rotazione sono codificate come quattro parametri separati - asse interno, parità, ripetizione e frame - che quindi consente di ridurre l'algoritmo da 24 casi a 2. Potrebbe essere un wiki utile in generale - Non ero venuto attraverso prima.

Al vecchio link fornito sembra essere rotto qui è un'altra copia di "Calcolo degli angoli di Eulero da una matrice di rotazione & Quot;.

Altri suggerimenti

In un sistema di coordinate cartesiane destrorso con l'asse Z rivolto verso l'alto, procedere come segue:

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

Ho cercato per diversi giorni una soluzione simile e alla fine mi sono imbattuto in questo sito Web che ha un algoritmo per convertire quaternioni in rotazioni arbitrarie di Eulero e Tait-Bryan!

Ecco il link: http://bediyap.com/programming/convert -quaternion-to-Euler-rotazioni /

Ed ecco il codice:

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

Ho pubblicato il mio documento intitolato "Conversione da quaternione ad angolo di Eulero per la sequenza di rotazione arbitraria usando metodi geometrici" sul mio sito web all'indirizzo noelhughes.net. Ho anche algoritmi per convertire qualsiasi set di angoli di Eulero in un quaternione e quaternione in / dalla direzione della matrice coseno che posterò questo fine settimana. Questi sono anche sul sito Web di Martin Bakers, anche se un po 'difficile da trovare. Google mi chiamo Noel Hughes e quaternioni e dovresti trovarlo.

Lo risolvo in questo modo:

passaggio 1 : assicurati di quale convenzione per la rotazione di Eulero desideri, per esempio, zyx .

passaggio 2 : calcola la matrice di rotazione analitica per la rotazione. Ad esempio, se si desidera R ( zyx ),

** R *** zyx * = ** R *** x * ( phi ) * ** R *** y * ( theta ) * ** R *** z * ( psi ), dove gli elementi diventano

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) 

passaggio 3 : dall'ispezione, puoi trovare il peccato o l'abbronzatura per i tre angoli usando gli elementi sopra. In questo esempio,

tan(phi) = -R23/R33

sin(theta) = -R13

tan(psi) = -R12/R11

passaggio 4 : calcola la matrice di rotazione dal tuo quaternione (vedi wikipedia ), per gli elementi necessari per calcolare gli angoli come in 3) sopra.

Altre convenzioni possono essere calcolate usando la stessa procedura.

Ecco un documento che ho scritto sulla conversione di un quaternione in angoli di Eulero.

Link 1

Ho anche messo un certo numero di documenti in questa posizione che discutono vari aspetti di quaternioni, angoli di Eulero e matrici di rotazione (DCM).

Link 2

Per quelli che inciampano in questa pagina mentre googling, di recente ho trovato derivazioni per queste conversioni per tutti i 12 intrinseci Tait-Bryan (1-2-3, 3-2-1, ecc.) e Eulero corretto (1-2 -1, 3-1-3, ecc.) Sequenze di rotazione nei seguenti due riferimenti:

Grazie a frodo2975 per il secondo link.

Wikipedia mostra come utilizzare le parti del quaternione e calcolare gli angoli di eulero.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top