Using an Ultrasonic Distance Sensor to illuminate NeoPixels

Tutorial Type:

Tutorial Difficulty

Parts Required

Part Description

Amazon.com

Arduino Uno Arduino Uno R3 with Atmega 328P
HC-SR04 Ultrasonic Sensor HC-SR04 Ultrasonic Ranging Sensor
Jumper Wires 60 Piece Jumper Wire Kit
Bread Board Tektrum 2200 Tie-Point Breadboard
1x 5V 2A Power Source USTEK 5V 2A Wall Adapter
1000 µF, 25V Capacitor 50pc 1000uF 25V Electrolytic Capacitors
Female DC Power adapter
10pc Female Power Jack Adapter
NeoPixel Strip Adafruit 1m 60-LED NeoPixel Strip
   

Tools Required

Tool Description

Download Link

Arduino  IDE Download from Arduino.cc
FastLED Arduino Library Download from Fastled.io
   

 

 

 

 

 

Download the code for this tutorial from Github: 

Illuminating NeoPixel LED's using an Arduino and a HC-SR04 Ultrasonic (Ping) Distance Sensor.

This is a really quick tutorial that will show you how to illuminate a sign when someone walks past it. I decided to write this simple tutorial after I hear one of my favorite makers, Jimmy Diresta, mention on a podcast that he has had clients ask him how to do something similar. Jimmy said that he knew that you could use an Arduino to do this, but was unsure of just how to pull it off. 

For thoses of you who don’t know who Jimmy Diresta is, let me clue you in a little. Jimmy is a New York based designer, artist, and maker extraordinaire who deals mainly in the woodworking, and metalworking mediums. Jimmy has been the star of a few television shows, and currently runs a very popular Youtube channel where he can be found making anything from treasure chest, to extremely high-quality serving bars for major whiskey manufacturers.  

HC-SR04 + Arduino + NeoPixels = an awesome Distance Triggered Illuminated DIRESTA Sign

Jimmy openly admits to not being very savvy with things like the Arduino, but says that he wants to dive into it one day soon. So I thought I could give him a push in the right direction, and challenge him to follow this tutorial and produce a sign that lights up when someone walks within 2 feet of its trigger. As you can see from the image above, I have 3D printed a small "box sign" with Jimmy's signature DIRESTA stenciled logo. The two holes on the front are for the HC-SR04 sensor to slip into. 

Wiring Up The Circuit:

Schematic for wiring up an HC-SR04 and NeoPixels to an Arduino.

(Click to enlarge the image)

Using the image above as a visual guide, wire up the circuit as listed below.  

  1. HC-SR04 VCC Pin to Breadboard VCC Rail 1
  2. HC-SR04 GND Pin to Breadboard GND Rail 1
  3. HC-SR04 Trigger Pin to Arduino Digital Pin 8
  4. HC-SR04 Echo Pin to Arduino Digital Pin 7
  5. NeoPixel Data In Pin to Arduino Digital Pin 6
  6. NeoPixel 5V Pin to Breadboard VCC Rail 2
  7. NeoPixel GND Pin to Breadboard GND Rail 2
  8. 1000uF Capacitor + Pin to Breadboard VCC Rail 2
  9. 1000uF Capacitor - Pin to Breadboard GND Rail 2
  10. Breadboard GND Rail 1 to Breadboard GND Rail 2
  11. Arduino VCC Pin to Breadboard VCC Rail 1
  12. Arduino GND Pin to Breadboard GND Rail 1
  13. Power Jack + Pin to Breadboard VCC Rail 2
  14. Power Jack - Pin to Breadboard GND Rail 2

Theory

With all of the components connected, and checked twice lets take a moment and talk about the theory of how these components work together to achieve our goal of having some LED’s illuminate when someone walks past them. 

We are using an HC-SR04 Ultrasonic Distance sensor aka a Ping Sensor. This sensor basically works like depth finders on boats, and radar works. The HC-SR04 sensor detects objects by emitting a very short ultrasonic burst and then "listens" for the echo. 

Using a host microcontroller such as an Arduino, the sensor emits a short 40 kHz (ultrasonic) burst. This burst travels through the air at the speed of sound which is 340 m/s or 29 microseconds per centimeter. If it hits an object, it will bounce back to the sensor. The sensor provides an output pulse to the host that will terminate when the echo is detected, hence the width of this pulse corresponds to the distance to the target. 

Since the ping travels out and back, so to find the distance of the object we take the distance the ping traveled and divide it by 2. In the code we using the following formula to determine the distance is from our sensor. (Microseconds / 29 / 2). The Arduino will take this information and by using “If” and “else” statements, will tell the NeoPixels whether to illuminate or not. 

Diagram showing how Ultrasonic (Ping) Sensors work. Image Courtesy of Digikey.

Using the FastLED Arduino Library and a subroutine, we can have the NeoPixels perform any animation you would like. At the bottom of this post, I have included links to a few extra versions of the code which will show you how to make the NeoPixels strobe, change their hue based on distance, and even perform an animation. 

A quick note on the NeoPixel strip itself. In my photos and video, you will see that I am only running a short strip with 7 pixels. Most Arduino’s that are Uno reference designs can dish out enough current on their 5V rail to power a strip of 30 NeoPixels. This does get a little dangerous when the pixels go into a white mode though, and you could damage your Arduino, the NeoPixel Strip, or both. 

Using an HC-SR04 Ultrasonic (Ping) sensor to turn NeoPixels on and off via an Arduino.

To avoid disaster, it is best practice to power the NeoPixels with a separate 5V 2A power source. Additionally, you should add a 1000uF 25V capacitor to this separate power rail. I rarely followed this methodology in my early experiences with NeoPixels, and as a result I killed about $50 worth of hardware. You don’t have to take my word for it though, as Adafruit suggest this in their NeoPixel Uberguide.  Since I am only using 7 pixels, you will sometimes see me not using an external power source, but I always use the capacitor. So in theory, I will be able to place the HC-SR04 Ultrasonic Sensor in the sign with its "horns" sitting flush with the face of the sign and when someone walks within 3 feet of the sign, it will light up. 

Ok with all of the boring stuff out of the way, lets get the code setup and uploaded to the Arduino. 

The Code:

Im going to break the code down in pieces here so that it is easier for some to understand. Lets get started with the Variable Declaration Section. This is where we tell the Arduino IDE to include the libraries we will be using as well as declaring the variables we will be using in our program.  This code is only read once during the upload process. 

First we need to tell the Arduino IDE to include any Libraries we might need. In this instance we will be including the FastLED Library. 

#include <FastLED.h>

Now we need to set up the variables for the HC-SR04 sensor. We need to tell the Arduino that the Trigger Pin is connected to Digital Pin 8 and the Echo Pin is connected to Digital Pin 7.  

const int trigPin = 8;
const int echoPin = 7;

Finally we need to set up the variables for the NeoPixels. We need to tell the Arduino how many LEDs are on the strip and that their data line is connected to Digital Pin 6. Lastly we need to define the array of LEDs. 

#define NUM_LEDS 7
#define DATA_PIN 6 
CRGB leds[NUM_LEDS];

The setup section,once when the program begins, follows the variable declaration section. Statements that lay the foundation for actions that happen later on in the program are put in the setup section. This section always begins with void setup() with its contents wrapped in brackets { }. The setup section only runs once and will not run again until the Arduino is reset or power cycled. 

The first thing we need to do in our setup is initialize the serial port, and tell it what baudrate to communicate at.  Then we need to initialize the NeoPixel strip. 

void setup() {
Serial.begin(9600);
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
}

Our final section is the Loop. This section contains code that is ran after the setup and loops over and over until the Arduino is either reset or powered off. Just like the setup section, statements in the loop section are placed between open and closed brackets { }. Additionally certain statements within the loop with also contain sets of brackets { }, and if a bracket is not where it should be, the sketch will not compile. 

To get the loop started we first need to establish variables for the duration of the ping, and its distance results in inches and centimeters. 

 long duration, inches, cm;

Now we need to trigger the sensor with a high pulse of at least 10 microseconds, but first we need to trigger a very short low pulse to ensure our high pulses are clean and crisp.

  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

Now we need to tell the Arduino to listen for the return pulse and read the signal from the sensor: It needs to listen for 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(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);

Now we need to tell the Arduino to convert the time it just read into a distance in both Inches and Centimeters, and then tell it to print the results to the serial console.

  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

Now we need to tell the Arduino what to tell the NeoPixel strip to do based on various distance measurements. To do this we will use “if” and “else if” statements in conjunction with the FastLED library. 

The first part of the code tells the Arduino that if the distance returned by the sensor is less than or equal to twenty inches (inches <= 20), then illuminate (FastLED.show)  the entire (fill_solid) strip (NUM_LEDS) with Blue (CRGB::Blue). 

if (inches <= 20)  {fill_solid( &(leds[0]), NUM_LEDS, CRGB::Blue);
 FastLED.show();
}

The second part of the code handles things in a similar way. Basically if the distance returned is greater than or equal to twenty one inches (inches >= 21)  then do not turn the LEDs on. With the FastLED library, the color black is used to tell the NeoPixels to stay off. 

else if (inches >= 11) {fill_solid( &(leds[0]), NUM_LEDS, CRGB::Black);
 FastLED.show();
  }

The last thing we need to do in our loop is to set a small delay to let everything settle down before we run the loop again. This is done with a delay statement. Don’t forget to close the loop with a close bracket }.

delay(100);
}

While the loop is the last main section of code, we need to write a quick subroutine that will handle the math that converts the microseconds to distance. 

First we need to convert Microsectonds to Inches. According to Parallax's (OEM of the original PING sensors) 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: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf for more information. 

long microsecondsToInches(long microseconds)
{
  return microseconds / 74 / 2;
}

Now we need to convert Microseconds to Centimeters. 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. 

long microsecondsToCentimeters(long microseconds)
{
return microseconds / 29 / 2;
}

Now that we know what each section of the code does, lets put it all together and upload it straight to our Arduino. 

// Turning NeoPixels on and off using a HC-SRO4 Ping Sensor
/*
This sketch reads a HC-SR04 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 Arduino then takes this information and illuminates a strip
NeoPixel's based on the distance of the object from the sensor.

This code was developed partially from Ping))) code found in 
the public domainwritten by David A. Mellis, and adapted to the 
HC-SRO4 by Tautvidas Sipavicius, while other portions were 
written by Charles Gantt and Curtis Gauger from 
http://www.themakersworkbench.com.
*/

//Tell the Arduino IDE to include the FastLED library
#include <FastLED.h>

//Setup the variables for the HC-SR04
const int trigPin = 8;
const int echoPin = 7;

//Setup the variables for the NeoPixel Strip

// How many leds in your strip?
#define NUM_LEDS 7 

// What pin is the NeoPixel's data line connected to?
#define DATA_PIN 6 

// Define the array of leds
CRGB leds[NUM_LEDS];

void setup()
// initialize serial communication:
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
}

void loop()
{
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, inches, cm;

  // The sensor is triggered by a HIGH pulse of 
  //10 or more microseconds.
  // Give a short LOW pulse beforehand to 
  //ensure a clean HIGH pulse:
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Read the signal from the sensor: 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(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);

  // convert the time into a distance
  inches = microsecondsToInches(duration);
  cm = microsecondsToCentimeters(duration);

  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

if (inches <= 20)  {fill_solid( &(leds[0]), NUM_LEDS, CRGB::Blue);
 FastLED.show();
}

else if (inches >= 21) {fill_solid( &(leds[0]), NUM_LEDS, CRGB::Black);
 FastLED.show();
}
delay(100);
}
 
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: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  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;
}

Wrapping It Up:

With the code uploaded, you should be able to move your hand close to and far away from the sensor and it will turn the NeoPixels on and off. It should be noted that the sensor needs a very clear line of sight into open space for this to work. If you have the corner of a desk, or even the surface of the desk too close to the sensor, then it will falsely trigger. I like to set the sensor so that it is slightly hanging over the edge of my desk. 

You can take this code further and modify it to switch on a relay, motor driver, or even your TV or computer. The heart and soul of this function is the if and else statements. Once you understand them, there is almost nothing you can not do with your Arduino. As I mentioned above, you can even write more subroutines that will animate the NeoPixels to fade, change hue, strobe and almost anything else you can think of. Below are links to my Github where I have 3 more examples of how subroutines can change the effects of the NeoPixels. 

Support The Makers Workbench on patreon and help us keep the dream alive!

If you would like more Ping sensor tutorials such as the aforementioned relay triggering, just let me know in the comments. Additionally, if you would like to see more tutorials like this, as well as the more of the other types of articles we post here at The Makers Workbench, head over to our Patreon page and consider donating monthly to help us keep the lights on. Every donation counts, and with your support, we can continue to post a couple of tutorials each week. 

Also, please take a moment to head over to Jimmy DiResta’s YouTube Channel, Instagram, and check out his Podcast, Making It. Jimmy Diresta, Bob Clagett and David Picciuto are living my dream, and they never cease to inspire me to keep on producing content that is fun, educational, and interesting. You can also support them on Patreon as well. 

That wraps up this tutorial. As always, if you have any issues, questions, or thoughts, please leave them in a comment below. We utilize Disqus comments as it is the easiest way for you to signup and organize your comments across tens of thousands of websites across the internet. Thanks for reading, and thanks for keeping the Maker Revolution alive! 

Other Articles You Might Like

Review: Lulzbot AO-100 3D Printer part 1Lulzbot AO-100 / AO-101 reviewed

Tutorial: DIY Telescope to PC CableDIY Telescope to PC Cable

Project: LED Strip Bench LightingDIY RGB LED Strip Bench lighting

Review: ISO-TIP Portable  Soldering KitISO-Tip Portable Soldering Kit Review

Article: Arduino Due Overview

Project: 3D Printed Balloon Powered CarPrint a Balloon powered Jet Car with your 3D printer