Upload
others
View
11
Download
0
Embed Size (px)
Citation preview
Portable Traffic Light System ELEC499 Report The Portable Traffic Light system is a safer and more efficient method for rerouting. The current solution of using traffic control person teams is neither safe nor cost effective. The prototype’s electrical, mechanical, and software designs are discussed in this report. The current prototype showed success in preliminary testing. Further development and testing must be applied before the system can be sold to industry. Team:
Faisal Hamood – V00703264
Nicolai Bailly – V00621089 Thomas Howell – V00218418 Nick Allen – V00197831 Supervisor: Dr Fayez Gebali Report submitted August 3rd 2012 Sponsored by:
1
Contents Problem Definition ........................................................................................................................................ 3
Portable Traffic Light Concept ...................................................................................................................... 3
Sponsorship and Support .......................................................................................................................... 4
Prototype Designs ......................................................................................................................................... 5
Electrical Drive Circuit ............................................................................................................................... 5
Mechanical Structure ................................................................................................................................ 7
Software Design ........................................................................................................................................ 9
Communication Protocol .................................................................................................................... 10
Pulse Width Modulation ..................................................................................................................... 11
Hardware Selection & Design ..................................................................................................................... 11
Radio Communication ............................................................................................................................. 11
Communication Security ......................................................................................................................... 12
Electrical Component Selection .............................................................................................................. 13
DC/DC Converter Design Pitfalls ......................................................................................................... 13
Microcontroller Selection ................................................................................................................... 13
Regulators ........................................................................................................................................... 14
Switching MOSFET’s ............................................................................................................................ 15
Implementation and Testing ....................................................................................................................... 16
Project Timeline ...................................................................................................................................... 16
Documented Progress ............................................................................................................................. 18
Testing ..................................................................................................................................................... 19
Conclusion ................................................................................................................................................... 20
Recommendations and Future Works ........................................................................................................ 20
Hardware Recommendations ............................................................................................................. 20
Appendix A – Data Sheets and Detailed Hardware Specifications ............................................................. 21
Appendix B – WorkSafeBC Data .................................................................................................................. 22
Appendix C – Original Structural Design ..................................................................................................... 23
Appendix D – Arduino Code ........................................................................................................................ 27
2
Table of Figures Figure 1: Flagperson Related Incidents ......................................................................................................... 3
Figure 2: Construction Site Reroute .............................................................................................................. 3
Figure 3: LED Drive Circuit 1 .......................................................................................................................... 5
Figure 4: LED Drive Circuit 2 .......................................................................................................................... 6
Figure 5: LED Drive Circuit 3 .......................................................................................................................... 7
Figure 6: Simple Fixture ................................................................................................................................ 8
Figure 7: Pylon State Diagram ....................................................................................................................... 9
Figure 8: Protocol Flow Chart ..................................................................................................................... 10
Figure 9: Arduino with Xbee Module .......................................................................................................... 12
Figure 10: Regulator .................................................................................................................................... 14
Figure 11: MOSFET Operation .................................................................................................................... 15
Figure 12: Team Photo ................................................................................................................................ 17
Figure 13: Team Progress ............................................................................................................................ 18
Figure 14: Final Product .............................................................................................................................. 19
3
Problem Definition The demand for a safer solution to reroute traffic is high, with 40 incidents per two years in British
Columbia alone (select incidents are shown in Figure 1; the full incident report is attached in Appendix
A). The idea of a traffic signal that could potentially replace these workers seemed reasonable and
feasible. The original solution is to rely on sensors, or radar signals to detect cars and switch each light
accordingly. The lights would communicate wirelessly, with a range of 1km and a minimum battery life
of 8-10 hours.
Figure 1: Flagperson Related Incidents
Portable Traffic Light Concept After meeting with potential clients, the municipality of Saanich, and representatives from the BC Traffic
Control Persons union, the scope of the project changed. It was agreed that a more successful product
and solution would be one that kept at least one traffic control person, with a remote control for the
portable lights, at a safe distance from traffic, thereby preserving jobs and keeping a trained worker on-
site. The light signals must communicate wirelessly and be battery operated; however, car detection
sensors are now omitted, as well as the timed routing mode of the system.
Figure 2: Construction Site Reroute
4
The proposed solution is better illustrated in the above Figure 2. Instead of using traffic control people
on each side of a construction site, one person will stand at a safe distance from traffic holding a
controller by which he/she will switch the state of the traffic lights (pylons).
The system is not necessarily limited to single lane construction sites, and can be used in remote areas
(mining sites), for temporary congestion control, and in emergency response rerouting; any situation
where traffic reroute is necessary. The system may, in the future, also include more than two traffic
lights for intersection control. The system must be easy to deploy, portable and mobile, reliable and cost
effective with a reasonable battery life and communication range.
Sponsorship and Support To build a prototype with two lights (pylons) and a controller, approximately $2500 in funding is
required for materials and partial labor. Local companies PBA Engineering, JSF Technology, and Tara
Precision provided sponsorship, including funding, materials, and some structural labor.
PBA Engineering’s sponsorship of $1000 was used to purchase Arduino processors and XBee radio
modules for communication. The funding was also used to purchase drive circuit components
(transistors, diodes, resistors, etc…), and miscellaneous other parts.
JSF donated two sets of AC powered three-color traffic LEDs lights with casing and structural mount
components. JSF also provided 24 high quality gel batteries (2V each with 25Ahrs).
Tara precision built the poles according to designs given to them. They provided reinforced aluminum
material and welded it to the specifications.
The city of Saanich, while not sponsoring the project directly, provided invaluable guidance and made
available some traffic signs for the system to be tested on the street (if possible).
5
Prototype Designs The aim for this prototype is to convey the concept of a portable traffic light system, and how it will
operate. Moreover, this prototype is necessary to assess feasibility and system practicality. Therefore,
with this prototype, we aim to achieve:
1. A battery lifetime of at least 12 hours (an approximation of a worker’s shift)
2. A communication range of at least 1km (an approximation of road work range)
3. A structure than can be pulled by an individual yet not carried by one (a balance of security and
portability)
4. A safe and error proof state transition (never display two greens, continuous handshaking for
signal loss, etc.)
5. A secure communication protocol (to avoid sabotage, both intentional and unintentional)
6. An analog fail safe solution (in case of processor failure)
Electrical Drive Circuit Initially with JSF supplying 12V test LED lights, the system was powered by 6 2V batteries in series. The
initial drive circuit, shown in Figure 3, was simulated and built for testing. The red pin operates on active
low, while yellow and green operate on active high. This configuration is chosen to ensure the red LED is
turned on if the processor fails.
Figure 3: LED Drive Circuit 1
6
However, the suppliers were unable to provide DC designed LEDs in all three colors. Instead they
supplied 2 standard AC three color traffic LEDs with heads. The heads were converted to DC simply by
discarding the converting circuit which stepped down 120V AC power to:
14.5V and 250mA for Red
10V and 350mA for Yellow
18V and 150 mA for Green
This change in LED spec caused a major redesign of the drive circuit. Voltage regulators and individual
LED grounds/lows were used to offset voltage and current individually. The schematic below illustrates
the solution.
Figure 4: LED Drive Circuit 2
The schematic was simulated, but the switching MOSFET of the green LED did not appear to work
properly with a ground or low of -9V. A more specific or specialized MOSFET with a higher threshold
voltage is needed to provide stable switching. The MOSFET had to be ordered from a vendor who was
unable to deliver the product before the deadline. Therefore, a third schematic was used.
Figure 5 illustrates the implemented drive circuit. The supply voltage of the system was stepped up to
20V (10 2V batteries) and regulated down to the individual LEDs. This solution provides higher battery
life (up to 100 hours of single light operation) and more structural weight.
7
Figure 5: LED Drive Circuit 3
The regulators, however, dissipate a lot of heat to step down power. This new problem was tackled by
mounting heat sinks on the three major regulators, and drilling vent holes in the casing. If the system
overheats then the regulators lose stability and the LEDs will start to flicker. An operational stress test
was conducted to ensure the heat sinks' effectiveness. All three LEDs were left on for 4 hours with no
switching to directly stress test the heat sinks. No flickering was present, and the system passed the
stress test.
Mechanical Structure For this system to be portable and easy to use, it must be moveable by a single individual. This property
will also contribute to the ease of deployment. Conversely, this property may cause the system to be
easily stolen, a concern Saanich reported. Moreover, extreme light weight may cause the light (pylon) to
tip over with heavy wind. Therefore, the structure was designed to be heavy enough at the base to not
be carried by one individual but to require at least two. The system can still be moved and pulled by one
individual.
An illustration of the structural design is attached in Appendix B. Stress analysis using SolidWorks was
performed to make sure the base plate can carry the battery weight (~20lbs). The structure with the JSF
8
supplied batteries should weigh ~30lbs if built with aluminum. The drafted heads are just for illustration;
they arrive pre-manufactured to city-required specifications from the supplying company along with the
LEDs. The pole of the structure collapses back on to the case where it rests and locks into a holder. A
handle can be attached to the LED heads to enable the pylon to be pulled by an individual, similar to a
travelling case.
Due to time constraints, the structure could not be built by Tara Precision in time for the demo.
Therefore, a simpler design was produced for the prototype. In this design, each light (pylon) can be
broken down into three pieces and assembled in the required position. The assembly of the structure is
rather simple and still provides ease of use and portability. The simple structure is drafted in Figure 6.
Figure 6: Simple Fixture
9
Software Design The processor chosen for this project utilizes Arduino's programming language, which is a variation of C,
with hardware interface libraries built in. The main disadvantage with the hardware chosen is the
limitations inherent in the serial channel. The serial channel only has space for a single message, and
messages are all broadcast: they cannot be directed to a given Arduino processor. This means that
receiving a message has the undesired effect of overwriting previously received messages. This is a
serious issue for the controller, who has to receive messages from both pylons. The loss of packets can
be limited by creating a message queue or spacing out messages in order to allow time for them to be
received and processed before they are overwritten. The communication protocol is discussed further in
the following subsection. The full source code of both controller and pylon are attached in Appendix C.
The pylons have 4 possible states: red, yellow, green, and all red. The all red state is included to allow
construction trucks to enter the site. The traffic control person or worker controls only which side
should be green; the transition to yellow then red is done automatically to limit human error and
simplify operation. A “buffer zone clear” button is added to allow the operator to manually confirm that
all traffic in crossing section has cleared. Only when the buffer button is pushed is the pylon allowed to
switch states to green, thus limiting human error when transitioning. The system states were tested for
various situations, and a further analysis is shown in the testing section. The state diagram for the pylon
side logic is shown in Figure 7.
Figure 7: Pylon State Diagram
10
Communication Protocol
The Arduino/XBee setup does not support message queuing, and there is no protocol built in to facilitate
direct messaging between processors. In order for the Controller to be able to send different commands
to each Pylon, a custom protocol had to be written.
In an effort to keep communication as simple as possible, the messages being passed back and forth
between Pylon and Controller are all exactly three characters long. The first position is the ID of the
message’s destination. The second character is the contents of the message itself, in the form of a single
character code, which corresponds to one of a set of acceptable commands. Finally, the third character
is the ID of the message’s source. Source IDs are theoretically unnecessary in the case of command
messages being sent to Pylons, since Pylons have no contact with each other, and thus should never
receive commands from anyone other than the Controller. This is simply a security measure to ensure
that the command pulse is from the Controller.
In the case of acknowledgement messages being sent back to the Controller, it is important that the
Controller can distinguish between the Pylons and understand which one is responding. The source ID
allows for the Controller to handle acknowledgment messages from multiple Pylons and update its state
model accordingly.
Given the Arduino/XBee setup’s lack of message queuing, the issue of broadcast messages overwriting
each other within an Arduino’s serial port had to be fixed early on. It is important to note that even
though messages are directed to a specific endpoint in the protocol, truthfully every message is a
broadcast, and will be received at every Arduino processor’s serial port. This is avoided as much as
possible by using the Controller’s command pulse to space out messages being sent to each Pylon from
one another, and, indirectly, space out the corresponding message acknowledgment pulses being sent
back from the Pylons. The Controller takes its command pulse rate, set at once per 250 milliseconds, and
divides it in half. Every 125 milliseconds, a command is sent to one of the Pylons, alternating each time,
and thusly achieving one set of commands, ie one pulse, every 250 milliseconds.
Figure 8: Protocol Flow Chart
11
Pulse Width Modulation
One of the more important aspects to LED driving comes from pulse width modulation (PWM). This
modulation allows the user to specify a duty cycle which corresponds to the supply on ratio of the input
source, with a 100% duty cycle referring to constant on and 50% duty cycle for equal switching portions
between on and off supply.
Though at first you might expect this to create a blinking light output, a correct choice of frequency
allows the user to switch at a speed which is not visible to the human eye. The Arduino operates at 500
Hz allowing for a wide range of usable duty cycles. Pulse width modulation has various uses for our
project. The first and most important use for PWM in our project is the power conservation. The
continuous switching requires overall less energy to drive the lights. Another aspect of PWM is the
ability to reduce the wear of the LEDs. High frequency switching minimizes the on time of the LEDs, and
maintains the optimal operating characteristics of the lights which would normally be affected by
heating caused by constant use. Through the averaging brought forth by PWM, the overall brightness of
the LED can easily be controlled. This aspect is useful for traffic lights where a higher intensity is
required during the day, but could be reduced for night purposes. In our project, the PWM is easily
implemented using the digital pins of the Arduino which control the switching logic of the circuit. The
digital pins allow you to simply set a duty cycle for each pin allowing for simplified control.
Hardware Selection & Design
Radio Communication The design requirements for radio communication were determined to be the following:
● Low power consumption ● Moderate range of several hundred meters. ● Low data rate ● Resilience to radio interference
Based on the requirements, the XBee Pro 100mW Transceiver was identified as an acceptable
component to provide radio communication between controller and pylons. The XBee radio module
operates using the “Zigbee” specification according to the IEEE 802.15.4 standard, which forms the basis
for a number of low-data rate personal area networks.
The relevant specifications of the XBee Pro Transceivers used in the project can be seen in the following
table.
XBee Pro Parameters Description/Value
Power output + 18 dBm
Outdoor range 1.6 km
RF Data Rate 250 kbps
12
Operating frequency 2.4 GHz
Receiver sensitivity -100 dBm
Transmit current 215 mA
Receive current 55 mA
Supply voltage 2.8 – 3.4 VDC
The XBee module communicates serially with the Arduino Microcontroller. The transceiver was
connected to the Arduino pins through a specialized breakout board designed to work with the XBee
modules and Arduino microcontroller. The XBee, Arduino Microcontroller, and breakout board assembly
can be seen in the following figure.
Figure 9: Arduino with Xbee Module
Communication Security
Unintentional interference from other devices was identified as a potential problem in the selection of
the radio communication components. It was found that the XBee devices each possess a four digit
hexadecimal personal area network ID (PAN ID); ZigBee devices are required to have the same PAN ID
and channel setting in order to communicate with one another. This results in a possible 65,536 PAN ID
tags per channel; with the XBee pro capable of transmitting over 12 channels, this results in 786,432
possible unique communication networks. The XBee Pro Transceivers used in the project were
reconfigured to the PAN ID 0x1111, and channel 12.
Additional security is achieved through software by the custom message protocol designed for
controller and traffic light pylon communication and handshaking.
13
Electrical Component Selection
DC/DC Converter Design Pitfalls
A V-Infinity VWRAS2-D12-D9-SIP 9V-18V in +/-9V out DC/DC converter was selected as a possible
voltage source for the green LED. The 18V bias required for the green light was achieved by using the -
9V as the ground, as seen in the second electrical design schematic. However, this did not allow for
proper switching of the green light, since the gate-source voltage always exceeded the threshold current
of the chosen MOSFET under this design.
Also investigated, was the concept of using the +/- 9V output converter to supply an isolated 18V supply
to the entire drive circuit by using the -9V output as the common ground. Under this design concept, the
stepped up isolated 18V supply could be regulated to 14V and 10V to power the red and yellow LED’s.
The pitfall of this design was due to the maximum output current limitation of 111 mA for the converter;
this current would be insufficient for the yellow state which required a current of 300 mA. Higher
current output DC/DC converters of the same specifications were sought, but none were found with an
output greater than 111 mA. Thus, the DC/DC converters were not used in the final design.
Microcontroller Selection
The design requirements for the microcontroller requirements were identified as the following:
● Low cost ● Low power consumption ● Compatibility with radio transceiver modules ● Familiar development environment
The Arduino Uno R3 Microcontroller was identified as a suitable fit to the above requirements. Arduino
is a popular open-source prototyping platform, using a language similar to C for programming
functionality. The Arduino Uno R3 board utilizes the ATmega328 microcontroller processor chip. The
ATmega328 includes a wide range of functionality of benefit to the system that was implemented in the
software; such functions include programmable watchdog timers and software defined pulse width
modulation output pins. A summary of the relevant Arduino and ATmega328 specifications can be seen
in the following table.
In addition, the Arduino Uno R3 was easily configured with the selected radio transceiver module which
was discussed in the Radio Communication section.
Table 1 Arduino Uno R3 Specifications
Arduino Uno R3 Parameter Description/Value
Microcontroller Processor ATmega328
Operating Voltage 5 VDC
14
Input Voltage 7-12 VDC
Digital I/O Ports 14
Analog Input Pins 6
DC I/O Pin Current 40 mA
Flash Memory 32 KB
SRAM 2 KB
EEPROM 1 KB
Clock Speed 16 MHz
Regulators
Once it was decided that stepping down to the appropriate voltages from a single source of 24V rather
than a combination of dc converters from a 12V source was the best option, regulators were acquired to
provide secure voltages to the drive system. A quick source from the UVic technical support provided us
with a collection of LM317 regulators. The LM317 is a linear, adjustable, three terminal positive
regulator. A typical set up, allowing for adjustable output voltage is shown below:
Figure 10: Regulator
These regulators allowed us to provide a steady power supply to each of the light components without
sacrificing current output. The limiting current output from the converters was the primary reason for
this design change.
Unfortunately, this switch to LM317 regulators issued another unexpected problem. With a 24V source
deploying regulated outputs of 18V, 14V, and 10V the power is dissipated across regulator in the form of
heat. With the larger regulation, for example the 10V, the heat produced can start to cause problems.
Higher heat changes the output characteristics of the regulation and had rather drastic effects on the
luminosity.
15
There are a number of ways this heat issue could be resolved. One of the first methods thought out was
to use the container as a medium for heat dissipation. With a metal enclosure, the surface would allow
for surface heat dispersion. However, the prototype enclosures used were made of plastic materials
making this solution unreasonable in the time frame necessary for completion. The solution that ended
up in the prototype was the use of individualized heat sinks for each regulator. Although this is a more
‘bulky’ approach, it accomplished the necessary goals for resolving the project and could be done
without making any changes to the built electrical drive system.
Switching MOSFET’s
The gate of the switching MOSFET’s were designed to be driven off of the Arduino digital output ports,
therefore a MOSFET with a suitable drain current output for a 5V gate signal was desired. The IRLD110
MOSFET was selected as an appropriate component for providing switching of the LED’s, the
characteristic curve of the IRLD110 MOSFET can be seen in the following figure. The MOSFET
specifications were selected slightly higher than required, to allow for reliable system performance.
Figure 11: MOSFET Operation
The basic specifications of the IRLD110 MOSFET can be seen in the following table:
IIRLD110 Power MOSFET Specifications
(at 25 degrees C)
Value/Description
Drain Source Voltage Limit 100 V
Rds(on) @ Vgs = 5.0V 0.54 ohms
Continuous Drain Current Limit 1.0 A
16
Implementation and Testing
Project Timeline Week 1: May 7
- Idea brain storming, and group formulation.
Week 2: May 14
- Proposal submitted, supervisor chosen, and individual research tasks assigned.
Week 3: May 21
- Initial design stage
- sponsorship hunt
- Initial website and logo design
Week4: May 28
- Design stage completed
- Website and logo updated
- Ardunios ordered and tested
- PBA sponsorship promised
- Saanich meeting
Week 5: June 4th
- Project re-design after Saanich meeting (project objective changed slightly)
- Receive sponsorship
- Begin initial implementation stage( time set Thursdays, 5pm, weekly, starting this week)
Week 6: June 11th
- Initial software testing for Arduinos
- Initial testing for software interrupts & one way communication between controller & pylon.
- State switch implementation using analog switches
- Hard-wired fail safe system for Arduino failure
Week 7: June 18th
- Software testing for full two pylon system, improving state transitions
- Power saving modules
- Designing interface for Arduino to LED drive
17
Week8: June 25th
- Part ordering
- JSF Meeting
- Finalizing electrical schematics
Week9: July 2nd
- Electrical design change, due to hardware spec change
- Mechanical structure explored and initial design drafted
Week10: July 9th
- Software testing
- New electrical design simulated and finalized
- Mechanical Structure finalized
Week11: July 16th
- JSF heads received
- Electric designs changed to accommodate AC light conversion
- Tara precision sponsorship promised
- Mechanical designs implemented
Week12: July 23rd
- Poster design and print
- Demo layout, setup, and preparation
- Final hardware assembly of pylons and controller
- Electrical Stress test
- Extensive scenario testing
June 27th, demo day, demo was successful. The team was awarded $400 for outstanding project idea
and performance.
Figure 12: Team Photo
18
Documented Progress
Figure 13: Team Progress
19
Testing Due to possible overheating, electrical stress testing was necessary. The system was run on full power
draw (all LEDs on) for 4 hours; this was done to stress the drive circuit and ensure regulator’s stability.
The system passed the stress test.
Software and scenario specific testing were implemented. All possible states were tested. Intensive
switching and system response were also tested, and a few bugs were fixed. Street/real testing was
never done. Hypothetical scenario testing was passed successfully.
The controller’s switches were marked and the system was given to a high school graduate to establish
ease of use. The individual, without an instructions manual, or any form technical explanation was given
the controller to try the system. After a few tries, the individual was able to understand and fully control
the system, thus proving the system is easy to understand and use.
The mechanical structure was tested for wind tipping, and found with the batteries placed properly at
the base, the structure can withstand high crosswinds.
Figure 14: Final Product
20
Conclusion The system is rigged with fail proof systems; however, further backup systems like a backup battery
system should be implemented. The system is portable and easy to use. The system aims to keep flag
persons involved in the operation of the system and minimize human error. At the cost of less than
$3000 for materials and labor the system is cost effective.
The prototype provides a view of the possible industrial version which could be implemented similarly. It
provides a safer and a more convenient tool for flag persons to operate.
Recommendations and Future Works For an industrial approved system a few improvements are required. The original structure must be built
and powder coated. The drive circuit must implement a digital step up DC converter for the LEDs to limit
the heat generated by the regulators. The heat generated is a waste of energy, and limiting it will
provide a longer battery life and a cheaper system.
Possible future works:
1) Solar panel integration for battery recharge
2) Higher batter life for controller
3) Lower voltage draw from battery (price reduction, weight compensation needed)
4) A more compact telescoping structure (maintaining current weight)
5) Possible auto mode with an LCD screen and timer settings
6) Sensors to alert controller for car presence and car clearance
7) Further failsafe systems and backup battery system implementation
Hardware Recommendations
Upon further research, two more methods for resolving the power dissipation issue. The solutions
involve switching regulators or specialized monolithic LED drivers such as the LT3478. Since this problem
was encountered rather late in the prototype build, the time frame did not allow for the ordering of
switching regulators or specialized drivers, both which would require shipping time and a design change
to the current electrical set up. Switching regulators regulate the rate and amount of energy allowed in
providing much more efficient and therefore better power dissipation across the regulator to solve the
heating issue. Monolithic LED drivers are much more complex with various input ranges, boost/buck
capabilities, built in switching regulators, and custom pulse width modulation.
21
Appendix A – Data Sheets and Detailed Hardware Specifications
IRLD110, SiHLD110 Power MOSFET, Document Number 91309 [online], Vishay Siliconix, Retrieved
August 2, 2012, from http://www.vishay.com/docs/91309/sihld110.pdf
XBEE MultiPoint RF Modules, Embedded RF Modules for OEMs, DIGI, Retrieved August 2, 2012, from
http://www.digi.com/pdf/ds_xbeemultipointmodules.pdf
Arduino Uno, Overview, Arduino, Retrieved August 2, 2012, from
http://arduino.cc/en/Main/ArduinoBoardUno/
LM317 3-Terminal Positive Adjustable Regulator, Document Rev 1.0.6, Fairchild Semiconductor,
Retrieved August 2, from: http://www.fairchildsemi.com/ds/LM/LM317.pdf
XBee Shield, SparkFun Electronics, Retrieved August 2, 2012, From:
https://www.sparkfun.com/products/9976
22
Appendix B – WorkSafeBC Data
23
Appendix C – Original Structural Design
24
25
26
27
Appendix D – Arduino Code
/*
* Pylon Code
* Author: Smart Traffic
*
* This code controls a Light Pylon and communicates with the Controller for
instructions
*/
/* Communication Codes
These are the codes used to signal the Pylons with instructions.
The Acknowledgements are codes used to signal the Controller that the
command was received
Exception: Connection command is Pylon-to-Controller, and ack goes
Controller-to-Pylon
NOTE: THESE MUST BE IDENTICAL IN BOTH CONTROLLER AND PYLON AND CANNOT
OVERLAP (OBVIOUSLY)
-Nick
*/
// Light Commands
const char CHANGE_TO_GREEN = 'a';
const char CHANGE_TO_RED = 'b';
const char ENABLE_ALL_RED = 'c';
// Light Command Acknowledgments
const char ACK_CHANGE_TO_GREEN = 'g';
const char ACK_CHANGE_TO_RED = 'h';
const char ACK_ENABLE_ALL_RED = 'i';
const char ACK_CHANGE_TO_YELLOW = 'j';
// Connection Commands (These are reverse of others: Request sent from Pylon,
Ack sent from Controller)
const char REQUEST_CONNECTION = 'm';
const char ACK_CONNECTION = 'n';
// Watchdog Timeout (in milliseconds)
const unsigned long TIMEOUT = 6000;
// Time in Yellow, before going to Red
const int YELLOW_DELAY = 4000;
// Pylon Id constants
const char CONTROLLER_ID = '0';
const char UNCONNECTED_PYLON_ID = '1';
const char LEFT_PYLON_ID = '2';
const char RIGHT_PYLON_ID = '3';
/* MESSAGE FORMAT
* Messages sent between Pylon and Controller are of the following format:
* [DESTINATION_ID, MESSAGE_CODE, SOURCE_ID]
* This is stored as a 3-char array.
*/
28
/**************************************************************/
// Pin Declarations
const int RED_PIN = 6;
const int YELLOW_PIN = 3;
const int GREEN_PIN = 5;
const int RESET_PIN = 12;
// Time last handshake was received from Controller
unsigned long previousTime;
// The Time between successive connection requests
const unsigned long SEND_REQUEST_FREQUENCY_RATE = 1000;
// Variable to hold this Pylon's Id, initialised to unconnected
char pylonId = UNCONNECTED_PYLON_ID;
/*
* Pylon State Variable
* FALSE = this pylon is on RED
* TRUE = this pylon is on GREEN
*/
boolean pylonState = false;
/*
* Pylon emergency All-Red state
*/
boolean allRedState = false;
/*
* Pylon Timeout State
*/
boolean timedOut = false;
/*
* LED Pulse Width Modulation Duty Cycle Constants
* An integer between 0 (0%) and 255 (100%)
*/
const int RED_DUTY_CYCLE = 25;
const int YELLOW_DUTY_CYCLE = 150;
const int GREEN_DUTY_CYCLE = 150;
// Pylon Initialisation Function
void setup() {
// initialize serial communication
Serial.begin(9600);
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(RESET_PIN, OUTPUT);
// Initialise to All On
redLight(true);
yellowLight(true);
greenLight(true);
// Establish Connection to Controller
29
unsigned long previousRequestTime = millis();
while(1)
{
if (((millis() - previousRequestTime) > SEND_REQUEST_FREQUENCY_RATE)
|| (millis() < previousRequestTime))
{
// Reset Command Spacing Timer
previousRequestTime = millis();
// Send Connection Request
sendMessage(REQUEST_CONNECTION);
// Listen for response
if (Serial.available())
{
char message[3];
Serial.readBytes(message, 3);
// Connection Acknowledgement received
if (message[1] == ACK_CONNECTION)
{
// Save the assigned Id from the Controller
pylonId = message[0];
break;
}
}
}
}
// Connected
flashLights();
changeToRed(false); // Skip Yellow Step
// Initialise watchdog timer
previousTime = millis();
}
// Main Code Loop
void loop(){
// Check Reset Button State
//if (digitalRead(RESET_PIN) == LOW)
//Reset();
// Check if Timeout has occurred
if ((millis() - previousTime) > TIMEOUT)
{
// Go to Safety Red State
timeoutSafetyState();
timedOut = true;
}
// Continuously check serial port for Controller communications
if (Serial.available() > 0) {
char command = receiveMessage();
if (command != NULL)
30
{
// Handle Received Message
switch (command) {
case ENABLE_ALL_RED:
if (!allRedState || timedOut) // Only change if not in All Red
state now, or returning after a timeout
enableAllRed();
sendMessage(ACK_ENABLE_ALL_RED);
break;
case CHANGE_TO_RED: // Change to Red
if (timedOut) // Coming out of Timeout
{
changeToRed(false); // Change directly to Red
}
else if (allRedState) // Coming out of All Red
{
changeToRed(false); // Change directly to Red
}
else if (pylonState) // Going from Green through Yellow, to Red
{
sendMessage(ACK_CHANGE_TO_YELLOW);
changeToRed(true); // Change to Red, through Yellow
}
allRedState = false;
sendMessage(ACK_CHANGE_TO_RED);
break;
case CHANGE_TO_GREEN: // Change from Red to Green
if (!pylonState || timedOut || allRedState) // Only change if not
in state already
changeToGreen();
allRedState = false;
sendMessage(ACK_CHANGE_TO_GREEN);
break;
default:
break;
}
// Message Received from Controller, so reset watchdog timer
previousTime = millis();
timedOut = false;
}
}
}
void Reset()
{
asm volatile(" jmp 0");
}
/*
* Message Send and Receive Functions
*/
void sendMessage(char message)
{
// Build Message according to format outlined above
String m = "";
31
m.concat(CONTROLLER_ID);
m.concat(message);
m.concat(pylonId);
// Send Message over Serial Channel
Serial.println(m);
}
char receiveMessage()
{
// Get Message String
char message[3];
Serial.readBytes(message, 3);
// Parse Message and return content (if meant for me)
if (message[0] == pylonId && message[2] == CONTROLLER_ID)
return message[1];
// Not addressed to me, so return null
return NULL;
}
/*
* Flash Lights Utility Function
* Flashes lights between on and off states every half second
*/
void flashLights()
{
redLight(false);
yellowLight(false);
greenLight(false);
delay(500); //wait for half second
redLight(true);
yellowLight(true);
greenLight(true);
delay(500); //wait for half second
redLight(false);
yellowLight(false);
greenLight(false);
delay(500); //wait for half second
redLight(true);
yellowLight(true);
greenLight(true);
delay(500); //wait for half second
redLight(false);
yellowLight(false);
greenLight(false);
delay(500); //wait for half second
redLight(true);
yellowLight(true);
greenLight(true);
delay(500); //wait for half second
redLight(false);
yellowLight(false);
greenLight(false);
}
32
/*
* LED Light Array State Change Functions
*/
void timeoutSafetyState()
{
// TODO: Change this to an appropriate safety state (All Red maybe)
redLight(true);
yellowLight(true);
greenLight(false);
}
void changeToGreen() {
// First, wait for other side to go through Orange
//delay(YELLOW_DELAY);
redLight(false);
yellowLight(false);
greenLight(true);
// Update internal state
pylonState = true;
}
void changeToRed(boolean yellow) {
redLight(false);
greenLight(false);
// Go to Yellow light for short time
if (yellow)
{
yellowLight(true);
delay(YELLOW_DELAY);
}
// Finally, go to Red
yellowLight(false);
redLight(true);
// Update internal state
pylonState = false;
}
/*
* All Red State Functions
*/
void enableAllRed()
{
redLight(false);
greenLight(false);
// If previously in Green, go through Yellow
if (pylonState && !timedOut)
{
sendMessage(ACK_CHANGE_TO_YELLOW);
yellowLight(true);
delay(YELLOW_DELAY);
33
}
redLight(true);
yellowLight(false);
greenLight(false);
// Update internal state
allRedState = true;
}
/*void disableAllRed()
{
// Must return to previous (before All Red enabled) state
if (pylonState) // Go back to Green State
{
changeToGreen();
// Need to inform Controller of new state
sendMessage(ACK_CHANGE_TO_GREEN);
}
else // Go back to Red State
{
changeToRed(false); // Skip Yellow Step
// Need to inform Controller of new state
sendMessage(ACK_CHANGE_TO_RED);
}
// Update internal state
allRedState = false;
}*/
/*
* LED Turn On/Off Functions
* Parameter: TRUE to turn light ON,
* FALSE to turn light OFF
*/
void redLight(boolean turnOn)
{
if (turnOn)
{
//digitalWrite(RED_PIN, LOW);
analogWrite(RED_PIN, RED_DUTY_CYCLE);
}
else
{
digitalWrite(RED_PIN, HIGH);
}
}
void yellowLight(boolean turnOn)
{
if (turnOn)
{
//digitalWrite(YELLOW_PIN, LOW);
analogWrite(YELLOW_PIN, YELLOW_DUTY_CYCLE);
}
else
{
34
digitalWrite(YELLOW_PIN, LOW);
}
}
void greenLight(boolean turnOn)
{
if (turnOn)
{
//digitalWrite(GREEN_PIN, LOW);
analogWrite(GREEN_PIN, GREEN_DUTY_CYCLE);
}
else
{
digitalWrite(GREEN_PIN, LOW);
}
}
35
/*
* Controller Code
* Author: Smart Traffic
*
* This code controls the Controller Arduino and communicates with the Pylons
*/
/* Communication Codes
These are the codes used to signal the Pylons with instructions.
The Acknowledgements are codes used to signal the Controller that the
command was received
Exception: Connection command is Pylon-to-Controller, and ack goes
Controller-to-Pylon
NOTE: THESE MUST BE IDENTICAL IN BOTH CONTROLLER AND PYLON AND CANNOT
OVERLAP (OBVIOUSLY)
-Nick
*/
// Light Commands
const char CHANGE_TO_GREEN = 'a';
const char CHANGE_TO_RED = 'b';
const char ENABLE_ALL_RED = 'c';
// Light Command Acknowledgments
const char ACK_CHANGE_TO_GREEN = 'g';
const char ACK_CHANGE_TO_RED = 'h';
const char ACK_ENABLE_ALL_RED = 'i';
const char ACK_CHANGE_TO_YELLOW = 'j';
// Connection Commands (These are reverse of others: Request sent from Pylon,
Ack sent from Controller)
const char REQUEST_CONNECTION = 'm';
const char ACK_CONNECTION = 'n';
// Watchdog Timeout (in milliseconds)
const unsigned long TIMEOUT = 6000;
// Time in Yellow, before going to Red
const int YELLOW_DELAY = 4000;
// Pylon Id constants
const char CONTROLLER_ID = '0';
const char UNCONNECTED_PYLON_ID = '1';
const char LEFT_PYLON_ID = '2';
const char RIGHT_PYLON_ID = '3';
/* MESSAGE FORMAT
* Messages sent between Pylon and Controller are of the following format:
* [DESTINATION_ID, MESSAGE_CODE, SOURCE_ID]
* This is stored as a 3-char array.
*/
/**************************************************************/
// The Time between successive command broadcasts to Pylons
const unsigned long SEND_COMMAND_FREQUENCY_RATE = 100;
36
// Input Pins
const int ALL_RED_SWITCH_PIN = 2;
const int LEFT_TO_RIGHT_SWITCH_PIN = 3;
const int BUFFER_BUTTON_PIN = 4;
// Reset Button Pin
const int RESET_BUTTON_PIN = 12;
// LED Indicator Pins
const int LEFT_RED_PIN = 5;
const int LEFT_YELLOW_PIN = 6;
const int LEFT_GREEN_PIN = 7;
const int RIGHT_RED_PIN = 8;
const int RIGHT_YELLOW_PIN = 9;
const int RIGHT_GREEN_PIN = 10;
// Pylon Id variables
int leftPylonId = -1, rightPylonId = -1;
/* State Variables for Left and Right Pylons
* False = Red Light, True = Green Light
* All Red States: True = enabled, False = Disabled
*/
boolean leftPylonState = false;
boolean rightPylonState = false;
boolean leftPylonAllRedState = false;
boolean rightPylonAllRedState = false;
// Time last acknowledgement was received
unsigned long previousTimeLeftPylon;
unsigned long previousTimeRightPylon;
// Time last command broadcast was made (to space out broadcasts)
unsigned long previousCommandTime;
// Variable used to alternate pulses to Left and Right Pylons
boolean leftRightPulse = false;
// Left and Right Command Signals
char leftSignal, rightSignal;
// Buffer button variables
boolean bufferButtonPressed = true;
int previousLeftRightSwitchState;
void setup() {
// Initialize serial communication
Serial.begin(9600);
pinMode(ALL_RED_SWITCH_PIN, OUTPUT);
pinMode(LEFT_TO_RIGHT_SWITCH_PIN, OUTPUT);
pinMode(BUFFER_BUTTON_PIN, OUTPUT);
pinMode(RESET_BUTTON_PIN, OUTPUT);
pinMode(LEFT_RED_PIN, OUTPUT);
37
pinMode(LEFT_YELLOW_PIN, OUTPUT);
pinMode(LEFT_GREEN_PIN, OUTPUT);
pinMode(RIGHT_RED_PIN, OUTPUT);
pinMode(RIGHT_YELLOW_PIN, OUTPUT);
pinMode(RIGHT_GREEN_PIN, OUTPUT);
// Wait for Left Pylon to connect
attachLeftPylon();
// Clear Serial Channel of old requests before attaching Right Pylon
delay(300);
if (Serial.available() > 0)
{
char message[3];
Serial.readBytes(message, 3);
}
// Wait for Right Pylon to connect
attachRightPylon();
// Initialise Watchdog Timers
previousTimeLeftPylon = previousTimeRightPylon = previousCommandTime =
millis();
// Initialise the previousLeftRightSwitchedState
previousLeftRightSwitchState = digitalRead(LEFT_TO_RIGHT_SWITCH_PIN);
}
void loop(){
/*
* Check Button States and Build Command Pulse Signals
*/
// Check Reset Button State
if (digitalRead(RESET_BUTTON_PIN) == HIGH)
Reset();
// Check state of Buffer Button
if (digitalRead(BUFFER_BUTTON_PIN) == HIGH)
bufferButtonPressed = true;
// Read All Red Switch State
if (digitalRead(ALL_RED_SWITCH_PIN) == HIGH)
{
leftSignal = rightSignal = ENABLE_ALL_RED;
}
// Left<->Right Switch state
else if (digitalRead(LEFT_TO_RIGHT_SWITCH_PIN) == HIGH)
{
// Switch has changed state, so reset the Buffer Button to false
if (previousLeftRightSwitchState == LOW)
{
bufferButtonPressed = false;
previousLeftRightSwitchState = HIGH;
}
38
leftSignal = CHANGE_TO_RED;
if (bufferButtonPressed && !rightPylonState)
leftSignal = CHANGE_TO_GREEN;
rightSignal = CHANGE_TO_RED;
}
else if (digitalRead(LEFT_TO_RIGHT_SWITCH_PIN) == LOW)
{
// Switch has changed state, so reset the Buffer Button to false
if (previousLeftRightSwitchState == HIGH)
{
bufferButtonPressed = false;
previousLeftRightSwitchState = LOW;
}
rightSignal = CHANGE_TO_RED;
if (bufferButtonPressed && !leftPylonState)
rightSignal = CHANGE_TO_GREEN;
leftSignal = CHANGE_TO_RED;
}
// Send out Command Pulses
if (((millis() - previousCommandTime) > (SEND_COMMAND_FREQUENCY_RATE/2)) ||
(millis() < previousCommandTime))
{
// Send out Right Pylon's Signal
if (leftRightPulse = !leftRightPulse)
sendMessage(rightPylonId, rightSignal);
// Send out Left Pylon's Signal
else
sendMessage(leftPylonId, leftSignal);
// Reset Command Spacing Timer
previousCommandTime = millis();
}
// Receive Ack messages, and update state accordingly
int tmp;
for (tmp = 0; tmp < 2; tmp++)
if (Serial.available())
{
char message[3];
Serial.readBytes(message, 3);
if (message[0] != CONTROLLER_ID)
continue;
// Switch on contents of message
switch (message[1])
{
case ACK_ENABLE_ALL_RED: // A Pylon has gone to All Red state
if (message[2] == leftPylonId)
{
// Update State
leftPylonAllRedState = true;
leftRedIndicator();
previousTimeLeftPylon = millis();
}
39
else if (message[2] == rightPylonId)
{
// Update State
rightPylonAllRedState = true;
rightRedIndicator();
previousTimeRightPylon = millis();
}
break;
case ACK_CHANGE_TO_YELLOW: // A Pylon is changing to Yellow, then Red
State
if (message[2] == leftPylonId)
{
// Update State
leftYellowIndicator();
previousTimeLeftPylon = millis();
}
else if (message[2] == rightPylonId)
{
// Update State
rightYellowIndicator();
previousTimeRightPylon = millis();
}
break;
case ACK_CHANGE_TO_RED: // A Pylon has gone to (Yellow, then) Red
State
if (message[2] == leftPylonId)
{
// Update State
leftPylonState = false;
leftRedIndicator();
previousTimeLeftPylon = millis();
}
else if (message[2] == rightPylonId)
{
// Update State
rightPylonState = false;
rightRedIndicator();
previousTimeRightPylon = millis();
}
break;
case ACK_CHANGE_TO_GREEN:
if (message[2] == leftPylonId)
{
// Update State
leftPylonState = true;
leftGreenIndicator();
previousTimeLeftPylon = millis();
}
else if (message[2] == rightPylonId)
{
// Update State
rightPylonState = true;
rightGreenIndicator();
previousTimeRightPylon = millis();
}
break;
default:
40
break;
}
}
}
void Reset()
{
asm volatile(" jmp 0");
}
void attachLeftPylon()
{
while(1) // First Connected will be Left Pylon
{
// Read Serial, assign first Pylon as Left Pylon
if (Serial.available() > 0)
{
char message[3];
Serial.readBytes(message, 3);
if (message[2] == UNCONNECTED_PYLON_ID && message[1] ==
REQUEST_CONNECTION)
{
leftPylonId = LEFT_PYLON_ID;
sendMessage(leftPylonId, ACK_CONNECTION);
break;
}
}
}
leftRedIndicator();
}
void attachRightPylon()
{
while(1) // Second Connected will be Right Pylon
{
// Read Serial, assign second Pylon as Right Pylon
if (Serial.available() > 0)
{
char message[3];
Serial.readBytes(message, 3);
if (message[2] == UNCONNECTED_PYLON_ID && message[1] ==
REQUEST_CONNECTION)
{
rightPylonId = RIGHT_PYLON_ID;
sendMessage(rightPylonId, ACK_CONNECTION);
break;
}
}
}
rightRedIndicator();
}
void sendMessage(char destination, char message)
{
char m[3] = {destination, message, CONTROLLER_ID};
Serial.println(m);
}
41
void rightRedIndicator()
{
digitalWrite(RIGHT_RED_PIN, HIGH);
digitalWrite(RIGHT_YELLOW_PIN, LOW);
digitalWrite(RIGHT_GREEN_PIN, LOW);
}
void leftRedIndicator()
{
digitalWrite(LEFT_RED_PIN, HIGH);
digitalWrite(LEFT_YELLOW_PIN, LOW);
digitalWrite(LEFT_GREEN_PIN, LOW);
}
void rightYellowIndicator()
{
digitalWrite(RIGHT_RED_PIN, LOW);
digitalWrite(RIGHT_YELLOW_PIN, HIGH);
digitalWrite(RIGHT_GREEN_PIN, LOW);
}
void leftYellowIndicator()
{
digitalWrite(LEFT_RED_PIN, LOW);
digitalWrite(LEFT_YELLOW_PIN, HIGH);
digitalWrite(LEFT_GREEN_PIN, LOW);
}
void rightGreenIndicator()
{
digitalWrite(RIGHT_RED_PIN, LOW);
digitalWrite(RIGHT_YELLOW_PIN, LOW);
digitalWrite(RIGHT_GREEN_PIN, HIGH);
}
void leftGreenIndicator()
{
digitalWrite(LEFT_RED_PIN, LOW);
digitalWrite(LEFT_YELLOW_PIN, LOW);
digitalWrite(LEFT_GREEN_PIN, HIGH);
}