// https://forum.arduino.cc/t/model-railroad-signaling-device-problem/1147370
// https://wokwi.com/projects/370078430529203201
/*
RRX light pattern:
1. Default green
2. When CALL TRAIN button is pressed
a. RRX begin flashing
b. Traffic lights cycle
(1) green 5 seconds
(2) yellow 3 seconds
(3) red for 10 seconds
c. Gates lower
3. After red timeout
a. RRX off
b. Traffic lights green
c. Gates raise.
*/
int millisDelay = 1000; // live time
// int millisDelay = 100; // 10x time for debug
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
char railstation[] = "St. Paul";
byte rail[] = { // custom character National Rail symbol
0b00100,
0b01000,
0b11111,
0b00000,
0b11111,
0b00010,
0b00100,
0b00000,
};
#include <Adafruit_NeoPixel.h>
int PIX = 32;
Adafruit_NeoPixel pixels (PIX, 6, NEO_GRB + NEO_KHZ800);
#include <Servo.h>
Servo servo0; // create servo object to control servo
Servo servo1;
int pos = 0; // variable to store the servo position
int rLED[] = {4, 12}; // red LED pins
int yLED[] = {3, 11}; // yellow LED pins
int gLED[] = {2, 10}; // green LED pins
int* LED[] = {rLED, yLED, gLED }; // array of LED arrays / multidim array
int redDelay = 10; // LED ON time
int yelDelay = 3; // LED ON time
int grnDelay = 5; // LED ON time
bool callTrain = false;
#define buttonPin 13
#define ON LOW // traffic LEDs ON - common anode
#define OFF HIGH // traffic LEDs OFF - common anode
void setup() {
Serial.begin(115200);
pixels.begin();
servo0.attach(5); // attach servo on pin 5 to a servo object/instance
servo1.attach(8); // attach servo on pin 8 to a servo object/instance
lcd.init();
lcd.backlight();
lcd.createChar(0, rail);
lcd.clear();
lcd.setCursor(0, 0);
lcd.write(0);
lcd.print(" NationalRail ");
lcd.write(0);
lcd.setCursor(4, 1);
lcd.print("St. Paul");
for (int i = 0; i < 3; i++) //
for (int j = 0; j < 2; j++) {
pinMode(LED[i][j], OUTPUT); // set all LEDs as OUTPUT
digitalWrite(LED[i][j], HIGH); // set all LEDs OFF
}
pinMode(buttonPin, INPUT_PULLUP);
welcome();
grnLEDs(ON);
}
void loop() {
readButton(); // immediate call for train arrival
if (callTrain)
sequenceRRX();
}
void sequenceTrafficLights() {
}
void readButton() {
if (!digitalRead(buttonPin)) {
delay(150); // debounce button
callTrain = true;
lcd.setCursor(1, 1);
lcd.print("Train arriving");
Serial.print("Train approaching (GREEN ");
Serial.print(grnDelay);
Serial.println(" seconds delay).");
}
}
void sequenceRRX() {
callTrain = false;
// wigwag(); // neopixels red strobe
delay(grnDelay * millisDelay);
grnLEDs(OFF);
yelLEDs(ON);
delay(yelDelay * millisDelay);
yelLEDs(OFF);
lowerGates();
redLEDs(ON);
delay(redDelay * millisDelay);
redLEDs(OFF);
raiseGates();
// only in the wild, wild, west
// yelLEDs(ON);
// delay(yelDelay * millisDelay);
// yelLEDs(OFF);
grnLEDs(ON);
lcd.setCursor(0, 1);
lcd.print(" St. Paul ");
}
void nextTrain(int val) {
lcd.print("Arrival: ");
lcd.print( val );
lcd.print("min");
}
void wigwag () {
// neoPixel wigwag awaiting non-blocking code (remove delay()s)
pixels.clear();
pixels.show();
// delay(100);
for (int i = 0; i < PIX / 4; i++)
{
pixels.setPixelColor (i, pixels.Color(255, 0, 0));
pixels.setPixelColor (i + 16, pixels.Color(255, 0, 0));
}
pixels.show();
}
void redLEDs(byte val) {
for (int i = 0; i < 2; i++) {
digitalWrite(rLED[i], val);
}
if (!val) { // if ON
Serial.print("Automobile traffic stopped (RED ");
Serial.print(redDelay);
Serial.println(" seconds delay)");
}
}
void yelLEDs(byte val) {
for (int i = 0; i < 2; i++) {
digitalWrite(yLED[i], val);
}
if (!val) { // if ON
Serial.print("Automobile traffic warned (YELLOW ");
Serial.print(yelDelay);
Serial.println(" seconds delay)");
}
}
void grnLEDs(byte val) {
for (int i = 0; i < 2; i++) {
digitalWrite(gLED[i], val);
}
if (!val) { // if ON
Serial.println("Automobile traffic passing (GREEN indefinite).");
Serial.println("Press CALL TRAIN for RRX sequence.");
}
}
void lowerGates() {
servo0.write(180);
servo1.write(0);
}
void raiseGates () {
servo0.write(90);
servo1.write(90);
}
void welcome() {
}R R X