Introduction: Arduino Traffic Light for Beginners

About: I help run makerspaces / hackerspaces, love learning new tools and technology by building and documenting projects, and enjoy exploring the world with my wife ; )

* 08/24/2013 - Updated to include Traffic Light Template (See PDF Below)

This instructable will walk you through the steps of creating a one way traffic light. It is designed to work in tandem with our Line Following Car for Beginners. By combining the two, you will have a Line Following Robot that obeys a Traffic Signal - if you want it to : ) Depending on how you source your parts, we estimate this project (without the car) costs approximately $30 to $50. We recommend you have a few hours of dedicated time for completion.

This project was originally designed for a summer camp at a Hackerspace in Ann Arbor, MI. If you aren't already familiar with what a Hackerspace/Makerspace is, we highly recommend you check one out! They can be a wonderful resource for both tools and information. Things like access to a LASER cutter can make this project look significantly better with minimal effort. Find one near you!

Suggested Tools:
- Soldering Iron
- Wire Snips
- Pliers (Needle Nose Preferred)
- Wire Strippers (22 AWG)
- Utility Knife
- Phillips Head Screwdriver (No. 1)
- Pencil
- Arduino UNO
- Breadboard
- 9V Battery Holder with 2.1mm Barrel Connector
- LASER Cutter

Suggested Materials:
- Solder
- 9V Battery
- Electrical Tape
- ~6" of HeatShrink (3/32")
- 8 x Sticky Rubber Feet
- Traffic Light Enclosure
- 3 x 220 Ohm Resistors (Red Red Brown)
- 1 x 100 Ohm Resistor (Brown Black Brown)
- 1 x 10k Ohm Resistor (Brown Black Orange)
- 1 x Red LED
- 1 x Yellow LED
- 1 x Green LED
- 3 x Blue LEDs (Any color will do, but all three should match)
- 1 x NPN Transistor (PN2222)
- 1 x Photocell
- 22 AWG Hook Up Wire, preferably in the colors Red, Black, Green, and Yellow.

Highly Recommended
- Clean workspace
- Good lighting
- Someone awesome to work with

Short on resources?
- Find out if there's a local hackerspace near by!
- Need it today? Radioshack. Can you wait a few days? Adafruit, and Sparkfun are excellent resources.

Who made this?
- This instructable was brought to you by Khevna Shah and Josh Williams, and much help from the World's Friendliest Hackerspace: All Hands Active

Step 1: Prepare Your Red, Green, and Yellow LEDs for Soldering

A note about this instructable:
We use photos for most of the instructions of the physical setup. For each step:
 - First, review the Tools & Materials Needed.
 - Second, open the first image.
 - Third, move your mouse cursor over the comment box for a short description.
 - Click the arrow on the right side of the image to move to the next image.
 - When no more arrows show up, close the image and move onto the next step.

Tools Needed:
- Hands
- Wire Strippers

Materials Needed:
- 1 x Red LED
- 1 x Green LED
- 1 x Yellow LED
- 1 x Black Wire (22 AWG Solid Core, ~21 cm in length


Step 2: Position and Solder Your Lights!

Tools Needed:
- Hands
- Wire Strippers
- Wire Snips
- Soldering Iron

Materials Needed:
- Unsoldered Traffic Light
- 1 x Red Wire (22 AWG, ~21cm in Length)
- 1 x Green Wire (22 AWG, ~21cm in Length)
- 1 x Yellow Wire (22 AWG, ~21cm in Length)
- 1 x Traffic Light Housing (two parts)

Step 3: Solder Track Lights

** MAKE THIS GIF SEPARATE PLZ KTHXBYE

Tools Needed:

- Hands
- Wire Strippers
- Wire Snips or Scissors
- Soldering Iron
- Heat Gun

Materials Needed:
- Solder
- 1 x Black Wire (22 AWG, ~41cm in Length)
- 1 x Red Wire (22 AWG, ~41cm in Length)
- 3 x Blue LEDs
- 2 x Heatshrink (2cm in length, 2.3mm (3/32") diameter)

FYI: The second image in this is step an absolutely amazing gif animation. Please hang tight, it might take a moment to load.

Step 4: Solder Photocell

* SPECIFY SIZES
* HOW LONG TO SHRINK BRO?

Tools Needed:

- Hands
- Wire Strippers
- Wire Snips or Scissors
- Soldering Iron
- Heat Gun

Materials Needed:
- Solder
- 1 x Black Wire (22 AWG, ~25cm in Length)
- 1 x Red Wire (22 AWG, ~25cm in Length)
- 1 x Photocell
- 2 x Heatshrink tube (4cm in length, 2.3mm (3/32") diameter)

There is no gif animation here. Maybe the next step will!

Step 5: Assembling Track Lights

Tools Needed:
- Hands
- Scissors
- No. 1 Phillips Screwdriver

Materials Needed:
- Pre-soldered Track Light
- Electrical Tape 

Step 6: Assembling Photocell Onto Track

Tools Needed:
- Hands
- Scissors
- No. 1 Phillips Screwdriver

Materials Needed:
- Pre-soldered Photocell Sensor
- Electrical Tape

Step 7: Attach Your Traffic Light!

Tools Needed:
- Hands
- Utility Knife
- Pencil

Materials Needed:
- Pre-soldered Traffic Light Setup
- Traffic Light Plates (If you're participating in the AHA Summer Camp, these are already in your kit!)
- - If you aren't in summer camp. You can use these files with a LASER Cutter.
- - Or Print them out on your printer and use it as a guide to cut out of cardboard!
- - Or design your own!


Step 8: Connect the Wires!

Tools Needed:
- Hands
- Arduino Uno
- Breadboard
- Wire Strippers
- Wire Snips
- Pliers

Materials Needed:
- Assembled Traffic Light
- Assembled Photocell / Sensor
- Assembled 3 x LED Setup
- Red Wire
- Black Wire
- Green Wire
- Yellow Wire
- Blue Wire
- 4 x 220 Ohm Resistors (Red Red Brown)
- 1 x 10k Ohm Resistor (Brown Black Orange)
- 1 x 100 Ohm Resistor (Brown Black Brown)
- 1 x NPN Transistor

Step 9: Set Up the Arduino Environment

This instructable makes many assumptions! Some people like to call these "prerequisites". In order to make sure you get the most out of this instructable, you should have:
 - The Arduino Software downloaded and installed on your computer.
 - Plugged in and tested your Arduino by following the installation guide appropriate for your computer.
 - Approximately one hour of time to spare, and a nice clean workspace with plenty of lighting.

Mission Complete? Continue on!

Note:
Go to this page for tutorials: http://arduino.cc/en/Tutorial/HomePage
Go to this page for references: http://arduino.cc/en/Reference/HomePage

Image Source:  The Getting Started w/Arduino Guide

Step 10: Basic Arduino Programming

You will write your code in two basic sections: the "setup" section and the "loop" section. These sections are known as functions. We will learn more about what a function is later on!

The Setup function runs once when the Arduino is turned on or reset.
The Loop function runs continuously after the setup function runs once.

Here's a basic Arduino program. This program doesn't do anything interesting yet, but that comes next!

voidsetup()
{
// code in here runs once
}

voidloop()
{
// after the setup function, code in here runs over and over
}



Step 11: Turn on Your Green LED

For you to turn on your LED, two things must happen.

First, you need to tell the Arduino that you will OUTPUT data on the pin you plugged the Green LED into.

You can do this by using the pinMode function.

An example of this is: pinMode(3, OUTPUT); where my pin number is 3.


Second, you need to send a HIGH signal to the LED to turn it on! (A "LOW" signal will turn the LED off.)

You can do this by using the digitalWrite function.

An example of this is: digitalWrite(3, HIGH); where my pin number is 3.


Now try turning on the Green LED! It should be on PIN 2. Here is some code to help you get started:

voidsetup()
{
// set the pinMode to OUTPUT
// your code here
}

voidloop()
{
// digitalWrite the pin to HIGH
  // your code here
}


Step 12: Variables!

In the previous step, we wrote the following line of code:  pinMode(2, OUTPUT); and digitalWrite(2, HIGH);

What if I wanted to move my Green LED to PIN 4? This would mean changing numbers in two different places! Yuck!

Instead, we tell the computer that the word GREEN means 2, and then use the word GREEN everywhere! That way, if I moved my Green LED to PIN 4, I would just tell the computer that GREEN now means 4!

To do this we use: Variables!

Variables allow you to give names to things. There are lots of different types of variables.

Today we're going to learn about a number variable called an int (short for integer). An int can be any whole number from -32,768 to 32,767. More details here: http://arduino.cc/en/Reference/Int

Variables have 3 properties: type, name, and value.

For instance:  int GREEN = 2; has a type of int, a name of GREEN, and a value of 2.

A variable is used in place of a value.

Anywhere you want to use a 2 you can now write GREEN

* Remember: You have to make a variable before you can use it!

Now try turning on the Green LED using the variable "GREEN." It should be on PIN 2. Here is some code to help you get started:

// make your variable
// your code here

voidsetup()
{
// set the pinMode to OUTPUT using GREEN
// your code here
}

voidloop()
{
// digitalWrite the pin to HIGH using GREEN
  // your code here
}


* Variables exist in different areas known as scopes. A scope is the area between a starting curly bracket { and its matching ending curly bracket  }. In our case, we're going to declare the variables all at the top of the code. These variables are known as global variables. A global variable can be used anywhere in the document.

Step 13: Make Your Green LED Blink! (Part 1/2)

To make the LED Blink, we'll need to use digitalWrite to write HIGH and then LOW to GREEN.

What happens when you try this:

// variables
int GREEN = 3;

voidsetup()
{
// setup LED modes
pinMode(GREEN, OUTPUT);
}

voidloop()
{
// High turns things on
digitalWrite(GREEN, HIGH);
// low turns things off
digitalWrite(GREEN, LOW);
}

Does it work? No? Go on to Part 2!

Step 14: Making Your Green LED Blink! (Part 2/2)

The code executes faster than your eye can notice!

To solve this problem, we're going to add a delay between the light being on and the light being off!

You can do this by using the delay function.

An example of this is: delay(100); where my delay is 100milliseconds.

More details here: http://arduino.cc/en/Reference/Delay



Use the variable DELAY_GREEN to create a 1 second, 1000 millisecond, delay between the light being on and off:

// variables
int GREEN = 3;
int DELAY_GREEN = 1000;

voidsetup()
{
// setup LED modes
pinMode(GREEN, OUTPUT);
}

voidloop()
{
// High turns things on
digitalWrite(GREEN, HIGH);

// we need a delay here!
// your code here

// low turns things off
digitalWrite(GREEN, LOW);

// what happens next?
}

Step 15: Blink Both the Green and the Yellow LEDs

Now you should create a variable for the Yellow LED called YELLOW and set it to 7 and another variable called DELAY_YELLOW and set it to be 500 milliseconds.

Set it up so that your Green LED stays on for 1000 milliseconds and your Yellow LED stays on for 500 milliseconds.

Start with this code:

// variables for green light
int GREEN = 2;
int DELAY_GREEN = 1000;

// variables for yellow light
// your code here

voidsetup()
{
// setup LED modes
pinMode(GREEN, OUTPUT);
}

voidloop()
{
// High turns things on
digitalWrite(GREEN, HIGH);

delay(DELAY_GREEN);

// low turns things off
digitalWrite(GREEN, LOW);

delay(DELAY_GREEN);
}



Tips for debugging:
* Did you create all your variables?
* Have you set all your pins to OUTPUT?
* Did you remember to turn off one LED and turn on the other?
* Did you put your delays so that after you turn on the LED, you use the same color's delay variable?

Step 16: Blink All the LEDs!

Can you set it up so that your Green LED stays on for 2000 milliseconds and your Yellow LED stays on for 500 milliseconds and your Red LED stays on for 1000 milliseconds?

Remember to use variables for your pins and delays!

Step 17: Use Functions!

In the previous step, we wrote the following lines of code to turn on ONLY the green light:

digitalWrite(GREEN, HIGH);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);


And then you had to repeat them for the yellow light and then again for the red light.

To avoid doing that, we use a Function. Functions also allow us to make our code easier to read.

Functions allow you to group instructions. Functions have 3 main parts. Input, instructions, and output!

Today we're going to focus on just the grouping of instructions!

Functions are just like variables. Once your create them, you can replace the sets of instructions you put into the function in the rest of your program.

Turning this set of instructions:

void loop()
{
  digitalWrite(GREEN, HIGH);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);

}


Into this:

void loop()
{
  green_light();
}

void green_light()
{
digitalWrite(GREEN, HIGH);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);
}


A function is used in place of instructions.

Anywhere you want to make a green light, you can now write green_light();.

Try completing the following code:

// variables
int GREEN = 2;
int YELLOW = 7;
int RED = 12;
int DELAY_GREEN = 5000;
int DELAY_YELLOW = 2000;
int DELAY_RED = 5000;

voidsetup()
{
// setup LED modes
pinMode(GREEN, OUTPUT);
pinMode(YELLOW, OUTPUT);
pinMode(RED, OUTPUT);
}

voidloop()
{
  green_light();
delay(DELAY_GREEN);

  // code to make a yellow light
delay(DELAY_YELLOW);

  // code to make a red light
delay(DELAY_RED);
}

void all_LEDs_off()
{
digitalWrite(GREEN, LOW);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);
}
void green_light()
{
  all_LEDs_off();
digitalWrite(GREEN, HIGH);
}

void yellow_light()
{
  // your code here
}

void red_light()
{
  // your code here
}

// 


Step 18: Add in Code for Your Blue Street Lights!

Can you set it up so that your Blue LEDs turn on when your Red LEDs turn on?

Call your street light PIN variable STREET_LIGHTS.

* Remember to use variables for your pins and set them to output mode!

* Remember to turn off your LEDs in the all_LEDS_off function!

Step 19: Sensors! Part 1: Reading Input

The very last thing we want our traffic light to do is to sense when cars are coming by!

You can read input values from the analog pins!

You can do this by using the analogRead function.

An example of this is: analogRead(A0); where my analog pin number is A0.

Earlier we talked about how functions have 3 main parts. Input, instructions, and output!

The analogRead function returns (outputs) an int (integer) between 0 and 1023.
More details here: http://arduino.cc/en/Reference/AnalogRead

Here is an example piece of code that stores the value that is returned by the analogReadfunction in a variable:

int SENSOR_PIN = A0;
int sensor_value = 0;

voidsetup()
{
}

voidloop()
{
  sensor_value = analogRead(SENSOR_PIN);
}

But now what?

Step 20: Sensors! Part 2: Displaying Text

So we have a sensor reading input, but now what?

Let's try seeing what information we're reading! This takes two steps.


First you need to inform the Arduino that you want to see some information.

You can do this by using the Serial.begin function.

An example of this is: Serial.begin(9600); where  9600 is the rate at which we want to see the information.

More details here: http://arduino.cc/en/Serial/Begin


Next you want to print out that information onto your computer!

You can do this by using the Serial.println function.

An example of this is: Serial.println(sensor_Value); where the information I want to see is sensorValue.

More details here: http://arduino.cc/en/Serial/Print


This is a great tool for debugging!

Let's see how it works.

First upload this code to your Arduino:

int SENSOR_PIN = A0;
int sensor_value = 0;

voidsetup()
{
  Serial.begin(9600);
}

voidloop()
{
  sensor_value = analogRead(SENSOR_PIN);
}

Now press the little magnifying glass on the top right of your Arduino Environment (as shown in the picture!).

Try covering your Photocell with your hand or pointing a flashlight at it! You should see values between 0 and 1023! Neat huh?

Step 21: Sensors! Part 3: Using the Input Information (If Statements and Comparisons)

So far we know that the sensor sees between 0 and 1023. So let's say the middle is 511.
int sensor_mid = 511;

Now we're going to use this value to turn on and off lights when the photocell sees more or less light than the middle value.

There are two really important things that will help!
You can do this by using the if statement and comparisons < and >.

An example of this is: if(sensor_value < sensor_mid) where I compare sensor_value and sensor_mid.

Let's take a second to think about what happens when you use an if statement. An if statement allows you to do two different things depending on whether the comparison is true or false.

An example of this is:
if(sensor_value < sensor_mid)
{
  // do something
else  {
  // do something else
}


Try turning on the green light when the sensor value is greater than the middle and turning on the red light when the sensor value is less than the middle!

int SENSOR_PIN = A0;
int sensor_mid = 511;


int GREEN = 2;
int YELLOW = 7;
int RED = 12;
int STREET_LIGHTS = 13;

voidsetup()
{
pinMode(GREEN, OUTPUT);
pinMode(YELLOW, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(STREET_LIGHTS, OUTPUT);

Serial.begin(9600);
}

voidloop()
{
int sensor_value = analogRead(SENSOR_PIN);
Serial.println(sensor_value);

if(sensor_value < sensor_mid)   
  {
// your code here
  }
//your code here
}

void all_LEDs_off()
{
digitalWrite(GREEN, LOW);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);
}

void green_light()
{
  all_LEDs_off();
digitalWrite(GREEN, HIGH);
}

void yellow_light()
{
  all_LEDs_off();
digitalWrite(YELLOW, HIGH);
}

void red_light()
{
  all_LEDs_off();
digitalWrite(RED, HIGH);
digitalWrite(STREET_LIGHTS, HIGH);
}

Step 22: Sensors! Part 4: Calibrating (While Loops)

In different lighting conditions, the photocell will see a different range of values. Try using the same code but in a dark place. Now try using the same code but in a really bright place. You'll see that the sensor is always off in a dark place, and that the code works really well in bright light.

To solve this issue, we do something called calibrating! When we calibrate the photocell, we look for the highest value it sees and lowest value it sees and then set the middle between those two values. We're going to calibrate the value for about 5 seconds.

To do this, we're going to be using a number of different tricks!

First, we're going to learn about time. The Arduino keeps track of how long it has been since the Arduino has been turned on. We can look at what that value is.

You can do this by using the millis function.

An example of this is: unsigned long current_time = millis(); where I store the value of time in the variable current_time.

What is an unsigned long? A long is like an integer but bigger! A long goes from -2,147,483,648 to 2,147,483,647. The word unsigned means that instead of going from -2,147,483,648 to 2,147,483,647, it goes from 0 to 4,294,967,295. Since time is never negative, we use an unsigned number for it!
More details here: http://arduino.cc/en/Reference/Long
and here: http://arduino.cc/en/Reference/UnsignedLong

Next we're going to use something called a while loop! A while loop is like an if statement, while the condition provided is true, it executes. The difference between an if statement and a while statement is that the while statement keeps on executing until the condition is false -- just like how the loopfunction runs until you turn off your Arduino. Make sure your end_time is also is an unsigned long.

An example of this is:
while(current_time < end_time)
{
  // do something

  // now update the current time
  current_time = millis();
}

The code you put in the "do something" area will keep going until the time goes past end_time


After that, what we need to do is look for the highest and the lowest values that the Photocell sees and store those values.

You can do this by first starting the high value at 0 and the low value at 1023.

sensor_low = 1023;
sensor_high = 0;

Next, every time we go through the while loop, we'll look to see if the sensor value is less than the lowest value it's seen, if so, since that new value is lower, we'll set the low value to that instead.

An example of this is:
if(sensor_value < sensor_low)
{
  sensor_low = sensor_value
}


Similarly with the high value, if the sensor sees a higher value, we'll set it to the higher value!

An example of this is:
if(sensor_value > sensor_high)
{
  sensor_high = sensor_value
}


After the 5 seconds of calibrating, we'll go ahead and set sensor_mid to the average of the low and high values.

Now try it yourself:
int SENSOR_PIN=A0;
int sensor_mid = 511;

int GREEN = 2;
int YELLOW = 7;
int RED = 12;
int STREET_LIGHTS = 13;

voidsetup()
{
pinMode(GREEN, OUTPUT);
pinMode(YELLOW, OUTPUT);
pinMode(RED, OUTPUT);
pinMode(STREET_LIGHTS, OUTPUT);

  calibrate();
}

voidloop()
{
int sensor_value = analogRead(SENSOR_PIN);
Serial.println(sensor_value);

if(sensor_value < sensor_mid)
  {
    green_light();
  }
else
  {
    red_light();
  }
}

void calibrate()
{
int sensor_high = 0;
int sensor_low = 1023;
int current_time = millis();
int end_time = current_time + 5000;
// we have to calibrate this in the first five seconds
while (current_time < end_time)
 {
  // now update the current time
  current_time = millis();
// update sensor value here!
// your code here

// record the minimum sensor value
if (sensor_value < sensor_low)
   {
//your code here
   }

// record the maximum sensor value
if//your code here
   {
     sensor_high = sensor_value;
   }
 }

//set mid to be the MIDDLE! :)
 sensor_mid = (sensor_high + sensor_low)/2;
}

void all_LEDs_off()
{
digitalWrite(GREEN, LOW);
digitalWrite(YELLOW, LOW);
digitalWrite(RED, LOW);
digitalWrite(STREET_LIGHTS, LOW);

}

void green_light()
{
  all_LEDs_off();
digitalWrite(GREEN, HIGH);
}

void yellow_light()
{
  all_LEDs_off();
digitalWrite(YELLOW, HIGH);
}

void red_light()
{
  all_LEDs_off();
digitalWrite(RED, HIGH);
digitalWrite(STREET_LIGHTS, HIGH);
}

Step 23: Sensors! Part 5: Sensors + Lights

So now we're going to try making the sensor work with our traffic light!

Let's first get the lights going from green to yellow to red!

Add your DELAY variables back to the top!

// variables for green light
int DELAY_GREEN = 1000;
int DELAY_YELLOW = 500;
int DELAY_RED = 1000;

Change your loop function from the previous step to:

voidloop()
{
  green_light();
delay(DELAY_GREEN);

  yellow_light();
delay(DELAY_YELLOW);

  red_light();
delay(DELAY_RED);
}

Step 24: Sensors! Part 6: Extending the Green Light

To extend the green light we're going to need to do two things.

First, we need to look for the car. This happens when the photocell sees less than sensor_mid.

Then, if the Photocell sees the car, we should extend the green light.

To do this we're going to need a new variable type: boolean. A boolean can be either true or false just like an int has a range of -32,768 to 32,767.

An example of this is: boolean i_love_kittens = true; where the variable i_love_kittens is set to true.

More details here: http://arduino.cc/en/Reference/BooleanVariables

Remember how we talked about Functions having three parts? Input, Instructions, and Output? Let's talk about outputs!

The setup and the loop function have outputs too. They're void. Void is computer language for nothing. Our function will output a boolean.

First you need to tell the Arduino that you want your function to output a boolean.
Then you need to actually return (ouput) a boolean value.

An example of this is:
boolean my_awesome_function()
{
  boolean i_love_kittens = true;
return i_love_kittens;
}

In the function, we're going to set the return_value to true when the car sensor sees the car.

Try adding this function to your code:

boolean look_for_car()
{
int current_time = millis();
int end_time = current_time + 2000; // we'll look for about two seconds
boolean saw_car = false;
while(current_time < end_time)
  {  
    sensor_value = analogRead(SENSOR_PIN);
    if(sensor_value < sensor_mid)
    {
// set the value of saw_car to true
// your code here
    }

// update the current time
// your code here
  }
return saw_car;
}

Then in the loop function, look for a car and then extend the green light if the Photocell sees the car.
If it sees the car, remember to add a second delay, if not, don't delay!

Quick example:

boolean saw_car = look_for_car();

Step 25: The Final Code

This step will be up after camps are over!

Arduino Contest

Participated in the
Arduino Contest