Arduino street light project
Posted on: 2012-09-02
I am done with my personal project that was to built a system of light to tell my wife when to stop the car inside the home's garage. The idea was to use Arduino microcontroller with a sensor to evaluate the distance of the car inside the garage. To make it look more "urban", I had the idea to use something that looks like a street light, with a red, yellow and green light.
Schema
The electronic part consist of an Arduino Diecimila that I already had (I think it has cost me around 35$ in the past). This will be used to have the logic that are to open the light, to evaluate the distance and to have some logic of "sleep" because we do not want the system to be always open. Also, I added the possibility to configure on the fly the machine with 2 buttons that will record in the permanent memory the distance for the yellow and red light.
So, you need an Arduino board with at least 12kb of ram memory. Diecimila is more than enough and the new popular one is over what we need. You need to have a relay to open 110 volts light bulb. I took one on Ebay called Yurobot that has 4 relay and handle the current/volt for Arduino to 110volt. It has worked flawless and it's pretty great to debug because it has 4 leds that indicate when the current is distributed. The cost is 8$.
Then, you need the input sensor for the distance. I have used the Ultrasonic Module HC-SR04, which work nice in straight line within a distance of 1 cm to 2 meters. The cost is 2$ on Ebay. For that price, you can be really picky. Of course.
Finally, I bought 1 60 watts red, yellow and green build for about 5$. The rest of the stock are wires (14 gaugs for 110 volts, and 22 gaugs for 5 volts) I had for around 5$. I bought 3 switchs (1 power switch and 2 pushbuttons) for about 3$. Finally, since I wanted 1 wire to be connectec to the 110 volts of my house, I bought an electric extension for 2$ and cut the end to use it as main electricity source. I needed also to have something to convert 110 volts to 9 volts for Arduino. I bought on Ebay a power supply for 5$. So, this cost me around 65$ to build + the wood/paint/nail that I already have. I guess you can get this project done under 80$ without a problem.
Code
I share to you the code. This code might not be optimized perfectly but work fine. I has many feature like
- Record Yellow light distance with a button
- Record Red light distance with a button
- Close automatically the light after 20 secondes of inactivity
- Record light distance in the EEPROM for permanent configuration
- Has a debug mode that contain protection of EEPROM and longer loop (for debugging on the screen)
- Has a lot of debug information that goes on the serial to be able to debug on screen
- Use a threshold of 1 cm before switching light (otherwise can't go in sleep mode easily
- Has a save confirm signal (switch light from red to green) when save occur
#include <EEPROM.h> boolean debug = false;
//Distance
long distance; //The current distance found
long lastDistance = 0; //The last distance found
int recordedDistance; //The recorded distance by a button
int light=0; //0= start, 1 = green, 2 = yellow, 3 = red
//Buttons
const int buttonMinDistancePin = 2; //Record the minimum distance = red distance
const int buttonMaxDistancePin = 3; //Record the maximum distance = yellow distance
int minButtonState; //Indicate if the minimum distance button is pushed
int maxButtonState; //Indicate if the maximum distance button is pushed
//Led const
int ledGreen = 8; //Pin on the Arduino's board for Green light
const int ledYellow = 9; //Pin on the Arduino's board for Yellow light
const int ledRed = 10; //Pin on the Arduino's board for Red light
//Pin for ultrasonic
const int trigPin =5; //Pin on the Arduino's board for triggering the Ultrasonic
const int echoPin =4; //Pin on the Arduino's board for echoing the Ultrasonic
//Value to compare too for led
int minDistance = 30; //Value for the red distance in cm
int maxDistance = 100; //Value for the yellow distance in cm
//Memory const
int minDistanceAddress= 0; //Permanent memory (EEPROM). Minimum distance = red distance
const int maxDistanceAddress = 1; //Permanent memory (EEPROM). Maximum distance = yellow distance
//Time
unsigned long lastActivity = 0; //Indicate the last activity time
const long secondBeforeSleep = 20; //Time in second before going in sleep mode (all light closed)
unsigned long lastButtonPress = 0; //Indicate the last time a button has been pressed
const long secondBeforeNewSave = 5; //Time in second before beeing able to save
void setup() {
//Initialize Arduino's pins
pinMode(ledYellow, OUTPUT);
pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
//When starting up, we read the distance if they are set
if(debug) {
minDistance = 20;
maxDistance = 50;
} else {
int v1 = EEPROM.read(minDistanceAddress);
int v2 = EEPROM.read(maxDistanceAddress);
if(v1 != 255) //No default value with no record yet
{
minDistance = v1;
}
if(v2 != 255) //No default value with no record yet
{
maxDistance = v2;
}
}
//Debug
Serial.begin (9600);
Serial.print("Min Distance : ");
Serial.println(minDistance);
Serial.print("Max Distance : ");
Serial.println(maxDistance);
CloseAllLights(); }
void loop() {
//Debug
Serial.println("New loop");
Serial.print("Min Distance : ");
Serial.println(minDistance);
Serial.print("Max Distance : ");
Serial.println(maxDistance);
//Ultrasonic trigger/echo to get the distance
digitalWrite(trigPin, HIGH);
delayMicroseconds(2);
digitalWrite(trigPin, LOW);
delayMicroseconds(10);
digitalWrite(echoPin, LOW);
distance = (pulseIn(echoPin, HIGH)/2) / 29.1;
//Nothing found
if(distance==0) {
CloseAllLights();
}
//Debug
Serial.print("Current distance and last distance: ");
Serial.print(distance);
Serial.print(" cm, ");
Serial.print(lastDistance);
Serial.println(" cm.");
unsigned long currentTime = millis();
//Debug
Serial.print("Current time-Last activity time = ");
Serial.print(currentTime);Serial.print("ms - ");
Serial.print(lastActivity);Serial.println("ms");
if(lastActivity != 0 && lastActivity < currentTime) //Check if we had an activity since we have started and check if we have not pass the overflow of the machine time (around 50 days)
{
if(currentTime - lastActivity > 1000*secondBeforeSleep)
//Since last activity, have we pass the x seconds before going to sleep
{
//SLEEP MODE
if(distance >= lastDistance-1 && distance <= lastDistance+1)
//The distance is about the same (+-1 cm) as the last time = no change for light if under x seconds. The +-1 cm is because sometime the distance is between two and toggle between two values very fast which make the light to stay open (no-sleep mode)
{
Serial.println("----->Sleep MODE : Starting");
CloseAllLights();
} else {
Serial.println("----->Sleep MODE : Done");
lastActivity = currentTime; //We are in sleep mode, but we have found a change. We change the mode to no-sleep
OpenLight();
}
} else {
if(distance == lastDistance)
//The distance is about the same (+-1 cm) as the last time = no change for light if under x seconds. The +-1 cm is because sometime the distance is between two and toggle between two values very fast which make the light to stay open (no-sleep mode)
{
Serial.println("----->Active MODE : Thinking to sleep");
} else {
Serial.println("----->Active MODE");
lastActivity = currentTime;
}
OpenLight();
}
} else {
lastActivity = currentTime; //We change the mode to no-sleep if we just start the application or if the time has overflow for Arduino.
}
//Record the minimum and maximum with the two buttons if they are pressed
minButtonState = digitalRead(buttonMinDistancePin);
if (minButtonState == HIGH) {
recordedDistance = EEPROM.read(minDistanceAddress);
Serial.print("Recorded Distance = ");
Serial.println(recordedDistance);
Serial.print("Min Distance = ");
Serial.println(minDistance);
if(recordedDistance != distance && currentTime - lastButtonPress > 1000*secondBeforeNewSave)
//Record only if really changed and some time since last button press occurs
{
if(distance < maxDistance) {
Serial.println("*** Saving Min Distance ***");
if(!debug) {
EEPROM.write(minDistanceAddress, distance);
}
minDistance = distance;
lastButtonPress = currentTime;
ConfirmSave();
}
}
}
//Reset if the current time has overflow
if(lastButtonPress > currentTime) {
lastButtonPress = 0;
}
maxButtonState = digitalRead(buttonMaxDistancePin);
if (maxButtonState == HIGH) {
recordedDistance = EEPROM.read(maxDistanceAddress);
Serial.print("Recorded Distance = ");
Serial.println(recordedDistance);
Serial.print("Max Distance = ");
Serial.println(maxDistance);
if(recordedDistance != distance && currentTime - lastButtonPress > 1000*secondBeforeNewSave)
//Record only if really changed and some time since last button has occurs
{
if(distance > minDistance) {
Serial.println("*** Saving Max Distance ***");
if(!debug) {
EEPROM.write(maxDistanceAddress, distance);
}
maxDistance = distance; lastButtonPress = currentTime; ConfirmSave();
}
}
}
lastDistance = distance;
//Record last distance to be able to check if change have been made
if(debug) {
delay(500);
} else {
delay(250);
}
}
//Close all lights
void CloseAllLights() {
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, HIGH);
}
//ConfirmSave
void ConfirmSave() {
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, HIGH);
delay(500);
digitalWrite(ledRed, LOW);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, HIGH);
delay(500);
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, LOW);
digitalWrite(ledGreen, HIGH);
delay(500);
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, LOW);
delay(500);
}
//Open the correct light
void OpenLight() {
//NO-SLEEP MODE
if(distance != lastDistance)
//If distance has changed (no boundary, very precise)
{
//Open the good light
if(distance<minDistance && distance>0) {
digitalWrite(ledRed, LOW);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, HIGH);
Serial.println("*RED*"); light = 3;
}
else if(distance<maxDistance && distance>0) {
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, LOW);
digitalWrite(ledGreen, HIGH);
Serial.println("*Yellow*");
light = 2;
} else if(distance>=maxDistance) {
digitalWrite(ledRed, HIGH);
digitalWrite(ledYellow, HIGH);
digitalWrite(ledGreen, LOW);
Serial.println("*Green*");
light = 1;
}
}
}
You can see the final version on YouTube. The physical enclosure may has be done more beautifully but I am not a carpenter. I am happy of the end result. Some thing that you might know : the power cable is too short. I bought a 1.5 meters extension cord and I think you should get at least 2.5 meters. Also, I had the idea to have the ultrasonic sensor outside the main enclosure and this is a good idea. The only error I did is that I bought a plastic enclosure too big for the purpose of having only the ultrasonic sensor (not a big deal). Last thing, the wood enclosure is too small, I had difficulty to put the relay, the Arduino, all the wire and the power supply.
As you can see, the space between the back of the light and the wood is about 1 inch.
Concerning the build part (left side of the last picture), it's okay. I put a plexiglass that I sandblasted with a black cardboard to make the letters from a stencil.
Conclusion
Arduino make it simple with under 300 lines of code I were able to make work a ultrasonic sensor with 3 lights. My main goal was to fulfill the requirement of having a system to know where to stop the car in the garage and I think it's a success. Also, as a personal goal, I always wanted to control physical stuff that were running on 110 volts and it was also a success. Now, time for another project!