¿Cómo simular la inestabilidad rotacional?

Estoy tratando de simular (para un juego educativo) el conocido efecto de que los objetos giratorios con tres momentos de inercia desiguales son inestables cuando giran alrededor del eje central.

Algunas explicaciones de este efecto se dan aquí:

La mayor parte de estas matemáticas están, por desgracia, por encima de mi cabeza (aunque lo estoy intentando). Pero para mis propósitos, necesito algo más que "es la forma de un oscilador armónico" o "no es un oscilador armónico"; Necesito reproducir realmente el efecto en la simulación.

Intenté esto usando el motor de física incorporado de Unity aquí:

Puede probarlo usted mismo si tiene (o instala) el complemento Unity gratuito; muestra un bloque de 1x4x7 de densidad uniforme, girando alrededor de su eje central. Con el botón "Poke" puede inducir un pequeño par aleatorio. Tocar el bloque repetidamente puede torcer su eje, pero una vez que dejas de tocarlo, el eje permanece fijo y gira constantemente en cualquier dirección. En ningún caso he podido hacerlo rodar (como se ve en este vídeo de una baraja de cartas, o este de alguna simulación).

Y su falta de caídas tiene mucho sentido para mí. Según tengo entendido, el estado de un cuerpo rígido se define por su posición, velocidad, orientación y velocidad angular. En ausencia de fuerzas externas, la velocidad y la velocidad angular deben permanecer sin cambios. La velocidad angular se puede describir como un eje y una velocidad de rotación. Entonces, sin ninguna fuerza externa actuando sobre él, ¿cómo puede cambiar el eje de rotación?

Claramente, falta algo tanto en mi comprensión intuitiva como en el motor de física dentro de Unity. No te concentres demasiado en lo último; Puedo programar mi propio motor de física, si entiendo lo que debería hacer. ¿Cuál es la parte clave que me falta, que explica cómo (y de qué manera) el eje de rotación puede cambiar sin ninguna fuerza externa? En pseudocódigo, estilo de integración de Euler directo simple, ¿cómo se simularía esto?

El momento angular de un objeto no cambia cuando un objeto cae, pero sí lo hace la orientación real del objeto con respecto al eje alrededor del cual gira. Creo que ha identificado un problema con el motor de física integrado de Unity.
Necesitas tu momento de tensor de inercia para moverte con el objeto. Para un objeto giratorio, los valores instantáneos del momento de inercia a lo largo de X, Y y Z cambian, por lo que la rotación alrededor de X, Y y Z debe cambiar para mantener un momento angular constante. Es por eso que hay caídas.
OK, esto casi tiene sentido. Si pensamos en la rotación como descompuesta en rotaciones individuales alrededor de los ejes X, Y y Z del mundo, entonces sí, la distancia de las diversas partículas en el cuerpo a estos ejes está cambiando, así que (como dices) las tasas de rotación tendría que cambiar para mantener el momento angular. De hecho, el mismo argumento se aplica si usamos el sistema de coordenadas local del objeto: una vez que se perturba el eje de rotación, tendríamos que volver a calcular los momentos de inercia relativos a este nuevo eje. Mmm. Todavía no lo entiendo lo suficientemente bien como para codificarlo, ¡pero me estoy acercando!
He intentado codificar mi comprensión aquí ( forum.unity3d.com/threads/259514 ); También actualicé la demostración web ( luminaryapps.com/temp/RotationDemo ). Parece funcionar, pero estoy un poco inseguro acerca de mi conversión de I_inverse de coordenadas locales a mundiales .

Respuestas (1)

ω = I 1 L , y L es constante en ausencia de fuerzas externas. Lo que creo que te estás perdiendo es que I gira con el cuerpo rígido, por lo que no es constante en general y tampoco lo es ω .

Jugué con su ejemplo en línea, y la velocidad angular parece permanecer siempre constante cuando no estoy empujando el bloque, lo cual es consistente con un tensor de inercia que es un múltiplo escalar de la identidad. Nunca he usado Unity, pero parece admitir tensores de inercia arbitrarios a través de Rigidbody.inertiaTensor y Rigidbody.inertiaTensorRotation , por lo que tal vez solo necesite configurarlos correctamente.

Si termina teniendo que desarrollar su propia física, aquí hay un pseudocódigo ingenuo, no probado y potencialmente incorrecto:

const double time_step = ...;
const Quaternion L = {0, Lx, Ly, Lz};  // angular momentum
const double K1 = 1/I1, K2 = 1/I2, K3 = 1/I3;  // reciprocals of principal-axis moments of inertia; no idea if there's a standard letter for this
Quaternion orientation = {1, 0, 0, 0};
while (1) {
    Quaternion transformed_L = conjugate(orientation) * L * orientation;
    Quaternion transformed_omega = {0, K1 * transformed_L.i, K2 * transformed_L.j, K3 * transformed_L.k};
    Quaternion omega = orientation * transformed_omega * conjugate(orientation);
    orientation = quaternion_exp(time_step * omega) * orientation;
    // ... or orientation = normalize((1 + time_step * omega) * orientation);
    // ... or orientation = normalize((1 + time_step * omega + 0.5 * (time_step * omega)**2) * orientation);
    output(orientation);
}
Esos se configuran automáticamente a partir de la geometría (o se supone que lo son). Ya había comprobado inertiaTensor, y es (54.2, 41.7, 14.2), que coincide con las expectativas. No había comprobado inertiaTensorRotation, pero es el cuaternión de identidad (es decir, sin rotación).
Agregué registros adicionales de estos en otros momentos, y nunca cambian. No estoy seguro ahora si eso se espera o no. Todavía estoy tratando de digerir tu primer comentario anterior.
inertiaTensor se ve bien y debe ser constante. La orientación del tensor debe ser la misma que la orientación del objeto. No puedo decir si inertiaTensorRotation es relativa a la orientación canónica o relativa a la orientación actual del objeto (como se indica en Rigidbody.rotation). En el primer caso, debería ser igual a Rigidbody.rotation. En este último caso debería ser el cuaternión identidad. Así que espero que lo primero sea correcto, ya que de lo contrario no tengo idea de qué está mal.
Después de investigar más, creo que inertiaTensorRotation es relativa a la rotación actual del objeto, y que sea una identidad es normal. Aunque solo por diversión, intenté establecerlo igual a Rigidbody.rotation en cada cuadro de física. Esto hace que el motor de física se asuste un poco de otras maneras (en realidad, traduciendo el objeto periódicamente), pero aún así no causa ninguna caída en el eje de rotación. Pero creo que esto es abusar del sistema; no creo que esté destinado a que inertiaTensorRotation cambie durante la simulación.
Por cierto, aprendí que Unity usa el motor Nvidia Physx, documentado (ligeramente) aquí ( docs.nvidia.com/gameworks/content/gameworkslibrary/physx/… ). En lugar de la matriz de tensor de inercia habitual de 3x3, mantienen solo la diagonal de esta matriz y dicen: "Si tiene una matriz de tensor de inercia no diagonal, debe diagonalizarla y establecer una transformación de espacio de masa apropiada". Creo que esto es para lo que sirve inertiaTensorRotation. Ah, y todos estos son relativos al sistema de coordenadas del objeto, por lo que no es sorprendente que sean constantes.
Terminé codificando mi propia física, no exactamente como se muestra, pero en la misma línea. ¡Gracias por señalarme en la dirección correcta! Voy a marcar esto como la respuesta aceptada.