Das Konzept von FYMT
Loksteuerung
Die Lokomotive wird durch einen Arduino nano, eine IR-Fernbedienung und einen entsprechenden Sender gesteuert. Als Motorsteuerungstreiberchip (H-Brücke) wird ein L293D verwendet. Die Steuerung ändert die Geschwindigkeit des Fahrzeugs in Fahrstufen. Außerdem gibt es als Funktionen eine Nothalttaste und eine schnellere Abbremsung, sowie den Fahrtrichtungswechsel.
IR-Fernbedienung
Es können beliebige Fernbedienungen verwendet werden. Allerdings muss man die Steuercodes, die sie sendet, ermitteln und entsprechend in den Sketch eintragen. Zur Ermittlung kann der Tester für Infrarot-Fernbedienungen dienen.
Wir nutzen folgende Fernbedienung:
Deren Steuercodes haben wir für die von uns verwendeten Tasten ermittelt:
Aufschrift | Farbe | Code | Funktion |
---|---|---|---|
CH | rot | FF6290 | Nothalt |
|<< | dunkelgrün | FF22DD | Rückwärts |
>>| | dunkelgrün | FF02FD | Vorwärts |
>|| | hellgrün | FFC23D | schnelle Abbremsung |
- | dunkelblau | FFE01F | langsamer (normal) |
+ | dunkelblau | FFA857 | schneller |
Die Schaltung
Vom "H-Brücken"-Chip L293D wird nur die eine Hälfe beansprucht.
Der orange Draht versorgt an Pin 16 die "Logik" des Chips L293D vom Arduino aus mit 5 V.
Zur 9 V Fahrstromversorgung dient der rote Draht an Pin 8.
Der IR-Sensor hat folgende Pin-Belegung (von vorne):
- links: Daten — Kabelfarbe: gelb
- Mitte: 5 V Stromversorgung — Kabelfarbe: rot
- rechts: Erde (GND — ground) — Kabelfarbe: schwarz
Das Datenkabel (gelb) verbindet den Daten-Pin des IR-Sensors mit Pin A5 des Arduino (im Code: int input_ir = A5).
Bei IR-Sensoren mit abweichender Pin-Belegung ist die Schaltung ensprechend anzupassen.
Die Lokomotive
Zur Erprobung von Schaltung und Software wurde eine Lokomotive mit viel Platz unter dem Gehäuse (nach Entfernung des Gewichts) hergerichtet.
Ein 9-V-Block dient zur Versorgung sowohl mit Fahr-, als auch mit Steuerstrom.
Die Erprobung der Lokomotive und der Software verlief erfolgreich.
Der Sketch
Am nachfolgenden Code haben viele mitgewirkt. Der "letzte Autor" kann hierfür am wenigsten "Ruhm und Ehre" beanspruchen.
/* Locomotive System V. 6.2.0 - 2019-01-01 released unter GPLv3 by the FYMT team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Made for a L293D motor control driver chip */ String VERSION = "6.2.0"; String NAME = "LocomotiveSystem for L293D"; /* one has to be the last; but the code is based on the work of many others */ String LASTAUTHOR = "Michael Stehmann"; String DATE = "2019-01-01"; #include <IRremoteInt.h> #include <IRremote.h> // built-in LED is used to confirm signals const unsigned int LED_PIN = 13; /* the following values _must_ be configured for every locomotive */ const unsigned int min_pwm = 60; // min pwm for keeping on driving const unsigned int max_pwm = 255; // max_pwm for maximum speed to avoid flying const unsigned int standby_pwm = 60; // standby emulates a loco ready to go, i.e. to make a little bit noise a.t.l. const unsigned int start_impulse = 180; // higher pwm for starting const unsigned int step_pwm = 20; unsigned int fast_stop_factor = 2; // how much break energy compared to normal decrease - Better don't set to 0 ;-) unsigned int start_factor = 2; // how much more energy for starting compared to move it - Better don't set to 0 ;-) /* IR Remote Control Key Constants The values may be different for other types of IR Remote Controls */ const uint32_t stop_key = 0XFF6290; // Emergency Stop CH // const uint32_t test_key = 0XFF906F; // Testfunction EQ const uint32_t inc_key = 0XFFA857; // Increase Speed + const uint32_t dec_key = 0XFFE01F; // Decrease Speed - const uint32_t bw_key = 0XFF22DD; // Backward |<< const uint32_t fw_key = 0XFF02FD; // Forward >>| const uint32_t fdec_key = 0XFFC23D; // Decrease Speed Fast >|| /* don't change the following values unless you know what your are doing */ // default = off/nothing/zero unsigned int pwm = 0; uint32_t IRCode = 0; unsigned int counter = 0; // arduino foo const unsigned int enable_pin = 9; const unsigned int direction_pin2 = 10; const unsigned int direction_pin1 = 5; const int input_ir = A5; IRrecv irrecv(input_ir); decode_results results; // debug stuff, switch on if needed int debug_flag = 0; int max_speed_flag = 0; int min_speed_flag = 0; unsigned int COUNT = 0; void drive(int); void switch_forward(void); void switch_backward(void); void switch_stop(void); void increase_speed(void); void decrease_speed(void); void decrease_speed_fast(void); void setup() { pinMode (direction_pin1, OUTPUT); pinMode (direction_pin2, OUTPUT); pinMode (enable_pin, OUTPUT); pinMode (input_ir, INPUT); pinMode (LED_PIN, OUTPUT); // LED Serial.begin(9600); // BAUD = 9600 (default) irrecv.enableIRIn(); // Start the receiver } void printinfo() { /* Print informations about the program */ Serial.print("Name of the program: "); Serial.println(NAME); Serial.print("Version: "); Serial.println(VERSION); Serial.print("Last editor: "); Serial.println(LASTAUTHOR); Serial.print("Date of last change: "); Serial.println(DATE); Serial.println(""); Serial.println("Type 'vvv' to repeat information"); Serial.println(""); Serial.println("Type '+++' to enable debug mode"); Serial.println(""); Serial.println("Type '---' to disable debug mode"); Serial.println(""); COUNT = 1; } void info() { /* Print informations especially for debugging */ if (Serial.available() > 0) { String COMMAND = Serial.readString(); Serial.println(COMMAND); if (COUNT == 0) { printinfo(); } if (COMMAND == "vvv") { Serial.println(""); printinfo(); } if (COMMAND == "+++") { debug_flag = 1; Serial.println(""); Serial.println("Debug Mode enabled"); Serial.println("Type '---' to disable debug mode"); } if (COMMAND == "---") { debug_flag = 0; Serial.println(""); Serial.println("Debug Mode disabled"); Serial.println("Type '+++' to enable debug mode"); } if (debug_flag == 1) { Serial.print("pwm: "); Serial.println(pwm); } } } void loop() { info(); if (irrecv.decode(&results)) { IRCode = results.value; irrecv.resume(); // Receive IR value switch (IRCode) { case(fw_key): // forward >>| switch_forward(); if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } break; case(bw_key): // backward |<< switch_backward(); if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } break; case(fdec_key): // decrease speed fast >|| if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } decrease_speed_fast(); break; case(stop_key): // emergency stop "ch" analogWrite(enable_pin, 0); if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } switch_stop(); break; case(dec_key): // slower - if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } decrease_speed(); break; case(inc_key): // faster + increase_speed(); if (debug_flag == 1) { Serial.print("result = "); Serial.println(IRCode, HEX); } break; default: if (debug_flag == 1) { Serial.print("."); } break; } } } void switch_forward() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); if (pwm <= standby_pwm) { // both direction pins set to low digitalWrite(direction_pin1, LOW); digitalWrite(direction_pin2, LOW); // set the right pin to high digitalWrite(direction_pin1, HIGH); if (debug_flag == 1) { Serial.println("Running forward"); } } } void switch_backward() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); if (pwm <= standby_pwm) { // both direction pins set to low digitalWrite(direction_pin1, LOW); digitalWrite(direction_pin2, LOW); // set the right pin to high digitalWrite(direction_pin2, HIGH); if (debug_flag == 1) { Serial.println("Running backward"); } } } void switch_stop() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); pwm = 0; digitalWrite(enable_pin, LOW); if (debug_flag == 1) { Serial.println("Emergency stop!"); } } void increase_speed() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); if ((debug_flag == 1) && (pwm < 255)) { Serial.println ("faster"); } if (pwm < min_pwm) { pwm = (start_impulse); drive(pwm); if (start_factor == 0) { start_factor = 2; // default value } pwm = min_pwm * start_factor; if (debug_flag == 1) { Serial.print ("Running with "); Serial.print (pwm); Serial.println (" pwm"); } } else { // printing max speed only once if (pwm < max_pwm) { max_speed_flag = 0; pwm += step_pwm; } if ((pwm >= max_pwm) && (max_speed_flag == 0)) { pwm = max_pwm; Serial.println ("Running as fast as possible"); max_speed_flag = 1; } } drive(pwm); } void decrease_speed() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); // printing min speed only once if (pwm > min_pwm) { min_speed_flag = 0; pwm -= step_pwm; } if ((debug_flag == 1) && (pwm > min_pwm)) { Serial.println ("slower"); } if ((pwm <= min_pwm) && (min_speed_flag == 0)) { pwm = 0; Serial.println("Engine stopped"); min_speed_flag = 1; } drive(pwm); } void decrease_speed_fast() { digitalWrite(LED_PIN, HIGH); delay(500); digitalWrite(LED_PIN, LOW); if (fast_stop_factor == 0) { fast_stop_factor = 2; // default value } int fast_step = step_pwm * fast_stop_factor; // printing min speed only once if (pwm > min_pwm) { min_speed_flag = 0; pwm -= fast_step; } if ((debug_flag == 1) && (pwm > min_pwm)) { Serial.println ("slower"); } if ((pwm <= min_pwm) && (min_speed_flag == 0)) { pwm = 0; Serial.println("Engine stopped"); min_speed_flag = 1; } drive(pwm); } void drive(int speed) { if (debug_flag == 1) { if ((speed < 255) && (speed > 0)) { Serial.print ("Confirmed pwm ="); Serial.println(speed); } } analogWrite(enable_pin, speed); }
Erläuterungen:
Leider gehören IRremote.h und IRremoteInt.h nicht zur Grundausstattung; daher gibt es eine Beschreibung des Downloads und der Installation.
Die Werte für die Pulswellenmodulation (pwm), nämlich min_pwm, max_pwm, standby_pwm und start_impulse müssen für jede Lokomotive und möglichweise auch abhängig von der Zuglast angepasst werden. Die Werte step_pwm (für den "Abstand" der Fahrstufen untereinander), fast_stop_factor (für schnelleres Abbremsen) und start_factor (für die Erhöhung der Leistung beim Anfahren aus dem Stand) sollen für viele Lokomotiven gelten.
Die Werte für die Signale der IR-Fernsteuerung sollten zunächst für die verwendete ermittelt und dann in den Code eingetragen werden.
Fahrstufensteuerung bedeutet, dass die pwm-Rate in festen Stufen zu- oder abnimmt. Hier sind es für das Beschleunigen und Abbremsen jeweils 20, für das schnelle Abbremsen das Doppelte.
- Auch dieser Sketch teilt bei der Eingabe von "vvv" auf der Konsole des Rechners mit, welches Programm in welcher Version auf dem Arduino gerade läuft.
Es wurde ferner ein Debug-Modus integriert, der an der Konsole mit "+++" ein- und mit "---" wieder ausgeschaltet werden kann.
Auch dieser Code kann heruntergeladen werden.
Das Konzept von FYMT