Last active
November 4, 2021 21:02
-
-
Save iremlopsum/4b08d1e8eca50b0b6e8394c1432d07a1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Traffic light with Raspberry Pi | |
import RPi.GPIO as GPIO | |
import time | |
# import sys for warning | |
import sys | |
# Variable that states if polling should be used | |
polling = False | |
# Listen to flags passed in from command line | |
if len(sys.argv) > 1: | |
# If -p or --polling is passed in, set polling to true | |
if sys.argv[1] == "-p" or sys.argv[1] == "--polling": | |
polling = True | |
# Print that program is using polling | |
print("Using polling") | |
# If -i or --interrupt is passed in, set polling to false | |
elif sys.argv[1] == "-i" or sys.argv[1] == "--interrupt": | |
polling = False | |
# Print that program is using interrupt | |
print("Using interrupt") | |
# If -h or --help is passed in, print help message with available flags | |
elif sys.argv[1] == "-h" or sys.argv[1] == "--help": | |
print("Usage: trafficlight.py [flag]") | |
print("Flags:") | |
print(" -p, --polling: Use polling") | |
print(" -i, --interrupt: Use interrupt, as is ran by default") | |
print(" -h, --help: Print this help message") | |
exit(0) | |
# Set up GPIO mode to BOARD | |
GPIO.setmode(GPIO.BOARD) | |
# turn off warnings for GPIO pins | |
GPIO.setwarnings(False) | |
# Create a map of traffic lights to GPIO pins | |
traffic_lights = { | |
"red": 17, | |
"yellow": 18, | |
"green": 27 | |
} | |
# Create a map of pedestrian lights to GPIO pins | |
pedestrian_lights = { | |
"red": 22, | |
"green": 23 | |
} | |
# Create a map of controls lights with a blue light | |
control_lights = { | |
"blue": 24 | |
} | |
# Create a map for pedestrian light button to GPIO pin | |
pedestrian_buttons = { | |
"button": 25 | |
} | |
# Variable that holds button pressed state | |
was_button_pressed = False | |
# Variable that holds the state of while loop | |
# that runs the traffic light sequence | |
has_pedestrian_loop_started = False | |
# Connect traffic lights to GPIO pins | |
for light, pin in traffic_lights.items(): | |
GPIO.setup(pin, GPIO.OUT) | |
# Connect pedestrian lights to GPIO pins | |
for light, pin in pedestrian_lights.items(): | |
GPIO.setup(pin, GPIO.OUT) | |
# Connect pedestrian button to GPIO pin | |
GPIO.setup(pedestrian_buttons["button"], GPIO.IN, pull_up_down=GPIO.PUD_UP) | |
# Helper function that tells if a light is on | |
def is_light_on(light): | |
return GPIO.input(light) == GPIO.HIGH | |
# Function that can turn on either traffic light or pedestrian light | |
def turn_light_on(light): | |
GPIO.output(light, GPIO.HIGH) | |
# Function that turns off either traffic light or pedestrian light | |
def turn_light_off(light): | |
GPIO.output(light, GPIO.LOW) | |
# Function that turns a light on for n amount of seconds | |
# and then turns that light off | |
def turn_light_on_for_n_seconds(light, n): | |
turn_light_on(light) | |
time.sleep(n) | |
turn_light_off(light) | |
# Function that can turn on multiple lights at once for | |
# n amount of seconds and then turn those lights off | |
def turn_on_multiple_lights_for_n_seconds(lights, n): | |
for light in lights: | |
turn_light_on(light) | |
time.sleep(n) | |
for light in lights: | |
turn_light_off(light) | |
# Function that turns off all traffic lights and pedestrian lights | |
def turn_all_lights_off(): | |
for light in traffic_lights: | |
turn_light_off(light) | |
for light in pedestrian_lights: | |
turn_light_off(light) | |
# Function that blinks light n times within n seconds with last state being on | |
def blink_light(light, n, s): | |
blink_time_off = 0 | |
blink_time_on = (s - (blink_time_off * (n - 1))) / n | |
for i in range(n): | |
turn_light_on_for_n_seconds(light, blink_time_on) | |
# If we are not on the last iteration, we have a delay between blinks | |
# so that transition to next light would be smooth | |
if i != n: | |
time.sleep(blink_time_off) | |
# Callback function for when the button is pressed | |
def button_callback(channel): | |
# Use global variables | |
global was_button_pressed | |
global polling | |
# If button was pressed and button pressed state is false | |
# turn on blue light and set button pressed state to true | |
if GPIO.input(channel) == GPIO.LOW and was_button_pressed == False: | |
was_button_pressed = True | |
# If polling is set to true, turn on blue light | |
if polling: | |
turn_light_on(control_lights["blue"]) | |
# Start listening for button press with a callback function | |
GPIO.add_event_detect( | |
pedestrian_buttons["button"], GPIO.FALLING, callback=button_callback, bouncetime=300) | |
# Turn off all of the lights when program starts | |
# because we want to start with all lights off | |
# in case previous program crashed | |
turn_all_lights_off() | |
# Function that runs the traffic light sequence in a while loop | |
def run_traffic_light_sequence(): | |
# Use global variables | |
global polling | |
global was_button_pressed | |
global has_pedestrian_loop_started | |
while True: | |
# If button is pressed, and pedestrian loop has not started, | |
# turn on pedestrian green with traffic red and set pedestrian loop to true | |
# else turn on traffic red with pedestrian red | |
if was_button_pressed and not has_pedestrian_loop_started: | |
has_pedestrian_loop_started = True | |
turn_on_multiple_lights_for_n_seconds( | |
[traffic_lights["red"], pedestrian_lights["green"]], 5) | |
turn_light_on(pedestrian_lights["red"]) | |
# If we use interrupt instead of polling, turn on blue light | |
if polling == False: | |
turn_light_on(control_lights["blue"]) | |
else: | |
turn_light_on(pedestrian_lights["red"]) | |
turn_light_on_for_n_seconds(traffic_lights["red"], 5) | |
turn_light_on_for_n_seconds(traffic_lights["yellow"], 1) | |
turn_light_on_for_n_seconds(traffic_lights["green"], 5) | |
blink_light(traffic_lights["yellow"], 3, 2) | |
# If button is pressed and pedestrian loop is set to true, | |
# set button pressed state to false, turn off blue light, | |
# and set pedestrian loop to false | |
if was_button_pressed and has_pedestrian_loop_started: | |
was_button_pressed = False | |
has_pedestrian_loop_started = False | |
turn_light_off(control_lights["blue"]) | |
# Try to run the traffic light sequence, with keyboard exception | |
# and print the exception to the console | |
try: | |
run_traffic_light_sequence() | |
except KeyboardInterrupt: | |
# print reason of exit and clean up | |
print("\nProgram stopped by user") | |
turn_all_lights_off() | |
GPIO.cleanup() | |
except: | |
# print reason of exit and clean up | |
print("\nUnexpected error:", sys.exc_info()[0]) | |
turn_all_lights_off() | |
GPIO.cleanup() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment