Image of Traffic Lights

Pedestrian Crossing

By Trevor Olsson, 25/10/2016

Teachers - want a complete Pedestrian Crossing in your classroom?
GPIO Support Services is pleased to announce that we have been given a set of real Pedestrian Crossing equipment that we can demonstrate in schools and colleges.

More Information - click the + sign to the right
The hardware includes a complete traffic signal (Red, Amber & Green) together with the red/green man box. With these children can write the code for the Pedestrian Crossing Project and see it working for real. If you would like us to come along to your school with these (no cost to the school & we are DBS checked) please get in touch.

If you are interested in how we got all of the hardware working you can read our blog here.

Introduction

This project builds on the traffic light project by adding code and hardware to simulate a UK pedestrian crossing.

Connect to the gPiO Box

The traffic lights project uses gPiO outputs 1,2 & 3 for the red, amber and green lights. We extend this to use all six gPiO outputs with red man, green man and wait light on outputs 4,5 & 6. We also use input A to sense when the button has been pressed. Refer to the traffic lights project if you are unsure how to make the physical connections.

Create the Code

Use the infographic below to understand the sequence of a puffin crossing.

pelican-crossing-graphic.The table below shows how the inputs & outputs are connected to the various lights.

Wiring arrangement

Notice that in the infographic there is no flashing amber. The newer Puffin crossings don’t have the flashing amber phase of the older Pelican Crossings but instead have a sensor that detects when pedestrians are no longer in the road. The flashing amber phase confused some pedestrians who were not sure what do do if the light started flashing.

Click + on right for an example - and don't panic!

  • You can code this project using a variety of platforms and languages.
  • We’ve shown two versions of text based languages and a Scratch script for the Raspberry Pi.
  • We’ve also shown the code using the PXT and Mu editors on the micro:bit.
  • All of these are available in the Code Library.

Raspberry Pi version

Python


Scratch


This is the Scratch 2 version of the project.

  • Please note that this requires a  Raspberry Pi version 2 or 3.
  • In addition the code needs a Raspberry Pi with a Raspbian image dated 21/6/2017 or later. There is more information on this here.
Scratch 2 code infographic

Scratch 2 Code for Pedestrian Crossing

C


This C code is rather different in that the code was written by a professional highway signals engineer and is designed to simulate an actual real world crossing, rather than the simplified Python & Scratch versions we have shown here. The code is relatively complex but may give some idea how C could be used. Many thanks to Chris Kennett at Green Signals Consulting Limited

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


/* 2 Phase UK Puffin Crossing Sequence
 *  
 *  Developed by Chris Kennett based on previous UK traffic signal emulations.
 *  This is designed as a simple traffic signal controller. It is designed
 *  for use with real LED signal heads from a scrapped traffic signal junction.
 *  
 *  Aspects being used are Imtech (PEEK) 'Elite' ELV CLS-LED and AGD ELV Toucan nearside display unit.
 *  
 *  Electronics are controlled by the RPi via opto-coupler and separate TRIAC,
 *  driving ELV traffic signal LED aspects. Working voltage is between 27.5v - 48v.
 *  Actual voltage chosen for this project is 30v (nominal) to avoid burning my eyes out.
 *  
 *  Opto-couplers are held high by a line from the 3.3v rail and sink to the output when switched
 *  low. 150R resistor is in line with the output and a separate 110R resistor is added on the 3.3v rail
 *  to limit pin current to between 6 and 12mA, depending on the number of aspects lit.
 *
 *  Do not try to drive more than 3 aspects, as the current available is not sufficient and the
 *  opto-couplers may not be triggered. 
 *  
 *  Resistor on TRIAC gate is approx 47R. LED aspects are not inductive, so no snubber
 *  circuit is needed. This circuit does not dim. If dimming is needed, use a different tapping
 *  or a separate transformer and switch between them.
 *  
 *  No audible bleeper of tactile rotatting cone is fitted. Tactile cones are likely to draw a high current
 *  and are potentially an inductive or disruptive load. 
 *  
 *  Push button demands must be registered on detectors (switches) through pin 24 
 *  to trigger interrupts. Extensions (such as on-crossing or kerbside detection) is polled and so can 
 *  be wired to any available digital IO. Inputs are pulled high and normally open-circuit.
 *  
 *  Pins have been chosen to allow Arduino to easily be swapped in/out for a Raspberry PI model B+ or later
 *  (40 pin IO). If this is done, beware differences in pin-out, operating voltages and lower pin-current
 *  thresholds.
 *  
 *  For details, contact Chris Kennett at chris.kennett[at]greensignals.co.uk
 */

int phaseDriveA[3] = {7, 8, 25};
int phaseDriveB[3] = {18, 15, 14};

//inputs associated to phases
int phaseDetA = 4;
int phaseDetB = 24;

//phase times
int minA = 7000;
int minB = 6000;

int maxA = 30000;
int extA = 1000;

//interStage times exclude closing and starting ambers
int interStage1_2 = 3;
int interStage2_1 = 6;

//starting and closing amber times
const int closeAmber = 3000;
const int startAmber = 2000;

//set up volatile variables for interrupts
volatile int demA = 1;
volatile int demB = 0;

//current stage
int stage = 0;

//demands
//String dA = String("_");
//String dB = String("_");

//extensions
//String eA = String("_");

//Phase changes
void startingAmberA() {
  digitalWrite(phaseDriveA[0], LOW);
  digitalWrite(phaseDriveA[1], LOW);
  digitalWrite(phaseDriveA[2], HIGH);
}

void greenA() {
  digitalWrite(phaseDriveA[0], HIGH);
  digitalWrite(phaseDriveA[1], HIGH);
  digitalWrite(phaseDriveA[2], LOW);
}

void greenB() {
  digitalWrite(phaseDriveB[0], HIGH);
  digitalWrite(phaseDriveB[2], LOW);
  demB = 0;
}

void redA() {
  digitalWrite(phaseDriveA[0], LOW);
  digitalWrite(phaseDriveA[1], HIGH);
  digitalWrite(phaseDriveA[2], HIGH);
}

void redB() {
  digitalWrite(phaseDriveB[0], LOW);
  digitalWrite(phaseDriveB[2], HIGH);
}

void closingAmberA() {
  digitalWrite(phaseDriveA[0], HIGH);
  digitalWrite(phaseDriveA[1], LOW);
  digitalWrite(phaseDriveA[2], HIGH);
}

void waitB() {
  digitalWrite(phaseDriveB[1], LOW);
}

void waitClearB() {
  digitalWrite(phaseDriveB[1], HIGH);
}



  //startup sequence
void startUp() {
  redB();
  waitB();
  demB = 1;
  delay(closeAmber);
  delay((interStage2_1)*1000);
  greenA();
  stage = 1;
  delay(minA);
}

//Stage Moves
void stage1_2() {
  closingAmberA();
  delay(closeAmber);
  redA();
  delay((interStage1_2)*1000);
  greenB();
  stage = 2;
  //printf("Stage ");
  //printf(stage);
  //printf("\n");
  waitClearB();
  demB = 0;
  delay(minB);
}

void stage2_1() {
  redB();
  if(digitalRead(phaseDetB) == LOW){
    demB = 1;
    waitB();
  }
  delay((interStage2_1)*1000);
  startingAmberA();
  delay(startAmber);
  greenA();
  stage = 1;
  //printf("Stage ");
  //printf(stage);
  //printf("\n");
  delay(minA);
}



//stage extensions
void extendSt1() {
  int timA = 0;
  while ((timA < maxA) && (digitalRead(phaseDetA) == LOW)){
    delay(extA);
    //serialOutput((timA/1000));
    timA += extA;
    //eA = "E";
  }
  //eA = "_";
  if ((timA < maxA) && (digitalRead(phaseDetA) == HIGH)){
  }
}

//detection interrupts (ISRs)
void det1(){
  demB = 1;
  waitB();
}

/*
*Serial Port responses
* int serialOutput(int tim) {
*  if (demA) {dA = "D";}
*  else {dA = "_";}
*  if (demB) {dB = "D";}
*  else {dB = "_";}
*  printf("Stage: ");
*  printf(stage);
*  printf("\n\tDemand\tExtension\tTime\tMax");
*  printf("\nPhase A\t\t");
*  printf(dA);
*  printf("\t");
*  printf(eA);
*  printf("\t\t");
*  printf(tim);
*  printf("\t");
*  printf(maxA/1000);
*  printf("\nPhase B\t\t");
*  printf(dB);
*  printf("\n");
*}
*/
int main(void) {

  wiringPiSetupGpio();
                  

  //initialise appropriate pins for phase drive outputs
  pinMode(phaseDriveA[0], OUTPUT);
  pinMode(phaseDriveA[1], OUTPUT);
  pinMode(phaseDriveA[2], OUTPUT);
  pinMode(phaseDriveB[0], OUTPUT);
  pinMode(phaseDriveB[1], OUTPUT);
  pinMode(phaseDriveB[2], OUTPUT);

  digitalWrite(phaseDriveA[0], HIGH);
  digitalWrite(phaseDriveA[1], HIGH);
  digitalWrite(phaseDriveA[2], HIGH);
  digitalWrite(phaseDriveB[0], HIGH);
  digitalWrite(phaseDriveB[1], HIGH);
  digitalWrite(phaseDriveB[2], HIGH);
  
  //initialise appropriate pins for detector inputs  
  pinMode(4, INPUT);
  pinMode(24, INPUT);


  pullUpDnControl(4, PUD_UP);
  pullUpDnControl(24, PUD_UP);


  delay(3000);

  wiringPiISR (24, INT_EDGE_BOTH, &det1);      //pin 7 (phaseDetB)
  startUp();
  
  while(1) {

	//serialOutput(0);
  	if(stage == 1){
    		if(demB == 1){
      		//printf("extending Stage 1\n");
      		extendSt1();
      		//printf("moving to stage 2\n");
      		stage1_2();
    		}
  	}else {
    	stage2_1();
  	}
  }
}





micro:bit version

Python - Mu Editor

from microbit import *

while True:
    pin0.write_digital(1) # Green Light On
    pin16.write_digital(1) # Red Man On
    if button_a.is_pressed():
       pin15.write_digital(1) # Wait Light on
       sleep(2000)
       pin0.write_digital(0) # Wait Light off
       pin12.write_digital(1) # Amber Light on
       sleep(2000)
       pin12.write_digital(0) # Amber Light off
       pin8.write_digital(1) # Red Light on
       sleep(2000)
       pin15.write_digital(0) # Wait Light off
       pin16.write_digital(0) # Red Man Off
       pin13.write_digital(1) # Green Man on # Pedestrians can cross
       sleep(5000)
       pin16.write_digital(1) # Red Man On
       pin13.write_digital(0) # Green Man off
       sleep(2000)
       pin12.write_digital(1) # Amber Light on
       sleep(2000)
       pin12.write_digital(0) # Amber Light off
       pin8.write_digital(0) # Red Light off

PXT Editor


Puffin Crossing Script

External Links

Puffin Good Practice Guide” (PDF). Department for Transport. 2006.


Save

Save