Kushagra Keshari
Published © CC BY-NC-ND

Automated Model Railroad Layout With Reverse Loops

Automate a point-to-point model railroad with reverse loops to make the train move continuously forward.

IntermediateFull instructions provided2 hours2,841
Automated Model Railroad Layout With Reverse Loops

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Adafruit Motor Sheild V2
×1
'Sensored' Track
×2
Jumper wires (generic)
Jumper wires (generic)
×10
Adafruit 12-volt DC SMPS
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Multitool, Screwdriver
Multitool, Screwdriver
A screwdriver with a small chisel end to tighten terminal screws of the motor driver sheid.

Story

Read more

Code

Arduino Code

Arduino
/*
   Arduino program to automate a continous-running single-track model railroad layout with
   reverse loops.

   Made by TechBuild: https://www.youtube.com/channel/UCNy7DyfhSD9jsQEgNwETp9g?sub_confirmation=1

   Feel free to modify the code to suit your layout.
*/
#include<Adafruit_MotorShield.h>//Make sure this library is installed in your IDE.


Adafruit_MotorShield AFMS = Adafruit_MotorShield();

Adafruit_DCMotor *mainline = AFMS.getMotor(1);//Connected to the single-track mainline's feeder.
Adafruit_DCMotor *loopline = AFMS.getMotor(2);//Connected to the two reverse loops' feeders.
Adafruit_DCMotor *turnout = AFMS.getMotor(4);//Connected to the reverse loops' turnouts connected in parallel.

#define sensorA A0//Sensor on mainline at the entrance of the first reverse loop.
#define sensorB A1//Sensor on mainline at the entrance of the second reverse loop.

int s;//Variable for storing the speed of the locomotive(0 to 255, from stop to max speed).
int tripCount = 2;//Number to trips the train will make around the layout.
int i;//Variable for use in a for() loop for tripCount.

//All the below values should be in the range of 0-255.
//Most locomotives don't start to move until 30.
//Speed vales greater than 180 might be too much for a model railroad.
int StandBySpeed = 35;//Speed at which the locomotive's lights turn on while it is still at rest(Not all locomotives can do this!).
int SlowSpeed = 60;//Speed at which the locomotive will start to move.
int FastSpeed = 90;//Maximum speed of the locomotive.

//Function to set the speed and direction of the locomotive on the mainline depending on the
//vlaue and the sign(+/-) of the variable 'sp', ranging from -255 to 255.
void mainlinePwr(int sp)
{
  if (sp > 0)
  {
    mainline->setSpeed(sp);
    mainline->run(FORWARD);
  }

  if (sp < 0)
  {
    mainline->setSpeed(-sp);
    mainline->run(BACKWARD);
  }

  if (sp == 0)
  {
    mainline->setSpeed(sp);
    mainline->run(RELEASE);
  }

}

//Functions to switch the turnouts to staright or side.

/*When this function is called(activated), the turnout in the first reverse loop must switch
  to straight and the turnout in the second reverse loop must switch to side.
*/
void turnout_straight()
{
  turnout->run(FORWARD);
  delay(50);
  turnout->run(RELEASE);
}

/*When this function is called(activated), the turnout in the first reverse loop must switch
  to side and the turnout in the second reverse loop must switch to straight.
*/
void turnout_side()
{
  turnout->run(BACKWARD);
  delay(50);
  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 i in void loop()).

   The sensor's output does not remains 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_track 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 sending 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 q, int t) { //Variable q 'tells' which sensor to consider.
  //Variable t 'tells' the clearance delay(in seconds).
  int a;
  while (digitalRead(q) != HIGH);
b:
  for (a = 0; a != 1000 * t; a++) {
    if (digitalRead(q) == HIGH) goto b; //If the sensor output turns HIGH in between the for() loop, it will start over.
    delay(1);
  }
}


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

  AFMS.begin(960);

  loopline->run(FORWARD);//Set the direction of current in both the reverse loops.
  //This will remain constant forever.

  turnout->setSpeed(255);//Allow maximum voltage(=supply voltage) to be applied to the turnouts whenever they need to be switched.


  //Switches the turnouts in both the directions on startup.
  //This can help check if the turnouts arr working or not.
  turnout_straight();

  turnout_side();


  //Set pins for the sensors as digital inputs.
  pinMode(sensorA, INPUT);
  pinMode(sensorB, INPUT);

}

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

  for (s = 0; s != StandBySpeed; s++)
  {
    mainlinePwr(s);
    loopline->setSpeed(s);
    delay(30);
  }

  delay(2000);

  for (s = s; s != SlowSpeed; s++)
  {
    mainlinePwr(s);
    loopline->setSpeed(s);
    delay(125);
  }


  //
  /*
     The below loop will go on until the value of the variable 'i' matches the value of the
     variable 'tripCount', i.e., until the train makes the set number of trips around the layout.
  */
  for (i = 0; i != tripCount; i++)
  {
    while (digitalRead(sensorA) != HIGH);

    waitToPass(sensorA, 4);

    mainlinePwr(-s);

    turnout_straight();

    for (s = s; s != FastSpeed; s++)
    {
      mainlinePwr(-s);
      loopline->setSpeed(s);
      delay(125);
    }

    while (digitalRead(sensorB) != HIGH);

    waitToPass(sensorB, 4);

    mainlinePwr(s);

    turnout_side();
  }
  //


  for (s = s; s != SlowSpeed; s--)
  {
    mainlinePwr(s);
    loopline->setSpeed(s);
    delay(250);
  }

  while (digitalRead(sensorB) != HIGH);

  waitToPass(sensorB, 1);

  for (s = s; s != StandBySpeed; s--)
  {
    mainlinePwr(s);
    loopline->setSpeed(s);
    delay(60);
  }

  delay(2000);

  for (s = s; s != 0; s--)
  {
    mainlinePwr(s);
    loopline->setSpeed(s);
    delay(60);
  }

  delay(5000);//Wait for a set amount of time before starting the entire process again.





}

Credits

Kushagra Keshari
19 projects • 70 followers
A casual electronics and a model railway hobbyist.
Contact

Comments

Please log in or sign up to comment.