Problemlösungen

Arduino Trimmrad zur Einstellung der Flugzeug-Trimmung (Teil 1)

Meine Flugsimulator-Historie


Arduino Mikrocontroller mit Ein- und Ausgabekomponenten
Der erste Flugsimulator, den ich mir kaufte, war “Falcon A.T.”. Falcon A.T. gameplay (PC Game, 1988)

Den “Microsoft Flight Simulator für Windows 95” habe ich noch im Regal stehen, gespielt hatte ich ihn aber nicht. Microsoft Flight Simulator for Windows 95 Official Trailer

Mit dem Simulator “F22 Air Dominance Fighter” habe ich dafür unzählige Stunden verbracht. F-22 Air Dominance Fighter – Red Sea Tour und F22 ADF – Gameplay

“F-22 Lightning II” gehört zwar auch zu meiner Sammlung, ist jedoch wie der Microsoft Flight Simulator weitgehend ungespielt geblieben. F-22 Lightning II gameplay (PC Game, 1996)

Microsoft Flight Simulator 2020


Und dann habe ich etwa 25 Jahre keinen Flugsimulator mehr angerührt. Bis Microsoft den “Microsoft Flight Simulator 2020” veröffentlicht hat. Abgesehen von der beeindruckenden Grafik steht nun dank Bing Maps erstmals die ganze Welt als Spielplatz zur Verfügung. Normalerweise spielte ich Open-World-Spiele nicht sonderlich gerne. Bei diesen Spielen ist die Welt zwar häufig sehr beeindruckend, aber die mitunter an völligen Schwachsinn heranreichenden grenzdebilen Aufgaben, mit denen die Entwickler die Spieler teilweise über hunderte Stunden durch diese Welt quälen (Laufe quer über die Karte, drücke einen Knopf und laufe zurück. Mache dies anschließend noch dutzende oder gar hunderte Male.) sind oft schon nach kurzer Zeit frustrierend.
Für einen Flugsimulator ist die ganze Welt aber genau richtig!

Markt für Steuergeräte leergefegt


Nach der Installation des Simulators hat sich ziemlich schnell gezeigt, dass er tatsächlich unglaublich beeindruckend ist … und dass er mit Maus und Tastatur nahezu unspielbar ist. Die nächste Anschaffung war also ein sogenanntes HOTAS-System (Hands on Throttle and Stick), also eine Kombination aus Joystick und Schubregler. Die Erkenntnis, dass solche Geräte wichtig sind, hatten zu dem Zeitpunkt offensichtlich bereits viele andere Spieler gehabt. Auf den bislang vergleichsweise geringen Markt stieß seit Veröffentlichung des neuen Flugsimulators von Microsoft mit einem Schlag ein großes Interesse. In der Folge war bei den meisten Angeboten das Schildchen “ausverkauft” angebracht. Für die Geräte, die noch verfügbar waren, wurden mitunter Preise verlangt, die jenseits von Gut und Böse lagen.
Mit einem ergatterten HOTAS-System war der Simulator dann auch tatsächlich sehr viel besser und präziser steuerbar. Flugzeuge haben nun allerdings die Eigenschaft, dass sie beim Flug abhängig von der Gewichtsverteilung dazu neigen nach unten oder nach oben zu kippen. Dagegen kann man dann natürlich permanent ansteuern. Das ist natürlich kein Vergnügen und so haben kluge Ingenieure Möglichkeiten gefunden, die sogenannte Trimmung komfortabler einzustellen. Dabei wird zwischen statischer und dynamischer Trimmung unterschieden. Eine kurze Erklärung hierzu findet man bei Wikipedia. Bei der statischen Trimmung wird der Schwerpunkt durch Verschieben von Masse (Treibstoff in verschiedene Trimmtanks pumpen, Ballast aufnehmen) verschoben. Die so eingestellten Trimmkräfte sind weitgehend unabhängig vom Zustand des Fahrzeuges. Bei der dynamischen Trimmung werden die Trimmkräfte durch die Verstellung bzw. Voreinstellung von aero- bzw. hydrodynamischen Flächen erzeugt. Diese Trimmkräfte verändern sich mit der Geschwindigkeit des Objekts.
Im Flugsimulator sind für die Anpassung der Trimmung standardmäßig die Tasten 7 (Nose Down) und 1 (Nose Up) auf dem Ziffernblock eingestellt. Bei der Steuerung über Tastatureingaben fehlt jedoch jegliches Gefühl für Änderungen der Trimmung. Nicht umsonst sind in Flugzeugen Trimmräder verbaut, die vom Piloten durch drehen angepasst werden. Auch solche gibt es für die Steuerung von Flugsimulatoren zum Anschluss an den PC. Zumindest vor dem MS Flight Simulator 2020. Mittlerweile sind diese Eingabegeräte nur noch schwer erhältich und zudem unverschämt teuer.

Trimmrad “Marke Eigenbau”


Da ich den Flugsimulator nicht in erster Linie zum spielen gekauft habe, sondern um möglichst viel über die Welt, Flugzeuge und Technik zu lernen, bietet sich hier direkt eine interessante Möglichkeit. Wenn es kein Trimmrad mehr zu kaufen gibt, dann ist es Zeit, selbst ein solches zu bauen. Doch wie kann man überhaupt Eingabegeräte bauen, die Daten an einen PC senden können? Und wie macht man der Flugsimulatorsoftare verständlich, was die Eingabedaten bedeuten? Probleme über Probleme.

Das Problem muss in Teilaufgaben zerlegt werden. Zu Beginn stellt sich die Frage, wie beispielsweise Tastaturen, Mäuse, Gamepads oder Joysticks mit einem Computer kommunizieren. Die Frage ist schnell geklärt: Über die Human Interface Devices (HID) Schnittstelle. Auch hier vermittelt Wikipedia wieder ein paar Grundlagen. Bei Human Interface Devices handelt es sich um eine Geräteklasse des USB-Standards für Computer, welche Geräte beschreibt, mit denen Benutzer direkt interagieren. Meist wird HID bei Geräten wie Tastatur, Maus, Joystick und Grafiktabletts verwendet. Allerdings kann HID auch für weitere Zwecke, wie zum Beispiel Relaiskarten, Steuerungen (Knöpfe und Schalter), Thermometer, Multimeter, Telefonie und viele weitere Einsatzzwecke verwendet werden. Erfeulicherweise sind HID-Gerätetreiber in den gängigen Betriebssystemen enthalten. Wird ein HID-Gerät (während des Betriebs) angeschlossen, wird es meist direkt als Gerätetyp Eingabegeräte (Human Interface Devices) erkannt und dann zum Beispiel im Gerätemanager von Microsoft Windows angezeigt. Über diesen Weg lassen sich also neue konstruierte Eingaberäte, wie etwa ein Trimmrad am Computer anschließen und nutzen.

Das nächste Problem: Da die notwendigen Komponenten dür die Schaltkreise nicht einfach im Bastelkeller hergestellt werden können, müssen entsprechende bauteile gefunden werden. Microkontroller und Sensoren werden benötigt. Glücklicherweise gibt es bereits Plattformen, wie Paspberri Pi oder Arduino. Während der Arduino aber auf einen Rechner angewiesen ist, um Programmiercode zu erhalten, ist der Raspberry Pi ein eigener kleiner Rechner, der per HDMI mit einem Monitor verbunden und per USB-Maus und -Tastatur gesteuert wird, wie bei TECHTAG nachgelesen werden kann.

Arduino ist eine aus Soft- und Hardware bestehende Physical-Computing-Plattform. Beide Komponenten sind quelloffen. Die Hardware besteht aus einem einfachen E/A-Board mit einem Mikrocontroller und analogen und digitalen Ein- und Ausgängen. Dies stellt eine gute Basis dar. Insbesondere das HID-fähige Arduino Board LEONARDO mit USB-Anschluss ist vielversprechend, wie eine Recherche ergab. Da es sich um Open Source Hardware handelt, gibt es die hardware von verschiedenen Herstellern. Beim Kauf ist also eine gewisse Vorsicht geboten. Es ist durchaus möglich, ein Board zu erwerben, dass sich nicht vollständig an die Vorgaben hält und daher nicht wie erwartet funktioniert. Als Einstieg empfiehlt sich ein Besuch auf der Website des Arduino-Projekts.

Arduino Mikrocontroller mit Ein- und Ausgabekomponenten


Nachdem die theoretischen Grundlagen erarbeitet und die notwendigen Komponenten geordert sind, beginnt der Zusammenbau. Das Ergebnis ist auf nachfolgendem Bild zu sehen.

Arduino Mikrocontroller mit Ein- und Ausgabekomponenten

Das Arduino-Board selbst kann über verschiedene Wege mit Strom versorgt werden. Da geplant ist, den Controller als USB-Gerät zu verwenden, wird in diesem Projekt einfach der USB-Anschluss auch für die Stromversorgung genutzt.
Auf dem Board sind verschiedene Pins, also Anschlüsse verbaut, über die zusätzliche Hardware mit dem Arduino verbunden wird.

Für dieses Projekt habe ich bis zu diesem Zeitpunkt folgende Komponenten verbaut:

ELEGOO Mega2560 R3 Mikrocontroller ATmega2560 ATMEGA16U2 mit USB-Kabel Kompatibel mit Arduino IDE oder Arduino Leonardo with Headers [A000057]

RUNCCI-YUN 6 x KY-040 Drehwinkelgeber Drehgeber Rotary Encoder Modul für Arduino

HUABAN 3 Stück KY-016 Dreifarbiges RGB-LED-Sensormodul für Arduino

Elegoo Jumper Wire

Arduino Mikrocontroller mit Ein- und Ausgabekomponenten


Drehwinkelgeber KY-040


Der Drehwinkelgeber KY-040 hat zusätzlich einen Knopf integriert und besitzt fünf Anschlüsse:

Masse, der dem im Regelfall das Potential null zugeordnet wird, welches das Bezugspotential für alle Signal- und Betriebsspannungen darstellt.
Positiver Pol der Speisespannung.
Gibt ein LOW-Signal weiter, wenn der Knopf gedrückt wird.
Datensignale.
Taksignale.
Beim Drehen werden zwischen jedem Einrasten zwei Zustände durchlaufen. Das Clock-Signal wechselt dabei immer von 0 nach 1. Das Data-Signal hingegen wechselt abhängig von der Drehrichtung von 0 nach 1 oder von 1 nach 0.
Mit diesen informationen kann man nun einiges anfangen. Bei jedem Wechsel des Clock-Signals fand eine halbe Drehung bis zum nächsten Einrasten statt. Und wie die nachfolgende tabellen zeigen sind die Signale von Clock und Data bei drehungen gegen den Uhrzeigersinn zu jedem Zeitpunkt identisch. Bei Drehungen im Uhrzeigersinn sind die Werte von Data und Clock hingegen gegensätzlich.
Das Clock-Signal gibt also Aufschluss darüber, ob eine Drehung stattfand und darüber hinaus, ob die Drehung bis zum nächsten Einrasten abgeschlossen ist. Ein Vergleich des Data-Signals mit dem Clock-Signal teilt it, ob gegen oder im Uhrzeigersinn gedreht wurde.

Position 1
Position 2
0
1
0
1
Position 1
Position 2
0
1
1
0
Der Druckknopf wird für das Trimmrad nicht benötigt. Aber wenn die Funktion schon vorhanden ist, warum dann nicht einfach nutzen? So gann optional auch eine Aktion ausgeführt werden, wenn man auf das Trimmrad drückt. Also habe ich auch den Switch-Pin des Drehreglers mit dem Arduino-Board verbunden.

Die Belegung der Pins kann dem beigefügten Quelltext entnommen werden.

Dreifarbiges RGB-LED-Sensormodul KY-016


Für diesen Aufbau nicht zwingend notwendig ist das verbaute LED-Modul Es diente zunächst der Fehlersuche. Bei einer Drehung im Uhrzeigersinn leuchtet die LED rot. Bei einer Drehung gegen den Uhrzeigersinn leuchtet die LED grün. Bei einem Druck auf den am Drehregler integrierten Button leuchtet die LED blau und wird dann bis zur nächsten Aktion abgeschaltet.

Entwicklungsumgebung: Arduino IDE


Bislang weiß die Schaltung nicht, was sie überhaupt tun soll. Deswegen müssen die notwendigen Anweisungen als Quelltext geschrieben, dann zu maschinenverständlichen Befehlen kompiliert und schließlich auf das Arduino-Board übertragen werden. Um dies zu bewerkstelligen werden üblicherweise Entwicklungsumgebungen verwendet, die Editoren mit Syntax-Highlighting und der Toolchain für das Kompilieren der Programme enthalten. Im Für Arduino-Projekte gibt es hierfür die Arduino IDE, welche auf der offiziellen Website heruntergeladen werden kann.

Die IDE muss anschließend auf dem Rechner installiert werden. Darüber hinaus werden verschiedene Treiber benötigt, die gleich mitinstalliert werden können. Eine Anleitung ist hier verfügbar.

Beim Anschluss des Arduino-Boards an den PC über ein USB-Kabel sollte die Hardware automatisch erkannt werden. Nun können die ersten Programme auf das Board übertragen werden. Zuvor sind aber noch Anpassungen sinnvoll, beziehungsweise notwendig.

HID-Project von NicoHood


Damit ein Gerät als HID-Device genutzt werden kann, muss das Gerät natürlich auch als HID-Device kommunizieren können. Glücklicherweise gibt es eine Bibliothek, welche die Grundlagen hierfür bereitstellt, das HID-Project von Nico Hood. Diese Bibliothek muss installiert werden. Die Installation kann auf verschiedenen Wegen durchgeführt werden.
Nachdem ich die benötigten Daten zunächst manuell in den dafür vorgesehenen Libraries-Ordner kopiert hatte, konnte ich aufgrund von Mehrdeutigkeiten keine Projekte mehr fehlerfrei kompillieren.
Über das Menü “Sketch → Bibliothek einbinden → Bibliotheken verwalten” oder alternativ “Werkzeuge → Bibliotheken verwalten” kann diese Bibliothek ebenfalls installiert werden. Dies hatte problemlos funktioniert. Eine Suche nach “HID-Project” im Repository führt schnell zur gesuchten Bibliothek. Eine Anleitung zum Installieren neuer Bibliotheken ist hier verfügbar.
Die Bibliotheken werden in einen Libraries-Ordner im Pfad abgelegt, der unter “Datei → Voreinstellungen → Sketchbook-Speicherort”.

Externen Editor verwenden


Der zur IDE gehörende Editor erfüllt die grundlegenden Anforderungen, ist aber nicht so komfortabel, wie etwa Notepad++. Um einen anderen Editor zur Bearbeitung der Quelltexte zu verwenden, kann im Menü “Datei → Voreinstellungen” ein Häkchen bei “Externen Editor verwenden” gesetzt werden. Anschließend werden die in der IDE geladenen Quelltexte ausgegraut dargestellt und können an dieser Stelle nicht mehr editiert werden. Stattdessen kann dann ein unabhängiger Editor genutzt werden.

Arduino IDE, Voreinstellungen

Quelltext


Der nachfolgende Quelltext basiert auf dem HID-Project von NicoHood. Der Code befindet sich noch in einem frühen Stadium. Er ist in keiner Hinsicht optimiert und gegebenenfalls fehlerhaft.

/*
  Sourcecode based on Arduino NicoHood HID API
  See HID Project documentation for more infos.
  https://github.com/NicoHood/HID/
*/
 
#include "HID-Project.h"
 
#define CLOCKWISE true
#define COUNTERCLOCKWISE false
 
// Arduino
const int arduino_led_1		= LED_BUILTIN;
 
// Rotary 1
const int rotary_1_switch	= 2; // Pin 2 to SW (switch pin) on rotary encoder.
const int rotary_1_clock	= 9; // Pin 9 to CLK (clock) on rotary encoder.
const int rotary_1_data		= 8; // Pin 8 to DT (data) on rotary encoder.
int rotary_1_position		= 0;
int rotary_1_clock_old;
int rotary_1_clock_new;
boolean rotary_1_direction;
boolean rotary_1_switch_old	= true;
boolean rotary_1_switch_new	= true;
 
// LED 1
const int led_1_red		= 5;
const int led_1_green		= 6;
const int led_1_blue		= 7;
 
void setup()
{
	pinMode(arduino_led_1, OUTPUT);
 
	pinMode(rotary_1_switch, INPUT_PULLUP);
	pinMode(rotary_1_clock, INPUT);
	pinMode(rotary_1_data, INPUT);
 
	pinMode(led_1_red, OUTPUT);
	pinMode(led_1_green, OUTPUT);
	pinMode(led_1_blue, OUTPUT);
 
	rotary_1_clock_old	= digitalRead(rotary_1_clock);
 
	// Sends a clean report to the host. This is important on any Arduino type.
	Gamepad.begin();
	Serial.begin(9600);
}
 
void loop()
{
	rotary_1_switch_new = digitalRead(rotary_1_switch);
 
	if (rotary_1_switch_new != rotary_1_switch_old)
	{
		if (!rotary_1_switch_new)
		{
			digitalWrite(arduino_led_1, HIGH);
 
			Gamepad.press(1);
 
			Gamepad.write();
 
			Serial.println ("Encoder Button: Pressed");
 
			digitalWrite(led_1_red, LOW);
			digitalWrite(led_1_green, LOW);
			digitalWrite(led_1_blue, HIGH);
		}
		else
		{
			digitalWrite(arduino_led_1, LOW);
 
			Gamepad.release(1);
 
			Gamepad.write();
 
			Serial.println ("Encoder Button: Released");
 
			digitalWrite(led_1_red, LOW);
			digitalWrite(led_1_green, LOW);
			digitalWrite(led_1_blue, LOW);
		}
	}
 
	rotary_1_switch_old = rotary_1_switch_new;
	rotary_1_clock_new = digitalRead(rotary_1_clock);
 
	// Bei jeder Drehung in eine beliebige Richtung soll bei Stufe 2 eine Aktion ausgeführt werden. Stufe 1 wird übersprungen. Andernfalls würden bei jeder Drehung zwei Aktionen ausgeführt werden.
	if ((rotary_1_clock_new != rotary_1_clock_old) && (true == rotary_1_clock_new))
	//if ((rotary_1_clock_new != rotary_1_clock_old))
	{
		//Serial.print("--> VAR rotary_1_clock: ");
		//Serial.println(digitalRead(rotary_1_clock));
 
		//Serial.print("--> VAR rotary_1_data: ");
		//Serial.println(digitalRead(rotary_1_data));
 
		if (digitalRead(rotary_1_data) != rotary_1_clock_new)
		{  // Clockwise
			rotary_1_position++;
			rotary_1_direction = CLOCKWISE; // clockwise
		}
		else
		{ //Counterclockwise
			rotary_1_position--;
			rotary_1_direction = COUNTERCLOCKWISE;
		}
 
		if (CLOCKWISE == rotary_1_direction) // Turning right will turn on red led.
		{ 
			Serial.println ("Encoder Rotation: Clockwise");
			digitalWrite(led_1_red, HIGH);
			digitalWrite(led_1_green, LOW);
 
			Gamepad.press(3);
			Gamepad.write();
 
			delay(50);
 
			Gamepad.release(3);
			Gamepad.write();
		}
		else // Turning left will turn on green led.   
		{
			Serial.println("Encoder Rotation: Counterclockwise");
			digitalWrite(led_1_red, LOW);
			digitalWrite(led_1_green, HIGH);
 
			Gamepad.press(2);
			Gamepad.write();
 
			delay(50);
 
			Gamepad.release(2);
			Gamepad.write();
		}
 
		Serial.print("Encoder RotPosition: ");
		Serial.println(rotary_1_position);
	}
 
	rotary_1_clock_old = rotary_1_clock_new;
}

Debuggen


Debug-Informationen werden über den seriellen Port ausgegeben und können in der Arduino IDE über einen Monitor, der unter “Werkzeuge → Serieller Monitor” oder einen Plotter, der über “Werkzeuge → Serieller Plotter” ausgegeben werden.
Gleichzeitig wird das Board auch als HID-Device angemeldet. Die Steuereingaben können über das Gamekontroller-Werkzeug angezeigt werden. Dies funktioniert allerdings nur, wenn das Fenster “Gamecontroller” den Fokus hat. Wenn ein anderes Fenster aktiviert ist, werden die Steuereingaben nicht dargestellt!

Windows, Controller einrichten

Nachfolgend ein Screenshot, in welchem die Debug-Informationen und die Controller-Eingaben angezeigt werden, um die Funktionalität zu prüfen.

Arduino IDE, Debuggen

HID-Device umbenennen


Der Name mit dem ein HID-Device am Rechner angemeldet wird, setzt sich zusammen aus einer Vendor ID (VID) und einer Product ID (PID). Diese IDs können “gegen Münzeinwurf” beim USB Implementers Forum beantragt werden. Man benötigt hierfür jedoch viele Münzen, wie hier nachgelesen werden kann.
Für Hobbyprojekte nicht praktikabel. Das Arduino-Board wird sich mit einer Standard-Bezeichnung, wie etwa “Arduino Leonardo” anmelden und so auch im System angezeigt. Bei einem einzigen angeschlossenen Arduino-Board ist das zwar unschön aber nicht problematisch. Hat man mehrere Boards angeschlossen, wird es etwas schwierig, das korrekte Board zu finden.
Als Notlösung kann jedoch ein Registry-Eintrag angepasst und lokal ein neuer “OEMName” vergeben werden:

Computer\HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_2341&PID_8036

HID-Device umbenennen