2009-06-23 23 views
26

Esiste un algoritmo esistente per convertire una rappresentazione di 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 la direzione della NASA, banca, convenzione di rotolamento) ma non per ordine di rotazione arbitrario.Esiste un algoritmo per convertire le rotazioni di quaternioni in rotazioni di Eulero?

Inoltre, poiché ci sono più rappresentazioni dell'angolo di Eulero di un singolo orientamento, questo risultato sarà ambiguo. Questo è accettabile (perché l'orientamento è ancora valido, potrebbe non essere proprio quello che l'utente si aspetta di vedere), tuttavia sarebbe ancora meglio se ci fosse un algoritmo che ha preso i limiti di rotazione (cioè il numero di gradi di in considerazione della libertà e dei limiti di ogni grado di libertà) e ha fornito la rappresentazione "più ragionevole" di Eulero a fronte di tali vincoli.

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


risolto: Ho appena realizzato che potrebbe non essere chiaro che ho risolto questo problema seguendo algoritmi di Ken Shoemake dalla grafica gemme. All'epoca ho risposto alla mia domanda, ma a me capita che non sia chiaro che l'ho fatto. Vedere la risposta, sotto, per maggiori dettagli.


Giusto per chiarire - io so come convertire da un quaternione al cosiddetto 'Tait-Bryan' rappresentazione - quello che mi stava chiamando la convenzione 'NASA'. Questo è un ordine di rotazione (assumendo la convenzione che l'asse 'Z' è attivo) di zxy. Ho bisogno di un algoritmo per tutti gli ordini di rotazione.

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

Inoltre, e questo forse dovrebbe essere una questione separata del tutto, qualsiasi conversione (supponendo un ordine rotazione nota, ovviamente) sta per selezionare una rappresentazione Eulero, ma ci sono infatti molti. Ad esempio, dato un ordine di rotazione di yxz, le due rappresentazioni (0,0,180) e (180,180,0) sono equivalenti (e darebbero lo stesso quaternione). C'è un modo per limitare la soluzione usando limiti sui gradi di libertà? Come fai in IK e le dinamiche del corpo rigido? Nell'esempio precedente, se vi fosse solo un grado di libertà attorno all'asse Z, la seconda rappresentazione può essere ignorata.


ho rintracciato un articolo che potrebbe essere un algoritmo in this pdf ma devo confessare che trovo la logica e la matematica un po 'difficile da seguire. Sicuramente ci sono altre soluzioni là fuori? L'ordine di rotazione arbitraria è davvero così raro? Sicuramente tutti i principali pacchetti 3D che consentono l'animazione scheletrica insieme all'interpolazione di quaternioni (ad esempio Maya, Max, Blender, ecc.) Devono aver risolto esattamente questo problema?

+0

Le persone di solito sono abbastanza pigre da cercare di conformarsi ad un tipo di standard. La mia ipotesi non istruita sarebbe quindi che difficilmente riusciresti a trovare una fonte per più di due o tre delle diverse permutazioni. –

+0

Si potrebbe cercare qualcos'altro, poiché gli angoli di Eulero ha una rappresentazione numerica infinita per ogni soluzione. –

+0

Vorrei _love_ non essere costretto a utilizzare gli angoli di Eulero per la rappresentazione, ma per il dominio in cui sto lavorando (animazione 3D) sono il modo standard in cui presentare le rotazioni all'utente. E a causa del problema inerente a loro (blocco cardanico, ecc.) È necessario che anche l'ordine di rotazione sia modificabile. –

risposta

13

Questo appare come un classico caso di vecchia tecnologia essere trascurato - sono riuscito a scavare una copia di grafiche Gems IV dal garage e sembra che Ken Shoemake abbia non solo un algoritmo per convertire da Eulero gli angoli dell'ordinativo 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 una raccomandazione che chiunque lavori con gli angoli di Eulero debba ottenere una copia di Graphics Gems IV dalla loro libreria locale e leggere la sezione che inizia a pagina 222 dovrà fare. Deve essere la spiegazione più chiara e concisa del problema che ho letto.


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

Per vecchio link fornito sembra essere rotto here è un'altra copia di "angoli di Eulero Computing da una matrice di rotazione ".

+1

(al momento della stesura di questo documento) il link cgafaq.info è morto. [webarchive] (http://web.archive.org/web/20110722193627/http://cgafaq.info/wiki/Euler_angles_from_matrix) è il meglio che ho potuto trovare. –

+1

Non riesco a sospenderlo abbastanza. Sto usando l'algoritmo di Shoemake per 5 anni, è davvero grandioso. È efficiente e completamente flessibile, implementando tutte le 24 combinazioni possibili di Eulero/Tait-Bryan e gestisce sia i frame di riferimento rotanti che stazionari. –

+0

Ho inventato autonomamente quello che risultò essere qualcosa di molto simile all'algoritmo di Shoemake. Il mio supervisore voleva che lo pubblicassi. Ho fatto qualche ricerca, ed è stato allora che ho trovato l'algoritmo di Shoemake. Nessuna carta Qualcuno ha portato il mio codice su Java; lo puoi ancora trovare su http://uahuntsville-siso-smackdown.googlecode.com/svn-history/r3/trunk/ez/siso/smackdown/utilities/EulerAngles.java (fino a quando il codice google si spegne a gennaio 2016). –

2

Wikipedia mostra come è possibile utilizzare le parti del quaterio e calcolare gli angoli di Eulero.

+1

Lo fa per i cosiddetti angoli di Tait-Bryan [http://en.wikipedia.org/wiki/Tait-Bryan_angles] ma non c'è alcun riferimento al fatto che gli angoli di Eulero possano avere altri ordini di rotazione. –

+0

Il semplice post di un link non è un contributo significativo – bobobobo

10

In un sistema di coordinate destrorso cartesiano con asse Z rivolto verso l'alto, fare questo:

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

Sì, questo usa la convenzione NASA: imbardata, beccheggio e rullata (o intestazione, beccheggio e rollio se lo si desidera). Questo sarebbe (assumendo il tuo cartesiano destrorso con Z in alto) un ordine di rotazione di zxy. Sto cercando un algoritmo che gestisce xyz, xzy, yxz, yzx, zxy e zyx. Forse l'unica opzione è di fornire essenzialmente sei diverse conversioni, derivate da quella che hai dato? E ci sarebbe un modo per estendere questo approccio in modo che i limiti comuni e i gradi di libertà possano essere usati per ottenere una rappresentazione di Eulero non ambigua? –

+0

Usando la mia interpretazione di "non ambiguo" la risposta breve è "no". :) –

+0

E se tenessi conto dei limiti comuni? Ad esempio, se si finiscono con due possibili rappresentazioni di Eulero, una di queste può essere eliminata perché è al di fuori del raggio di movimento di un particolare giunto. Non dovresti risolvere questo problema quando si genera l'animazione scheletrica dai dati di acquisizione del movimento? –

3

Ho pubblicato il mio documento intitolato "Quaternion to Euler Angle Conversion per la sequenza di rotazione arbitraria mediante metodi geometrici" sul mio sito web all'indirizzo noelhughes.net. Ho anche algoritmi per convertire qualsiasi insieme di angoli di Eulero in un quaternione e quaternione in/da una matrice di coseno di direzione che posterò questo fine settimana. Questi sono anche sul sito di Martin Bakers, anche se un po 'difficili da trovare. Google il mio nome, Noel Hughes e quaternioni e dovresti trovarlo.

3

ho risolto in questo modo:

passo 1: Assicurarsi che convenzione per la rotazione di Eulero si desidera, ad esempio, ZYX.

passaggio 2: calcolare la matrice di rotazione analitica per la rotazione. Per 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) 

fase 3: Con un controllo, è possibile trovare il peccato o marrone per i tre angoli utilizzando gli elementi sopra. In questo esempio,

tan(phi) = -R23/R33 

sin(theta) = -R13 

tan(psi) = -R12/R11 

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

Altre convenzioni possono essere calcolate utilizzando la stessa procedura.

3

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

Link 1

ho anche mettere un numero di documenti in questa posizione discutere vari aspetti di quaternioni, angoli di Eulero e matrici di rotazione (DCM).

Link 2

4

Ho cercato per diversi giorni per una soluzione simile, e alla fine ho sono imbattuto in questo sito che ha un algoritmo per la conversione quaternioni arbitrariamente Eulero e rotazioni Tait-Bryan!

ecco il link: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

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

Per coloro che inciampare su questa pagina, mentre usare Google, di recente ho trovato derivazioni per queste conversioni per tutti i 12 intrinseco Tait-Bryan (1-2-3, 3-2-1, etc.) e Proper Eulero (1-2-1, 3-1-3, ecc) sequenze di rotazione nei due seguenti riferimenti:

Grazie a frodo2975 per il secondo collegamento.

Problemi correlati