Pages: [1]   Go Down
Author Topic: Beginner Traffic light project  (Read 1776 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey every one,
Im new to the arduino and I was given two separate assignments where I pulled some code out of a book, they were both successful now Im trying to create an actual fully functional traffic light.  The gist is I want a traffic light to run under a certain loop constantly but then when a button is pressed I want it to give the green light a set amount of time before turning on a pedestrian light.  Say in the normal loop the light is green for 15s and I press the button at 5s, have the light stay on another 5s before changing to red to allow for a pedestrian. run this loop once then move back to the normal light.  Im using an interrupt function (which Im still wrapping my head around) and you might be able to see what I had in mind, or I might have just created a hack job.  Ill paste my code below and any other hints to help me expedite use of this forum would be welcome with much appreciation.

Thank you,


// Project 4 - Interactive Traffic Lights
int carRed = 10; // assign the car lights
int carYellow = 9;
int carGreen = 8;
int pedRed = 11; // assign the pedestrian lights
int pedGreen =12;
int button = 2; // button pin
int crossTime = 5000; // time allowed to cross
int ledDelay = 5000;
unsigned long changeTime; // time since button pressed

// declare state, volatile has to do w/interrupt
volatile int state = LOW;

void setup() {
  pinMode(carRed, OUTPUT);
  pinMode(carYellow, OUTPUT);
  pinMode(carGreen, OUTPUT);
  pinMode(pedRed, OUTPUT);
  pinMode(pedGreen, OUTPUT);
  pinMode(button, INPUT); // button on pin 2
  // turn on the green light
  digitalWrite(carGreen, HIGH);
  digitalWrite(pedRed, HIGH);
 
/* RISING cause when ur button is pressed it changes from LOW to HIGH to LOW, so rly any of the commands wld do
but if you had a sit like flipping a switch then you wld have to choose the correct one */
  attachInterrupt(0, buttonPressed, RISING);
}

void loop() {
 
 
 if (state == LOW){
   normalOperation();}
 
  /* check if button is pressed and if it is
  over 5 seconds since last button press */
  /* Added another 2 brackets around the second part cause the        >5000 part wasnt inside em */
if (state == HIGH) {
    // Call the function to change the lights
    changeLights();
  }
 

void normalOperation(){
  delay(10000);
digitalWrite(carGreen, LOW);
  digitalWrite(carRed, LOW);
  digitalWrite(carYellow, LOW);
  digitalWrite(pedGreen, LOW);
  digitalWrite(pedRed, LOW);
  digitalWrite(carRed, HIGH);
digitalWrite(pedGreen, HIGH);
delay(ledDelay);
digitalWrite(pedGreen, LOW);
for (int x=0; x<10; x++) {
    digitalWrite(pedGreen, HIGH);
    delay(250);
digitalWrite(pedGreen, LOW);
    delay(250);
  }
digitalWrite(carRed, LOW);
digitalWrite(carGreen, HIGH);
digitalWrite(pedRed, HIGH);
delay(ledDelay);
digitalWrite(carGreen, LOW);
digitalWrite(carYellow, HIGH);
delay(3000);
digitalWrite(carYellow, LOW);
digitalWrite(pedRed, LOW);

}
void changeLights() { 
  delay(5000);
  digitalWrite(carGreen, LOW);
  digitalWrite(carRed, HIGH); // red on
  delay(1000); // wait 1 second till its safe
digitalWrite(pedRed, LOW); // ped red off
  digitalWrite(pedGreen, HIGH); // ped green on
  delay(crossTime); // wait for preset time period
  // flash the ped green
for (int x=0; x<10; x++) {
    digitalWrite(pedGreen, HIGH);
    delay(250);
digitalWrite(pedGreen, LOW);
    delay(250);
  }
  // turn ped red on
  digitalWrite(pedRed, HIGH);
  delay(500);
digitalWrite(carYellow, HIGH); // yellow on
  digitalWrite(carRed, LOW); // red off
  delay(1000);
digitalWrite(carGreen, HIGH);
  digitalWrite(carYellow, LOW); // yellow off
// record the time since last change of lights
  changeTime = millis();
  // then return to the main program loop

/* return state to low after this loop so that the normal operation will run again and someone cant just keep hitting the button and stay in pedestrian mode. */
state = LOW;
}

//**** Added function to change state to high w/buttonpress
void buttonPressed(){
   state = HIGH;}
Logged

Queens, New York
Online Online
Faraday Member
**
Karma: 99
Posts: 3619
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

First: please edit this and put it in code tags #.
Second: this is overly complicated for just switching between LEDs. To simplify your code, use case statements, and/or use direct port manipulation. It will cut this code in half, or more.
« Last Edit: February 16, 2013, 04:47:47 pm by HazardsMind » Logged

Created Libraries:
TFT_Extension, OneWireKeypad, SerialServo, (UPD)WiiClassicController, VWID

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18778
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Please edit your post, select the code, and put it between [code] ... [/code] tags.

You can do that by hitting the # button above the posting area.


You have three valid states, don't you? red / yellow / green.

Why not put those three into a function for a start?

Code:
void redLight ()
  {
  digitalWrite (carRed, HIGH);
  digitalWrite (carYellow, LOW);
  digitalWrite (carGreen, LOW);
  }

Ditto for the others. At least then it will be easier to read.

Quote
... use direct port manipulation ...

Not for a beginner. digitalWrite is fine.
Logged


Queens, New York
Online Online
Faraday Member
**
Karma: 99
Posts: 3619
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Not for a beginner. digitalWrite is fine.

True, but it will be good to use for future developments.
Logged

Created Libraries:
TFT_Extension, OneWireKeypad, SerialServo, (UPD)WiiClassicController, VWID

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
// Project 4 - Interactive Traffic Lights
int carRed = 10; // assign the car lights
int carYellow = 9;
int carGreen = 8;
int pedRed = 11; // assign the pedestrian lights
int pedGreen =12;
int button = 2; // button pin
int crossTime = 5000; // time allowed to cross
int ledDelay = 5000;
unsigned long changeTime; // time since button pressed

// declare state, volatile has to do w/interrupt
volatile int state = LOW;

void setup() {
  pinMode(carRed, OUTPUT);
  pinMode(carYellow, OUTPUT);
  pinMode(carGreen, OUTPUT);
  pinMode(pedRed, OUTPUT);
  pinMode(pedGreen, OUTPUT);
  pinMode(button, INPUT); // button on pin 2
  // turn on the green light
  digitalWrite(carGreen, HIGH);
  digitalWrite(pedRed, HIGH);
 
/* RISING cause when ur button is pressed it changes from LOW to HIGH to LOW, so rly any of the commands wld do
but if you had a sit like flipping a switch then you wld have to choose the correct one */
  attachInterrupt(0, buttonPressed, RISING);
}

void loop() {
 
 
 if (state == LOW){
   normalOperation();}
 
  /* check if button is pressed and if it is
  over 5 seconds since last button press */
  /* Added another 2 brackets around the second part cause the        >5000 part wasnt inside em */
if (state == HIGH) {
    // Call the function to change the lights
    changeLights();
  }
 

void normalOperation(){
  delay(10000);
digitalWrite(carGreen, LOW);
  digitalWrite(carRed, LOW);
  digitalWrite(carYellow, LOW);
  digitalWrite(pedGreen, LOW);
  digitalWrite(pedRed, LOW);
  digitalWrite(carRed, HIGH);
digitalWrite(pedGreen, HIGH);
delay(ledDelay);
digitalWrite(pedGreen, LOW);
for (int x=0; x<10; x++) {
    digitalWrite(pedGreen, HIGH);
    delay(250);
digitalWrite(pedGreen, LOW);
    delay(250);
  }
digitalWrite(carRed, LOW);
digitalWrite(carGreen, HIGH);
digitalWrite(pedRed, HIGH);
delay(ledDelay);
digitalWrite(carGreen, LOW);
digitalWrite(carYellow, HIGH);
delay(3000);
digitalWrite(carYellow, LOW);
digitalWrite(pedRed, LOW);

}
void changeLights() { 
  delay(5000);
  digitalWrite(carGreen, LOW);
  digitalWrite(carRed, HIGH); // red on
  delay(1000); // wait 1 second till its safe
digitalWrite(pedRed, LOW); // ped red off
  digitalWrite(pedGreen, HIGH); // ped green on
  delay(crossTime); // wait for preset time period
  // flash the ped green
for (int x=0; x<10; x++) {
    digitalWrite(pedGreen, HIGH);
    delay(250);
digitalWrite(pedGreen, LOW);
    delay(250);
  }
  // turn ped red on
  digitalWrite(pedRed, HIGH);
  delay(500);
digitalWrite(carYellow, HIGH); // yellow on
  digitalWrite(carRed, LOW); // red off
  delay(1000);
digitalWrite(carGreen, HIGH);
  digitalWrite(carYellow, LOW); // yellow off
// record the time since last change of lights
  changeTime = millis();
  // then return to the main program loop

/* return state to low after this loop so that the normal operation will run again and someone cant just keep hitting the button and stay in pedestrian mode. */
state = LOW;
}

//**** Added function to change state to high w/buttonpress
void buttonPressed(){
   state = HIGH;}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for the response.  I must stress the fact that I am an absolute beginner to the arduino and programming in general.  So it would be best if any info posted would be in the style of explaining to a five year old.  Trust me I will not get offended, Id rather read through micellanious instruction and get the point driven home than left wondering. 

A.)  If I were to create specific banks of code, Im guessing like creating classes like c++, would I put these at the beginning of voidloop() or would they have to be in voidsetup(). or else where. 
B.)  The way Im trying to go about it is to have turning the green light on as a specific function and then based on the if statements, be turned off at different time intervals in the two separate lines of code pertaining to whether the button has been pressed or not. 

I am available to do IM or skype or a google+ hang out if any one is interested in knowing exactly how a newbie is looking at this stuff. 
Logged

Queens, New York
Online Online
Faraday Member
**
Karma: 99
Posts: 3619
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

EDIT
Ok, you made a good effort, but there is just TOO much code for some thing that is just too simple.

I want you to take Nick's advice and make your LEDs into functions. When you have done so post your code.
« Last Edit: February 17, 2013, 01:26:09 pm by HazardsMind » Logged

Created Libraries:
TFT_Extension, OneWireKeypad, SerialServo, (UPD)WiiClassicController, VWID

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright loaded up and working.  I got this part down, including pedestrian lights with my normalOperation() code, but lets start working off your code so I can learn some thing.  The digitalWrite(pedColors', state) are for a seperate set of red and light pedestrian lights that change along with the car traffic light.  Heres a link to the two projects so you can get a better idea of what im lookinng at.  Its basically a trumped up project 4 pg.33

http://www.cs.unca.edu/bruce/Spring13/180/ASKManualRev5.pdf:

Code:
digitalWrite(carGreen, LOW);
  digitalWrite(carRed, LOW);
  digitalWrite(carYellow, LOW);
  digitalWrite(pedGreen, LOW);
  digitalWrite(pedRed, LOW);
  digitalWrite(carRed, HIGH);
digitalWrite(pedGreen, HIGH);
delay(ledDelay);
digitalWrite(pedGreen, LOW);
for (int x=0; x<10; x++) {
    digitalWrite(pedGreen, HIGH);
    delay(250);
digitalWrite(pedGreen, LOW);
    delay(250);
  }
digitalWrite(carRed, LOW);
digitalWrite(carGreen, HIGH);
digitalWrite(pedRed, HIGH);
delay(ledDelay);
digitalWrite(carGreen, LOW);
digitalWrite(carYellow, HIGH);
delay(3000);
digitalWrite(carYellow, LOW);
digitalWrite(pedRed, LOW);

}
note; ledDelay obviously being an int described at the top. 
Also I really like how you broke up the code with
\*=================================
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I set all the lights to low at the beginning because I was getting a few stragllers when the code first started running but after it ran once it was fine.  Setting all the lights to LOW at the beginning fixed it.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just read your edit.  Im writing the functions now.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
int carRed = 10; // assign the car lights
int carYellow = 9;
int carGreen = 8;
int pedRed = 11; // assign the pedestrian lights
int pedGreen =12;
int button = 2; // button pin
int crossTime = 5000; // time allowed to cross
int ledDelay = 5000;
int digitalDelay = 10000;
unsigned long changeTime; // time since button pressed



void setup() {
  pinMode(carRed, OUTPUT);
  pinMode(carYellow, OUTPUT);
  pinMode(carGreen, OUTPUT);
  pinMode(pedRed, OUTPUT);
  pinMode(pedGreen, OUTPUT);
  pinMode(button, INPUT);
}

void loop(){
 
   void greenLight(){
   digitalWrite(carGreen, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedGreen, LOW);
   delay(digitalDelay);
  }
 //===========================================
  void yellowLight(){
   digitalWrite(carYellow, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carGreen, LOW);
   digitalWrite(pedGreen, LOW);
   delay(5000);
  }
  //==========================================
  void redLight(){
   digitalWrite(carRed, HIGH);
   digitalWrite(pedGreen, HIGH);
   digitalWrite(carGreen, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedRed, LOW);
   delay(digitalDelay);
  }
}

Now Im getting an error " a function-definition is not allowed here before '{' token" highlighted on the very first void function within voidloop.  Im guessing this is because Im not allowed to have functions within functions?  I did this with c++ recently and it seemed to work.
Logged

Rome, Italy
Offline Offline
Sr. Member
****
Karma: 20
Posts: 442
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you group different function calls into a separate function (see comment #2) you improve the readability of your code, but also get a clearer picture of the logic of your program. Besides, you can delay the implementation of some functions. There are really many advantages.

In your case you have a cycle involving four states. You can immediately translate it into four function calls. Let's call them (for brevity) green(), yellowPed(), yellowCar(), red(). Then you need to define the logic of the transition, involving either a timer or a button.

One thing that is worth remembering is that each loop() function is executed many times a second, so you have two choices:
- use delay() with large values, and interrupts when the button is pressed (your approach); this way, a single loop can last many seconds;
- add conditions that trigger a change of state. This is the approach followed when programming a PLC, and I believe is the one you are trying to emulate.

Let's call the four states G, P, Y, R. Leaving aside the button, the transition is based on a timer. Here is a simple one (not the best one, but it works):

Code:
// declare this as a global variable
long timer_start = millis();

int check_timer(int duration_in_seconds)
{
  long current_time = millis(); // get current time in milliseconds
  // compare the seconds since last reset with duration_in_seconds
  if ((current_time - timer_start) / 1000 > duration_in_seconds)
  {
    return 1;
  }
  return 0;
}

// let's also add a reset function
int reset_timer() {
  timer_start = millis();
}

Now in your loop you can call check_timer with different durations.

Code:
char current_state;
long timer_start;

void setup()
{
  current_state = 'R';
// edited: initialize the timer
  reset_timer();
}

void loop()
{
  switch(current_state) {
  case 'G':
    if (check_timer(4))
    {
      reset_timer();
      current_state = 'P';
      yellowPed();
    }
    break;
  case 'P':
    if (check_timer(2))
    {
      reset_timer();
      current_state = 'Y';
      yellow();
    }
    break;
  case 'Y':
    if (check_timer(2))
    {
      reset_timer();
      current_state = 'R';
      red();
    }
    break;
  case 'R':
    if (check_timer(5))
    {
      reset_timer();
      current_state = 'G';
      green();
    }
    break;
  }    
}

See the advantage of having green(), yellow(), red() defined as separate functions? They don't clutter the logic and you may decide to implement them at a later time. You must define them now, otherwise the code won't compile, but you can just let them do a Serial.println().

As you can see, I have hard-coded the duration in the call to check_timer(), and this is bad practice, but you can find a way to make the value configurable.

Now this loop() is fast since there are no calls to delay(), so you can also manage a buttonpress without an interrupt. The buttonpress would only shorten the duration passed to check_timer() when the lights are red. Does it make sense?
« Last Edit: February 17, 2013, 02:59:29 pm by spatula » Logged

Leeds, England
Offline Offline
God Member
*****
Karma: 15
Posts: 650
Quick, chuck it in the bin before the boss finds out...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you done a search of the forums for 'traffic light'? Someone else was working on a similar project some time ago and reported on their progress as it developed. However, IIRC it was based on the UK system which may be different to yours.
Logged

Beginners guide to using the Seeedstudio SIM900 GPRS/GSM Shield

Queens, New York
Online Online
Faraday Member
**
Karma: 99
Posts: 3619
"Of all the things I've ever lost, I miss my mind the most" -Ozzy Osbourne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void loop(){
 
   void greenLight(){
   digitalWrite(carGreen, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedGreen, LOW);
   delay(digitalDelay);
  }
 //===========================================
  void yellowLight(){
   digitalWrite(carYellow, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carGreen, LOW);
   digitalWrite(pedGreen, LOW);
   delay(5000);
  }
  //==========================================
  void redLight(){
   digitalWrite(carRed, HIGH);
   digitalWrite(pedGreen, HIGH);
   digitalWrite(carGreen, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedRed, LOW);
   delay(digitalDelay);
  }
}

Close, but function go outside the loop(). What you want to do is call the functions. So it would look like this.

Code:
void loop() {
//timer goes up here and does calls one of the functions when needed.
greenLight();
yellowLight();
redLight();
}

//functions go here
void greenLight(){
   digitalWrite(carGreen, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedGreen, LOW);
   delay(digitalDelay);
  }

  void yellowLight(){
   digitalWrite(carYellow, HIGH);
   digitalWrite(pedRed, HIGH);
   digitalWrite(carRed, LOW);
   digitalWrite(carGreen, LOW);
   digitalWrite(pedGreen, LOW);
   delay(5000);
  }

  void redLight(){
   digitalWrite(carRed, HIGH);
   digitalWrite(pedGreen, HIGH);
   digitalWrite(carGreen, LOW);
   digitalWrite(carYellow, LOW);
   digitalWrite(pedRed, LOW);
   delay(digitalDelay);
  }

If it looks like crap, its because I just C & P your stuff and put it together.
« Last Edit: February 17, 2013, 04:04:40 pm by HazardsMind » Logged

Created Libraries:
TFT_Extension, OneWireKeypad, SerialServo, (UPD)WiiClassicController, VWID

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

THANK YOU, Ive been wondering why I kept getting error messages.  So I declare the functions after the loop and just reference them inside it.  I think this is what Ive been fighting the whole time.  I just ran my original code and it went through fine.  In the library now, when I get home I'll load it on the board and let you know how it worked.
Logged

Pages: [1]   Go Up
Jump to: