Tuesday, October 1, 2013

Traffic Signal Prototype

Leave a Comment
After achieving success with getting the RGB NeoPixels to work, I quickly put together a sketch to control a traffic signal for a four-way intersection.

This is what it looks like while running:

A few things that I learned while putting this together.

1. NeoPixels are awesome!

My original intent in using NeoPixels rather than separate Red, Yellow, and Green LEDs or even "normal" RGB LEDs was to reduce the wiring needed, and the NeoPixels have certainly lived up to my intent. Using ordinary LEDs, each pair of like colored LEDs would have required a separate Arduino pin and a separate circuit leading from the power supply to the LED. This would have meant 6 separate sets of wires leading to the traffic signal, with additional wiring between the LEDs. Using ordinary RGB LEDs would have still required two separate pins and circuits, but with the NeoPixels I can independently control all four signal lights with just one pin and circuit.

The full sketch is included at the bottom of this post for reference, but the code for controlling each NeoPixel is as simple as:
 strip.setPixelColor(0, red);
 strip.setPixelColor(1, green);
 strip.show();
 delay(timeGreen);
The strip.setPixelColor function sets the color of the first pixel (0) red and the second pixel (1) green, and then the strip.show function actually makes the strip light up. So even though the NeoPixels are all wired together in one strip, you can still address each LED on an individual basis.

2. External libraries can be useful

Of course, there's a lot more to make these NeoPixels work than just the code in my sketch. These strip functions are actually calling very complex code that is contained in an external library, which was called by the initial line:
#include <Adafruit_NeoPixel.h>
The Adafruit_NeoPixel library contains the code that does the "heavy-lifting" that tells the Arduino what to do to get the pixel strand to work. The great thing about these external libraries is that you don't need to know any of the details about how these functions work, you just need to know the proper syntax to call up these functions, including the variables to be passed to get the results that you want. This also simplifies your own sketch, as you do not need to include the actual lines of code that define these functions; they are contained in the external library.

3. Define a value once, easily tweak many times later

In this sketch, there are several values that appear multiple times in the code, such as the RGB values for the different colors and the time periods for how long each color is on. While the program would work just fine if the actual values are typed in for each occasion that it is needed, if later tweaks are required (and they inevitably are) it becomes quite a chore to manually change those values to new ones, especially if there are many repetitions. A very effective technique is to declare variables in your sketch to hold these values, and then call these variables rather than the actual values themselves in the rest of your sketch. This way, if you need to tweak the values later, you just need to change the variable value once.

For example, in my traffic signal sketch, I declare these variables:
// Define the color codes by name to make it easier to call later on
uint32_t red = strip.Color(255, 0, 0);
uint32_t green = strip.Color(0, 255, 0);
uint32_t yellow = strip.Color(255, 100, 0);

// Define time intervals to make it easier to tweak later
timeGreen = 5000; // time interval that light stays green
timeYellow = 2000; // time interval that light stays yellow
timeRed = 1000;  // time interval that light stays red before other signal turns green
The first three variables define the RGB codes for red, green, and yellow, while the other three define the time intervals for how long the various colors stay on. I had to tweak the RGB values for yellow multiple times to get the right shade, and it was significantly easier to just change the value in one location in my sketch rather than each time yellow was called. It was also easier to just call "red" rather than write out stripe.Color(255, 0, 0) each time I needed the NeoPixel to be red. If I want to change the time that the traffic signal stays green, I can just change the value of timeGreen once and it would apply throughout without having to manually change the delay value at each location.

Judicious use of variables can greatly speed up the fine-tuning of a project.

Full Sketch:

#include <Adafruit_NeoPixel.h>

#define PIN 6

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(4, PIN, NEO_RGB + NEO_KHZ800);

// Define the color codes by name to make it easier to call later on
uint32_t red = strip.Color(255, 0, 0);
uint32_t green = strip.Color(0, 255, 0);
uint32_t yellow = strip.Color(255, 100, 0);

// Define time intervals to make it easier to tweak later
timeGreen = 5000; // time interval that light stays green
timeYellow = 2000; // time interval that light stays yellow
timeRed = 1000;  // time interval that light stays red before other signal turns green

void setup()
{
 strip.begin();
 strip.show();  // Initialize all pixels to 'off'
}

void loop()
{
 //Traffic Light, Phase 1
 strip.setPixelColor(0, red);
 strip.setPixelColor(2, red);
 strip.setPixelColor(1, green);
 strip.setPixelColor(3, green);
 strip.show();
 delay(timeGreen);

 //Traffic Light, Phase 2 - Green lights turn to yellow, then red
 strip.setPixelColor(1, yellow);
 strip.setPixelColor(3, yellow);
 strip.show();
 delay(timeYellow);
 strip.setPixelColor(1, red);
 strip.setPixelColor(3, red);
 strip.show();
 delay(timeRed);

 //Traffic Light, Phase 3 - Red lights turn Green
 strip.setPixelColor(0, green);
 strip.setPixelColor(2, green);
 strip.show();
 delay(timeGreen);

 //Traffic Light, Phase 4 - Green lights turn to yellow, then red
 strip.setPixelColor(0, yellow);
 strip.setPixelColor(2, yellow);
 strip.show();
 delay(timeYellow);
 strip.setPixelColor(0, red);
 strip.setPixelColor(2, red);
 strip.show();
 delay(timeRed);
}

0 comments:

Post a Comment