rotacion quaternion octoniones matricial forma euler definicion cuaternios cuaterniones aplicaciones angulos language-agnostic math animation quaternions euler-angles

language agnostic - quaternion - ¿Hay un algoritmo para convertir rotaciones de cuaternión a rotaciones de ángulos de Euler?



octoniones (8)

Aquí hay un artículo que escribí sobre la conversión de un cuaternión a ángulos de Euler.

Enlace 1

También he puesto una cantidad de documentos en este lugar donde se discuten varios aspectos de los cuaterniones, los ángulos de Euler y las matrices de rotación (DCM).

Enlace 2

¿Existe un algoritmo existente para convertir una representación cuaternaria de una rotación en una representación de ángulo de Euler? El orden de rotación para la representación de Euler es conocido y puede ser cualquiera de las seis permutaciones (es decir, xyz, xzy, yxz, yzx, zxy, zyx). He visto algoritmos para una orden de rotación fija (por lo general, el encabezado de la NASA, el banco, la convención del rollo) pero no para una orden de rotación arbitraria.

Además, debido a que hay múltiples representaciones de ángulos de Euler de una sola orientación, este resultado será ambiguo. Esto es aceptable (porque la orientación sigue siendo válida , puede que no sea la que el usuario espera ver), sin embargo, sería aún mejor si hubiera un algoritmo que tomara límites de rotación (es decir, el número de grados de libertad y los límites en cada grado de libertad) en cuenta y produjo la representación de Euler "más sensible" dadas esas limitaciones.

Tengo la sensación de que este problema (o algo similar) puede existir en los dominios de dinámica de cuerpo rígido o IK.

Resuelto: Me acabo de dar cuenta de que podría no estar claro que resolví este problema siguiendo los algoritmos de Ken Shoemake de Graphics Gems. Respondí mi propia pregunta en ese momento, pero se me ocurre que quizás no esté claro que lo hice. Ver la respuesta, a continuación, para más detalles.

Solo para aclarar, sé cómo pasar de un cuaternión a la así llamada representación de '' Tait-Bryan '', lo que yo llamaba la convención de la ''NASA''. Este es un orden de rotación (asumiendo la convención de que el eje ''Z'' está arriba) de zxy. Necesito un algoritmo para todas las órdenes de rotación.

Posiblemente, la solución es tomar la conversión de orden zxy y derivar otras cinco conversiones para las otras órdenes de rotación. Creo que esperaba que hubiera una solución más "general". En cualquier caso, me sorprende que no haya podido encontrar soluciones existentes.

Además, y esto quizás debería ser una pregunta por separado, cualquier conversión (asumiendo un orden de rotación conocido, por supuesto) va a seleccionar una representación de Euler, pero de hecho hay muchas. Por ejemplo, dado un orden de rotación de yxz, las dos representaciones (0,0,180) y (180,180,0) son equivalentes (y producirían el mismo cuaternión). ¿Hay alguna manera de restringir la solución usando límites en los grados de libertad? ¿Como lo haces en IK y la dinámica rígida del cuerpo? es decir, en el ejemplo anterior si solo había un grado de libertad con respecto al eje Z, entonces la segunda representación puede ignorarse.

He rastreado un documento que podría ser un algoritmo en este pdf, pero debo confesar que encuentro que la lógica y las matemáticas son un poco difíciles de seguir. Sin duda, hay otras soluciones por ahí? ¿Es realmente raro el orden de rotación arbitrario? Seguramente, todos los principales paquetes en 3D que permiten la animación esquelética junto con la interpolación de cuaterniones (es decir, Maya, Max, Blender, etc.) deben haber resuelto exactamente este problema.


En un sistema de coordenadas cartesianas diestro con el eje Z apuntando hacia arriba, haz esto:

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


He estado buscando varios días para una solución similar, y finalmente encontré este sitio web que tiene un algoritmo para convertir los cuaterniones en rotaciones arbitrarias de Euler y Tait-Bryan.

Aquí está el enlace: http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

Y aquí está el 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; } }


He publicado mi artículo titulado "Quaternion to Euler Angle Conversion for Arbitrary Rotation Sequence Using Geometric Methods" en mi sitio web en noelhughes.net. También tengo algoritmos para convertir cualquier conjunto de ángulos de Euler a una matriz de coseno de cuaternión y cuaternión hacia / desde la dirección que publicaré este fin de semana. Estos también están en el sitio web de Martin Bakers, aunque son un poco difíciles de encontrar. Busca mi nombre, Noel Hughes, y cuaterniones y deberías encontrarlo.


Lo resuelvo de esta manera:

paso 1 : asegúrese de qué convención para la rotación de Euler desea, por ejemplo, zyx .

paso 2 : calcule la matriz de rotación analítica para la rotación. Por ejemplo, si quieres R ( zyx ),

** R *** zyx * = ** R *** x * ( phi ) * ** R *** y * ( theta ) * ** R *** z * ( psi ), donde se convierten los elementos

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)

paso 3 : mediante la inspección, puede encontrar el pecado o el bronceado para los tres ángulos utilizando los elementos anteriores. En este ejemplo,

tan(phi) = -R23/R33 sin(theta) = -R13 tan(psi) = -R12/R11

paso 4 : calcula la matriz de rotación de tu cuaternión (ver wikipedia ), para los elementos que necesitas para calcular los ángulos como en 3) arriba.

Otras convenciones se pueden calcular utilizando el mismo procedimiento.



Parece un caso clásico de tecnología antigua que se pasa por alto: logré extraer una copia de Graphics Gems IV del garaje y parece que Ken Shoemake no solo tiene un algoritmo para convertir ángulos de Euler de orden de rotación arbitraria , sino que también responde la mayoría de mis otras preguntas sobre el tema. ¡Hurra por los libros! Si tan solo pudiera votar la respuesta del Sr. Shoemake y recompensarlo con puntos de reputación.

Supongo que es una recomendación que cualquier persona que trabaje con ángulos de Euler debería obtener una copia de Graphics Gems IV de su biblioteca local y leer la sección que comienza en la página 222 tendrá que hacer. Tiene que ser la explicación más clara y concisa del problema que he leído aún.

Aquí hay un enlace útil que he encontrado desde - http://www.cgafaq.info/wiki/Euler_angles_from_matrix - Esto sigue el mismo sistema que Shoemake; las 24 permutaciones diferentes del orden de rotación están codificadas como cuatro parámetros separados - eje interno, paridad, repetición y marco - que luego le permiten reducir el algoritmo de 24 casos a 2. Podría ser un wiki útil en general - No había venido a través de ella antes.

Al enlace anterior proporcionado parece estar roto here hay otra copia de "Calcular ángulos de Euler a partir de una matriz de rotación".


Wikipedia muestra cómo puedes usar las partes del cuaternión y calcular los ángulos euler.