Wie simuliert man Rotationsinstabilität?

Ich versuche (für ein Lernspiel) den bekannten Effekt zu simulieren, dass rotierende Objekte mit drei ungleichen Trägheitsmomenten instabil werden, wenn sie um die Mittelachse gedreht werden.

Einige Erklärungen zu diesem Effekt finden Sie hier:

Das meiste dieser Mathematik geht leider über meinen Kopf (obwohl ich es versuche). Aber für meine Zwecke brauche ich mehr als nur „ist die Form eines harmonischen Oszillators“ oder „ist kein harmonischer Oszillator“; Ich muss den Effekt tatsächlich in der Simulation reproduzieren.

Ich habe dies mit der integrierten Physik-Engine von Unity hier versucht:

Sie können es selbst ausprobieren, wenn Sie das kostenlose Unity-Plugin haben (oder installieren); es zeigt einen 1x4x7-Block mit einheitlicher Dichte, der sich um seine Mittelachse dreht. Mit der "Poke"-Taste können Sie ein kleines zufälliges Drehmoment induzieren. Wiederholtes Stoßen des Blocks kann seine Achse schief schlagen – aber sobald Sie aufhören, ihn zu stoßen, bleibt die Achse an Ort und Stelle und dreht sich stetig um die jeweilige Richtung. Unter keinen Umständen konnte ich es zum Fallen bringen (wie in diesem Video eines Kartenspiels oder in diesem einer Simulation zu sehen).

Und sein Mangel an Taumeln macht für mich absolut Sinn. So wie ich es verstehe, wird der Zustand eines starren Körpers durch seine Position, Geschwindigkeit, Orientierung und Winkelgeschwindigkeit definiert. Ohne äußere Kräfte sollten Geschwindigkeit und Winkelgeschwindigkeit unverändert bleiben. Die Winkelgeschwindigkeit kann als Achse und Rotationsgeschwindigkeit beschrieben werden. Wie kann sich also die Rotationsachse ändern, ohne dass äußere Kräfte darauf einwirken?

Offensichtlich fehlt sowohl meinem intuitiven Verständnis als auch der Physik-Engine in Unity etwas. Konzentrieren Sie sich nicht zu sehr auf Letzteres; Ich kann meine eigene Physik-Engine programmieren, wenn ich verstehe, was sie tun soll. Was ist der Schlüssel, den ich vermisse, der erklärt, wie (und auf welche Weise) sich die Rotationsachse ohne äußere Kraft ändern kann? Wie würde man dies in Pseudocode simulieren, einfacher Vorwärts-Euler-Integrationsstil?

Der Drehimpuls eines Objekts ändert sich nicht, wenn ein Objekt taumelt, aber die tatsächliche Ausrichtung des Objekts in Bezug auf die Achse, um die sich das Objekt dreht, ändert sich. Ich glaube, Sie haben ein Problem mit der integrierten Physik-Engine von Unity identifiziert.
Sie benötigen Ihren Trägheitstensor, um sich mit dem Objekt zu bewegen. Bei einem rotierenden Objekt ändern sich die Momentanwerte des Trägheitsmoments entlang X, Y und Z, und daher muss sich die Drehung um X, Y und Z ändern, um einen konstanten Drehimpuls aufrechtzuerhalten. Deshalb gibt es Taumeln.
OK, das ergibt fast Sinn. Wenn wir uns die Rotation zerlegt in einzelne Rotationen um die X-, Y- und Z-Achsen der Welt vorstellen, dann ja, der Abstand der verschiedenen Teilchen im Körper zu diesen Achsen ändert sich, also (wie Sie sagen) die Rotationsraten müsste sich ändern, um den Drehimpuls aufrechtzuerhalten. In diesem Zusammenhang gilt dasselbe Argument, wenn wir das lokale Koordinatensystem des Objekts verwenden: Sobald die Rotationsachse gestört ist, müssten wir die Trägheitsmomente relativ zu dieser neuen Achse neu berechnen. Hmm. Ich verstehe es noch nicht gut genug, um es zu codieren, aber ich komme näher!
Ich habe versucht, mein Verständnis hier zu verschlüsseln ( forum.unity3d.com/threads/259514 ); Ich habe auch die Webdemo aktualisiert ( luminaryapps.com/temp/RotationDemo ). Es scheint zu funktionieren, aber ich bin mir etwas unsicher über meine Konvertierung von I_inverse von lokalen in Weltkoordinaten.

Antworten (1)

ω = ICH 1 L , Und L ist ohne äußere Kräfte konstant. Das bisschen, was ich denke, dass Sie vermissen, ist das ICH dreht sich mit dem starren Körper, ist also im Allgemeinen nicht konstant und ist es auch nicht ω .

Ich habe mit Ihrem Online-Beispiel gespielt, und die Winkelgeschwindigkeit scheint immer konstant zu bleiben, wenn ich nicht in den Block stoße, was mit einem Trägheitstensor übereinstimmt, der ein skalares Vielfaches der Identität ist. Ich habe Unity noch nie verwendet, aber es scheint beliebige Trägheitstensoren über Rigidbody.inertiaTensor und Rigidbody.inertiaTensorRotation zu unterstützen , also müssen Sie diese vielleicht nur richtig einstellen.

Wenn Sie am Ende Ihre eigene Physik würfeln müssen, hier ist ein naiver, ungetesteter und möglicherweise falscher Pseudocode:

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);
}
Diese werden automatisch aus der Geometrie gesetzt (oder sollen). Ich hatte bereits inertiaTensor überprüft, und es ist (54,2, 41,7, 14,2), was den Erwartungen entspricht. Ich hatte inertiaTensorRotation nicht überprüft, aber es ist die Identitätsquaternion (dh keine Rotation).
Ich habe diese zu anderen Zeiten zusätzlich protokolliert, und sie ändern sich nie. Ich bin mir jetzt nicht sicher, ob das erwartet wird oder nicht. Ich versuche immer noch, Ihren ersten Kommentar oben zu verdauen.
inertiaTensor sieht gut aus und sollte konstant sein. Die Ausrichtung des Tensors sollte dieselbe sein wie die Ausrichtung des Objekts. Ich kann nicht sagen, ob inertiaTensorRotation relativ zur kanonischen Ausrichtung oder relativ zur aktuellen Ausrichtung des Objekts (wie durch Rigidbody.rotation angegeben) ist. Im ersteren Fall sollte es gleich Rigidbody.rotation sein. Im letzteren Fall sollte es die Identitätsquaternion sein. Also hoffe ich, dass ersteres richtig ist, da ich sonst keine Ahnung habe, was falsch ist.
Nach mehr Graben glaube ich, dass inertiaTensorRotation relativ zur aktuellen Rotation des Objekts ist und dass es normal ist, dass es Identität ist. Obwohl nur aus Spaß, habe ich versucht, es gleich der Rigidbody.rotation auf jedem Physik-Frame einzustellen. Dies führt dazu, dass die Physik-Engine auf andere Weise ein wenig ausrastet (das Objekt tatsächlich periodisch verschiebt ), aber immer noch kein Taumeln in der Rotationsachse verursacht. Aber ich denke, das missbraucht das System – ich glaube nicht, dass es beabsichtigt ist, dass sich inertiaTensorRotation während der Simulation ändert.
Übrigens habe ich erfahren, dass Unity die Nvidia Physx-Engine verwendet, die hier (dünn) dokumentiert ist ( docs.nvidia.com/gameworks/content/gameworkslibrary/physx/… ). Anstelle der üblichen 3x3-Trägheitstensormatrix behalten sie nur die Diagonale dieser Matrix bei und sagen: "Wenn Sie eine nicht diagonale Trägheitstensormatrix haben, müssen Sie sie diagonalisieren und eine geeignete Massenraumtransformation festlegen." Ich glaube, dafür ist inertiaTensorRotation da. Oh, und diese sind alle relativ zum Koordinatensystem des Objekts, also ist es nicht verwunderlich, dass sie konstant sind.
Am Ende habe ich meine eigene Physik codiert, nicht genau wie gezeigt, aber in die gleiche Richtung. Danke, dass du mich in die richtige Richtung weist! Ich werde dies als akzeptierte Antwort markieren.