Die koordinierten Zusatzfunktionen des Schlumpfo 4:
Drehscheibe, LED-Lichtfunktionen und Sound
Funktionsbeschreibung
Der Schlumpfo 4 war schon immer ein Actionmodell und hat immer schon viel Aufmerksamkeit auf sich gelenkt. Nur leider waren die Funktionen bisher nie richtig koordiniert und es war im manuellen Fahrbetrieb auch nie möglich es entsprechend um zu setzen. Das sollte mit der technischen Restaurierung des Schlumpfo deutlich verbessert werden. Mit Hilfe eines ESP32 Mikrocontrollers und eines kombinierten Gyroskop mit Beschleunigungssensoren kann der Antrieb des Modelles Rotation und Translation koordinieren. Auf Basis diser Erweiterung lässt sich nun auch die Cockpit-Drehscheibe unter der Kuppel mit der Rotationsgeschwindigkeit des Modells synchronisieren. Über die Sensorik erkennt die Software nun die lineare Bewegungsrichtung des Modells. In Kombination lässt sich daher bei reiner Rotation des Schlumpfo eine stehende Drehscheibe (RotMode) realisieren, oder bei kombinierter Rotation und Translation ein permanentes Ausrichten auf die translative Bewegungsrichtung (SyncMode) umsetzen. Das gilt natürlich auch für die zwei RGB-LED Ringe die das ganze visuell noch verstärken. Zusätzlich wurde auch die Blitzlichtfunktion über neue High Power LEDs in die koordinierten Modi mit aufgenommen.
Natürlich sollte die ursprüngliche Fahrtreglerfunktion (PropMode) der Scheibe auch erhalten bleiben, über die sich Geschwindigkeit und Drehrichtung der Scheibe mit der Fernsteuerung manuell regeln lässt. Als zusätzlicher Aha-Effekt gibt es noch die Möglichkeit die Drehscheibe von - 180° bis + 180° manuell drehen zu lassen (ServoMode), wie es eine Servoansteuerung machen würde. Auch diese Modi werden über die LEDs mit entsprechenden Ansteuerungen betont. All diese Funktionen werden über nur einen RC-Kanal mit unserem SwitchProp gesteuert, wobei in den Modi RotMode und SyncMode der Proportionalanteil des SwitchProp nicht genutzt wird.
Das gilt auch für die per Fernsteuerung zuschaltbare Geräuscherzeugung, die zwischen Stillstand, ServoMode, Bewegung und reine Rotation unterscheidet und entsprechend unterschiedliche Sounds abspielt, die in ihrer Geschwindigkeit varieren, je nachdem wie schnell sich Schlumpfo bewegt.
Auslegung der Hardware
Drehscheibe
Zur Ansteuerung der Drehscheibe habe ich mich für einen Schrittmotor (NEMA 17) mit dazu passendem Treiber (L298N) entschieden, der genug Drehmoment aufbaut um die notwendigen Geschwindigkeiten von mehr als 2 Umdrehungen pro Sekunde zu realisieren. Um nach dem Einschalten des Schlumpfo die Drehscheibe auf eine definierte Position zu bringen gibt es eine Kalibrierungsfunktion, die mit Hilfe eines Hallsensors und eines kleinen Magneten die Scheibe ausrichtet. Das Hallsensormodul ist fix in den Halter des Schrittmotormodules montiert. Der Magnet ist am mitdrehenden Auslieger der Kupplung der Drehscheibenachse befestigt. Im Durchgang ist die Drehscheibe in Fahrtrichtung Vorne positioniert. Sowohl der Schrittmotortreiber, als auch der Hallsensor werden über GIO Pins am ESP32 angesteuert (bzw eingelesen) und über den BEC mit VCC (5 Volt) versorgt. Am Treibermodul werden auch noch 12 Volt für den Schrittmotor benötigt.
Farb-LED Ringe
Die einzelnen RGB-LEDs sind natürlich über ihre Einbauposition im Modell und ihre Position im Stripe definiert. Hier habe ich mich um Interrupt-Konflikten im ESP32 aus dem Weg zu gehen für eine LED-Kette mit WS2801 Treibern entschieden. Es sind insgesammt 24 LEDs, die in einem inneren Ringen, zur Betonung der Drehscheibe und einem äusseren Ring zur Betonung der Modellbewegung in den Ecken des Schlumpfo 4 Aufbaues plaziert sind. Die LED-Kette wird vom ESP32 über die SPI Schnittstelle angesprochen. Der WS2801 Stripe benötigt 5 Volt und ist daher auch am dedizierten BEC angeschlossen, der bis zu 3 Ampere abgeben kann.
Flash-LEDs
Die vier Ersatzmodule für die alten Kamerablitzlichter bestehen aus jeweils 8 High Power LEDs mit 3 Volt, wobei jeweils vier LEDS in Reihe geschaltet sind. So kann ich die vollen 12 Volt direkt auf die Module schalten. Geschaltet wird über ein Vierkanal MOSFET Schaltmodul, da entsprechende Relaismodule für die Anwendung zu langsam sind. Die Ansteuerung über den ESP32 erfolgt auch hier über GIO Ports und eine VCC Versorgung über den BEC. Da man diese Funktion wohl nicht permanet laufen lassen will, wenn das Modell im Einsatz ist, kann man den MOSFET per RC-Relaisschalter den Saft abdrehen. Die Softwarefunktion läuft aber kontinuirlich durch.
Geräuschgenerator über DAC
Der ESP32 hat ja zwei GIO Ports, die auch als DAC (Digital-Analog-Wandler) genutz werden können, wie ich sie auch schon bei der Renovierung des STRAWAP eingesetzt habe. Da für den Schlumpfo am ESP32 aber GIO Knappheit besteht muss es auch mit einem DAC Kanal gehen, der zum 15 Watt Mono-Verstärkermodul mit einem 10KΩ zu 1KΩ Spannungsteiler gegen Masse beschaltet ist. Der alte Lautsprecher im Schlumpfo wird weiterhin mit 12 Volt am Verstärker betrieben. Auch hier ist ein Zuschalten des Verstärkers über einen RC-Relaisschalter umgesetzt, wie es auch das obige Blockschaltbild aufzeigt. So braucht sich auch hier die SW nicht darum kümmern die Geräusche stum zu schalten.
Umsetzung in Software
Für die SW-Entwicklung nutze ich die sich für mich bewärte Arduino IDE mit der Erweiterung zur unterstützung der ESP32 Mikrocontroller weiter. Die Umsetzung der Schlumpfo 4 Softwarefunktionen sind auch hier recht modular und flexibel gestaltet. Jede Funktionskomponente befindet sich in einer eigenen ino Datei, die über die Arduino IDE mitgeladen wird. Auch lassen sich viele Funktionalitäten über Konstanten im Definitionsbereich der Dateien konfigurieren. So ist es recht einfach Teilfunktionen, wie hier, herauszulösen. Ebenso befinden sich die Definitionen der für die Funktionen benötigten GPIO Pins in diesen Funktions-Dateien und müssen ggf. angepasst werden.
Allgemein habe ich meine Entwicklungen recht ausführlich kommentiert, damit ich selbst auch in einigen Jahren noch nachvollziehen kann, was die SW da eigentlich machen soll.
Die Auswertungen des RC-PWM Signales, des Gyros und die daraus hervorgehenden Berechnungen für den Translations-Rotations-Koordinator sowie die Ausgabe für die Ansteuerung der VS-Antrieben über Servos laufen in einer 20ms Schleife, wie es das RC-PWM Protokoll ja vorgibt. Diese Funktionalitäten sind im (noch nicht veröffentlichten) Bericht zur Translationsregelung beschrieben.
Die Schrittmotorregelung für die Drehscheibe
Die globale 20ms Schleife ist für einen kontinuierlich anzusteuernden Schrittmotor um das Zehnfache zu langsam, wenn sein Limit von mehr als 2 Umdrehungen in der Sekunde auch ausgereizt werden soll und wir keine blockierenden Funktionsaufrufe haben wollen. Diese würde die genutzte Stepper Library allerdings erzeugen, wenn mehrere Steps pro Aufruf gemacht werden sollen. Da der ESP32 ja einen zweiten Prozessor (Core) hat ist eine deutlich hochfrequentere Abarbeitung dieser Funktion von der Prozessorauslastung her kein Problem. Allerdings wird auch für den Schrittmotor die Berechnung immer für den ganzen 20ms berechnet, damit die Daten auch für andere Funktionen und deren Aufrufe im Intervall konsistent sind. Somit wird in der Main-Loop des Cors die Funktion runTable() einmalig im Zyklus aufgerufen. Die Funktion befindet sich, in der Turntable.ino, die sich auch um die definitionen des Schrittmotors kümmert. Über stepsPerTurn sollte mal die Anzahl der Schritte des Motors für eine Umdrehung eintragen und über stepSpeed die mit dem Motor mögliche (gewünschte) Maximalgeschwindigkeit. So präpariert wird in der Funktion geprüft in welchem Modus sich der Schlumpfo befindet und dann die entsprechend Unterfunktion für den Modus zur Berechnung der in diesem Zyklus notwendigen Motorschritte (CycleSteps) und deren Richtung (c_wise) aufgerufen.
Um bei allen Rotationsgeschwindigkeiten also eine gleichmäßige Bewegung zu erhalte und um blockierende Aufrufe der step Funktion zu verhindern berechnen diese Unterfunktionen für die Bewegungsmodi runPosTable() (für den SyncMode), runRotTable() (für den RotMode) und runServoTable() (für den ServoMode) erst einmal die Anzahl der nötigen steps für den anliegenden Intervall von 20ms, wobei das Vorzeichen die Drehrichtung vorgibt. In der Unterfunktion PrepDeltaStep(int, bool) wird daraus die Verweildauer stepDuration zwischen zwei steps berechnet und die Drehrichtung in c_wise zwischengespeichert. In der Unterfunktion stepNow(int) wird noch geprüf, ob wir einen sehr kurzen step-Interval haben, der mit einem doppelten step Aufruf berücksichtigt wird.
Da ein step-Aufruf im 20ms Intervall meist nicht ausreicht wird für den verbleibenden Rest des Zyklus immer wieder die Funktion ReStep() aufgerufen, die über eine Timestamp-Abfrage zum richtigen Zeitpunkt erneut die StepNow() Funktion auslöst und CycleSteps entsprechend herunterzählt. Da die Millis() Funktion nur bis zu 1ms auflösen kann interpoliert die stepDuration über zwei Werte, wenn in PrepDeltaStep() Durations zwischen zwei Ganzzahlwerten berechnet werden. Auch wird geprüft, das es keine Doppelsteps gibt, wenn im Intervall nur noch ein step notwendig ist.
Um nach dem Einschalten des Schlumpfo die Drehscheiben auf eine definierte Position zu bringen gibt es noch eine Kalibrierungsfunktion findTableZero(), die mit Hilfe eines Hallsensors die Scheibe in die Startposition bringt. Sie wird einmalig im Setup aufgerufen und lässt den Schrittmotor maximal 3 volle Umdrehungen nach der Startposition suchen. Das Auslesen und aufbereiten der Sensorwerte findet in der Hallsensor.ino statt. Hier dient über den Funktionsaufruf setHallLimit() der erste Durchlauf zum einlernen der Sensorwerte. Ab der zweiten Rotation wird nach dem gefundenen Maximalwert gesucht und gestopt.
Die Ansteuerung der RGB-LED Kette
Für die WS2801 RGB-LEDs konnte ich mit dem ESP32 die FastLED Library nutzen, da hierbei keine Interrupt-Steuerung benötigt wird, was ich in der LEDstipe.ino dann auch umgesetzt habe. Im Bereich der Definitionen (adjustable values) sollte hier die Anzahl der LEDs eingetragen werden. Der Rest berechnet sich selbst, da die Software nur für zwei gleichlange ringförmige Bereiche designend ist. Mit Blinks und blinkmilles kann man nur noch die Anzahl und Dauer von Blinkfunktionen an die eigenen Bedürfnisse anpassen. Da in unserem Modell aus einbautechnischen Gründen die Stripes nicht im Bug beginnen, gibt es auch noch das LEDPos[LEDnum] Array um die Reihenfolge der einzelnen RGB-LED im Ring anzupassen.
Da die Gyro Setupphase sehr lange dauert wird diese über die Funktion runLEDatStartUp mit einem laufenden Grün begleitet. Wenn das beendet ist wird im laufenden 20ms Zyklusbetrieb dann über den Funktionsaufruf runLEDstripes() der aktuell gültige Modus selektiert und an die dafür zuständigen Unterfunktionen zur Berechnung der Änderungen weitergegeben. Die Modi sind dabei in 4 unterschiedliche Gruppen einsortiert, die eine hierarchische Struktur haben. Die höchste Priorität haben die Alarmzustände in LED_Amode für ungültige RC Signale und Wasseralarm. Wenn es keine Alarme gibt, kommen die Spezialmodi aus LED_Smode zur Auswertung, die sich um die Fehlerstatus der Drehscheibe kümmern. Erst danach kommt über die Auswertung des LED_Mmode die Lichtfunktionen zur Betonung der Bewegung des Schlumpfos zur Ausführung. Über die Unterfunktion runLEDTT(bool) werden die RGB-LEDs an der Drehscheibe angesteuert, die sich auch an deren Position orientieren. Über runLEDir(bool) wird die restliche LED-Kette im äusseren Ring angesteuert, die sich an der Bewegungsrichtung des Modells orientiert. Beide Funktionen können über den mitgegebenen bool Wert invertiert genutzt werden um auch alle bis auf eine LED des Ringes leuchten zu lassen. Wenn über diese Unterfunktionen das LED-Array Objekt LEDrgb[] befüllt ist wird zum Schluß mit FastLED.show() alles übertragen. Daher sind auch die hoch priorisierten Modi in der Auswertung am Ende, damit sie überschreiben können.
Die Ansteuerung der High Power LEDs
Die Ansteuerungsfunktionen der high power LEDs befindet sich in der FlashLED.ino. Sie folgt den Funktionen der Drehscheibe und wertet die aktuelle Position des Schrittmotors stepOffset und die in diesem Zyklus zu laufenden Schritte Steps aus. Daher werden die Funktionen der FlashLEDs im Modus Koordinator runTable() der Turntable.ino gleich mit aufgerufen und die benötigten Werte dort mit übergeben. Im Definitionsbereich der FlashLED sind Konstanten FlashPosXXX[] in Feldwerte für die einzelnen Sektoren in denen die Drehscheibenfront mit den Verbauposition der einzelnen Flash-LEDs überlagern hinterlegt. Sie gehen von einem Schrittmotor mit 200 Schritten pro Umdrehung aus. Die Software geht desweitern von 6 FlashLED Segmenten aus, wobei Segment 1 und 4 nicht angesteuert werden. Je schneller rotiert wird desto kürzer wird jeder einzelne Blitz ausgelöst. Das Ganze kann über die Variable FlashDurFactor skaliert werden.
Die Soundausgabe
Die Funktionen zur Soundausgabe über den DAC sind in der Wave.ino zusammengefast. Zur Ausgabe der unsigned 8-bit PCM Wave-Daten nutze ich die XT_DAC_Audio library. Diese stellt auch eine Funktion zur Manipulation der Abspielgeschwindigkeit und zur Überlagerung von mehreren Geräuschen zur Verfügung, welche zur Betonung unterschiedlicher Bewegungsgeschwindigkeiten des Schlumpfo genutzt wird.
Wir haben insgesamt 5 unterschiedliche Geräusche, die als Headerdateien eingebunden sind. In der Funktion RunWave werden diverse Zustandsvariablen aus den anderen Funktionen ausgewertet, um den für diesen Modus richtigen Sound abzuspielen. Das selektierte Geräusch wird per Definition in der setup_Wave() in einer Endlosschleife Objekt.RepeatForever=true gestartet nachdem in der Unterfunktion StopOtherPlay(int) geprüft wurde, ob ein anderes Geräusch aktiv ist. Wenn das der Fall ist wird Dieses dort auch gestoppt. In der Feldvariablen ItemPlaying[int] wird der Abspielstatus der einzelnen Waves koordiniert. Das 5te Geräusch wird nur dazu gemischt und über das Flag mixing verwaltet. Wenn das richtige Geräusch läuft wird in den Unterfunktionen dann nur noch auf Basis der Zustandsvariablen die Abspielgeschwindigkeit neu berechnet und im Objekt mit .Speed gesetzt.
Auch beim Sound hat der Alarmmodus höchste Priorität und der dazugehörige Sound Alert wird direkt abgespielt. Alle anderen Modi werden in ihren eigenen Unterfunktionsaufrufen angesteuert. Im Stillstand PlayMoLess() wird Musik gespielt, wenn sich die Drehscheibe nicht im Servo-Mode befindet. In diesem Fall PlayServo(Float) gibt es ein sich mit dem Ausschlag der Scheibe steigerndes Ping-Geräusch. Wenn der Schlumpfo in einer linearen Bewegung unterwegs ist wird in PlayDrive(float) ein Geschwindigkeitsabhängiges Antriebsgeräusch (Wasserplätschern) abgespielt. Bei reinen Rotationsbewegungen wird über die Unterfunktion PlayTurbo() zum Antriebsgeräusch noch ein ebenso geschwindigkeitsabhängiges Warp-Geräusch zugemischt bei welchem die Lautstärke zusätzlich noch gesteigert wird Warp.Volume. In Summe soll das den Eindruck eines baldigen Abhebens erzeugen.
Zur Erzeugung der 8-Bit codierten Wave-Dateien bin ich den vorgeschlagenen Weg der Libraryentwickler mit den kostenlos verfügbaren Tools Audacity and HxD gegangen. Nach einigen Tests mit unterschiedlichen Bitraten habe ich für mich 11025 Baut als den besten Kompromiss zwischen Datengrösse und Klangqualität entschieden. Allerdings definiere ich die PCM-Daten in ihren Headerdateien als const, damit sie nicht im DRAM des ESP32 abgelegt werden, da dieser sonst recht schnell zur Neige geht.
Referenzierungen
Arduino Entwicklungsumgebung:
Arduino IDE DownloadseiteArduino IDE Erweiterung für ESP32 Mikrocontroller:
Arduino-ESP32 Installationsbeschreibung von ESPRESSIFSteuerung von WS2801 RGB-LEDs mit der FastLED Library für Arduino und ESP
FastLED von focalintent und kriegsmanVorstellung DACAudio Library für den ESP32 eigenen DAC
DacAudio Library - Download und Installation von XTRONICALAusgabe von PCM-Wave Daten mit der DACAudio Library über den ESP32 eigenen DAC
DacAudio Library - Abspielen von Wave Datein von XTRONICAL