Free Your Model Train (FYMT)
Loksteuerung mit Fahrstufen (L293D)

Das Konzept von FYMT

Dokumentation zu 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:

Foto: IR-Fernbedienung

Deren Steuercodes haben wir für die von uns verwendeten Tasten ermittelt:

AufschriftFarbeCodeFunktion
CHrotFF6290Nothalt
|<<dunkelgrünFF22DDRückwärts
>>|dunkelgrünFF02FDVorwärts
>||hellgrünFFC23Dschnelle Abbremsung
-dunkelblauFFE01Flangsamer (normal)
+dunkelblauFFA857schneller

Die Schaltung

Schaltung Loksteuerung

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):

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

Lokomotive

Zur Erprobung von Schaltung und Software wurde eine Lokomotive mit viel Platz unter dem Gehäuse (nach Entfernung des Gewichts) hergerichtet.

Lokomotive offen

Ein 9-V-Block dient zur Versorgung sowohl mit Fahr-, als auch mit Steuerstrom.

Elektronik in der Lokomotive

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:

Auch dieser Code kann heruntergeladen werden.

Das Konzept von FYMT

Dokumentation zu FYMT