Introduction: Proximity Stoplight

This Instructable is perfect for those who think that a tennis ball on a string is a far too simple (albeit effective) way to know when to stop the car when pulling into the garage. I will walk you through how to build/modify and automate a stoplight which helps you park at the perfect distance every time!

I used a $20 novelty stoplight for my project because it required very little modification to serve my purposes. This isn't to say you couldn't build your own from scratch or use a different kind, though.


This project makes use of relays to control 120v AC electricity, which is very dangerous if improperly handled. Do not attempt this project unless you have a thorough understanding of electrical theory and safety practices.

Step 1: What You'll Need

In addition to the items above (and your general Arduino/electronics toolkit), you'll need to download the following Arduino libraries:

LiquidCrystal_I2C (for the 16 x 2 line LCD display)

NewPing (for the HC-SR04 proximity sensor)

Wire (for the I2C communication for the LCD display)

Included in the Arduino IDE

Step 2: Initial Modifications to the Stoplight

Since we want to control the three lights of the stoplight individually using relays, we'll need to do the following:

1) Make sure nothing is plugged in!!! This goes for every step except the final testing phase.

2) Remove the bulbs that came with the stoplight and replace them with standard 7w nightlight bulbs. This only applies if you are using the same sort of randomly blinking stoplight that I purchased.

3) Snip and strip the hot lead to each light socket and tin the wire with solder

4) Build and solder jumpers to carry the hot lead to each of the three relays (see pics)

5) Connect the incoming hot lead from the stoplight plug to the series of jumpers

6) Leave the neutral side alone. These are already wired in parallel and should work as they are.

Step 3: Connect the Relays

I used 18ga. wire to carry AC current to the relays, as this was the size used in the stoplight wiring.

Relay connections are as follows:

Relay #1 (Green/In1) - NC = Empty, NO = hot lead to bottom bulb, COM = hot lead from plug

Relay #2 (Yellow/In2) - NC = Empty, NO = hot lead to center bulb, COM = hot lead from jumper to Relay #1 COM

Relay #3 (Red/In3) - NC = Empty, NO = hot lead to top bulb, COM = hot lead from jumper to Relay #2 COM

Step 4: Mount the Arduino, Relay Module, and LCD Display

I mounted these directly to the back plate of the stoplight using a combination of store-bought and home-made stand-offs. Where screws were not an option, I used hot glue. The LCD stand-offs had to be longer to lift it up flush with the case I was building.

Step 5: Run 5V Power From Arduino and Ground Back

The LCD screen, proximity sensor and relay module all require 5V (labeled VCC) and Ground connections. I decided to give the proximity sensor its own jumpers (see the very left edge of the pic), but created "Y" jumpers to run power and ground to the other two jointly.

Step 6: Make Data Connections

In addition to power and ground connections, I made the following pin choices so that I could use shorter jumpers, but you can use other pins if you prefer.

Pin 5 = Relay In1 (Green light)

Pin 6 = Relay In2 (Yellow light)

Pin 7 = Relay In3 (Red light)

Pin 12 = HC-SR04 Trigger

Pin 13 = HC-SR04 Echo

SCL = To SCL on LCD Display

SDA = To SDA on LCD Display

Step 7: Build a Nifty Case

I built mine out of 1/4" MDF, hot glued and spray painted black. I'm sure there are better options out there.

My case has the following features:

-Box below stoplight with two holes drilled out of the faceplate to accommodate the sonar proximity sensor.

-Top plate for screws to secure the light to the case and one centered hole for potential hanging option

-Sides of adequate depth to encase the electronics on the back

-Inset stop blocks for back plate

-Back plate with cutout for LCD display and finger hole for removal

-Hole in bottom/side for 9V DC adapter cord

Step 8: Power

Both the Arduino's 9V DC power supply and the stoplight itself are connected to AC power via the garage door light via a female Edison adaptor plugged into one of the light sockets. This means the device/Arduino are only powered on when the garage door is opened, and they automatically turn off when the light times out (about 3 minutes for mine).

Step 9: The Code and What It Does

Using the three libraries mentioned before, the code performs these basic functions:

1) The sonar proximity module sends and receives a set of pings each time the loop runs (I have a 200ms delay between loops). The results of the set of pings is averaged and any aberrant data is thrown out, resulting in a single result in milliseconds. This time is then converted to inches. I found the averaging function to be very useful as the sonar sensor was occasionally mis-reading distance and returning invalid results, making the wrong lights flash.

2) Depending on the result (in distance) of the pings, the relays are told how to react (which lights to turn on and off). You can decide what your distance parameters are for each light color. In my code, a flashing sequence runs if an object gets extremely (<10in.) close to the sensor.

3) In addition to turning on the lights, the LCD screen prints the result of the ping every time the loop runs.


//include libraries for LCD display, HC-SR04 Distance Sensor, and I2C devices
#include <LiquidCrystal.I2C.h> #include <NewPing.h> #include <Wire.h>

//define pin assignments for the NewPing library #define TRIGGER_PIN 12 #define ECHO_PIN 13 #define MAX_DISTANCE 300

//Set variables for NewPing library NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // Set the LCD address to 0x3f for a 16 character, 2 line display LiquidCrystal_I2C lcd(0x3f, 16, 2);

//identify the correct digital I/O pins on Arduino as the different stoplight colors const int Green = 5; const int Yellow = 6; const int Red = 7;

int echoTime = 0; int inches = 0;

void setup() {

//Set up the pins as outputs and set them to a default of "HIGH"/open, except for green, which begins in the "on" state //Note:"HIGH" in the case of the "NO" port on the relay is open. pinMode (Green, OUTPUT); digitalWrite (Green, LOW); pinMode (Yellow, OUTPUT); digitalWrite (Yellow, HIGH); pinMode (Red, OUTPUT); digitalWrite (Red, HIGH);

//initialize the lcd display using the LiquidCrystal_I2C library lcd.begin(); lcd.backlight();

} void loop() {

//define variables for the sonar pings echoTime = sonar.ping_median(6); inches = sonar.convert_in(echoTime); lcd.clear(); lcd.print(check());

if (inches >= 60 || inches == 0) { digitalWrite (Green, LOW); digitalWrite (Yellow, HIGH); digitalWrite (Red, HIGH); } if (inches >= 20 && inches < 60) { digitalWrite (Green, HIGH); digitalWrite (Yellow, LOW); digitalWrite (Red, HIGH); } if (inches >= 10 && inches < 20) { digitalWrite (Green, HIGH); digitalWrite (Yellow, HIGH); digitalWrite (Red, LOW); } if (inches < 10 && inches > 0) { digitalWrite (Green, HIGH); digitalWrite (Yellow, HIGH); digitalWrite (Red, HIGH); delay (250); digitalWrite (Red, LOW); delay (250); digitalWrite (Red, HIGH); delay (250); digitalWrite (Red, LOW); delay (250); digitalWrite (Red, HIGH); delay (250); digitalWrite (Red, LOW); delay (100); } delay(200); }

String check() { String myString = "Impact in " + String(inches) + " in."; return myString; }

Step 10: The End Product

If all goes well, you'll have a really awesome tennis ball replacement to wow your friends and save the back wall of your garage from accidental ramming! Have fun!


The HC-SR04 sonar proximity sensor is not a fan of soft, narrow, or non-vertical surfaces because it relies on the return of a bounced sound wave. You'll need to aim it at the widest, most vertical part of your car. Mine works best aimed at the front bumper/grille area. Most windshields are probably at too great an angle to return reliable/accurate pings. I haven't tried this project with other types of distance sensors yet, but there may be a better one out there.