Ultrasonic Gesture Based TV Remote Control

13K5118

Intro: Ultrasonic Gesture Based TV Remote Control

This is a fairly simple project that is designed to introduce key components to a new Arduino user. I created this in a few hours of tinkering using existing Arduino libraries and a SainSmart starter kit. Real world applications could include users who have difficulty using remote controls or are in food preparation areas etc.

The IR code is configured for use with a Sony TV, the library is courtesy of http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html
I also took some IR codes for the TV from here: http://www.openremote.org/pages/viewpage.action?pageId=15532260

Everything else uses the built in Arduino functions and libraries or my own work.

STEP 1: Materials

You will need:
1. An Arduino UNO.
2. An HC-SR04 ultrasonic module
3. An Infra-red LED
4. An appropriate resistor for your Infra-red LED (I used 220R but the signal is quite weak!)
5. An RGB LED (and resistors if they aren't built in).
6. A breadboard and wires.

STEP 2: The Electronics

The configuration is straight forward.

1. Connect the IR LED to pin 3 via an appropriate resistor, and then connect the cathode to GND.

2. Connect the ultrasonic sensor to 5v and GND where the pins specify. Connect the trigger pin to pin 8 and the echo pin to 7. You can configure these pins in the sketch.

3. Connect the RGB LED to GND and pins 11 (red), 10 (green), 9 (blue). These pins are also configurable.
NOTE: Make sure your LED module has built in resistors or you will damage the LED.

STEP 3: The Sketch

The following code should be uploaded to the Arduino.

/* Swipe Remote Control

This sketch uses an ultrasonic rangefinder to determine the user's gesture and outputs an IR signal to a sony TV based on the command given.
- High swipe (> 10in) = Channel Up
- Low swipe = Channel Down
- High hold (> 10in) = Volume Up
- Low hold = Volume Down
- Cover sensor (< 3in) = Turn On / Off

Created by Dan Nicholson.

This example code is in the public domain.

This code uses the IRremote library (https://github.com/shirriff/Arduino-IRremote)

*/
#include <IRremote.h>

// Defines for control functions
#define CONTROL_CH 1 // Channel change
#define CONTROL_VOL 2 // Volume
#define CONTROL_POW 3 // Power

#define CONTROL_UP 1
#define CONTROL_DOWN -1

#define DIST_MAX 20 // Maximum distance in inches, anything above is ignored.
#define DIST_DOWN 10 // Threshold for up/down commands. If higher, command is "up". If lower, "down".
#define DIST_POW 3 // Threshold for power command, lower than = power on/off

// IR PIN
const int irPin = 3; // this is defined in the library, this var is just a reminder. CHANGING THIS WILL NOT CHANGE PIN IN LIBRARY
// 2 Pin Ping Sensor
const int pingPin = 8;
const int echoPin = 7;
// Confirmation LED Pins
const int led = 13; //internal LED for up/down debugging
const int ledR = 11;
const int ledG = 10;
const int ledB = 9;
// LED on timer
unsigned long timer;
// IR transmitter object
IRsend irsend;
// Power confirmation flag (needs two swipes to send signal)
boolean powerConfirmed = false;

void setup() {
  // initialize serial communication and set pins
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT); 
  pinMode(pingPin, OUTPUT);
  pinMode(echoPin, INPUT);
  timer = millis();
}

void loop()
{

//  Serial.println(millis());
  long duration, inches;
  int value;

  // Check for a reading
  duration = doPing();

  // Timer to confirm actions (currently only power)
  if (timer && timer < (millis() - 5000) && (millis() > 5000))
  {
    Serial.println("timer reset");
    timer = false;
  }

   digitalWrite(led, LOW);
   setColor(0, 0, 0); // off


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

  // If less than max inches away, act
  if (inches < DIST_MAX)
  {
    // Debug output
    Serial.print(inches);
    Serial.println("in");

    // If very close, it is a "power" signal
    if (inches < DIST_POW)
    {
      Serial.println(timer);
      // on or off
      if (timer)
      {
        doIR(CONTROL_POW, 0);
        timer = false;
        delay(2000); // don't want to be sending this more than once. 2 second delay
      }
      else
      {
        Serial.println("power flag set");
        timer = millis();
        setColor(255,50,50);
        delay(500);
      }
    }
    else // is volume or channel
    {
      // Distance determines control direction
      value = handleDist(inches);
      // wait half a second
      delay(300);
      // check again, has hand disappeared?
      if (microsecondsToInches(doPing()) > DIST_MAX)
      {
        doIR(CONTROL_CH, value); // swipe
      }
      else
      {
        // volume
        int d = 500; // first delay is longer for single volume change
        // repeat until hand is removed
        while (inches < DIST_MAX)
        {
          value = handleDist(inches); // is up or down?
          doIR(CONTROL_VOL, value); // fire off IR signal
          delay(d); // wait
          inches = microsecondsToInches(doPing()); // check for hand again
          d = 100; // delays are shorter for quick multiple volume adjustment
        }
        delay(500); // this stops accidental channel change after volume adjustment
      }
    }
  }
  delay(50); // Short enough to detect all swipes.
}
/*
* If distance is within threshold, mark as 'up' and turn on corresponding LED.
*/
int handleDist(int inches)
{
  if (inches > DIST_DOWN)
  {
    digitalWrite(led, HIGH);
    return CONTROL_UP;
  }
  else
  {
    digitalWrite(led, LOW);
    return CONTROL_DOWN;
  }
}

/*
* Fire off correct IR code
*/
void doIR(int control, int val)
{
  switch(control)
  {
  case CONTROL_POW:
    // power
    Serial.println("power on / off 0xa90");
    for (int i = 0; i < 3; i++)
    {
      setColor(255, 0, 0);
      irsend.sendSony(0xa90, 12); // Sony TV power code
      delay(40);
    }
    break;
  case CONTROL_CH:
    setColor(0, 255, 0);
    // output 'channel up / down' depending on val
    if (val == CONTROL_UP)
    {
      digitalWrite(led, HIGH);
      for (int i = 0; i < 3; i++)
      {
        irsend.sendSony(0x90, 12);
        delay(40);
      }
      Serial.println("channel up 0xD00A");
    }
    else // down
    {
      for (int i = 0; i < 3; i++)
      {
        irsend.sendSony(0x890, 12);
        delay(40);
      }
      Serial.println("channel down 0x3002");
    }
    break;
  case CONTROL_VOL:
    setColor(0, 0, 255);
    // output 'volume up / down' depending on val
    if (val == CONTROL_UP)
    {
      digitalWrite(led, HIGH);
      for (int i = 0; i < 3; i++)
      {
        irsend.sendSony(0x490, 12);
        delay(40);
      }
      Serial.println("volume up 0x490");
    }
    else //down
    {
      for (int i = 0; i < 3; i++)
      {
        irsend.sendSony(0xC90, 12);
        delay(40);
      }
      Serial.println("volume down 0xC90");
    }
    break;
  }
}
void setColor(int red, int green, int blue)
{
  analogWrite(ledR, red);
  analogWrite(ledG, green);
  analogWrite(ledB, blue);
}

long doPing()
{
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  return pulseIn(echoPin, HIGH);
}

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;
}

STEP 4: Let It Run!



Controls
The controls are explained in the video, and are as follows:

Power
Swiping over the sensor within 3 inches will cause the LED to flash purple. This is the confirmation that a 'turn on / off' signal is ready to be sent. To prevent it accidentally turning the TV off I have made the sketch wait for a second swipe within 5 seconds of the first to confirm. At this point the signal is sent to the TV to turn on or off.

Channel
Swiping within 10 inches of the sensor (but not within 3)  will cause the channel to change down. Swiping between 10 and 20 inches will cause the channel to change up.

Volume
Holding your hand within 10 inches of the sensor (but not within 3)  will cause the volume to change down. Holding between 10 and 20 inches will cause the volume to change up. The volume will continue to change (up or down) until your hand is removed.

18 Comments

sir it works on any tv

sir we already made the sensor works but how do we know if the IR LED is sending signal?

You can actually see the light from an IR LED if you look at it through a video camera (smartphone camera would work), but it has to be on long enough for you to see, which this might not be. You could set up an IR detector with another arduino and output the results to the serial monitor.

thanks sir! We managed to make the IR Led flash now, but the problem is we cannot make the TV work using it, how would we know the ir codes in our remote Tv?

I don't have a list of codes for all TVs I'm afraid, but most are available online if you search for them.

thanks for the response sir! :) we already made it out of nowhere haha idk but i just downloaded the IR Library then included in the arduino IDE. It is now working :) but the problem is it's working only in our tv at home, we're gonna exhibit this project in our circuits fair at school, will it work in other tvs?

Typically each brand of TV has different codes so I would suggest you test beforehand or take the TV with you to make sure it will work.

hi ! i have a samsung smart tv, where do i find that specific code just like you did for sony ?

Please give some idea about that.

Hi Devi, I'm afraid I don't have any special access to codes. It is just a matter of searching the internet. Sorry I can't be more help!

hai mr, I want to createa tool likethis, butI havedifficultyin finding thecode forSHARPtvprogram,could you give mesome help tosource code,thanksbefore:), you can sendit to email : guen_ter@yahoo.co.id

hello sir i have onida tv , so i cant run the code which u have given can u please send me the code please give me replay

hi i want to control dslr cameras with ultrasonic is this possible

Hey! I wish to do this project, but I own a LG TV..can you tell me what all changes i will need to do? and i wish to change the gesture for the same like, i wanted the volume to change on rotating the finger clockwise and anti clockwise, change channel on swiping with entire hand(like in mobile phone's gallery),so what changes do i make for this?

Hi, You would need to get a hold of the LG sending protocol and codes which may be available on the internet. As far as rotating your finger to change the volume: the sensor is one dimensional by definition, I don't see a way that you could do that without adding additional sensors and calibrating them to detect that precise motion. Have you considered a Leap Motion controller instead?

and can I use it with my arduino board in the same way? like, just replace hc-sr04 with leap motion controller, and use the same code(with LG sending codes?)

Well, no I actually have no idea about leap motion controller..can u please brief something about it? Also, can I remove my arduino IC and use the programmed IC on a circuit of it's own? (kinda stand-alone?) thank u :)

The code shows an error, check the attached photo.

The error indicates that you have not included the IR remote library from https://github.com/shirriff/Arduino-IRremote correctly.