Introduction: Ultrasonic Garage Parking Assistant With Arduino and an ATtiny85

About: I burnt the cider.

Hello fellow makers, I want to share with you a simple project that I have put together. I am new to prototyping/circuits and only took two semester of Java courses, so when I went looking for simple projects to build my skills, I was disappointed at how complex some of the code I saw was. While there are many other projects out there, with almost exactly the same in functionality, they were just too complex for the simplicity of the project. I believe I have put together a version that is much simpler and one that anyone can follow. In doing so, there may be some sacrifices in robustness(delay haters) but It works great so who really cares. 

Let's talk about the exact functionality. We are sensing distance all the time and have an rgb LED to indicate whether to keep coming, slow down, stop, or go back. A button is used to store the current distance as the desired parking distance. Even though the LED is super low power consumption, I am an environmentalist, so lets program in a power save mode to turn off the LED when there is no car in the garage and around 30 seconds after the car has parked in the right spot. Also, we cannot expect that the car will be parked at the exact, down to the inch, distance it was set at, so we will include a range of about 6 inches. You don't want to end up moving back and forth a dozen times before you get in right*. This is a big improvement over ones you can buy at Home Depot that only have 1, 2, and 3 foot distance settings and only 3 indicator stages. Plus, all the big box store ones look cheap and all have this ugly two part design where the LED or sensor are on a pull string. Not what I want in a classy garage.

If you then want to make it smaller, cheaper and more permanent, plus, not have to leave your Arduino in it, flash the software over to an ATtiny85-20PU.  We will go over all the required steps to use the Arduino as the ISP to load the software to the ATtiny.


First lets gather some parts along with some approximate prices
$15 - Arduino(any will do)
Projet housing
$3 - HC-SR04 Ultrasonic distance sensor
$4 - Breadboard
$1 - RGB LED (I prefer one that has a high brightness rating and is frosted) 
$2 - Button
$1 - 3 resistors ~ 220 ohm (this all really depends on the strength of the LED you choose)
      1 resistor ~ 10k ohm ( button)
$1 - Jumpers 
$3 - Power supply - You have a few options here depending on whether you chose to leave the Arduino board inside or use the ATtiny85

If you choose to use the ATtiny then you will need
$2 - ATtiny85
$2 - DC input jack
$1 - 5V regulator
$1 - 2x 10uf electrolytic capacitors 

~ or ~

$4 - Breadboard power supply



Step 1: Build a Project Box

A great project box for this tupperware. It is particularly good because it is most of the time transparent and even better, it is often frosted. This is all important in spreading the light of the LED to make it as visible as possible. Also, its widely available, cheap and easy to cut. I used the plastic box that came with my Arduino starter kit, which turned out to work quite nicely.

Cut two holes for the ping sensor

This by far the trickiest part. You want try to get them as snug as possible so that you dont have to get out the hot glue gun. The sensors are 16mm wide, so its doubtful that the average person has a drill bit of that nature lying around. This may not be the most orthodox method of cutting holes but with the soft plastic, it worked for me. 

First, I drilled a pilot hole in the exact center of where each whole needed to be.

Using some sharp scissors, I pushed it through the hole and twisted* allowing the wedge shape of the scissor blade to widen the hole as I twisted until it was wide enough for the sensor to fit through.

Repeat for the other sensor hole.


Cut a hole for the button

Placing the button on the exterior of the box is crucial for easy access to setting your desired distance. A button with threads and a nut are perfect for this. 


Cut a hole for the power plug

Depending on how you plan to power the device will affect what kind of hole you make, I used a 5.5x2.1mm DC power jack to connect it to  a 9V power adapter.

Step 2: Wiring the Circuit

To make this easier to understand lets break the circuit into 3 parts. The LED, the Button and the Ping sensor.
Note, in the photos, I have wired my rails backwards. This is to accomodate the 5V regulator(optional). I realize now that I could have turned it around, used the other rails to not have it backwards but owell.

UPDATE: Adjustment have been made to the circuit diagram. (not reflected in photos) The LED has been routed to pins 0 & 1 in order to use PWM for brightness control. This is important in getting a nice yellow color. 

The LED
Connect the common cathode (longest pin) of the LED to a 5V rail on your breadboard. The other 3 pins, require a resistor between them and the connection to the arduino I/O pin. Here is a helpful website to find the kind of resistor you will need http://led.linear1.org/1led.wiz. This is a pull up style circuit so the code will be inverted, high will be off and low will be on. You may use a resistor on the common cathode to not have this situation. I did this because I did not realize the ATtiny85 had pwm pins and I wanted to dim the green LED some by adding 2 resistors. When using red and green to make yellow, green was just too dominant over red an it looked yellow-green. A future fix is to move the green connection to a pwm pin and dim the green via pwm. Here's a link to a more complete tutorial on LED circuits http://www.ladyada.net/learn/arduino/lesson3.html

The Button
Connect 5V to a lead of the button. Connect a 10k ohm resistor between ground and the other lead on the button. Connect a jumper from the arduino to the ground lead of the button. While a common breadboard button will work okay, but if you plan to move it into a project box, it may be a hassle to reach the button. We want to have easy access to the button so that you won't have to move the sensor to press the button, that would make setting your distance quite difficult. I used a threaded momentary button from radio shack. Im not sure if it needs the resistor like the smaller breadboard button but I left it in and it works fine.  Here's a link to a more complete tutorial on buttons http://arduino.cc/en/tutorial/button

The Ping Sensor
Simply connect 5V and GND to your corresponding rails and the echo and trigger pins to the arduino.
Here is a link to the NewPing library which describes all the functions of sensor. http://playground.arduino.cc/Code/NewPing.

Congratulations, your circuit is finished! 

Step 3: Upload the Code to the Arduino

First off, dowload and install the latest Arduino IDE (1.0.5) here's a link to the download page http://arduino.cc/en/Main/Software.
We now what to install the NewPing library, Here is a link on instructions to download and install the NewPing library http://playground.arduino.cc/Code/NewPing.

If you plan on using the ATtiny then part of the file NewPing.cpp must be edited. There are two big section of the code devoted to timers, comment all of this out. NewPing.h can be left alone.

It is important to use this library and NOT to perform the distance measurement manually. The reason is because when the ping sensor cannot return a distance, it will delay for a full second instead of multiple times per second like it should. This is a problem when pulling the car in and there is no response from the unit for a brief period. In that time a car can move several feet and make the device useless. This library fixes that issue thus maintaing responsiveness. 


The pin arrangement will be however you chose to connect up your arduino board, so be sure to adjust this code to work with your circuit. Remember, if you want to use pwm to get your color brightness just right be sure to use pins with a ~ symbol for your LED or refer to the ATtiny85 pinout diagram for pwm pins. I did not include any use of the blue pin, simply because the ATtiny85 does not have enough pins without reprograming the reset pin to be I/O. I didn't bother to do so.

You may want to add some new colors or change it up to suit your mood. If you need a more precise indication, you may want to lower the range value to 1 or 2 (keep in mind that its +/-, so a 2 for the range variable will give a 4 inch range) or bring it up higher if you have room to spare. You may also want to edit the distances at which each color of LED will change. I found 120 and 50 inches to be just right. 


UPDATE: LED has been moved to pins 0 & 1. The yellow() method has been updated to include PWM. You may have to find which values work best with your LED. 


Code

#include <NewPing.h>            //include the NewPing library

//I/O pins

int rLED = 0;
int gLED = 1; 
int buttonPin = 2;
int echo = 3;
int trigger = 4;



//values to keep track of
int distance = 0;
int set = 0;
int upper = 0;             
int lower = 0;
int range = 3;                                   //range is +/- so it is double the value in inches
int count = 0;
boolean lastButton = LOW;          //keep track of button status
boolean currentButton = LOW;
int previous = 0;                              //keep track of distances to identify when car is parked
int current = 0;

NewPing sonar(0, 1, 500);       //constructor for NewPing sonar(triggerPin, echoPin, max_CM)

void setup()
{
pinMode(gLED, OUTPUT);
pinMode(rLED, OUTPUT);
pinMode(buttonPin, INPUT);
}
void loop()
{
  distance = sonar.ping_in();                  //detect distance in inches
  if(distance == 0) distance = 500;          //if no distance is read, set at max distance
  current = distance;                                //to check how long car has been parked in order to enter power save

  delay(100);                                             //Slow program down - save battery?

  currentButton = debounce(lastButton);            //reads button status and performs debounce, fixes unexpected button behavior

  if(lastButton == LOW && currentButton == HIGH)          //when button pushed, set desired distance for parking
  {
    set = distance;                                //new variable for distance measured
    flashGreen();                                  //flicker green LED 3 times
    flashGreen();
    flashGreen();
  }

  lastButton = currentButton;            //reset button status

  upper = set + range;                        //  +/- inch tolerance range 
  lower = set - range; 

  if(distance <= upper && distance >= lower)            //within set area, stop!
  {
    //distance fluctuates some resulting in false movement detection
    if(current == previous || current == previous + 1 || current == previous - 1 )
    {
      count++;                           //increase count if car has not moved
    }
    else
    {
      count = 0;                          //resent count if there is a significat change in distance
    }

    // if distance doest change for 250 cycles (30 sec) turn off LED -> power saving mode
    if(count >= 250)
    {
      off();
      count = 250;                        //dont increment forever
    }
    else
    {
      red();                                   // within range, stop. red LED on
    }

  }
  if(distance > upper)
  { 
    count = 0;                            //if car moves slow enough, it may never reset the count in above code, we reset again, just in case

    if(distance >= set+120)              //sensor becomes innacurate at distances much further than 120 inches
    {                                                   //no car in garage turn LED off 
      off();
    }                                              
    if(distance < set+120 && distance > set+50)                  //car is detected
    {                                                                                           //if distance is less than set + 120 inches and greater than set +50 inches
      green();
    }
    if(distance <= set+50 && distance > upper)                  //wihtin 50 inches of set distance, slow down
    { 
      yellow();
    } 
  }
  if(distance < lower)                                                           //car is too close, you must back up
  {
    count = 0;                                                                         //same situation for if car moves very slowly
    flashRed();
  }

  previous = distance;                                                        //update distances
}                                                                                            //end of loop

//debounce method to correct for voltage spikes that cause unexpected behavior
boolean debounce(boolean last)
{
  boolean current = digitalRead(buttonPin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(buttonPin);
  }
  return current;
}

//color methods;
void green()
{
   digitalWrite(rLED, HIGH);                 //because of pull-up resistor circuit, code is inverted
   digitalWrite(gLED, LOW); 
}
void red()
{
  digitalWrite(gLED, HIGH);   
  digitalWrite(rLED, LOW);
}
void yellow()
{
  digitalWrite(rLED, 0); 
  digitalWrite(gLED, 100);
}
void flashRed()
{
  digitalWrite(gLED, HIGH);                     //flash red LED
  digitalWrite(rLED, LOW);
  delay(100);
  digitalWrite(rLED, HIGH);
  delay(100);
}
void flashGreen()
{
  digitalWrite(rLED, HIGH);
  digitalWrite(gLED, LOW);                  //flicker green LED when button pushed
  delay(50);
  digitalWrite(gLED,HIGH);
  delay(50);
}
void off()
{
  digitalWrite(gLED, HIGH);                  //turn off the LED
  digitalWrite(rLED, HIGH);
}


End of Code



Copy and Paste the code into the Arduino IDE and hit upload.

Again, be sure to edit the pin numbers to accomodate your circuit and make whatever changes you wish. 




Step 4: Uploading the Software to an ATtiny85

In order to make this project more permanent, cheaper, smaller and all around more legit. I will show you the steps required to shrink all of this down to a chip the size of your thumbnail.

First we need to install ATtiny support to Arduino IDE. 
Locate your Arduino sketchbook folder (you can find its location in the preferences dialog in the Arduino software)
Create a new sub-folder called “hardware” in the sketchbook folder, if it doesn’t exist already.
Download attiny-master.zip folder from below and copy the “attiny” folder (not the attiny-master folder) from the unzipped ATtiny master.zip to the “hardware” folder. You should end up with folder structure like Documents > Arduino > hardware > attiny
Restart the Arduino development environment.
You should see ATtiny entries in the Tools > Board menu.
A great tutorial to this can be found here http://hlt.media.mit.edu/?p=1695


Uploading software to ATtiny85
The Arduino board can be used as a programmer for the ATtiny chips. To do so plug the ATtiny chip into a breadboard and wire a breadboard in the following way.
1. With jumpers, connect VCC to 5V and GND to GND. Connect pin 10 to Reset, 11 to pin 0, 12 to pin 1, 13 to pin 2.
2. Open the program ArduinoISP from File -> Examples -> ArduinoISP. Upload it to the board.
3. Connect a 10uf capacitor between Reset and GND of the Arduino board.
4. Now open a blank program, only void() and setup() methods are present and are blank. (Im not sure about this step but I tried doing it with code in it and it broke the ATtiny) 
5. Select from Tools -> Board -> ATtiny85 (internal 8MHz clock)  and select from Tools -> Programmer -> Arduino as ISP. Upload the blank program. (you should see 2 avrdude errors. Not to worry, this is normal)
6. Select from Tools -> burn bootloader. This changes clock speed from its default 1MHz to 8MHz.
7. Now go back to the parking sensor code and upload it. Be sure to have the correct board and programmer selected. (you should see the same two avrdude errors)

If everything went smoothly, carefully pull the ATtiny out and transplant it back into your breadboard circuit.

Next, we need to modify the circuit. Because we are removing the Arduino board from the equation, we are also losing its regulated power supply, so we need to make our own. This will require 2x 10uf electrolytic capacitor and a 5V regulator.


The Regulator
Connect the incoming positive voltage to the input lead and the negative to negative lead of 10 uf capacitor, connect these two leads to their respective input and negative pin on the regulator. Arrange this on the bread board so that a the negative and output pins are plugged into a vertical rail. Add another 10 uf capacitor after the 5V regulator on the vertical rails, to their respective lead, of course. The capacitors smooth out the voltage. I am using a 9V DC power adapter, this is low enough to not require a heat-sink on the regulator but if you go higher, then you might need to add one. Now that the circuit is modified, let's get it on* the ATtiny85. Here is a helpful instructable that I used myself https://www.instructables.com/id/How-to-make-your-own-Arduino-board/step3/Adding-the-5v-regulator/.

All that's left is to connect up a power source!


Future Changes
Switch the 5V regulator to have the correct corresponding +/- rails.
Use the calculated resistors for the LED
Use PWM to adjust brightness to get yellow just right
Add a piezo element for an audible indication
Use an RGB LED strip instead of just one LED.
Construct a bamboo housing.


Pocket Sized Electronics

Participated in the
Pocket Sized Electronics