Inhaltsverzeichnis

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:

* AAngularVelocity liefert die mittlere Rate — aus zwei Lagen lässt sich der Verlauf dazwischen nicht bestimmen. Wer eine Momentanrate braucht, muss messen.
* AAttClampRate skaliert 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
 
ASlewPeakRate ist nicht einfach wMax. Bei einem kurzen Schwenk wird die Höchstrate nie erreicht; wer trotzdem wMax meldet, ü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.