- The walls, and
- the car.
- I don’t want to have wires running all over the garage.
- I don’t want to use batteries
- I want to use minimal sensors
- I want to be simply informed when I’m in the right spot within a certain tunable range
- It should be cheap to build (well mostly)
- The sensor is a single distance sensor at the front of the parking area. LED lights can be close by.
- My outlets are at the front of the parking area, so I can use a power supply transformer.
- I found this: Sharp range sensor, so a single sensor could do it.
- 3 LEDs would do… too close (go back), just right (stop), too far (keep going).
- 3 LEDs, 1 Sharp range sensor, 1 220 ohm resistor, 1 5v transformer, 1 arduino (uno) => <$50
- yellow, too close, pin 2
- red, stop, pin 6
- green, keep going, pin 10
 The functioning system in a video:
The functioning system in a video:
/*
   Parking Assistant Using Range Sensor
   Created by Mark Slemko - October 5, 2013
   Parts taken from: http://arduino.cc/en/Tutorial/AnalogInput
   refined 2015-10-17
     - adjusted to accomodate shorter distance
   refined 2021-01-31
     - adjusted to clarify code, clean up, and to work on arduino pro mini
*/
#include <math.h>
#include <SoftwareSerial.h>
SoftwareSerial Serial7Segment(8, 9); //RX pin, TX pin
int pingPin = 2;    // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED
int colorR = 7;
int colorGnd = 6;
int colorG = 4;
int colorB = 5;
int settleTime = 5000; // when same value is reached for this time, stop checking as often
int recheckTime = 0;
int timer = 0;
double settleDistance = 0.0;
double variance = 2.0;
#define STOP_DISTANCE     70.0
#define STOP_BRACKET      6.0
#define MAX_RECHECK_TIME  2000
#define NORMAL_RECHECK_TIME 100
#define SENSOR_ACTIVE     250.0
#define SENSOR_TOO_CLOSE  20.0
#define LED_ACTIVE_PING_INDICATOR_TIME 10
void setColor( int r, int g, int b) {
  digitalWrite(colorGnd, LOW);
  digitalWrite(colorR, r);
  digitalWrite(colorG, g);
  digitalWrite(colorB, b);
}
void setup() {
  // declare the ledPin as an OUTPUT:
  pinMode(ledPin, OUTPUT);  
  
  pinMode(colorR, OUTPUT);
  pinMode(colorGnd, OUTPUT);
  pinMode(colorG, OUTPUT);
  pinMode(colorB, OUTPUT);
  
  setColor(LOW, LOW, LOW);
  
  Serial.begin(9600);
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
}
long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 343 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  double cm = (double)microseconds / 58.32;  // 29.16 * 2 us
  return (long)cm;
}
long sonicPing() {
  long duration, cm;
  
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(20);
  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH) - 350;
  Serial.print(duration);
  Serial.print("us ");
  cm = microsecondsToCentimeters(duration);
  return cm;
}
void loop() {
  // read the value from the sensor:
  double distance = sonicPing();
  Serial.print(distance);
  Serial.print("cm ");
  
  // display the distance
  char tempString[10]; //Used for sprintf
  sprintf(tempString, "%4d", (int)distance); //Convert deciSecond into a string that is right adjusted
  Serial7Segment.print(tempString);
  // give visual indication that a ping occurs
  digitalWrite(ledPin, HIGH); // turn the ledPin on  
  delay(LED_ACTIVE_PING_INDICATOR_TIME); // stop the program for a few milliseconds to show a ping just occurred
  digitalWrite(ledPin, LOW); // turn the ledPin off:        
  Serial.print(" wait ");
  bool settledTimeReached = checkSettleTimeReached(distance);
  timer += NORMAL_RECHECK_TIME; // increment timer
  // check if settle time reached to turn off LED
  if (settledTimeReached) {
    // turn off LED
    setColor( LOW, LOW, LOW);
    
    recheckTime = timer;
    if (recheckTime < settleTime) {
      if (recheckTime > MAX_RECHECK_TIME) {
        recheckTime = MAX_RECHECK_TIME;
      }
    } else {
      timer = recheckTime = settleTime;
    }
    
    
    // turn off RGBLED
    setColor( LOW, LOW, LOW);
  } else {
    recheckTime = NORMAL_RECHECK_TIME;
    setColor( LOW, LOW, LOW);
    if (shouldShowStopLED(distance)) {
      if (distance < (STOP_DISTANCE - STOP_BRACKET)) {
        // too close - blue on
        setColor( HIGH, HIGH, HIGH);
        Serial.print(" too close ");
      } else if (distance > (STOP_DISTANCE + STOP_BRACKET)) {
        // too far - green on
        setColor( LOW, HIGH, LOW);
        Serial.print(" too far ");
      } else  {
        // perfect - red on
        setColor( HIGH, LOW, LOW);
        Serial.print(" stop ");
      }
    }
  }
  
  Serial.print(" delay recheck ");
  Serial.print(timer);
  delay(recheckTime); // wait for next check
  
  Serial.println("");
}
boolean shouldShowStopLED(double distance) {
   //abs(distance - STOP_DISTANCE) < (variance * (1.0 + distance / 50.0)) + (STOP_BRACKET * 2)) {
  if ( abs(distance) < SENSOR_ACTIVE && abs(distance) > SENSOR_TOO_CLOSE) {
    return true;
  }
  return false;
}
boolean checkSettleTimeReached(double distance) {
  boolean delta = abs(settleDistance - distance) > (variance * (1.0 +  distance / 100.0));
  
  // if the delta is too big, reset the timer
  if (delta) {
    timer = 0;
  }
  
  if (timer < settleTime) {
    settleDistance = distance;
    return false;
  } else {
    return true;
  }
}
Notes:
- The power supplied via the USB cable connected to a computer changes the result of the output coming from the sensor.
- The formula for determining the distance is fairly accurate using the USB power, however, the values are 'stretched' using the power supply through the 5v transformer.
- The LEDs suck quite a bit of power, and without the current limiting resistor, the LEDs draw more than the power supply can provide and keep the arduino powered
- The LEDs when they turn on changes the power supply's voltage/current levels affecting the measurement of distance
- A 5v transformer is not enough power for the arduino, and need to use a bigger one. A 12v one is used and restores the distance measurements to be far more accurate and stablizes the circuit.
- The sensor reading is quite variable as the distance grows, and I'm not sure how to reduce the variability. Is it related to the power supply ripple? Or it's own circuit power draw?
I got an Arduino Pro Mini, which is sufficient for this purpose (and quite a bit cheaper), to test the idea that the issues with the distance variability is related to loose wiring or power supply ripple. I've discovered a couple of things during my minor update:
- Soldering the wiring did improve the stability a little.
- The measurements using the IR Distance Sensor variability was minimal in my work area.
- Aiming the IR Distance Sensor at the headlights produced horrible distance measurements
- By chance I aimed the IR Distance Sensor at the license plate with similarly horrible distance measurements. So I re-aimed the Sensor at the hood as before, which improved things immensely
- I washed my car and to my surprise, the IR Distance Sensor produced quite variable distance measurements.
- When the sun is in direct line of the IR Distance Sensor, it cannot get a proper reading at all. Much like the sun shining in your eyes... hopelessly unable to 'see'.