Traffic lights for streets


How about 6 outputs driving the 6 different lights on the traffic lights where two streets intersect. And we will make sure that both are red for a little bit at the same time to have less accidents by those people who do not sit and text at the red lights, and takes off right before the green light goes...well, the traffic crossing him/her would have had a red light for a bit now, so take off buddy, the next red light is waiting for you!

Active traffic lights for scenery...

Something simple EVERY layout can use for the price of 1 Arduino (read $3) controlling 6 LEDs and 6 resistors! A traffic light simply steps through green, yellow and red from one direction and then allows the other direction to do the same.

So you would need a green LED and its appropriate current limiting resistor to set the brightness you want, a yellow one with its resistor and the same for the red signal. Then you make at least one more copy of this for the cross traffic and more sets if you also need to show the opposing directions.

The code is written with Object-oriented Programming (OOP), which is in short, a way to write code where you can instantiate an object that contains all its own methods and data variables. Big words right? But all to write less code, so all worth the heartache. Without OOP, we would create a long list of instructions to interact with a long list of variables, for example:

// no-OOP Trafficlight code, like in the old days

void setup() {

 // make all pins outputs

 pinMode( northRedLED, OUTPUT );

 // ... and 5 more of these for the other signal light pins...

 // and then turn only the Red ones on and the rest off

 digitalWrite( northRedLED,    LOW  );  // turn the red on

 digitalWrite( eastRedLED,     LOW  );  // turn the red on

 digitalWrite( northYellowLED, HIGH );  // yellow off

 digitalWrite( eastYellowLED,  HIGH );  // yellow off

 digitalWrite( northGreenLED,  HIGH );  // green off

 digitalWrite( eastGreenLED,   HIGH );  // green off

} // setup

void loop() {

 // We start with going north getting the green

 digitalWrite( northRedLED, HIGH );  // turn the red off

 digitalWrite( northGreenLED, LOW ); // turn the green on

 // east is already red

 delay( 2000 );                      // 2 seconds green, or more if you like


 // northbound yellow

 digitalWrite( northGreenLED, HIGH ); // turn the green off

 digitalWrite( northYellowLED, LOW ); // turn the yellow on

 // east is still red

 delay( 1000 );                       // 1 second yellow


 // northbound red

 digitalWrite( northYellowLED, HIGH ); // turn the yellow off

 digitalWrite( northRedLED, LOW );     // turn the red on

 // east is still red

 delay( 1000 );                        // 1 second red on both


 // eastbound green

 digitalWrite( eastRedLED, HIGH );     // turn the red off

 digitalWrite( eastGreenLED, LOW );    // turn the green on

 // north is still red

 delay( 5000 );                        // 5 seconds green


 // and so forth … with maybe 6 more lines of code for east’s yellow and then both red again

} // loop


/******************************* END OF FILE **********************************/

You can see that, even though this is not a humongous long list of instructions, if you want to change anything in the cycle, you need to do it in two places, for going north and going east further down. If you want to add another set of lights at another street intersection (since you do have 6 more free pins, right?) you need to duplicate every line of code, except the delays and then change the pin numbers to use:


 // We start with going north getting the green

 digitalWrite( northRedLED1,   HIGH );  // turn the red off at the corner of Main and First street

 digitalWrite( northRedLED2,   HIGH );  // turn the red off at the corner of Main and Station street

 digitalWrite( northGreenLED1, LOW  );  // turn the green on at the corner of Main and First street

 digitalWrite( northGreenLED2, LOW  );  // turn the green on at the corner of Main and Station street


Well, you could simply wire the LEDs into the same pins, but you can only do that so many times before you reach the pin’s current limit. And, what are you going to do when you don’t want the lights at every street corner to be perfectly in sync? That is not how the prototype does it, well don’t model that either, since nobody likes stopping at every light!


So, in OOP, you put all the signal managing code in a class, TrafficLite, in my code, then create an object (or two) from it and simply call the methods in the object to move the signal to the next phase. The methods you can call are Go(), DelayStart(), IsRed() or Update():


TrafficLite lite1( NS_REDPIN, NS_YELPIN, NS_GRNPIN );
TrafficLite lite2( EW_REDPIN, EW_YELPIN, EW_GRNPIN );

void setup() {

 lite1.Go();

 lite2.DelayStart();

} // setup


void loop() {

 lite1.Update();
 lite2.Update();

} // loop

 

So, in the code above, we have the class start the signal in the Go() method at red, and turn the other two off, and we simply check the time expired every time Update() is called to move the signal to the next state. To keep it a little easier on the audience, the two signals is synced to each other by specific, but instead have their phases delayed by DelayStart();. So as long as you make sure the time for red is longer than yellow plus green, they will stay out of phase and appear in sync. The point here was to show that if I wanted 2 more traffic lights, all I need to add is:


TrafficLite lite3( NS_REDPIN2, NS_YELPIN2, NS_GRNPIN2 ); TrafficLite lite4( EW_REDPIN2, EW_YELPIN2, EW_GRNPIN2 );


And get them to go in setup() and then in loop() have:


 lite1.Update();  lite2.Update();

 lite3.Update();  lite4.Update();


When you use an Arduino Mega 2560, you have 56 digital I/O pins and can easily do 9 intersections! And you don’t want to deal with 9 x 18 lines of code, I hope.
// TrafficLight
//
// Two ways to do this, each pole runs on its own cycle, you just need to start them at the right time
// or a higher power change the states and each light just light the right light, right?
//
// I added a "delayStart", which sends the 2nd light into a short red wait, before going green, when the 
// first lite goes red. So there is some time for both to be red, safety fizshhhht offisah!
//
// Something to check out http://playground.arduino.cc/Code/FiniteStateMachine


// North South (NS) and East West (EW) 
#define NS_REDPIN   3
#define NS_YELPIN   5
#define NS_GRNPIN   6
#define EW_REDPIN   9
#define EW_YELPIN   10
#define EW_GRNPIN   11

#define UPDATETIME 50

#define INTER_RED_DELAY 30  //  30x50 = 1.5 seconds
#define GREEN_TIME 100      // 100x50 = 5.0 seconds
#define YELLOW_TIME 30      //  30x50 = 1.5 seconds
#define RED_TIME 20+GREEN_TIME+YELLOW_TIME+INTER_RED_DELAY

// The Class contains all the variables and code to operate a TrafficLite // In the newer Arduino IDEs, you can put all this code in a TrafficLite.h // file, so you can use it somewhere else too. class TrafficLite {   // Class Member Variables   // These are initialized at startup   int redPin; // the number of the red LED pin   int yelPin; // the number of the yellow LED pin   int grnPin; // the number of the green LED pin       // These maintain the current state   int ledState; // ledState used to set the LED, 0 off, 1 red, 2 yellow, 3 green, 4 delay start while red   int countDown;   unsigned long previousMillis; // will store last time LED was updated       // turn the led on for the current state, to avoid keeping track of which light to turn off, we turn them   //all off, and then the needed one on.   void Output() {     digitalWrite( redPin, HIGH ); // turn all off     digitalWrite( yelPin, HIGH );     digitalWrite( grnPin, HIGH );          switch ( ledState ) {       case 0: break; // stay off       case 4: // red, while the other light is red too       case 1: // red         digitalWrite( redPin, LOW ); //         break;       case 2: // yellow         digitalWrite( yelPin, LOW ); //         break;       case 3: // green         digitalWrite( grnPin, LOW ); //         break;       default: ;          break;     }; // switch   } // output      public:   // Constructor - creates a Traficlite
 // and initializes the member variables, state and pins   TrafficLite( int rPin, int yPin, int gPin ) {     redPin = rPin;     yelPin = yPin;     grnPin = gPin;     pinMode( redPin, OUTPUT );     pinMode( yelPin, OUTPUT );     pinMode( grnPin, OUTPUT );             countDown = 0;     ledState = 0;      Output();     previousMillis = millis();   } // TrafficLite(int, int, int) constructor   // start off in the green state   void Go() {     ledState = 3; // go green     countDown = GREEN_TIME;     Output();   } // Go()      // the only way to get into state 4, and we go red and wait the   // inter_red_delay, while the other lite is red.   void DelayStart() {     ledState = 4; // go red and wait     countDown = INTER_RED_DELAY;     Output();   } // DelayStart()   // true if the lite is in the red state, need to turn the other lite on at the right time   bool isRed() {     return ledState == 1;   } // isRed()   // to avoid using "delay", we rather check the current time and so how far we are from  //   last time, to decide if a lite needs to change color   void Update() {     unsigned long now = millis();           if ( now - previousMillis >= UPDATETIME ) {       previousMillis = now;       if ( countDown > 0 ) {         countDown--;       } else {         ledState--;          // 4 goes to 3 only once, so no need to switch case 4:         switch ( ledState ) {         case 0:           ledState = 3;         case 3:           countDown = GREEN_TIME;           break;         case 2:           countDown = YELLOW_TIME;           break;         case 1:           countDown = RED_TIME;           break;                    }; // switch         Output();                   // Update the actual LEDs       } // time for change yet?     } // if   } // Update() }; // TrafficLite Class   TrafficLite lite1( NS_REDPIN, NS_YELPIN, NS_GRNPIN ); TrafficLite lite2( EW_REDPIN, EW_YELPIN, EW_GRNPIN ); unsigned char firstTime; // let the first lite run and when it goes red, start the                          // second one with the inter-lite red delay first void setup() {  firstTime = 1;  lite1.Go();  Serial.begin( 115200 );  Serial.println( "RRRduino TrafficLite v0.01"); } // setup     void loop() {  if ( firstTime == 1 ) {   // only the first time, wait for red and delayStart lite2    if ( lite1.isRed() ) {      lite2.DelayStart();      firstTime = 0;    } // if isRed  } // if firstTime  // and this is all that runs after the first time...  lite1.Update();  lite2.Update(); } // loop /******************************* END OF FILE **********************************/
Well, that was quite number of lines, but to add another intersection is 6 more lines of code and to change the timing on let’s say the green phase, is changing the one and only #define GREEN_TIME xxx. You will also notice that all 6 pins in use are PWM capable pins, labeled with a ~ on the Uno, so to fade the green, red or yellow in and/or out, you simply create one more function in the TrafficLite class and all the LEDs will do the fading.

Want to make it a little more advanced, something no-one else has done before? Add a pedestrian light and give a guest a button to press to cross the road! One more LED and resistor and one pushbutton switch with a pullup resistor! Or what about those green turn signals, ever seen those on a model train layout?

A small warning about copying code from pdfs and other documents, make sure the funny characters like double and single quotes end up in your program as the straight looking ones:
There is a big difference between , and ". Only the last one is useful. Again, the code is in a .ino file below if fast typing was not giving you your nickname.

The yellow and green turn arrows and the 20 second pedestrian flashing crossing lite, should be an easy homework task for you by now!


ċ
TrafficLite_OOP.ino
(5k)
Gert (TxAdmin) Muller,
Apr 14, 2017, 11:39 PM