Monday, December 30, 2013

The Micro And The Garrage

So there I was in Radio Shack minding my own business
Me. Shortly Before Chrismas.
(buying batteries for my car remote) a few days before Christmas, stuck in a line of people confusedly making their way through innumerable forms while signing for phone contracts that my bored co-worker whom I had dragged in after lunch noticed an Arduino display in the back of the store. 

Shortly I was checking out an Arduino Micro, a sonar range finder, a bread board and a bunch of miscellaneous tools and things.

Arduino Micro and Co.

A quick Google search later I had the Arduino SDK installed on my MacBook.  And I was ready to play.

The first project was supposed to be a simple garage parking sensor.  You put it on the wall of your garage and then as you pull in, it indicates how close you are getting to the wall.  It was inspired by a couple of close encounters between the rear gate of my wife's SUV and the closing mechanism of the garage in my old house.  
Essentially if you wanted to park indoors and unload your groceries or whatever you had stashed in the back of the car you had to make sure you pulled in all the way. describes a rather elegant option.

This problem has been solved in the past with technologies as simple as well placed tennis balls and strings.  It certainly does not require micro controllers and LEDs and ultra sonic range finders.  But we are in the 21st century here.  So we have to find something to do with our cool gadgets.  And this project was simple enough that I thought I should be able to tackle it on a quite pre christmas morning.  Luckily I was right.

So here is a quick video I made demonstrating the functionality of the completed sensor in my home office.  Cars not included.

Putting things together was pretty simple.  Especailly because the example code for the range sensor got me 90% there.  The sensor is ridiculously clever.  After giving it a 2ms pulse it originates a sonar pulse and measures when the return happens.  Then it gives back a pulse of the exact duration of the sonic round trip time.  No protocols.  No special bits.  No nothing.  (don't get too excited.   Things got more difficult as my ambition grew).    Here is what final project looked like.

I had even decided to use two indicators to show how close the car is to the wall.  One was a normal LED that started blinking ever more rapidly as you got closer and finally went solid when you were at 20cm.  The other was a color LED that chagned color from blue (system on) to green (I see you) to yellow, amber and finally red.

So while I (again - professing my utter inexperience with all things electronic) can't upload a drawing, I will upload the source code.  I hope the picture will do.

(quick note - in my short experience with things Arduino, I can attest to a fairly high number of bad parts.   The range sensor for example, I originally got did not manage to give me more than 2 good readings out of 20.  A replacement worked great.  A co-worker also bought the Mega board shortly after I got mine, and it failed to allow him to upload any code while mine worked really well with his setup.  So while I am generally of the persuasion that external factors ( libraries, kernels, cosmic rays ) are the last things to blame while diagnosing a problem have to concede that in this case in my experience the worst thing to do is to loose confidence because of a bad component.  Get two.  Return the second one if it turns out you did not need it).

Final note.  I will figure out how to get source code to look better.  Soon.

 /* Ping))) Sensor  
   This sketch reads a PING))) ultrasonic rangefinder and returns the  
   distance to the closest object in range. To do this, it sends a pulse  
   to the sensor to initiate a reading, then listens for a pulse   
   to return. The length of the returning pulse is proportional to   
   the distance of the object from the sensor.  
   The circuit:  
      * +V connection of the PING))) attached to +5V  
      * GND connection of the PING))) attached to ground  
      * SIG connection of the PING))) attached to digital pin 7  
   created 3 Nov 2008  
   by David A. Mellis  
   modified 30 Aug 2011  
   by Tom Igoe  
   This example code is in the public domain.  
 #define RED 1  
 #define BLUE 2  
 #define GREEN 3  
 // this constant won't change. It's the pin number  
 // of the sensor's output:  
 const int pingPin = 7;  
 // The number of the led pin  
 const int ledPin = 13;  
 const int redPin = 12;  
 const int bluePin = 11;  
 const int greenPin = 10;  
 // This is the blink timer  
 long lastMillis = 0;  
 void setup() {  
  // initialize serial communication:  
  pinMode( ledPin, OUTPUT );  
  digitalWrite( ledPin, LOW );  
  pinMode( redPin, OUTPUT );  
  digitalWrite( redPin, LOW );  
  pinMode( bluePin, OUTPUT );  
  digitalWrite( bluePin, LOW );  
  pinMode( greenPin, OUTPUT );  
  digitalWrite( greenPin, LOW );  
  lastMillis = millis();  
 void loop()  
  // establish variables for duration of the ping,   
  // and the distance result in inches and centimeters:  
  long duration, inches, cm;  
  int val;  
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.  
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:  
  pinMode(pingPin, OUTPUT);  
  digitalWrite(pingPin, LOW);  
  digitalWrite(pingPin, HIGH);  
  digitalWrite(pingPin, LOW);  
  // 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);  
  // convert the time into a distance  
  inches = microsecondsToInches(duration);  
  cm = microsecondsToCentimeters(duration);  
  Serial.print("Duration: ");  
  Serial.print(" us in: ");  
  Serial.print("  cm: ");  
  if ( cm > 200 ) {  
   //At 200 cm we don't bother  
   digitalWrite( ledPin, LOW );  
   lastMillis = millis();  
   // Set the light to Blue to signify the system is on  
   setColor( 0, 0, 255 );  
  } else if( cm <= 20 ) {  
   //At 20 cm - we are constant on  
   digitalWrite( ledPin, HIGH );  
   lastMillis = millis();  
   // Set the light to Red to show we are in the danger zone  
   setColor( 255, 0, 0 );  
  } else if( cm <= 200 && cm > 100 ) {  
   // At 200 - 100 cm we blink two times per second  
   if( millis() - lastMillis > 500 ) {  
    val = digitalRead( ledPin );  
    // blink  
    digitalWrite( ledPin, val ? LOW : HIGH );  
    lastMillis = millis();   
   // Set the light to green. We see you  
   setColor( 0, 255, 0 );  
  } else if( cm <= 100 && cm > 50 ) {  
   // At 100 - 50 cm we blink four times per second  
   if( millis() - lastMillis > 250 ) {  
    val = digitalRead( ledPin );  
    // blink  
    digitalWrite( ledPin, val ? LOW : HIGH );  
    lastMillis = millis();   
   // Set the light to Yellow. Cover that break pedal.  
   setColor( 255, 255, 0 );  
  } else if( cm <= 50 ) {  
   // At 50 to 20 cm we blink five times per second  
   if( millis() - lastMillis > 100 ) {  
    val = digitalRead( ledPin );  
    // blink  
    digitalWrite( ledPin, val ? LOW : HIGH );  
    lastMillis = millis();  
   // Set the color to Organgish. Start breaking  
   setColor( 255, 128, 0 );  
  delay( 50 );   
 long microsecondsToInches(long microseconds) {  
  // According to Parallax's datasheet for the PING))), there are  
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per  
  // second). This gives the distance travelled by the ping, outbound  
  // and return, so we divide by 2 to get the distance of the obstacle.  
  // See:  
  return microseconds / 74 / 2;  
 long microsecondsToCentimeters(long microseconds) {  
  // The speed of sound is 340 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.  
  return microseconds / 29 / 2;  
 void setColor(int red, int green, int blue) {  
  analogWrite(redPin, 255-red);  
  analogWrite(greenPin, 255-green);  
  analogWrite(bluePin, 255-blue);