Dennis M. Drury

Hi Everyone,

Here is the code to implement a fully functional ABS signal system using the Arduino Uno or ProMini.  The code is open source to please feel free to copy and modify it as you choose.  Please let me know if there are any questions.

Cheers, Dennis Drury

Reno, NV

/*
  ABS Signal circuit using the Arduino microcontroller.
  This code implements a single section of bi-directional ABS signals using either the Uno, Leonardo, or ProMini boards.
  Version 1.1 by Dennis Drury
  Version history
  V1.0 Initial Release
  V1.1 Added approach lighting
  This code is in the public domain and may be freely copied or modified.
 
                      Sig_1
                      0-

  ------
  Blk_1   Blk_2   Blk_3
                      Sig_2
 
  The Flashing Yellow section includes modified code from the Arduino.cc website that is in the public domain
  http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
/>  
*/

// There are six detected blocks
// Blk_1 to Blk_6
int Blk_1 = A5;
int Blk_2 = A4;
int Blk_3 = A3;
int Blk_4 = A2;
int Blk_5 = A1;
int Blk_6 = A0;

// There are six signal outputs
// Sig_1r, Sig_1y, Sig_1g, Sig_2r, Sig_2y and Sig_2g
const int Sig_1r = 6;
const int Sig_1y = 7;
const int Sig_1g = 8;
const int Sig_2r = 9;
const int Sig_2y = 10;
const int Sig_2g = 11;

// There are four internal variables that will change.  These are only used for the flashing yellow aspects.
int Sig_1y_f = LOW;
int Sig_2y_f = LOW;
long previousMillis1 = 0;
long previousMillis2 = 0;

// The following variables are the flash rates for the signals.  Note these values may need to change depending on the size of your final code and the clock speed of

your processor.
// The numbers are slightly different because in my experience no two prototype flashing relays ever flashed at the exact same rate.
long interval1 = 800;
long interval2 = 810;

// The setup routine runs once on bootup or pressing the reset button
void setup() {
  // Set up the blocks as inputs
  pinMode(Blk_1, INPUT);
  pinMode(Blk_2, INPUT);
  pinMode(Blk_3, INPUT);
  pinMode(Blk_4, INPUT);
  pinMode(Blk_5, INPUT);
  pinMode(Blk_6, INPUT);
  pinMode(Blk_6, INPUT);
 
  // Set up the signals as outputs
  pinMode(Sig_1r, OUTPUT);
  pinMode(Sig_1y, OUTPUT);
  pinMode(Sig_1g, OUTPUT);
  pinMode(Sig_2r, OUTPUT);
  pinMode(Sig_2y, OUTPUT);
  pinMode(Sig_2g, OUTPUT);
}
// This loop runs continously
void loop()
{

  // Read block occupancy
  Blk_1 = digitalRead(A5);
  Blk_2 = digitalRead(A4);
  Blk_3 = digitalRead(A3);
  Blk_4 = digitalRead(A2);
  Blk_5 = digitalRead(A1);
  Blk_6 = digitalRead(A0);

  // Set signal 1 Green
  if (Blk_3 == HIGH && Blk_2 == HIGH && Blk_1 == HIGH && Blk_4 == LOW)
   {
   digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g, LOW);
   }
   
  // Set signal 1 Flashing Yellow
  if (Blk_3 == HIGH && Blk_2 == HIGH && Blk_1 == LOW && Blk_4 == LOW)
    {
     digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1g, HIGH);
     unsigned long currentMillis1 = millis();
 
  if(currentMillis1 - previousMillis1> interval1)
    {
    // save the last time you blinked the LED
    previousMillis1 = currentMillis1;  

    // if the LED is off turn it on and vice-versa:
    if (Sig_1y_f == LOW)
      Sig_1y_f = HIGH;
    else
      Sig_1y_f = LOW;

    // set the LED with the state of the variable:
    digitalWrite(Sig_1y, Sig_1y_f);
    }
    }
   // Set signal 1 Yellow
  if (Blk_3 == HIGH && Blk_2 == LOW && Blk_4 == LOW)
   {
   digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, LOW); digitalWrite(Sig_1g, HIGH);
   }
 
  // Set signal 1 Red
  if (Blk_3 == LOW && Blk_4 == LOW)
   {
   digitalWrite(Sig_1r, LOW); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g, HIGH);
   }
 
  // Set signal 1 to Off
  if (Blk_4 == HIGH)
    {
    digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g, HIGH);
    }
    
// Set signal 2 Green
  if (Blk_4 == HIGH && Blk_5 == HIGH && Blk_6 == HIGH && Blk_3 == LOW)
     {
     digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g, LOW);
     }
     
  // Set signal 2 Flashing Yellow
  if (Blk_4 == HIGH && Blk_5 == HIGH && Blk_6 == LOW && Blk_3 == LOW)
    {
    digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2g, HIGH);
    unsigned long currentMillis2 = millis();
 
  if(currentMillis2 - previousMillis2> interval2)
    {
    // save the last time you blinked the LED
    previousMillis2 = currentMillis2;  
    // if the LED is off turn it on and vice-versa:
    if (Sig_2y_f == LOW)
      Sig_2y_f = HIGH;
    else
      Sig_2y_f = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(Sig_2y, Sig_2y_f);
    }
    }
  // Set signal 2 Yellow
  if (Blk_4 == HIGH && Blk_5 == LOW && Blk_3 == LOW)
     {
     digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, LOW); digitalWrite(Sig_2g, HIGH);
     }
 
  // Set signal 2 Red
  if (Blk_4 == LOW && Blk_3 == LOW)
   {
   digitalWrite(Sig_2r, LOW); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g, HIGH);
   }
   
   // Set signal 2 to Off
   if (Blk_3 == HIGH)
   {
   digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g, HIGH);
   }
}

 

Dennis M. Drury

Dayton, NV

Reply 0
Dennis M. Drury

Code formatting

Looks like the formatting of the code did not come through in the post.  If anyone would like a copy emailed to them please let me know at cowrr1984 AT gmail DOT com.

Cheers, Dennis

 

Dennis M. Drury

Dayton, NV

Reply 0
Ngwpwer

Excellant work

Dennis, will try this next week or so.

Thank You.

RJ

Reply 0
dbernst497

Question on Arduino inputs

I am just starting to learn how to implement Arduino projects for my layout, so your ABS post was timely.  What are you using for block detection as the inputs into A0 through A6?

Reply 0
pschmidt700

Nice work, Dennis

Quick question: with the flashing yellow aspect, the code is written for a three-block, four-aspect ABS signal system -- G>FY>Y>R. How would you edit it for a two-block, three-aspect ABS system -- G>Y>R? Thanks, and well done.
Reply 0
Dennis M. Drury

Thanks

Thanks RJ.  Please let me know how it goes and let me know if you need further assistance.

Dennis M. Drury

Dayton, NV

Reply 0
Dennis M. Drury

Detectors

I have successfully used the cpOd detector from Model Railroad Control Systems and the BOD-8 from RR-Cirkits.  There are others that may work but I have not validated them.

Cheers, Dennis

 

Dennis M. Drury

Dayton, NV

Reply 0
Dennis M. Drury

Flashing Yellow

Hi Paul,

If you'd like I could send you the modified code to eliminate the flashing yellow.  Just send me an email.  I can also modify the code to disable the approach lighting if so desired.  That's the beauty of the Arduino, modifications are SO easy.

Cheers, Dennis

 

Dennis M. Drury

Dayton, NV

Reply 0
Bob the Younger

schematic drawing

Good morning Dennis. I am just starting using an Arduino uno. Can you show me how to wire the Arduino to work with your ABS system? Thanks Bob.

BSNRy taking a load off your mind!

Reply 0
David Husman dave1905

Tumble down

I assume you could do tumble down by looking out to the next absolute signal, next controlled signal or last block.

Dave Husman

Visit my website :  https://wnbranch.com/

Blog index:  Dave Husman Blog Index

Reply 0
Dennis M. Drury

Hi Bob, I'm currently on

Hi Bob,

I'm currently on vacation. I'll send you the schematic when I get home.

Dennis M. Drury

Dayton, NV

Reply 0
Dennis M. Drury

Hi Dave, yes it should be

Hi Dave, yes it should be possible to implement APB with tumble down.  Perhaps that will be my next project.

Dennis M. Drury

Dayton, NV

Reply 0
Bob the Younger

Schematic & holidays

Enjoy your holidays. Bob.

BSNRy taking a load off your mind!

Reply 0
Dennis M. Drury

Arduino Uno Schematic

Hi Bob,

Here's the schematic to wire up the Uno.  Please let me know if you need further info.

chematic.PNG 

Dennis M. Drury

Dayton, NV

Reply 0
Bob the Younger

Uno Schematic

Thank you Dennis. I am attempting to incorporate the Arduino Uno into my layout and also into the layout of a friend of mine. When, not if I need assistance I'll contact you. Have a great day. Bob.

BSNRy taking a load off your mind!

Reply 0
bobbyeh

Code formating

Dennis. I just read your posts on arduino and signaling and was wondering if you could possibly help my friend Dave and I with our code . We have ho layouts with dcc . We are using IR digital sensors for block detection and single bulb bicolor leds for red/green/yellow signal aspects. We are having a hard time keeping the first block active  until we clear the second block. So we can run shorter trains or just a locomotive between blocks.we are also using pwm for IO pins for red brilliance. We don't need approach lighting or flashing colors like I saw in your sketch .just red yellow and green. My friend Dave Shepard is our arduino guy and understands it a little better than me.if you think you have the time to possibly help us please let us know and we can send you our sketch.

thank you very much

Bob Bijeau

Reply 0
Dennis M. Drury

Code for Automatic Block Signals using the Uno

Hi Bob,

Please send me your sketch and I'll take a look.  My email is cowrr1984@gmail.com

Cheers, Dennis

 

Dennis M. Drury

Dayton, NV

Reply 0
bobbyeh

Thank you Dennis I will have

Thank you Dennis I will have my friend Dave Shepard send it to you with some detail. 

 

Thank you you for helping us

Reply 0
Dennis M. Drury

Version 1.4 of the ABS code

I've updated the code for the Arduino ABS system.  A direct link to the code file is here:

https://groups.yahoo.com/neo/groups/Arduini/files/Dennis%20Drury/ABS%20Signals/

Or, here's a text version.

/*
ABS Signal circuit using the Arduino microcontroller.
This code implements a single section of bi-directional ABS signals using either
the Uno, Leonardo, Nano, or ProMini boards.
Pin assignments for this version are set up to use the Nano board.
Version 1.4 by Dennis Drury
Version history
V1.0 Initial Release
V1.1 Added approach lighting
V1.2 Changed pin assignments to better match up with the Pro Mini board.
V1.3 Changed pin assignments to better match up with the Nano board.
V1.4 Changed block nomenclature to better match what's in the system documentation.
This code is in the public domain and may be freely copied or modified.
Sig_1 (Westward)
0-

--------
West_D2 West_D West_H
Sig_2 (Eastward)
The Flashing Yellow section includes modified code from the Arduino.cc website
that is in the public domain
http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
/> */
// There are six detected blocks
// West_D2 to East_D2
int West_D2 = A1; // 2nd distant block for advance approach in a westward direction
int West_D = A2; // Distant block for approach in a westward direction
int West_H = A3; // Home block for stop in a westward direction
int East_H = A4; // Home block for stop in an eastward direction
int East_D = A5; // Distant block for approach in an eastward direction
int East_D2 = A6; // 2nd distant block for advance approach in an eastward direction
// There are six signal outputs
// Sig_1r, Sig_1y, Sig_1g, Sig_2r, Sig_2y and Sig_2g
const int Sig_1r = 4;
const int Sig_1y = 5;
const int Sig_1g = 6;
const int Sig_2r = 7;
const int Sig_2y = 8;
const int Sig_2g = 9;
// There are four internal variables that will change. These are only used for the
flashing yellow aspects.
int Sig_1y_f = LOW;
int Sig_2y_f = LOW;
long previousMillis1 = 0;
long previousMillis2 = 0;
// The following variables are the flash rates for the signals.
// Note these values may need to change depending on the size of your final code and
the clock speed of your processor.
// The numbers are slightly different because in my experience no two prototype
flashing relays ever flashed at the exact same rate.
long interval1 = 800;
long interval2 = 810;
// The setup routine runs once on bootup or pressing the reset button
void setup() {
// Set up the blocks as inputs
pinMode(West_D2, INPUT_PULLUP);
pinMode(West_D, INPUT_PULLUP);
pinMode(West_H, INPUT_PULLUP);
pinMode(East_H, INPUT_PULLUP);
pinMode(East_D, INPUT_PULLUP);
pinMode(East_D2, INPUT_PULLUP);
// Set up the signals as outputs
pinMode(Sig_1r, OUTPUT);
pinMode(Sig_1y, OUTPUT);
pinMode(Sig_1g, OUTPUT);
pinMode(Sig_2r, OUTPUT);
pinMode(Sig_2y, OUTPUT);
pinMode(Sig_2g, OUTPUT);
}
// This loop runs continously
void loop()
{
// Read block occupancy
West_D2 = digitalRead(A1);
West_D = digitalRead(A2);
West_H = digitalRead(A3);
East_H = digitalRead(A4);
East_D = digitalRead(A5);
East_D2 = digitalRead(A6);
// Set signal 1 Green
if (West_H == HIGH && West_D == HIGH && West_D2 == HIGH) //If approach lighting
add "&& East_H == LOW" to if statement
{
digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g, LOW);
}
// Set signal 1 Flashing Yellow
if (West_H == HIGH && West_D == HIGH && West_D2 == LOW) //If approach lighting add
"&& East_H == LOW" to if statement
{
digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1g, HIGH);
unsigned long currentMillis1 = millis();
if(currentMillis1 - previousMillis1> interval1)
{
// save the last time you blinked the LED
previousMillis1 = currentMillis1;
// if the LED is off turn it on and vice-versa:
if (Sig_1y_f == LOW)
Sig_1y_f = HIGH;
else
Sig_1y_f = LOW;
// set the LED with the state of the variable:
digitalWrite(Sig_1y, Sig_1y_f);
}
}
// Set signal 1 Yellow
if (West_H == HIGH && West_D == LOW) //If approach lighting add "&& East_H == LOW"
to if statement
{
digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, LOW); digitalWrite(Sig_1g, HIGH);
}
// Set signal 1 Red
if (West_H == LOW) //If approach lighting add "&& East_H == LOW" to if statement
{
digitalWrite(Sig_1r, LOW); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g, HIGH);
}
/*
Uncomment the /* pair to enable approach lighting
// Set signal 1 to Off
if (East_H == HIGH)
{
digitalWrite(Sig_1r, HIGH); digitalWrite(Sig_1y, HIGH); digitalWrite(Sig_1g,
HIGH);
}
*/
// Set signal 2 Green
if (East_H == HIGH && East_D == HIGH && East_D2 == HIGH) //If approach lighting
add "&& West_H == LOW" to if statement
{
digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g,
LOW);
}
// Set signal 2 Flashing Yellow
if (East_H == HIGH && East_D == HIGH && East_D2 == LOW) //If approach lighting add
"&& West_H == LOW" to if statement
{
digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2g, HIGH);
unsigned long currentMillis2 = millis();
if(currentMillis2 - previousMillis2> interval2)
{
// save the last time you blinked the LED
previousMillis2 = currentMillis2;
// if the LED is off turn it on and vice-versa:
if (Sig_2y_f == LOW)
Sig_2y_f = HIGH;
else
Sig_2y_f = LOW;
// set the LED with the ledState of the variable:
digitalWrite(Sig_2y, Sig_2y_f);
}
}
// Set signal 2 Yellow
if (East_H == HIGH && East_D == LOW) //If approach lighting add "&& West_H == LOW"
to if statement
{
digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, LOW); digitalWrite(Sig_2g,
HIGH);
}
// Set signal 2 Red
if (East_H == LOW) //If approach lighting add "&& West_H == LOW" to if statement
{
digitalWrite(Sig_2r, LOW); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g, HIGH);
}
/*
Uncomment the /* pair to enable approach lighting
// Set signal 2 to Off
if (West_H == HIGH)
{
digitalWrite(Sig_2r, HIGH); digitalWrite(Sig_2y, HIGH); digitalWrite(Sig_2g,
HIGH);
}
*/
}

Dennis M. Drury

Dayton, NV

Reply 0
Dennis M. Drury

Formatting error in text file

Sorry, but the formatting for the blocks and signals did not come through.  Let's try this again.

                                                       0-


---------------

 West_D2      West_D       West_H        East_H        East_D        East_D2

                              Sig_2 (Eastward)

 

Dennis M. Drury

Dayton, NV

Reply 0
sdcruz

Hi Dennis Can you please post

Hi Dennis

Can you please post some photos of how you connect the BOD-8 with the Arduino as I am thinking of buying the BOD-8 but not sure how to connect the outputs from the BOD-8 to the Arduino.

Thanks and Regards
Shelton

Reply 0
Dennis M. Drury

BOD-8 connected to an Arduino

Hello Shelton,
 
I don't have a BOD-8 connected directly to an Arduino on my layout but here are two images of a BOD-8 connected to an IOX board from Model Railroad Control Systems, http://www.modelrailroadcontrolsystems.com/cpnode/  http://www.modelrailroadcontrolsystems.com/iox32-version-2-0-32-line-i-o-expander/  This board then talks to an Arduino.  On the BOD-8 the wires going down below the benchwork connect to the current transformers (Tombstones).  The multi-color ribbon cable then gets connected to the IOX / Arduino.  You should note the ribbon cable also has wires for +5 and GND for the BOD-8.  Hope this helps.
 
img.jpeg 
 
img.jpeg 

Dennis M. Drury

Dayton, NV

Reply 0
Nathan Rich

APB

This is very cool. I would also like to get into the APB line, as the Milwaukee Road used it over Snoqualmie Pass and I helped a friend build a layout of it. I have also been working on actual signals. We will use ones that are US&S-looking. Is it too much to have 4 wires per head with Red/yellow/green and a ground?
Reply 0
sdcruz

Thanks for the photos Dennis.

Thanks for the photos Dennis. I may have to ask you more questions later.

Regards
Shelton

Reply 0
leroc

Hi Dennis question for you

Hi Dennis question for you can this be implemented for block reading with i r sensors on the arduino uno analogue pins ? if yes this might be the code i have been searching for minus the flashing yellow 

see my code below for 1 signal 

int sensePin1 = A0;
int sensePin2 = A1;
int RED = 6;
int YELLOW = 5;
int GREEN = 3;
int POWER = 8;


void setup() {
  Serial.begin(9600);
  pinMode(RED, OUTPUT);
  pinMode(YELLOW, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(POWER, OUTPUT);

}
enum SIGNALSTATES
{
  ST_GREEN,
  ST_RED1,
  ST_RED2,
  ST_YELLOW,
};
SIGNALSTATES signalState = ST_GREEN;

void loop() {
  int valA1 = analogRead(sensePin1);
  int valA2 = analogRead(sensePin2);
  Serial.println(valA1);
  Serial.println(valA2);
  delay(200);

  switch (signalState)
  {
    case ST_GREEN:
      signalgreen(valA1, valA2);
      break;
    case ST_RED1:
      signalred1(valA1, valA2);
      break;
    case ST_RED2:
      signalred2(valA1, valA2);
      break;
    case ST_YELLOW:
      signalyellow(valA1, valA2);
      break;
  }
}

void signalgreen(int valA1, int valA2) {
  digitalWrite(GREEN, LOW);
  digitalWrite(RED, HIGH);
  digitalWrite(YELLOW, HIGH);
  digitalWrite(POWER, HIGH);

  if (valA1 < 500 && valA2> 500) {
    signalState = ST_RED1;
  }
  else if (valA1> 500 && valA2 < 500) {
    signalState = ST_RED2;
  }
}

void signalred1(int valA1, int valA2) {
  digitalWrite(GREEN, HIGH);
  digitalWrite(RED, LOW);   
  digitalWrite(YELLOW, HIGH);
  digitalWrite(POWER, HIGH);

  if (valA1> 500 && valA2 < 500) {
    signalState = ST_YELLOW;
  }
}

void signalred2(int valA1, int valA2) {
  digitalWrite(GREEN, HIGH);
  digitalWrite(RED, LOW);
  digitalWrite(YELLOW, HIGH);
  digitalWrite(POWER, HIGH);

  if (valA1 < 500 && valA2> 500) {
    signalState = ST_YELLOW;
  }

}

void signalyellow(int valA1, int valA2) {
  digitalWrite(GREEN, HIGH);
  digitalWrite(RED, HIGH);
  digitalWrite(YELLOW, LOW);
  digitalWrite(POWER, HIGH);
  delay(5000);

  if (valA1> 500 && valA2> 500) {
    signalState = ST_GREEN;
  }
}

 

if anyone wants to use this code for a single ir detected 3 aspect signal with two detectors and operates both ways then feel free

Kind regards Paul

Reply 0
Reply