std.astro.attitude — Lagefehler, Drehraten, Schwenkzeiten
import std.astro.attitude;
Die Lageseite von std.astro: wie weit ist die Ist-Lage vom Ziel entfernt, wie schnell wird gedreht, wie lange dauert ein Schwenk. Lagen sind Quaternionen, Winkel in Radiant, Raten in rad/s.
→ std.astro (Übersicht) · std.astro.guidance · std.quat · Guide: Kurs und Lage im 3D-Raum
1. Gültigkeit
| Funktion | Rückgabe | Bedeutung |
|---|---|---|
AAttThreshold() | f64 | 1e−12 — unterhalb gilt eine Drehung als „keine„ |
AAttValid(q, eps) | bool | ist q ein Einheitsquaternion (bis auf eps)? |
AAttIsError(q) | bool | ist q der Fehlerwert? |
Eine Lage, die keine Einheitslänge hat, ist keine Drehung — sie skaliert zugleich. Nach jeder Verkettung normalisieren; AAttPropagate tut das selbst.
2. Lagefehler
| Funktion | Rückgabe | Bedeutung |
|---|---|---|
AAttError(qIst, qSoll) | Quat | Fehlerquaternion — die Drehung, die von qIst nach qSoll führt |
AAttErrorAngle(qIst, qSoll) | f64 [rad] | ihr Betrag: wie weit ist es noch? |
AAttErrorAxis(qIst, qSoll) | AVec3 | die Drehachse als Einheitsvektor |
AAttErrorVector(qIst, qSoll) | AVec3 | Achse mal Winkel — die Form, die ein Regler direkt als Stellgröße nimmt |
Der Fehlervektor ist die praktisch wichtigste der vier: sein Betrag ist der Winkel, seine Richtung die Achse, und ein PD-Regler kann ihn unmittelbar mit einem Beiwert multiplizieren. Bei verschwindendem Fehler liefert AAttErrorAxis den Nullvektor statt einer beliebigen Richtung.
3. Drehraten
| Funktion | Rückgabe | Bedeutung |
|---|---|---|
AAngularVelocity(qVon, qNach, dt) | AVec3 [rad/s] | mittlere Winkelgeschwindigkeit, die qVon in dt nach qNach bringt |
AAttPropagate(q, w, dt) | Quat | eine Lage um w·dt weiterdrehen, normalisiert |
AAttRateWithin(w, wMax) | bool | hält die Rate die Grenze ein? |
AAttClampRate(w, wMax) | AVec3 | Rate auf wMax begrenzen, Richtung erhalten |
Zwei Feinheiten, die der Quelltext ausdrücklich benennt:
*AAngularVelocityliefert die mittlere Rate — aus zwei Lagen lässt sich der Verlauf dazwischen nicht bestimmen. Wer eine Momentanrate braucht, muss messen.
*AAttClampRateskaliert den ganzen Vektor. Komponentenweise zu klemmen wäre falsch: das dreht die Achse und damit das Ziel.
4. Schwenkmanöver (Slew)
Ein Schwenk mit begrenzter Rate und begrenzter Beschleunigung hat zwei Formen: dreieckig (beschleunigen, sofort bremsen — wMax wird nie erreicht) und trapezförmig (beschleunigen, halten, bremsen).
| Funktion | Rückgabe | Bedeutung |
|---|---|---|
ASlewTime(winkel, wMax, aMax) | f64 [s] | Dauer; wählt selbst zwischen beiden Formen |
ASlewTriangleLimit(wMax, aMax) | f64 [rad] | bis zu diesem Winkel bleibt es dreieckig: wMax²/aMax |
ASlewPeakRate(winkel, wMax, aMax) | f64 [rad/s] | höchste erreichte Rate — im dreieckigen Fall kleiner als wMax |
ASlewPeakRateist nicht einfachwMax. Bei einem kurzen Schwenk wird die Höchstrate nie erreicht; wer trotzdemwMaxmeldet, überschätzt die Belastung der Aktorik. Im Beispiel unten: 5 Grad Schwenk erreichen 0.707 statt 1.0 Grad/s.
Die beiden Zeitformeln treffen sich an der Dreiecksgrenze exakt — das ist die schärfste Probe der Umsetzung, denn ein Fehler in einem der Zweige bricht die Stetigkeit genau dort.
5. Beispiel
import std.astro.state;
import std.astro.attitude;
import std.quat;
import std.math;
import std.io;
fn zeig(n: pchar, v: f64, d: int64): void { Print(n); PrintLn(FloatToStr(v, d)); }
fn BI(b: bool): int64 { if (b) { return 1; } return 0; }
fn main(): int64 {
var rad: f64 := Pi() / 180.0;
var ist: Quat := QuatIdentity();
var soll: Quat := QuatFromAxisAngle(0.0, 0.0, 1.0, 30.0 * rad);
zeig("Fehlerwinkel Grad : ", AAttErrorAngle(ist, soll) / rad, 2);
var achse: AVec3 := AAttErrorAxis(ist, soll);
Print("Fehlerachse z : "); PrintLn(FloatToStr(achse.z, 3));
var fv: AVec3 := AAttErrorVector(ist, soll);
zeig("Fehlervektor |.| : ", AMagnitude(fv) / rad, 2);
Print("Lage gueltig : "); PrintLn(IntToStr(BI(AAttValid(ist, 0.000001))));
// Rate aus zwei Lagen, 10 s auseinander — und wieder zurueck
var w: AVec3 := AAngularVelocity(ist, soll, 10.0);
zeig("Rate Grad/s : ", AMagnitude(w) / rad, 3);
var neu: Quat := AAttPropagate(ist, w, 10.0);
zeig("Restfehler Grad : ", AAttErrorAngle(neu, soll) / rad, 6);
// Schwenk: 30 Grad bei 1 Grad/s und 0.1 Grad/s^2
zeig("Slewzeit s : ", ASlewTime(30.0*rad, 1.0*rad, 0.1*rad), 2);
zeig("Dreieck bis Grad : ", ASlewTriangleLimit(1.0*rad, 0.1*rad) / rad, 2);
zeig("Spitzenrate Grad/s : ", ASlewPeakRate(30.0*rad, 1.0*rad, 0.1*rad) / rad, 3);
zeig("Slew 5 Grad s : ", ASlewTime(5.0*rad, 1.0*rad, 0.1*rad), 2);
zeig("Spitzenrate dabei : ", ASlewPeakRate(5.0*rad, 1.0*rad, 0.1*rad) / rad, 3);
var schnell: AVec3 := AVec(0.0, 0.0, 3.0 * rad);
Print("Rate im Rahmen? : "); PrintLn(IntToStr(BI(AAttRateWithin(schnell, 1.0*rad))));
zeig("geklemmt Grad/s : ", AMagnitude(AAttClampRate(schnell, 1.0*rad)) / rad, 3);
return 0;
}
Fehlerwinkel Grad : 30.00
Fehlerachse z : 1.000
Fehlervektor |.| : 30.00
Lage gueltig : 1
Rate Grad/s : 3.000
Restfehler Grad : 0.000000
Slewzeit s : 40.00
Dreieck bis Grad : 10.00
Spitzenrate Grad/s : 1.000
Slew 5 Grad s : 14.14
Spitzenrate dabei : 0.707
Rate im Rahmen? : 0
geklemmt Grad/s : 1.000
Die Zeile Restfehler 0.000000 ist die Probe: die aus zwei Lagen gerechnete Rate, über dieselbe Zeitspanne wieder aufintegriert, trifft das Ziel exakt. Rate und Propagation sind also zueinander konsistent.
Der Schwenkvergleich zeigt die zwei Formen: 30 Grad liegen über der Dreiecksgrenze von 10 Grad, also trapezförmig — 40 s bei voller Rate. 5 Grad bleiben darunter: 14.14 s, und die Rate erreicht nur 0.707 Grad/s.
Letzte Aktualisierung: 2026-09-01 — Seite neu angelegt aus std/astro/attitude.lyx (Commit 32353cc, #1900, 83 Prüfungen); Beispiel mit lyxc 1.1.16A gebaut und ausgeführt.
