Künstlicher Horizontindikator auf HTML5-Leinwand

Im Folgenden wird eine Implementierung einer der ungewöhnlichen Ideen zur Visualisierung der räumlichen Position eines kontrollierten Objekts mittels HTML5 vorgestellt. Der Code kann in Browsergames verwendet werden, die das Fahren im dreidimensionalen Raum simulieren. Die Art der Darstellung von Informationen konzentriert sich auf Simulatoren von Subterinen oder anderen fantastischen Maschinen.







Zweck und Umfang des künstlichen Horizonts



Ein künstlicher Horizont im engeren Sinne ist eine Visualisierung der Neigung eines Objekts relativ zur lokalen Vertikalen, die zur Steuerung seiner Bewegung verwendet wird. Die Steigung wird durch die Werte der beiden Euler-Winkel Roll und Pitch definiert . Segler bevorzugen das Synonym "Trim" gegenüber dem Luftfahrtbegriff "Pitch".



Bezogen auf den künstlichen Horizont (aber nicht ganz synonym) russischsprachige Begriffe: "künstlicher Horizont", "Flugbefehlsgerät". Im Englischen werden die Ausdrücke "Lageindikator" , "künstlicher Horizont" oder "Kreiselhorizont" verwendet .



Bekannte Visualisierungstechniken



Die meisten Arbeiten zur Suche nach erfolgreichen Lösungen im Bereich der Pitch-and-Roll-Anzeige wurden im Interesse der Luftfahrt durchgeführt. Dafür gibt es eine einfache Erklärung: Der Pilot muss Informationen schnell lesen, und jeder Fehler in seiner Wahrnehmung des Weltraums droht tödlich zu werden.



Die meisten bekannten Lösungen auf dem Gebiet der Roll- und Nickanzeige basieren auf der Verwendung einer Flugzeugsilhouette und eines speziellen Hintergrunds. Allgemeine Merkmale:



  • Der Hintergrund ist durch eine Linie, die den Horizont darstellt, in zwei Teile unterteilt, die Himmel und Erde symbolisieren.
  • Die Silhouette des Flugzeugs ist eine vereinfachte Rückansicht, die sich farblich vom Hintergrund abhebt.
  • Der Rollwinkel wird vom Indikator als Winkel zwischen der symbolischen Horizontlinie und der Verbindungslinie zwischen den Flügelspitzen der Silhouette bestimmt (normalerweise ist eine Referenzskala zum genauen Ablesen vorhanden).
  • Der Nickwinkel wird entlang einer Skala senkrecht zum bedingten Horizont gemäß der Position des Kontrollpunkts in der Mitte der Silhouette gemessen.






In der Massenproduktion implementierte Systeme haben eine Reihe gemeinsamer Lösungen:



  • Informationen werden durch die relative Position der Silhouette und des Hintergrunds gegeben;
  • Die Änderung des Rollwinkels ist mit der Winkelbewegung der Silhouette relativ zum Hintergrund verbunden.
  • Die Änderung des Nickwinkels ist mit der linearen Verschiebung der Silhouette relativ zum Hintergrund verbunden.


Es ist jedoch nicht schwer zu erraten, dass die gewünschte Relativbewegung auf verschiedene Arten realisiert werden kann. Nach vielen Versuchen und Irrtümern des letzten Jahrhunderts hat die Luftfahrtentwicklung zwei brauchbare Kombinationen hinterlassen:



1. Feste Silhouette, Bewegung im Roll- und Pitch-Hintergrund. Verwendete Namen: "direkte Anzeige", "Blick vom Flugzeug auf den Boden", seltener "egozentrische Anzeige".







2. Eine Silhouette, die sich nur entlang der Rolle bewegt, ein Hintergrund, der sich nur entlang der Tonhöhe bewegt. Verwendete Namen: "umgekehrte Anzeige" und "Blick vom Boden zum Flugzeug", seltener "geozentrische Anzeige".







Beachten Sie, dass die Namen von Abschnitt 2 für das gesamte System gelten, jedoch nur das darin verwendete Prinzip der Rollwinkelanzeige widerspiegeln. Die Nickwinkelanzeige in beiden verwendeten Systemen ist "gerade" und "egozentrisch".



In vorhandenen Flugsimulatoren wie Microsoft Flight Simulator und Digital Combat Simulator können beide Anzeigetypen in Aktion angezeigt werden.



Es ist erwähnenswert, dass nicht alle bekannten Lösungen in das obige Muster passen. Als Beispiel für das Überschreiten des festgelegten Rahmens betrachten wir zwei Patente für Erfindungen: RU 2561311 und RU 2331848.



Das erste Patent ist dem "Künstlichen Horizont mit in der Höhe beabstandeten Nick- und Rollindikatoren" gewidmet, dessen Autoren: V. I. Putintsev und N. A. Lituev. Das folgende Diagramm ist genommen aus dem Patent.







Bei Bedarf finden Sie im Text der Originalquelle eine Dekodierung der Bezeichnungen und eine Beschreibung der Arbeit... Insgesamt ist die Idee der Erfindung recht einfach: Die Idee eines „Blicks vom Boden zum Flugzeug“ wird sowohl in Roll- als auch in Nickrichtung (vollständiger „Geozentrismus“) verwirklicht, die Anzeige ist jedoch in zwei unabhängige Komponenten unterteilt.



Die zweite Erfindung hat einen komplexeren Namen: "Flugbefehlsvorrichtung zur logischen Anzeige der Position und Steuerung des Flugzeugs im Weltraum." Autoren des Patents: A. P. Plentsov und N. A. Zakonova Die Idee der Pitch-and-Roll-Anzeige ist hier eher ungewöhnlich.







Eine Erläuterung der Bezeichnungen der Schaltung, eine Beschreibung der Vorrichtung, ein Vergleich mit Analoga und zusätzliche Schaltungen mit geringfügigen Unterschieden im Design sind im Patent angegeben .



Eine Gemeinsamkeit mit der vorherigen Erfindung ist das Konzept des Geozentrismus für beide Kanäle. Gleichzeitig hat der künstliche Horizont wie bei den vorhandenen Modellen nur ein „Flugzeugsymbol“, dies ist jedoch keine Silhouette mehr, sondern ein dreidimensionales Modell - ein „Volumenmodell“. Wenn sich herausstellt, dass die Rollbewegung der in der "Rückwärts" -Anzeige implementierten ähnlich ist, sehen Pitching und Tauchen auf diesem Gerät original aus.







Es gibt eine Reihe von Faktoren, die Innovationen bei der Gestaltung realer Anzeigesysteme behindern. Einer der vernünftigen Gründe für Konservativismus ist beispielsweise der Wunsch, die Kontinuität der vom Bediener erworbenen Fähigkeiten, einschließlich der Fähigkeiten zur Wahrnehmung von Informationen, aufrechtzuerhalten. Computerspiele können viel mehr Kreativität bieten. Ohne auf eine vergleichende Analyse der Lösungen einzugehen, werden wir die Erfindung als Grundlage nehmen, die am effektivsten aussieht.



Lösungsanforderungen



Bevor Sie mit dem Schreiben des Codes beginnen, definieren wir die Aufgabe:



1. Es ist erforderlich, die Funktion drawAttitude () zu schreiben, die den Indikator für den künstlichen Horizont mithilfe von Canvas auf der Grundlage der Erfindung von A.P. Plentsov und N.A. Zakonova zeichnet.



2. Die Funktion verwendet den Canvas- Kontext , Koordinaten die Mitte des Indikators, die Werte der Roll- und Nickwinkel in Grad, der Radius der Indikatorfläche.



3. Die Werte des Nickwinkels sind auf das Intervall von minus 30 bis plus 30 Grad begrenzt.



4. Die Werte des Rollwinkels sind auf das Intervall von minus 45 bis plus 45 Grad begrenzt.



5. Wenn der Wert des Arguments über den in p angegebenen Wert hinausgeht. 3 und 4 begrenzt der Indikator zeigt den nächsten zulässigen Wert an.



Funktionserstellung



Der Funktionscode enthält folgende Teile:



1. Überprüfung der eingegebenen Werte auf Überschreitung der Grenzwerte.



2. Winkel in Bogenmaß umrechnen.



3. Skalieren Sie die charakteristische Größe des "Layouts" und der Schriftart mit dem Wert des Indikatorradius.



4. Zeichnungskomponenten:

a) Anzeigekörper.

b) Layout.

c) Pitch and Roll-Skalen.



Die folgende Funktion ist in dieser Reihenfolge geschrieben und ihre Teile sind durch Kommentare getrennt.



Vollständiger Code
Html - Datei Code :



<!DOCTYPE html>
<html>

<head>
  <title>Attitude</title>
  <script src="js/attitude.js"></script>
</head>

<body>
  <canvas id="drawingCanvas" width="640" height="480"></canvas>
</body>

</html>


attitude.js:



window.onload = function () {

    let canvas = document.getElementById("drawingCanvas");
    let context = canvas.getContext("2d");
    
    let run = function () {
        drawAttitude(context, 320, 240, 30 * Math.sin(performance.now() / 2000), 45 * Math.sin(performance.now() / 5000), 200);
    }

    let interval = setInterval(run, 1000 / 60);
};


drawAttitude = function (ctx, centreX, centreY, pitch, roll, radius = 100) {
    //   :
    if (pitch > 30) pitch = 30;
    if (pitch < -30) pitch = -30;

    if (roll > 45) roll = 45;
    if (roll < -45) roll = -45;
    //  :
    roll *= Math.PI / 180;
    pitch *= Math.PI / 180;
    // ""  :
    let vehicleSize = radius * 0.8;
    ctx.font = Math.round(radius / 8) + "px Arial";
    //    :
    ctx.lineWidth = 2;
    ctx.strokeStyle = "Black";
    // :
    ctx.beginPath();
    ctx.arc(centreX, centreY, radius, 0, Math.PI, false);
    ctx.fillStyle = "Maroon";
    ctx.stroke();
    ctx.fill();
    // :
    ctx.beginPath();
    ctx.arc(centreX, centreY, radius, 0, Math.PI, true);
    ctx.fillStyle = "SkyBlue";
    ctx.stroke();
    ctx.fill();
    //"":
    ctx.beginPath();
    //:
    let topSideIsVisible = (pitch >= 0);
    ctx.strokeStyle = topSideIsVisible ? "Orange" : "Brown";
    ctx.fillStyle = topSideIsVisible ? "Yellow" : "Red";
    ctx.lineWidth = 3;
    //
    //  4 ,       ,
    //  :
    ctx.moveTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
    ctx.lineTo(centreX + vehicleSize * Math.cos(roll), centreY + vehicleSize * Math.sin(roll) * Math.cos(pitch));
    ctx.lineTo(centreX, centreY - 2 * Math.sin(pitch) * vehicleSize);
    ctx.lineTo(centreX - vehicleSize * Math.cos(roll), centreY - vehicleSize * Math.sin(roll) * Math.cos(pitch));
    ctx.lineTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
    ctx.stroke();
    ctx.fill();
    // :
    // :
    ctx.beginPath();
    ctx.strokeStyle = "Black";
    ctx.fillStyle = "Black";
    ctx.lineWidth = 1;
    //:
    ctx.fillText(30, centreX - radius * 0.28, centreY - vehicleSize + radius / 20);
    ctx.fillText(20, centreX - radius * 0.28, centreY - vehicleSize * 0.684 + radius / 20);
    ctx.fillText(10, centreX - radius * 0.28, centreY - vehicleSize * 0.348 + radius / 20);
    // - :
    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.684);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.684);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.348);
    ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.348);
    ctx.stroke();
    // :
    ctx.beginPath();
    ctx.strokeStyle = "White";
    ctx.fillStyle = "White";
    //:
    ctx.fillText(30, centreX - radius * 0.28, centreY + vehicleSize + radius / 20);
    ctx.fillText(20, centreX - radius * 0.28, centreY + vehicleSize * 0.684 + radius / 20);
    ctx.fillText(10, centreX - radius * 0.28, centreY + vehicleSize * 0.348 + radius / 20);
    // - :
    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.684);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.684);
    ctx.stroke();

    ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.348);
    ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.348);
    ctx.stroke();

    // :
    ctx.lineWidth = 2;

    //+-15 :
    ctx.fillText(15, centreX + radius * 0.6, centreY + radius * 0.22);
    ctx.moveTo(centreX + 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
    ctx.lineTo(centreX + 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);

    ctx.fillText(15, centreX - radius * 0.75, centreY + radius * 0.22);
    ctx.moveTo(centreX - 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
    ctx.lineTo(centreX - 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);

    //+-30 :
    ctx.moveTo(centreX + 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
    ctx.lineTo(centreX + 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);

    ctx.moveTo(centreX - 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
    ctx.lineTo(centreX - 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);

    //+-45 :
    ctx.moveTo(centreX + 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
    ctx.lineTo(centreX + 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);

    ctx.moveTo(centreX - 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
    ctx.lineTo(centreX - 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);

    ctx.stroke();
}






Am schwierigsten zu verstehen ist der Code zum Zeichnen des "Layouts". Betrachten wir es genauer. Als Layout wurde beschlossen, eine flache symmetrische Figur in Form eines Pfeils zu verwenden.







Die Ober- und Unterseite des Layouts unterscheiden sich in Umriss- und Füllfarben. Die Auswahl des aktuellen Farbschemas ist der erste Teil des Codes.

Als nächstes folgt die Konstruktion der Kontur der Figur.



Die schwierigste Aufgabe besteht darin, die Koordinaten der Projektionen der Figurenscheitelpunkte auf der YOZ- Ebene zu bestimmen . Dies lösen Ausdrücke mit trigonometrischen Funktionen. Die Eckpunkte im Code werden in der Reihenfolge ihrer Nummerierung in der Abbildung durchlaufen.



Der größte Teil des Codes ist Skalen und Signaturen gewidmet. Skalenmarkierungen weisen viele Unterschiede auf: oben und unten, links und rechts, mit und ohne Beschriftung. Die beeindruckende Anzahl von Zeilen ist auf das Schreiben des "individuellen" Codes für jedes Element zurückzuführen.



Trigonometrische Funktionen der entsprechenden Winkel werden zum Anbringen von Rollmarkierungen verwendet. Da die Werte der Winkel jedes Etiketts im Voraus bekannt sind, werden vorgefertigte Werte von Sinus und Cosinus in den Code geschrieben.



Es ist besser, das Erscheinungsbild des Indikators in der Dynamik zu bewerten. Lassen Sie uns die Nick- und Rollschwingungen mit der neuen Funktion zeigen. Lassen Sie uns für die maximale Vielfalt von Positionen die Schwingungsamplituden entsprechend den Indikatorgrenzen und den Perioden unterschiedlich und gegenseitig einfach gestalten.







Fazit



Streng genommen sollte der obige Code für die Roll- und Nickvisualisierung als Hinweis "basierend auf" der Erfindung von A. P. Plentsov und N. A. Zakonova bezeichnet werden. Einige Abweichungen von den ursprünglichen Schemata werden vorgenommen, um das Problem zu vereinfachen, andere, um die Implementierung zu verbessern.



Der vorgestellte Indikator ist in Bezug auf das Design alles andere als ideal. Die akzeptierten Einschränkungen der angezeigten Werte sind für kein objektives Kriterium optimal. Dennoch kann die Aufgabe, einen Demonstrator einer interessanten Technologie zu erstellen, als gelöst betrachtet werden.



All Articles