Arduino Project – LED Skull 4: Add HC-SR04 Ultrasonic Module

Oct 27, 2015

 

The next step in creating a spookier skull was to add an HC-SR04 ultrasonic module that would fire the LEDs based on proximity to a viewer.

 

The existing code works pretty well – the LED eyes come on, wink, and fade back out. The only shortcoming is that it is not at all interactive – they just keep following the same pattern on a loop. It would be more realistic, and spookier, if the LED routine somehow interacted with the viewer.

This can be addressed with an ultrasonic proximity sensor that detects the distance to a viewer, and responds based on that distance. In this case the LED eyes would come on when someone came within distance, and fade out as they moved away.

 

Wiring

We chose the HC-SR04 Ultrasonic Module, purchased on Amazon from Virtuabotix (about $6). It was connected to the Arduino Uno board like this – close to but not exactly the setup in the Virtuabotix documentation because some of the pins they specified were already in use. It is ultrasonic range finder that detects the distance of the closest object in front of the sensor.

 

HC-SR04 Ultrasonic Module

Arduino Uno
Gnd GND
Echo 13
Trig 12
Vcc 5V

 

 

Library

It's important to note that for this sensor to work the Ultrasonic.h library, which is not included in the native Arduino IDE, has to be installed.

First you need to download the library, from here or elsewhere. Then, in the Mac version of the IDE go to the navigation bar and choose:

Sketch > Include Library > Add .ZIP Library

...then locate the library that you downloaded.

 

 

Code

As a starting point we looked to this HC-SR04 demo project and melded it with the existing code so it looked like this. The changes are described below.

 

// BRIGHTNESS
// minimum brightness level for the led
int brightness_minimum = 1;
// maximum brightness level for the led
int brightness_maximum = 75;
 
// PAUSES
// pause between each increase in brightness
int pause_between_increase = 12;
// pause between each decrease in brightness
int pause_between_decrease = 64;
// pause at max brightness, before the wink effect
int pause_at_max_before_wink = 2000;
// pause for the wink effect
int pause_for_wink = 100;
// pause at max brightness, after the wink effect
int pause_at_max_after_wink = 200;
// the pause at min brightness
int pause_at_min_brightness = 600;
 
 
#define trigPin 12
#define echoPin 13
 
const int ledPin1 = 9; // the pin that the LED is attached to
const int ledPin2 = 10; // the pin that the LED is attached to
void setup () {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin1, OUTPUT); // declare pin 9 to be an output:
  pinMode(ledPin2, OUTPUT); // declare pin 10 to be an output:
}
 
 
void loop() {
  long duration, distance;
  digitalWrite(trigPin, LOW); // Added this line
  delayMicroseconds(2); // Added this line
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); // Added this line
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;
 
 
  if (distance < 8) { // within proximity limit; start routine
    analogWrite(ledPin1, 255); // When the Red condition is met, the Green LED should turn off
    analogWrite(ledPin2, 255);
  }
  else { // outside proximity limit; do not start routine
    analogWrite(ledPin1, 1);
    analogWrite(ledPin2, 1);
  }
  delay(5);
}
 
/*
  void loop()
  {
  // ramp up led brightness
  for (int brightness_current=brightness_minimum; brightness_current<=brightness_maximum;brightness_current++) //loop from brightness_minimum to brightness_maximum
  {
  analogWrite(ledPin1, brightness_current); // set the brightness of pin 9:
  analogWrite(ledPin2, brightness_current); // set the brightness of pin 10:
  delay(pause_between_increase);
  }
 
  // hold at max brightness before wink
  delay(pause_at_max_before_wink);
 
  // wink (optional)
  if (pause_for_wink > 0) {
  analogWrite(ledPin1, 0); // turn first led off, creating the wink effect:
  delay(pause_for_wink);
  analogWrite(ledPin1, brightness_maximum); // restore first led to max brightness, ending the wink effect:
  }
 
  // hold at max brightness after wink
  delay(pause_at_max_after_wink);
 
  // ramp down led brightness
  for (int brightness_current=brightness_maximum; brightness_current>=brightness_minimum;brightness_current--) //loop from brightness_maximum down to brightness_minimum
  {
  analogWrite(ledPin1, brightness_current); // set the brightness of pin 9:
  analogWrite(ledPin2, brightness_current); // set the brightness of pin 10:
  delay(pause_between_decrease);
  }
 
  // hold at minimum brightness
  delay(pause_at_min_brightness);
 
  }
*/

 

First we commented out the big section of existing code that deals with ramping the LED brightness up and down. It gets added back in later but for now the focus is on getting the proximity sensor to work, and it's just easier to keep that part lean.

The new lines all relate to setting up the HC-SR04 unit and are quite straightforward.

Another section, also new, is where we use the sensor to detect distance. This works by sending out a burst of ultrasound (the ping) and then listening for the echo that  bounces back off of an object and, most importantly, keeping track of the time between the ping leaving the sensor and the echo coming back. This, the time taken by the sound to travel to the object and back to the sensor can be converted to distance using the speed of sound.

At the end of this section we have a variable (distance) that represents the distance to the object in cm.

The final new section decides what to do based on that distance. In this test we say that if the object is more than 8 cm away the LEDs should stay at low power (1) , and if the object is closer than 8 cm they should switch to full power (255).

This worked so the next step was to uncomment and reintroduce the original LED ramp up/down routine:

 

// BRIGHTNESS
// minimum brightness level for the led
int brightness_minimum = 1;
// maximum brightness level for the led
int brightness_maximum = 75;
 
// PAUSES
// pause between each increase in brightness
int pause_between_increase = 12;
// pause between each decrease in brightness
int pause_between_decrease = 64;
// pause at max brightness, before the wink effect
int pause_at_max_before_wink = 2000;
// pause for the wink effect
int pause_for_wink = 100;
// pause at max brightness, after the wink effect
int pause_at_max_after_wink = 200;
// the pause at min brightness
int pause_at_min_brightness = 600;
 
// DISTANCE
// minimum distance before starting routine (cm)
int min_distance = 30;
 
 
#define trigPin 12
#define echoPin 13
 
const int ledPin1 = 9; // the pin that the LED is attached to
const int ledPin2 = 10; // the pin that the LED is attached to
 
void setup () {
  pinMode(ledPin1, OUTPUT); // declare pin 9 to be an output:
  pinMode(ledPin2, OUTPUT); // declare pin 10 to be an output:
 
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
 
}
 
 
 
void loop() {
 
 
 
  // set leds to minimum brightness
  analogWrite(ledPin1, brightness_minimum);
  analogWrite(ledPin2, brightness_minimum);
 
  long duration, distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;
 
  if (distance < min_distance ) { // within proximity limit; start routine
 
    // ramp up led brightness
    for (int brightness_current = brightness_minimum; brightness_current <= brightness_maximum; brightness_current++) //loop from brightness_minimum to brightness_maximum
    {
      analogWrite(ledPin1, brightness_current); // set the brightness of pin 9:
      analogWrite(ledPin2, brightness_current); // set the brightness of pin 10:
      delay(pause_between_increase);
    }
 
    // hold at max brightness before wink
    delay(pause_at_max_before_wink);
 
    // wink (optional)
    if (pause_for_wink > 0) {
      analogWrite(ledPin1, 0); // turn first led off, creating the wink effect:
      delay(pause_for_wink);
      analogWrite(ledPin1, brightness_maximum); // restore first led to max brightness, ending the wink effect:
    }
 
    // hold at max brightness after wink
    delay(pause_at_max_after_wink);
 
    // ramp down led brightness
    for (int brightness_current = brightness_maximum; brightness_current >= brightness_minimum; brightness_current--) //loop from brightness_maximum down to brightness_minimum
    {
      analogWrite(ledPin1, brightness_current); // set the brightness of pin 9:
      analogWrite(ledPin2, brightness_current); // set the brightness of pin 10:
      delay(pause_between_decrease);
    }
 
    // hold at minimum brightness
    delay(pause_at_min_brightness);
  }
 
  else {
 
    // outside proximity limit; do not start routine
    // we're just going to loop back and test proximity again, but we pause briefly to conserve power
    // there is no need to use power checking proxinity continuously
    delay(100);
 
  }
 
}

 

We've also moved the distance value up to the top, just like the brightness and timing values, to make fine-tuning easier.

This works pretty well. When an object moves within the distance then the LEDs ramp up, wink and fade out.

But after that... not so great. As long as a target stays within the distance the LED routine just keeps repeating – ramp up, wink, fade out.

It would be better if the LEDs stayed at full brightness as long as the object was in range, so we made these changes:

 

// BRIGHTNESS
// minimum brightness level for the led
int brightness_minimum = 1;
// maximum brightness level for the led
int brightness_maximum = 75;
// current brightness level for the led
// changes throughout the script but we set the default here
int brightness_current = brightness_minimum;
 
// PAUSES
// pause between each increase in brightness
int pause_between_increase = 12;
// pause between each decrease in brightness
int pause_between_decrease = 64;
// pause at max brightness, before the wink effect
int pause_at_max_before_wink = 2000;
// pause for the wink effect
int pause_for_wink = 100;
// pause at max brightness, after the wink effect
int pause_at_max_after_wink = 200;
// the pause at min brightness
int pause_at_min_brightness = 600;
 
// DISTANCES
// minimum distance before starting led routine (cm)
int led_distance = 30;
 
 
 
#define trigPin 12
#define echoPin 13
 
const int ledPin1 = 9; // the pin that the LED is attached to
const int ledPin2 = 10; // the pin that the LED is attached to
 
void setup () {
 
  // LEDS
  pinMode(ledPin1, OUTPUT); // declare pin 9 to be an output:
  pinMode(ledPin2, OUTPUT); // declare pin 10 to be an output:
  // set leds to minimum brightness
  analogWrite(ledPin1, brightness_current);
  analogWrite(ledPin2, brightness_current);
 
  // PROXIMITY SENSOR
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
 
}
 
 
 
void loop() {
 
  long duration, distance;
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;
 
  if (distance < led_distance ) { // within led proximity limit; start routine
 
    // ramp up led brightness
    for (int brightness_temp = brightness_current; brightness_temp <= brightness_maximum; brightness_temp++) //loop from brightness_minimum to brightness_maximum
    {
      analogWrite(ledPin1, brightness_temp); // set the brightness of pin 9:
      analogWrite(ledPin2, brightness_temp); // set the brightness of pin 10:
      delay(pause_between_increase);
    }
 
    // safely assume current brightness is now maximum brightness
    brightness_current = brightness_maximum;
 
 
    // hold at max brightness before wink
    delay(pause_at_max_before_wink);
 
    // wink (optional)
    if (pause_for_wink > 0) {
      analogWrite(ledPin1, 0); // turn first led off, creating the wink effect:
      delay(pause_for_wink);
      analogWrite(ledPin1, brightness_maximum); // restore first led to max brightness, ending the wink effect:
    }
 
    long duration, distance;
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);
    distance = (duration / 2) / 29.1;
 
    if (distance > led_distance ) {
 
      // ramp down led brightness
      for (int brightness_current = brightness_maximum; brightness_current >= brightness_minimum; brightness_current--) //loop from brightness_maximum down to brightness_minimum
      {
        analogWrite(ledPin1, brightness_current); // set the brightness of pin 9:
        analogWrite(ledPin2, brightness_current); // set the brightness of pin 10:
        delay(pause_between_decrease);
      }
 
      // safely assume current brightness is now minimum brightness
      brightness_current = brightness_minimum;
 
    }
 
  }
 
 
  else {
 
    // outside proximity limit; do not start routine
    // we're just going to loop back and test proximity again, but we pause briefly to conserve power
    // there is no need to use power checking proxinity continuously
    delay(100);
 
  }
 
}

 

These changes to just that, and give us the most lifelike/spookiest effect yet.

 

 



Tags: Arduino

Related Content

Arduino Project – LED Skull 5: Adding Subroutines/Functions

This code was a great opportunity to introduce the idea of subroutines and returning values from subroutines (functions) with an Arduino Uno.

Fire Breathing Arduino Pumpkin With IR Remote Control

A small change to another fire-breathing Arduino pumpkin replaces a proximity sensor with an small IR remote control.

Arduino Project – LED Skull Eyes 3: Adding a Second Eye

The next step involves adding a second "eye" (LED), independent of the first, to maintain the wink effect.

Arduino Project – LED Skull Eyes 2: Wink Effect

More variables and the addition of a "wink" effect to make the LED skull eyes seem more animated.

Arduino Project – LED Skull Eyes 1

The first part of this project (adding LED "eyes" to a skull, driven by an Arduino UNO) was about teaching code optimization, abstraction and commenting.

Arduino IDE "'lt' was not declared in this scope" Error

Be aware of a small encoding issue and the resulting "lt/gt was not declared in this scope" error when pasting into the excellent Arduino IDE for Mac.

Category List


Tag List


Tag Cloud



Archive