Steve_Massikker
Published © MIT

Automation of Railway Models Part 4 - Tutorial

Complete step-by-step instruction on the use of Arduino with an example of planning a railway layout. The use of sensors.

IntermediateFull instructions provided12 hours801
Automation of Railway Models Part 4 - Tutorial

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1

Software apps and online services

Arduino IDE
Arduino IDE
Arduino Train (Android app)

Hand tools and fabrication machines

URB unit

Story

Read more

Schematics

Plan railway layout

Slayout 1 ungjrmun4h

Code

Code snippet #1

Plain text
// ARDUINORAILWAYCONTROL.COM
// Communication_station_simple_layout.ino
// V.1
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// COMMUNICATE STATION ///////


#include <SoftwareSerial.h>
#include <Servo.h>
#include <Wire.h>

//// GPIO PINS ////

SoftwareSerial Bluetooth(12, 13);// RX, TX

// L298
#define IN1_PIN 2
#define IN2_PIN 4
#define IN3_PIN 5
#define IN4_PIN 7
#define ENA_PIN 3
#define ENB_PIN 6

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;
#define JUNCTION2_PIN 10
Servo J2;


//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
int addressI2C;
byte dataToI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin();  // Master I2C mode

// Initialize Serial
  Serial.begin(9600);
  Bluetooth.begin(9600); // Software serial
  inputString.reserve(16); 

// Initialize Motor Driver
  pinMode(IN1_PIN, OUTPUT); 
  pinMode(IN2_PIN, OUTPUT);
  pinMode(ENA_PIN, OUTPUT); 

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION2_PIN, OUTPUT); J2.attach(JUNCTION2_PIN);  
  pinMode(JUNCTION_EN, OUTPUT); 

}

void loop() {

  if (stringComplete) {
    

// ----------- START COMMAND PARSING ----------- // 

    //THROTTLE
    if (inputString.charAt(0) =='t') {   
      if (inputString.charAt(1) =='0') analogWrite(ENA_PIN, 0);
      if (inputString.charAt(1) =='1') analogWrite(ENA_PIN, 50);
      if (inputString.charAt(1) =='2') analogWrite(ENA_PIN, 100);
      if (inputString.charAt(1) =='3') analogWrite(ENA_PIN, 150);
      if (inputString.charAt(1) =='4') analogWrite(ENA_PIN, 200); 
      if (inputString.charAt(1) =='5') analogWrite(ENA_PIN, 255); 
    }

    // DIRECTION 
    if (inputString.charAt(0) =='d') {
      if (inputString.charAt(1) =='r') {
        digitalWrite(IN1_PIN, HIGH);
        digitalWrite(IN2_PIN, LOW);
      }
      if (inputString.charAt(1) =='f') {
        digitalWrite(IN1_PIN, LOW);
        digitalWrite(IN2_PIN, HIGH);
      }
      if (inputString.charAt(1) =='s') {
        digitalWrite(IN1_PIN, LOW);
        digitalWrite(IN2_PIN, LOW);
        analogWrite(ENA_PIN, 0);
      } 
    }
 
    // JUNCTIONS

    // J1
    if (inputString.charAt(0) =='j') {
      if (inputString.charAt(1) =='a') {
        J1.write(0);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH); // servo power on
        millisJunction = millis();  // servo power off
        Bluetooth.print("az"); // feedback command 
      }
      if (inputString.charAt(1) =='b') {
        J1.write(180);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("bz");
      } 

    // J2   
      if (inputString.charAt(1) =='c') {
        J2.write(0);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("cz");
      }  
      if (inputString.charAt(1) =='d') {
        J2.write(180);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("dz");
      } 

    // J3              
      if (inputString.charAt(1) =='e') {
        dataToI2C = 30; 
        addressI2C = 2;
        sendDataViaI2C(); 
        Bluetooth.print("ez");
      }  
      if (inputString.charAt(1) =='f') {
        dataToI2C = 31; 
        addressI2C = 2;
        sendDataViaI2C(); 
        Bluetooth.print("fz");
      }

    // J4              
      if (inputString.charAt(1) =='g') {
        dataToI2C = 30; 
        addressI2C = 3;
        sendDataViaI2C(); 
        Bluetooth.print("gz");
      }  
      if (inputString.charAt(1) =='h') {
        dataToI2C = 31; 
        addressI2C = 3;
        sendDataViaI2C(); 
        Bluetooth.print("hz");
      } 
    }      

// ----------- END COMMAND PARSING ----------- // 
    dataToI2C = 0;
    inputString = "";
    stringComplete = false;    
  }

  bluetoothEvent();
  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);  // delay servo power OFF
 
}

// ----------- FUNCTIONS ----------- // 

void serialEvent() {
  if (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == 'z') {
      stringComplete = true;
    }
  }
}

void bluetoothEvent() {
  if (Bluetooth.available()) {
    char inChar = (char)Bluetooth.read();
    inputString += inChar;
    if (inChar == 'z') {
      stringComplete = true;
    }
  }
}

void sendDataViaI2C() {
  Wire.beginTransmission(addressI2C);
  Wire.write(dataToI2C);
  Wire.endTransmission();
}

Code snippet #2

Plain text
// ARDUINORAILWAYCONTROL.COM
// Communication_station_simple_layout.ino
// V.1
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// COMMUNICATE STATION ///////


#include <SoftwareSerial.h>
#include <Servo.h>
#include <Wire.h>

//// GPIO PINS ////

SoftwareSerial Bluetooth(12, 13);// RX, TX

// L298
#define IN1_PIN 2
#define IN2_PIN 4
#define IN3_PIN 5
#define IN4_PIN 7
#define ENA_PIN 3
#define ENB_PIN 6

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;
#define JUNCTION2_PIN 10
Servo J2;


//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
int addressI2C;
byte dataToI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin();  // Master I2C mode

// Initialize Serial
  Serial.begin(9600);
  Bluetooth.begin(9600); // Software serial
  inputString.reserve(16); 

// Initialize Motor Driver
  pinMode(IN1_PIN, OUTPUT); 
  pinMode(IN2_PIN, OUTPUT);
  pinMode(ENA_PIN, OUTPUT); 

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION2_PIN, OUTPUT); J2.attach(JUNCTION2_PIN);  
  pinMode(JUNCTION_EN, OUTPUT); 

}

void loop() {

  if (stringComplete) {
    

// ----------- START COMMAND PARSING ----------- // 

    //THROTTLE
    if (inputString.charAt(0) =='t') {   
      if (inputString.charAt(1) =='0') analogWrite(ENA_PIN, 0);
      if (inputString.charAt(1) =='1') analogWrite(ENA_PIN, 50);
      if (inputString.charAt(1) =='2') analogWrite(ENA_PIN, 100);
      if (inputString.charAt(1) =='3') analogWrite(ENA_PIN, 150);
      if (inputString.charAt(1) =='4') analogWrite(ENA_PIN, 200); 
      if (inputString.charAt(1) =='5') analogWrite(ENA_PIN, 255); 
    }

    // DIRECTION 
    if (inputString.charAt(0) =='d') {
      if (inputString.charAt(1) =='r') {
        digitalWrite(IN1_PIN, HIGH);
        digitalWrite(IN2_PIN, LOW);
      }
      if (inputString.charAt(1) =='f') {
        digitalWrite(IN1_PIN, LOW);
        digitalWrite(IN2_PIN, HIGH);
      }
      if (inputString.charAt(1) =='s') {
        digitalWrite(IN1_PIN, LOW);
        digitalWrite(IN2_PIN, LOW);
        analogWrite(ENA_PIN, 0);
      } 
    }
 
    // JUNCTIONS

    // J1
    if (inputString.charAt(0) =='j') {
      if (inputString.charAt(1) =='a') {
        J1.write(0);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH); // servo power on
        millisJunction = millis();  // servo power off
        Bluetooth.print("az"); // feedback command 
      }
      if (inputString.charAt(1) =='b') {
        J1.write(180);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("bz");
      } 

    // J2   
      if (inputString.charAt(1) =='c') {
        J2.write(0);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("cz");
      }  
      if (inputString.charAt(1) =='d') {
        J2.write(180);
        delay(25);
        digitalWrite(JUNCTION_EN, HIGH);
        millisJunction = millis();
        Bluetooth.print("dz");
      } 

    // J3              
      if (inputString.charAt(1) =='e') {
        dataToI2C = 30; 
        addressI2C = 2;
        sendDataViaI2C(); 
        Bluetooth.print("ez");
      }  
      if (inputString.charAt(1) =='f') {
        dataToI2C = 31; 
        addressI2C = 2;
        sendDataViaI2C(); 
        Bluetooth.print("fz");
      }

    // J4              
      if (inputString.charAt(1) =='g') {
        dataToI2C = 30; 
        addressI2C = 3;
        sendDataViaI2C(); 
        Bluetooth.print("gz");
      }  
      if (inputString.charAt(1) =='h') {
        dataToI2C = 31; 
        addressI2C = 3;
        sendDataViaI2C(); 
        Bluetooth.print("hz");
      } 
    }      

// ----------- END COMMAND PARSING ----------- // 
    dataToI2C = 0;
    inputString = "";
    stringComplete = false;    
  }

  bluetoothEvent();
  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);  // delay servo power OFF
 
}

// ----------- FUNCTIONS ----------- // 

void serialEvent() {
  if (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == 'z') {
      stringComplete = true;
    }
  }
}

void bluetoothEvent() {
  if (Bluetooth.available()) {
    char inChar = (char)Bluetooth.read();
    inputString += inChar;
    if (inChar == 'z') {
      stringComplete = true;
    }
  }
}

void sendDataViaI2C() {
  Wire.beginTransmission(addressI2C);
  Wire.write(dataToI2C);
  Wire.endTransmission();
}

Code snippet #3

Plain text
// ARDUINORAILWAYCONTROL.COM
// URB_2_simple_layout.ino
// V.1
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// URB#2 ///////

#include <Servo.h>
#include <Wire.h>

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;

//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
byte dataFromI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin(2);  // I2C address 2
  Wire.onReceive(receiveI2C);

// Initialize Serial
  Serial.begin(9600);

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION_EN, OUTPUT); 

}

void loop() {
// COMMAND PARSING
  if (dataFromI2C != 0) {
    switch (dataFromI2C) {

    case 30: J1.write(0);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); break;

    case 31: J1.write(180);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); break;
    } 

  dataFromI2C = 0;

  }

  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);

} 

// ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}

Code snippet #4

Plain text
// ARDUINORAILWAYCONTROL.COM
// URB_2_simple_layout.ino
// V.1
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// URB#2 ///////

#include <Servo.h>
#include <Wire.h>

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;

//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
byte dataFromI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin(2);  // I2C address 2
  Wire.onReceive(receiveI2C);

// Initialize Serial
  Serial.begin(9600);

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION_EN, OUTPUT); 

}

void loop() {
// COMMAND PARSING
  if (dataFromI2C != 0) {
    switch (dataFromI2C) {

    case 30: J1.write(0);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); break;

    case 31: J1.write(180);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); break;
    } 

  dataFromI2C = 0;

  }

  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);

} 

// ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}

Code snippet #7

Plain text
// ARDUINORAILWAYCONTROL.COM
// URB_2_simple_layout.ino
// V.2
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// URB#2 ///////

#include <Servo.h>
#include <Wire.h>

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;

// RELAY
#define RELAY_1 12
#define RELAY_2 13

//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
byte dataFromI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin(2);  // or Wire.begin(3);
  Wire.onReceive(receiveI2C);

// Initialize Serial
  Serial.begin(9600);

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION_EN, OUTPUT);

// Initialize Relays   
  pinMode(RELAY_1, OUTPUT);
  pinMode(RELAY_2, OUTPUT);

}

void loop() {
// COMMAND PARSING
  if (dataFromI2C != 0) {
    switch (dataFromI2C) {

    case 30: J1.write(0);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); 
             delay(50);
             digitalWrite(RELAY_1, HIGH);
             digitalWrite(RELAY_2, LOW); break;

    case 31: J1.write(180);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); 
             delay(50);
             digitalWrite(RELAY_1, LOW);
             digitalWrite(RELAY_2, HIGH); break;
    } 

  dataFromI2C = 0;

  }

  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);

} 

// ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}

Code snippet #8

Plain text
// ARDUINORAILWAYCONTROL.COM
// URB_2_simple_layout.ino
// V.2
// 01.04.2017
// Author: Steve Massikker
// For Universal Rail Bus unit  V.2.4 and higher

/////// URB#2 ///////

#include <Servo.h>
#include <Wire.h>

// SERVO
#define JUNCTION_EN 8
#define JUNCTION1_PIN 9
Servo J1;

// RELAY
#define RELAY_1 12
#define RELAY_2 13

//// VARIABLES ////
boolean stringComplete = false;
String inputString = "";
byte dataFromI2C; 
unsigned long millisJunction;

void setup() {

// Initialize I2C
  Wire.begin(2);  // or Wire.begin(3);
  Wire.onReceive(receiveI2C);

// Initialize Serial
  Serial.begin(9600);

// Initialize Servos
  pinMode(JUNCTION1_PIN, OUTPUT); J1.attach(JUNCTION1_PIN);
  pinMode(JUNCTION_EN, OUTPUT);

// Initialize Relays   
  pinMode(RELAY_1, OUTPUT);
  pinMode(RELAY_2, OUTPUT);

}

void loop() {
// COMMAND PARSING
  if (dataFromI2C != 0) {
    switch (dataFromI2C) {

    case 30: J1.write(0);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); 
             delay(50);
             digitalWrite(RELAY_1, HIGH);
             digitalWrite(RELAY_2, LOW); break;

    case 31: J1.write(180);
             delay(25);
             digitalWrite(JUNCTION_EN, HIGH);
             millisJunction = millis(); 
             delay(50);
             digitalWrite(RELAY_1, LOW);
             digitalWrite(RELAY_2, HIGH); break;
    } 

  dataFromI2C = 0;

  }

  if (millis() > (millisJunction + 800)) digitalWrite(JUNCTION_EN, LOW);

} 

// ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}

Code snippet #9

Plain text
#define HALL_A 10
#define HALL_B 11

//// VARIABLES ////
byte dataToI2C, dataFromI2C; 

Code snippet #10

Plain text
#define HALL_A 10
#define HALL_B 11

//// VARIABLES ////
byte dataToI2C, dataFromI2C; 

Code snippet #11

Plain text
// Initialize Halls
  pinMode(HALL_A, INPUT); 
  pinMode(HALL_B, INPUT);

  Wire.onReceive(receiveI2C);
  Wire.onRequest(requestI2C);

Code snippet #12

Plain text
// Initialize Halls
  pinMode(HALL_A, INPUT); 
  pinMode(HALL_B, INPUT);

  Wire.onReceive(receiveI2C);
  Wire.onRequest(requestI2C);

Code snippet #13

Plain text
  if ((digitalRead(HALL_A) == LOW) || (digitalRead(HALL_B) == LOW) ) dataToI2C = 1;    
  else dataToI2C = 0;

  // ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}
  
void requestI2C() {
  Wire.write(dataToI2C);
}

Code snippet #14

Plain text
  if ((digitalRead(HALL_A) == LOW) || (digitalRead(HALL_B) == LOW) ) dataToI2C = 1;    
  else dataToI2C = 0;

  // ----------- FUNCTIONS ----------- // 

void receiveI2C(int howMany) {
  while (Wire.available() > 0) {
    dataFromI2C = Wire.read();
    if (dataFromI2C != 0) {
      Serial.println("I2C - ");  
      Serial.print(dataFromI2C);
    }
  }
}
  
void requestI2C() {
  Wire.write(dataToI2C);
}

Code snippet #15

Plain text
// --------------- I2C REQUEST --------------- // 

  static unsigned long prevTime = 0;

  if (millis() - prevTime > 25) {
    addressI2C = 2;
    Wire.requestFrom(addressI2C, 1);    // request byte from slave device 
    prevTime = millis();
    dataFromI2C = Wire.read(); 
  }

  if ((dataFromI2C == 1) && (!deblockAWS)) {
     Bluetooth.print("hall1z");
     analogWrite(ENA_PIN, 0);
  } 

  if (millis() > (millisAWS + 5000)) deblockAWS = false;  

Code snippet #16

Plain text
// --------------- I2C REQUEST --------------- // 

  static unsigned long prevTime = 0;

  if (millis() - prevTime > 25) {
    addressI2C = 2;
    Wire.requestFrom(addressI2C, 1);    // request byte from slave device 
    prevTime = millis();
    dataFromI2C = Wire.read(); 
  }

  if ((dataFromI2C == 1) && (!deblockAWS)) {
     Bluetooth.print("hall1z");
     analogWrite(ENA_PIN, 0);
  } 

  if (millis() > (millisAWS + 5000)) deblockAWS = false;  

Code snippet #17

Plain text
// ----------- START COMMAND PARSING ----------- // 

    //AWS
    if (inputString =='d1') deblockAWS = true; 

 

Code snippet #18

Plain text
// ----------- START COMMAND PARSING ----------- // 

    //AWS
    if (inputString =='d1') deblockAWS = true; 

 

Credits

Steve_Massikker

Steve_Massikker

7 projects • 44 followers
Contact

Comments