Project tutorial
Simple Automated Model Railroad Loop with Yard Siding

Simple Automated Model Railroad Loop with Yard Siding © CC BY-NC-ND

A basic Arduino-controlled model railway layout with an oval loop and a yard siding to house a train, working in an automated sequence.

  • 1,993 views
  • 0 comments
  • 5 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
Adafruit motor shield v2
×1
IR proximity sensor
Use appropriate sensors which can be used to make 'sensored' tracks for this project: https://www.instructables.com/id/Make-a-Low-Cost-Sensored-Track-in-Minutes/
×2
11026 02
Jumper wires (generic)
×4
Adafruit 12-volt DC power source
×1
826 04
Male/Female Jumper Wires
Two sets of these wires containing three of them are required to connect the sensors' power, ground, and signal connection to the Arduino microcontroller.
×6

Apps and online services

About this project

This project is an upgraded version of one of my previous projects. This uses an Arduino microcontroller, a great open-source prototyping platform, to automate a model railway layout. The layout comprises of a simple oval loop and a yard siding branching out from it to house the train. The Arduino microcontroller gets feedback from two 'sensored' tracks installed at two locations of the layout to carry out specific functions when the train crosses over them.

So, without further ado, lets get started!

Step 1: Watch the Video

Watch the above video to understand how this project works.

Step 2: Get All the Parts and Stuff

For this project, you will require:

  • An Arduino microcontroller board compatible with the Adafruit motor shield v2
  • An Adafruit motor driver shield v2(Learn more about it here)
  • An expansion shield(Optional but recommended to expand the power and ground pin connections for the sensors.)
  • Two 'sensored' tracks
  • Two sets of 3 male to female jumper wires(To connect the 'sensored' tracks to the Arduino board.)
  • 4 male to male jumper wires(2 each for connecting the track power and the turnout to the motor shield's output terminals.)
  • A 12-volt DC power source with a current capacity of at least 1A(1000mA)
  • An appropriate USB cable (To connect the Arduino board to a computer.)
  • A computer(To program the Arduino microcontroller.)

Step 3: Program the Arduino Board

Make sure you have the Adafruit motor driver shield v2 library installed in your IDE. Go through the Arduino code to get an idea of how it works and how you can modify it in the future to experiment with the setup.

Connect the Arduino board to your computer and upload the attached Arduino code on it.

Step 4: Make a Test Layout

Click on the above image before proceeding to get more info about the layout. Make sure all the rail joints are properly made and the track's rails are cleaned to prevent the train from derailing and/or stalling.

Step 5: Install the Motor Shield on the Arduino Board

Install the shield carefully on the Arduino board by aligning the pins of the shield with the headers of the Arduino board. Do it gently and make sure no pins of the shield get bent.

Step 6: Connect the Track Power Feeder and the Turnout Wires to the Motor Shield

Connect the output terminals of the shield marked as M1 to the track power wires and those marked as M4 to the turnout wires. Make note that the setup is compatible with only two wire solenoid type turnouts.

Step 7: Connect the 'Sensored' Tracks to the Arduino Board

Install the expansion shield on the motor shield and connect each sensor's GND and VCC pins to the GND and +5-volt headers of the shield. Then make the following pin connections:

  • Connect the output pin of the first sensor to the input pin A0 of the Arduino board.
  • Connect the output pin of the second sensor to the input pin A1 of the Arduino board.

Step 8: Place the Train in the Siding

Place the train in the yard siding to prepare for the test run. Use of a rerailer tool is recommended to ensure that the locomotive and the rolling stock are placed properly on the tracks to prevent derailments.

Step 9: Connect the Arduino Board to Power

Connect the 12-volt DC power source to the Arduino board either through the power terminal block of the motor shield or the female barrel jack connector of the Arduino board. Before turning on the power, make sure all the wiring connections are made correctly and none of them are loose.

Step 10: Turn On the Power and Watch Your Train Go

After turning on the power if the turnout switches the wrong way or the train starts to move in the wrong direction, reverse the polarity of the respective wires connected to the motor shield's output terminals.

Step 11: What's Next?

If you have reached this far, you might want to relax a bit and enjoy your project. But if you want to do more stuff then you can try to modify the Arduino code and experiment with the setup to do something new. Whatever you do, all the best!

Code

Simple_Automated_Oval_Layout_With_Yard_Siding.inoArduino
/*
 * Arduino code to run a train in a simple oval layout with a yard siding in an automated sequence.
 * 
 * Made by Tech Build: https://www.youtube.com/channel/UCNy7DyfhSD9jsQEgNwETp9g?sub_confirmation=1
 * 
 * Previous version:https://www.youtube.com/watch?v=HqcdEgkYbN8
 *  
 */
#include<Wire.h>
#include<Adafruit_MotorShield.h>//Make sure this library is installed in your IDE.

Adafruit_MotorShield AFMS = Adafruit_MotorShield();

Adafruit_DCMotor *loco = AFMS.getMotor(1);//Track power connected to the terminal 'M1'.
Adafruit_DCMotor *turnout = AFMS.getMotor(3);//Turnout connected to the terminal 'M4'.

int s, a;
int q;// Variable to store the number of rounds made by the train. It is used at various for() loops in the code.
int r = 2;//Number of rounds the train will take around the loop at the set MaxSpeed.
int m = 2;//Number of rounds the train will take around the loop at the set MidSpeed.

int MinSpeed = 70;
int MidSpeed = 100;
int MaxSpeed = 150;

int firstSensor = A0;//Sensor installed just after the turnout in the mainline with respect to the trains direction of motion.
int secondSensor = A1;//Sensor installed somewhere midway in the mainline.
/*
 * Custom function made to set the speed and direction of the train 
 * depending on the input integer and sign(-255 to 255).
 */
void loco_go(int i){
 if(i>=1&&i<=255){
  loco->setSpeed(i);
  loco->run(FORWARD);
 }
 if(i<=-1&&i>=-255){
  loco->setSpeed(-i);
  loco->run(BACKWARD);
 }
 if(i==0){
  loco->setSpeed(i);
  loco->run(RELEASE);
 }
}

void turnout_side(){
turnout->setSpeed(255);
turnout->run(FORWARD);
delay(100);
turnout->setSpeed(0);
turnout->run(RELEASE);
}

void turnout_straight(){
turnout->setSpeed(255);
turnout->run(BACKWARD);
delay(100);
turnout->setSpeed(0);
turnout->run(RELEASE);
}
/*
 * Custom function made to wait for the train to pass the 'sensored' track connected to the 
 * input pin declared in the bracket(in the place of int j in void loop()).
 * 
 * The sensor's output does not remains to be steady HIGH when a train is passing over it.
 * This can be observed by the flickering light of the sensor when the train crosses over it.
 * 
 * This means that the earlier used while() statement can't be used here.
 * 
 * To slove, it a for() loop is made which waits for the sensor output to remain low for 
 * a long enough time to ensure that the train has crossed the 'sensored' track.
 * 
 * When the train crosses the 'sensored' track, the ocasional flicker of the LED(Meaning that
 * sensor is sensding digital HIGH signals to the Aruino board.) causes the loop to reset.
 * This loop ends only sfter the complete train has crossed the 'sensored' track.
 */

void WaitToPass(int j){
  b:
  for(a=0;a!=500;a++){
    if(digitalRead(j)==HIGH) goto b;//If the sensor output turns HIGH in between the for() loop, it will start over.
    delay(10);
  }
}

void setup() {
  // put your setup code here, to run once:

  pinMode(firstSensor, INPUT);
  pinMode(secondSensor, INPUT);
  AFMS.begin();

  turnout_side();

}

void loop() {
  // put your main code here, to run repeatedly:


  for(s=0;s!=30;s++){//The locomotive does nothing till about 30, so increasing it quickly.
    loco_go(s);
    delay(60);
  }

  for(s=s;s!=MinSpeed;s++){//Increasing the speed to MinSpeed for the train to start moving slowly.
    loco_go(s);
    delay(500);
  }

  while(digitalRead(firstSensor)!=HIGH);//Waiting for the train to reach the 'sensored' track to reach the turnout inatalled just after the turnout on the mainline.

  for(s=s;s!=80;s++){//Speeding up the train a bit.
    loco_go(s);
    delay(250);
  }

  WaitToPass(firstSensor);//Waiting for the train to completely cross the first ' sensored' track.

  turnout_straight();//Switching the turnout to straight.

  while(digitalRead(secondSensor)!=HIGH);//Waiting for the train to reach the second 'sensored' track.

  for(s=s;s!=MidSpeed;s++){//Increasing the speed of the train to MidSpeed.
    loco_go(s);
    delay(500);
  }

  WaitToPass(secondSensor);//Waiting for the train to pass over the second 'sensored' track.

  while(digitalRead(firstSensor)!=HIGH);//Waiting for the train to reach the first 'sensored' track, completing one round.

  for(s=s;s!=MaxSpeed;s++){//Increasing the speed of the train to the maximum set value.
    loco_go(s);
    delay(250);
  }

  WaitToPass(firstSensor);//Waiting for the train to pass the first 'sensored' track.

 /*
  * for() loop for the train to make number of rounds in the loop at set MaxSpeed, dtermined
  * by the variable 'r'.
  */
  for(q=1;q!=r;q++){//
  while(digitalRead(A0)!=HIGH);

  WaitToPass(firstSensor);
  }

  while(digitalRead(firstSensor)!=HIGH);//Waiting for the train to reach the first 'sensored' track.

  for(s=s;s!=MidSpeed;s--){//Reducing the train's speed to set MidSpeed.
    loco_go(s);
    delay(250);
  }

  WaitToPass(firstSensor);//Waiting for the train to pass over the first 'sensored' track.

  
  for(q=0;q!=m;q++){//for() loop to run the trains for 'm' number of rounds st MidSpeed.
  while(digitalRead(secondSensor)!=HIGH);

  WaitToPass(secondSensor);
  }

  while(digitalRead(secondSensor)!=HIGH);//Waiting for the train to reach the second sensor.

  for(s=s;s!=MinSpeed;s--){//Reducing the speed of the train to the set MinSpeed.
    loco_go(s);
    delay(250);
  }

  while(digitalRead(firstSensor)!=HIGH);

  WaitToPass(firstSensor);

  for(s=s;s!=30;s--){//Slowing down the train.
    loco_go(s);
    delay(250);
  }

  for(s=s;s!=0;s--){//Bringing the train to a halt.
    loco_go(s);
    delay(60);
  }

  turnout_side();//Switching the turnout to side to connect the yard siding to the mainline.

  delay(2000);//Waiting for a few seconds, here 2.

  for(s=s;s!=-30;s--){//Starting the train backwards.
    loco_go(s);
    delay(60);
  }

  for(s=s;s!=-MinSpeed;s--){//Speeding it up till set MinSpeed in backward direction.
    loco_go(s);
    delay(250);
  }

  while(digitalRead(firstSensor)!=HIGH);

  WaitToPass(firstSensor);

  for(s=s;s!=-30;s++){//Slowing down the train.
    loco_go(s);
    delay(250);
  }

  for(s=s;s!=0;s++){//Bringing the train to a halt.
    loco_go(s);
    delay(60);
  }

  delay(5000);//Witing for a few seconds, here 5, before starting the whole operation again.
  
  
  
}

Comments

Similar projects you might like

Automated Point to Point Model Railroad with Yard Siding

Project tutorial by Kushagra Keshari

  • 1,408 views
  • 1 comment
  • 9 respects

Simple Automated Point to Point Model Railroad

Project tutorial by Kushagra Keshari

  • 1,272 views
  • 1 comment
  • 7 respects

Simple Automated Model Railway Layout | Arduino Controlled

Project tutorial by Kushagra Keshari

  • 4,810 views
  • 1 comment
  • 14 respects

Automated Model Railway Layout with Passing Siding

Project tutorial by Kushagra Keshari

  • 8,282 views
  • 10 comments
  • 41 respects

Model Railway Layout with Automated Passing Siding (V2.0)

Project tutorial by Kushagra Keshari

  • 522 views
  • 0 comments
  • 2 respects

Keyboard Controlled Model Train | PS/2 Interface

Project tutorial by Kushagra Keshari

  • 1,040 views
  • 1 comment
  • 10 respects
Add projectSign up / Login