1920's traffic light help

I have an old traffic light from the 1920's and it has eight lights (four green & four red). so when they was in operation green was "go" red was "stop" but before it would go to red the light would go green and red at the same time. so I am wanting to use an 8 channel relay board and need help with the code and possibly ideas.

I want to control each light on its own relay and be able to edit the times

  • What hardware and Arduino software experience do you have ?

  • What lamps are inside the equipment ?

Always show us a good schematic of your proposed circuit.
Show us a good image of your ‘actual’ wiring.
Give links to components.

Arduino code based on a State Machine would be a starting point.

There were several types, as time passed they got more complicated. I remember in the 50's the one in the town square was replaced. The old one had red and green on four sides. Green was on the top and was wired across and then to the red on the bottom. It simply lit green for EW and red for NS, then would change. It had a mechanical timer that would slow down as it got colder. The next was almost the same, the Yellow, all four, were on at the same time between red and green. The town was small, only had one light which they purchased used from a nearby town. No clue as to how old it was.

1 Like

I am using an arduino uno and I am not a coder but have only dabbled in a couple of arduino things. I have found a basic 4 relay sketch that could work if I double it. but the issue I'm having is getting two or more relays to come on at the same time.

In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch.

Use the </> icon from the ‘reply menu’ to attach the copied sketch.

```cpp
#define RELAY1 7  //Defining the pin 7 of the Arduino for the 4 relay module
#define RELAY2 6  //Defining the pin 6 of the Arduino for the 4 relay module
#define RELAY3 5  //Defining the pin 5 of the Arduino for the 4 relay module
#define RELAY4 4  //Defining the pin 4 of the Arduino for the 4 relay module

void setup() {
  pinMode(RELAY1, OUTPUT);  //Defining the pin 7 of the Arduino as output
  pinMode(RELAY2, OUTPUT);  //Defining the pin 6 of the Arduino as output
  pinMode(RELAY3, OUTPUT);  //Defining the pin 5 of the Arduino as output
  pinMode(RELAY4, OUTPUT);  //Defining the pin 4 of the Arduino as output
}

void loop() {
  digitalWrite(RELAY1, LOW);   // This will Turn ON the relay 1
  delay(5000);                 // Wait for 5 seconds
  digitalWrite(RELAY1, HIGH);  // This will Turn the Relay Off

  digitalWrite(RELAY2, LOW);   // This will Turn ON the relay
  delay(5000);                 // Wait for 5 seconds
  digitalWrite(RELAY2, HIGH);  // This will Turn the Relay Off

  digitalWrite(RELAY3, LOW);   // This will Turn ON the relay
  delay(5000);                 // Wait for 5 seconds
  digitalWrite(RELAY3, HIGH);  // This will Turn the Relay Off

  digitalWrite(RELAY4, LOW);   // This will Turn ON the relay
  delay(5000);                 // Wait for 5 seconds
  digitalWrite(RELAY4, HIGH);  // This will Turn the Relay Off
}

Which lamps are you using? AC or DC? Incandescent or LED or...?
Lamp voltage? Current or wattage?

I plan on using some 12 volt LED with their own power supply. so as soon as I can make the relays do what I want then I'll be able to use what ever lamps I desire

The problem with using delay( ) is all other code execution stops while in the delay period.


Read through this discussion, when you understand it, come back.

Hello rccraze

Do you have video showing 1920’s traffic light available?
I not born to that time.

This task can besolved by a led sequencer simply.

image

Confirm:
Is this a 4 way control light i.e East goes, then North goes, then West goes, then South goes ?
OR
Is this a 2 way control light i.e. East/West goes then North/South goes ?


Let's assume 2 (two) way:

  • 1 eastGreen ON, westGreen ON, northRed ON, southRED ON
  • 2 eastGreen ON, eastRed ON, westGreen ON, westRed ON, northRed ON, southRedON
  • 3 eastRed ON, westRed ON, northGreen ON, southGreenON
  • 4 eastRed ON, westRed ON, northGreen ON, northRed ON, southRed ON, southGreenON
  • Back to #1

Let's assume 4 (four) way:

  • 1- eastGreen ON, westRed ON, northRed ON, southRED ON
  • 2- eastGreen ON, eastRed ON, westRed ON, northRed ON, southRedON
  • 3- eastRed ON, westGreen ON, northRed ON, southRedON
  • 4- eastRed ON, westGreen ON, westRed ON, northRed ON, southRed ON
  • 5- eastRed ON, westRed ON, northGreen ON, southRed ON
  • 6- eastRed ON, westRed ON, northGreen ON, northRed ON, southRed ON
  • 7- eastRed ON, westRed ON, northRed ON, southGreen ON
  • 8- eastRed ON, westRed ON, northRed ON, southGreen ON, southRed ON
  • Back to #1

Hi, @rccraze
Welcome to the forum.

Can you please post some images of your traffic lights, as traffic light assemblies are not the same world wide, particularly 1920's style.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:
PS. Nice project.

This sketch should give you a very good grounding on what needs to be done for an 8 state State Machine.

It should be very easy for you to teak it to your needs.


// TrafficLight_1920_8States.ino

// https://forum.arduino.cc/t/1920s-traffic-light-help/1058420

//********************************************^************************************************
// Version    YY/MM/DD    Description
// 1.00       22/11/27    Running sketch
//
//

//********************************************^************************************************
//Macros
#define NOOP                          asm("nop\n")
#define PULSE63_13                    cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()

#define CLOSED                        LOW
#define OPENED                        HIGH

#define PUSHED                        LOW
#define RELEASED                      HIGH

#define LEDon                         HIGH
#define LEDoff                        LOW

#define RELAYon                       LOW
#define RELAYoff                      HIGH

#define RUNNING                       true
#define notRUNNING                    false

#define ENABLED                       true
#define DISABLED                      false

//********************************************^************************************************

const byte heartbeatLED             = 13;     // +5V----[220R]----[A->|-K]----GND

byte LEDsequence;

//****************************
//LED/relay definitions and states
//E=east, N=north, W=west, S=south, R=red, G=green
//
//                                     ER EG NR NG WR  WG  SR  SG
//                                      0  1  2  3  4  5   6   7
const byte LEDs[]                   = { 5, 6, 7, 8, 9, 10, 11, 12};

const byte LEDstates[8][8] =
{
  //E  E  N  N  W  W  S  S
  //R  G  R  G  R  G  R  G
  //0  1  2  3  4  5  6  7  Element
  { 0, 1, 1, 0, 1, 0, 1, 0}, //0     |
  { 1, 1, 1, 0, 1, 0, 1, 0}, //1     |
  { 1, 0, 0, 1, 1, 0, 1, 0}, //2     |  
  { 1, 0, 1, 1, 1, 0, 1, 0}, //3    /    AKA  LEDsequence #s
  { 1, 0, 1, 0, 0, 1, 1, 0}, //4    \   1 = LED ON,  0 = LED OFF
  { 1, 0, 1, 0, 1, 1, 1, 0}, //5     |
  { 1, 0, 1, 0, 1, 0, 0, 1}, //6     |
  { 1, 0, 1, 0, 1, 0, 1, 1}  //7     |
  //
};

//****************************
//timing stuff
unsigned long heartbeatTime;
unsigned long switchTime;
unsigned long stateMachineTime;
unsigned long commonTime;

unsigned long commonInterval        = 0;

const unsigned long oneLEDinterval  = 10 * 1000ul;  //10 seconds
const unsigned long twoLEDinterval  =  3 * 1000ul;  // 3 seconds

const unsigned long toggleInterval  = 500ul;        //500ms

//****************************
//State Machine
//change names to what serves you best
enum States {Startup, State0, State1, State2, State3, State4, State5, State6, State7};
States mState = Startup;


//                                       s e t u p ( )
//********************************************^************************************************
void setup()
{
  Serial.begin(9600);

  //all traffic LEDs/relays are outputs
  for (byte x = 0; x < sizeof(LEDs); x++)
  {
    digitalWrite(LEDs[x], LEDoff);
    pinMode(LEDs[x], OUTPUT);
  }

  pinMode(heartbeatLED, OUTPUT);

}  //END of   setup()


//                                        l o o p ( )
//********************************************^************************************************
void loop()
{
  //*************************************           heartbeat T I M E R
  //to see if the sketch has blocking code,
  //toggle the heartbeat LED (every 500ms)
  if (millis() - heartbeatTime >= toggleInterval)
  {
    //restart the TIMER
    heartbeatTime = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //*************************************           checkMachine T I M E R
  //is it time to check the the State Machine ? (every 1ms)
  if (micros() - stateMachineTime >= 1000ul)
  {
    //PULSE63_13;

    //restart this TIMER
    stateMachineTime = micros();

    //service the State Machine
    checkMachine();
  }

  //*********************************
  //other non blocking code goes here
  //*********************************

} //END of   loop()


//                               c h e c k M a c h i n e ( )
//********************************************^************************************************
//checking to see if the State Machine needs servicing
void checkMachine()
{
  switch (mState)
  {
    //**********************                                    Startup
    case Startup:
      {
        //starting point in our LED sequence
        LEDsequence = 0;

        //update to the next LED states
        LEDControl(LEDsequence++, oneLEDinterval);

        mState = State0;
      }
      break;
    //END of  case

    //**********************                                    State0
    case State0:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, twoLEDinterval);

          //next state in our machine
          mState = State1;
        }
      }
      break;
    //END of  case

    //**********************                                    State1
    case State1:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, oneLEDinterval);

          //next state in our machine
          mState = State2;
        }
      }
      break;
    //END of  case

    //**********************                                    State2
    case State2:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, twoLEDinterval);

          //next state in our machine
          mState = State3;
        }
      }
      break;
    //END of  case

    //**********************                                    State3
    case State3:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, oneLEDinterval);

          //next state in our machine
          mState = State4;
        }
      }
      break;
    //END of  case

    //**********************                                    State4
    case State4:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, twoLEDinterval);

          //next state in our machine
          mState = State5;
        }
      }
      break;
    //END of  case

    //**********************                                    State5
    case State5:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, oneLEDinterval);

          //next state in our machine
          mState = State6;
        }
      }
      break;
    //END of  case

    //**********************                                    State6
    case State6:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //update to the next LED states
          LEDControl(LEDsequence++, twoLEDinterval);

          //next state in our machine
          mState = State7;
        }
      }
      break;
    //END of  case

    //**********************                                    State7
    case State7:
      {
        //has the TIMER expired ?
        if (checkCommonTimer())
        {
          //back to the 1st LED sequence
          LEDsequence = 0;

          //update to the next LED states
          LEDControl(LEDsequence++, oneLEDinterval);

          //next state in our machine
          mState = State0;  //          <-----<<<<  back the beginning
        }
      }
      break;
      //END of  case

  } //END of   switch/case

} //END of   checkMachine()


//                                  L E D c o n t r o l ( )
//********************************************^************************************************
//update the 8 LED states, set and restart the common TIMER
void LEDControl(byte arrayElement, unsigned long interval)
{
  //update all LEDs to their next states
  for (byte x = 0; x <= 7; x++)
  {
    //set/reset all 8 LED states
    //if the LEDs/relays are HIGH true, remove the ! in the next line  <------<<<<<
    digitalWrite(LEDs[x], !LEDstates[arrayElement][x]);
  }

  //set the TIMER interval of the common TIMER
  commonInterval = interval;

  //restart the common TIMER
  commonTime = millis();

} //END of   LEDcontrol()


//                            c h e c k C o m m o n T i m e r ( )
//********************************************^************************************************
//checking the common TIMER condition
bool checkCommonTimer()
{
  //has the TIMER expired ?
  if (millis() - commonTime >= commonInterval)
  {
    //the TIMER has expired
    return true;
  }

  //the TIMER has not expired
  return false;

} //END of   checkCommonTimer()


//********************************************^************************************************
1 Like

2 way Option number two is the way the was it is supposed to be but now that you mentioned option 1, I personally think that would be cool. And I do not have any pics or videos at this time but will as I work on it.

Scott Spaid

Thanks Larry, I will definitely try that sketch out and see how it goes and I'll put up some videos and pics about it as well.

Scott Spaid

This is not my light but the same style except mine is a hanging light and not a post mount but I will definitely be posting progress videos when I get to it in a few weeks.

Scott Spaid

2 Likes

Hello rccraze

Here comes my suggestion coded in C++ for your traffic light control. I borrowed the sequence from LarryD.
This sequence can be easily changed and added in the array without touching the rest of the code.

TRAFFICLIGHT trafficLights[]
{
  //E  E  N  N  W  W  S  S
  //R  G  R  G  R  G  R  G  light time
  {{0, 1, 1, 0, 1, 0, 1, 0}, 10000, 0, true},
  {{1, 1, 1, 0, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 0, 1, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 1, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 0, 1, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 1, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 0, 0, 1}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 0, 1, 1}, 10000, 0, false},
};

For each sequence you can specify a traffic light time.

Check it, test it and make changes for your needs.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  Many thanks to LarryD
  https://aws1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  https://forum.arduino.cc/t/1920s-traffic-light-help/1058420
  Tested with Arduino: Mega[ ] - UNO [x] - Nano [ ]
*/
#define ProjectName "1920’s traffic light"
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
// copy from larryD
//                        E  E  N  N  W  W  S  S
//                        R  G  R  G  R  G  R  G
constexpr byte LedPins[] {2, 3, 4, 5, 6, 7, 8, 9}; // portPin o---|220|---|LED|---GND
constexpr unsigned long Blink512Hz {9};     // blinkrate for heartbeat function
#define OutPutTest
constexpr  unsigned long OutPutTestTime {100};
unsigned long currentTime;
struct TIMER
{
  const unsigned long  Duration;
  int unsigned long stamp;
  int onOff;
};
struct TRAFFICLIGHT
{
  int pattern[8];
  TIMER patternTime;
};
/* copy from larryD
  //E  E  N  N  W  W  S  S
  //R  G  R  G  R  G  R  G
  //0  1  2  3  4  5  6  7  Element
  { 0, 1, 1, 0, 1, 0, 1, 0}, //0     /
  { 1, 1, 1, 0, 1, 0, 1, 0}, //1     |
  { 1, 0, 0, 1, 1, 0, 1, 0}, //2     |  AKA  LEDsequence #s
  { 1, 0, 1, 1, 1, 0, 1, 0}, //3    <
  { 1, 0, 1, 0, 0, 1, 1, 0}, //4     |  1 = LED ON,  0 = LED OFF
  { 1, 0, 1, 0, 1, 1, 1, 0}, //5     |
  { 1, 0, 1, 0, 1, 0, 0, 1}, //6     |
  { 1, 0, 1, 0, 1, 0, 1, 1}  //7     \
  //
*/
TRAFFICLIGHT trafficLights[]
{
  //E  E  N  N  W  W  S  S
  //R  G  R  G  R  G  R  G  light time
  {{0, 1, 1, 0, 1, 0, 1, 0}, 10000, 0, true},
  {{1, 1, 1, 0, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 0, 1, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 1, 1, 0, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 0, 1, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 1, 1, 0}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 0, 0, 1}, 10000, 0, false},
  {{1, 0, 1, 0, 1, 0, 1, 1}, 10000, 0, false},
};

void heartBeat(int rate)
{
  bool myBlink {currentTime & bit(rate)};
  digitalWrite(LED_BUILTIN, myBlink);
}
// -------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto LedPin : LedPins) pinMode(LedPin, OUTPUT);
#ifdef OutPutTest
  // check outputs
  Serial.print(F("led test"));
  for (auto LedPin : LedPins) Serial.print(F(".")),digitalWrite(LedPin, HIGH), delay(OutPutTestTime);
  for (auto LedPin : LedPins) Serial.print(F(".")),digitalWrite(LedPin, LOW), delay(OutPutTestTime);
  Serial.print(F("done\n"));
#endif
}
void loop () 
{
  currentTime = millis();
  heartBeat(Blink512Hz);

  for (auto &trafficLight : trafficLights)
  {
    if (currentTime - trafficLight.patternTime.stamp >= trafficLight.patternTime.Duration && trafficLight.patternTime.onOff)
    {
      static int patternCounter = 0;
      int element=0;
      trafficLight.patternTime.onOff = false;
      for (auto LedPin : LedPins) digitalWrite(LedPin, trafficLights[patternCounter].pattern[element++]);
      trafficLights[patternCounter].patternTime.onOff = true;
      trafficLights[patternCounter].patternTime.stamp = currentTime;
      if (++patternCounter == (sizeof(trafficLights) / sizeof(trafficLights[0]))) patternCounter = 0;
    }
  }
}

Ok I see that you added a 1 second time per sequence but I'm confused on if I add your code in place of something on Larry's code or in addition somewhere. I apologize as I simply don't understand coding very well.

Scott Spaid

Hello rccraze

Which sequence time is needed.

I´ll change it.

“Is this a 2 way control light i.e. East/West goes then North/South goes.”

If the above is the way it should be, simply paralleling the East red/green lamps with the West red/green lamps, and North with South, will simplify things a lot.


If you use the code from post #13, you only need to change the times for the two delays to what’s needed.

i.e.

const unsigned long oneLEDinterval  = 10 * 1000ul;  //10 seconds
const unsigned long twoLEDinterval  =  3 * 1000ul;  // 3 seconds

  • What relays are you going to use ?

I like Paul’s use of Structures.
I have not tried his version but I’m sure it will work too.

For new users it might be a bit more difficult to follow or modify.

His methods should be learned by new people once they become more confident with their programming skills.


FYI
Diagnostic hint:

As a side note, if you have access to an oscilloscope, you can use it to double check sketch timing etc.

Here we have line 124 uncommented to run the code PULSE63_13 macro, as it is defined; this generates a 62ns pulse every time we check the State Machine, i.e. every 1ms.