Radio Shack IR emitter/detector pair test

Ok. For my first Arduino project, I needed to create a tachometer/RPM counter. I used my google-fu and found several of the optical tachometer projects, and decided that would be the best solution.

So, I grabbed the Radio Shack IR LED Emitter and Detector pair.

Alas, that was probably not the best choice. I suggest that if anyone is interested in the same solution I used, look at the reviews for this product and compare to other IR emitters/detectors (sold as separate items) before making an informed decision.

But, I was bound to dance with the one I brung. So, I looked to other projects to test whether the emitter/detector pair even worked. In the course of doing that, it became a good exercise in learning about Arduino i/o and the programming generally.

So, in an effort to "pay it forward" for others getting into this stuff, and for feedback from people who know alot more than me, I now present my IR LED test sketch.

What this does it puts the emitter and detector on different pins, and measures the analog readings of the detector. It then keeps track of a minimum and maximum value. Using these, I could set a threshold in my tach sketch - above a certain value meant the "beam" had been "tripped" and to count that towards the RPM. Also, note that for my purposes, the emitter and detector are mounted side-by-side, so the LACK of IR means that it is between rotations. When the IR is reflected back to the detector, it means that the arm traversed across the beam. (Oh, I also put an LED on pin 13 because I'd just finished the blink tutorials.)

Diagrams:

Sketch:

/*---------------------------
IR LED and phototransistor beam test and calibration

debug stuff:
min/max val = whatever the value is when it changes
LED is always on
----------------------------*/
// defines for pins
#define IRoutputPin 2        // digital output pin
#define IRinputAnalogPin 0   // analog input pin
#define LEDsignalPin 13      // LED signal pin

// int and long values
int val = 0;           // variable to store the value read from input pin
int minVal = 1000;
int maxVal = 0;
int oldVal= 0;

// strings
String outputString;
String intro = "JTD IR test and calibration init";
boolean needIntro = true;
String signalBase = "Signal Strength: ";
String minBase = "Min: ";
String maxBase = "Max: ";

void setup()
{
  pinMode(IRoutputPin,OUTPUT);
  digitalWrite(IRoutputPin,HIGH);
  pinMode(LEDsignalPin, OUTPUT);
  Serial.begin(9600);
}
void loop()
{
  // print header
   if (needIntro == true)
    {Serial.println(intro);
    needIntro = false;}
  digitalWrite(LEDsignalPin, HIGH);    // turn signal LED on
 
 // read value of analog input   
  val = analogRead(IRinputAnalogPin);    // read the input pin
  //Serial.println(val);             // debug value
  
  if (val != oldVal)          // if the new value is different than the old value, then do stuff
  {
 
   String outputString = signalBase + val;     // concatenates output for signal strength
  Serial.println(outputString);
    outputString = minBase + minVal;     // concatenates output for min
  Serial.println(outputString);
    outputString = maxBase + maxVal;     // concatenates output for max
  Serial.println(outputString);
    oldVal = val;
    
  delay(500);                      // wait half a second
  }

    
    if (val < minVal)      // conditional if val is less than prior minVal
  {  //String outputString = minBase + val;     // concatenates output
  Serial.println(outputString);
    minVal = val;}
    
  if (val > maxVal)      // conditional if val is greater than prior maxVal
  {  String outputString = maxBase + val;     // concatenates output
  //Serial.println(outputString);
    maxVal = max(maxVal, val);}
}

Again - this is by no means authoritative. All feedback is welcome. Also, I plan on trying to incorporate this into a self-calibration routine in the actual tachometer. Someone can spin whatever it is they want to get the RPM of, the routine will map the min and max to a value range, and anything above the middle is a "count." Basically, it would self-determine what the ambient is, and what the reflected value is.

And thanks to all those who share their knowledge in forums like this. It makes it much easier for n00bs like me.

Hi,

Its good that you have something up and running, for your next project you can move anything that you want to do once only such as your print your intro into the setup function, its there to do one time setup and anything else you want to happen once before loop starts. I often do something similar to you and have my sketches send the sketch name and version to serial, put this into setup and you can take the if statement and extra variables out of loop, you can move setting the LED High into setup as well.

I don't know how interested you are in the programming side of things, it looks as if you might be interested because you are doing some very good things, I like that you have long readable variable names minVal, maxVal, oldVal instead of n,m,x,y etc. Its also really good that you are using define statements for your fixed values. If you had a look through loop you could find some lines of code that could be moved, for instance if its not a new value its not a new min or max value either so you could move these two tests inside the first test for a new value.

Its not essential, but it makes code easier to manage as you get onto bigger projects.

Duane B

rcarduino.blogspot.com

Thank you very much! I had not realized you can send the serial.print during setup! I don't think I saw that. I will absolutely do that.

Good point about moving the new minVal/maxVal test. I will incorporate that earlier in the loop. Also, it now strikes me that I can assign initial min/max during the setup, too. That way, I don't have the artificial 0/1000 at the beginning of the "real" loop.

My background is far stronger in programming than in soldering, THAT is for sure, but still purely at the hobbyist level! I fondly recall working in DOS (config.sys and autoexec.bat, etc.) before the fancy full-screen text editors came out. :wink: And BASIC/Fortran before that.

Thanks for the feedback.

You need a current limiting resistor for the external LED connected to pin 13. You might think there is one on the board but you would be incorrect.

Also, I believe that you have the emitter and the base swapped on your drawing of the phototransistor. It is typically the base that has no external connection.

Don

Ah - interesting. I'm still very new to the schematics stuff. It may be that I just had it set up wrong before.

As for pin 13, I will admit to some confusion. :blush:

NOTE: Digital pin 13 is harder to use as a digital input than the other digital pins because it has an LED and resistor attached to it that's soldered to the board on most boards. If you enable its internal 20k pull-up resistor, it will hang at around 1.7 V instead of the expected 5V because the onboard LED and series resistor pull the voltage level down, meaning it always returns LOW. If you must use pin 13 as a digital input, use an external pull down resistor.

And http://www.arduino.cc/en/Tutorial/BlinkingLED

Ideally we use pin 13 on the Arduino board because it has a resistor attached to it, needing only an LED.

Do you mean that the "internal" resistor is dedicated to the onboard LED? I have started using the pin 13 LED as a sort of visual feedback for my sketches, so I want to be sure not to fry it! :slight_smile: (Or any LEDs!)

Thanks!

And http://www.arduino.cc/en/Tutorial/BlinkingLED
Ideally we use pin 13 on the Arduino board because it has a resistor attached to it, needing only an LED.

That page has not been updated in nearly five years, but the Arduinos have changed since then.
Unfortunately there is no way for a mere mortal to get outdated information removed from the website.

Do you mean that the "internal" resistor is dedicated to the onboard LED?

Yes. At least since the introduction of the Duemilanove, and possibly prior to that.

I have started using the pin 13 LED as a sort of visual feedback for my sketches

That's what the onboard LED is for.

I want to be sure not to fry it!

Your external LED will probably survive but the Arduino output pin will not.

Don

Thanks T_Lex,

I also went out and bought that Radio Shack IR LED Emitter and Detector pair, and I also felt "I was bound to dance with the one I brung." But I was lucky, I found your post. Thanks for paying it forward.

I've taken your sketch, gotten it running, and then gone beyond -- I hooked up a speaker, and I have it playing a tone based on the value reported by the Detector. I positioned the Emiiter and Detector just far enough apart that I can put a piece of paper between them to block the signal.

When I do, the speaker plays a lower note. In fact, as I slowly lower the piece of paper between the Emitter and Detector, I can make the note slowly fall down to the min pitch value -- kinda analog synth trippy!

Also, if I disconnect the Emitter, and then use various remotes from around my house, I can "hear" their signal from the Speaker. This usually produces stutter tones (a series of hi and lo notes) at a specific inteval. Each remote is different.

BRAVO.

Here is my sketch. Note that I seriously reworked your code, removing the stuff for the LED on pin 13, and adding stuff for the speaker on pin 8. Also, I changed the #defines into consts, and added a debugging switch (bool debug). Setting debug to false turns off all serial port tracing, so you can hear the speaker in "real time" -- i.e. as fast as the Arduino can process everything.

Sketch:

//
// IR_Sensors_2.ino -- play the current value of an IR Sensor on a 5v speaker, adjusting 
// from a base pitch of C3 (220hz)
//
// Dervied from http://arduino.cc/forum/index.php?topic=94690.0
//
// Note: Detector is clear, emitter is dark
//
//

	// Constants

const int IR_IN_ANALOG_PIN	= 0;	// analog input pin -- Detector (clear)
const int IR_OUTPUT_PIN		= 2;	// digital output pin -- Emitter/dark)
const int SPKR_PIN			= 8;	// Speaker

const int NOTE_C3	= 220;

const String INTRO	= "Starting...";

	// IR level values

int irLevel		= 0;		// variable to store the value read from input pin
int minIRLevel	= 1000;
int maxIRLevel	= 0;
int lastIRLevel	= 0;
int irTone		= 0;

bool firstLoop	= true;
bool debug		= false;		// Set false to turn off Serial tracing
bool newRange	= false;


// 
// setup
//
void setup() {

		// Set up the output LED

	pinMode( IR_OUTPUT_PIN, OUTPUT );
	digitalWrite( IR_OUTPUT_PIN, HIGH );	// Turns on the emitter

		// Turn on tracing

	if ( debug ) {
		Serial.begin( 9600 );
	}
}


//
// loop -- show the current input to the detector.  Sense and highlight changes to the observed
// min, max and avg values of the signal
//
void loop() {

		// read value of analog input  

	irLevel	= analogRead( IR_IN_ANALOG_PIN );

		// Play its value 

	irTone	= NOTE_C3 + irLevel;
	tone( SPKR_PIN, irTone );
	
		// print header & initial irLevel

	if ( firstLoop == true ) {
		if ( debug ) {
			Serial.println( INTRO );
			Serial.print( "initial irLevel = " );
			Serial.println( irLevel ); 	
		}					
		firstLoop	= false;
	}

		// Check if irLevel changed

	newRange	= false;
	if ( irLevel != lastIRLevel ) {
	
			// Trace the new IR level

		if ( debug ) {

				// Print the level

			Serial.print( "irLevel = " );
			Serial.print( irLevel ); 

				// Print increase/decrease

			if ( irLevel > lastIRLevel ) {
				Serial.print( " +++" );
			} else {
				Serial.print( " ---" );
			}
		}						

			// Save new minimum

		if ( irLevel < minIRLevel ) {
			if ( debug ) {
				Serial.print( " new MIN" );
			}
			newRange	= true;
			minIRLevel		= irLevel;
		}

			// Save new maximum

		if ( irLevel > maxIRLevel ) {
			if ( debug ) {
				Serial.print( " new MAX" );
			}
			newRange	= true;
			maxIRLevel	= irLevel;
		}

			// Finish the trace line

		if ( debug ) {
			Serial.println( "" );
		}

			// Print new range

		if ( newRange ) {
			if ( debug ) {
				Serial.print( "Range: [ " );
				Serial.print( minIRLevel );
				Serial.print( ", " );
				Serial.print( maxIRLevel );
				Serial.println( " ]" );
			}
		}

			// Save the irLevel

		lastIRLevel	= irLevel;

			// wait half a second

		if ( debug ) {
			delay( 500 );
		}
	}


}

I hope you see this post, and enjoy it. And for anyone else who bought the Radio Shack IR LED Emitter and Detector pair, here is something else to do with it!

Signed,
Happy Mrex

i stumbled on this through a google search and i thought i would put my two cents in on this:

remember that the IR detector is a npn transistor with no base as the IR light serves as the base making it a "npn" (never checked to see if these come in pnp) photo transistor. if IR light hits it, the base goes high. the IR emitter is simply an IR wavelength led.

if you plan to use this as a tachometer, as i plan to do, you might want to consider using the ISR (Interrupt Service Routine) for polling the detector. it will give far more uninterrupted samples over time, something like up to 8 or 16 MHz, i forgot the clock max, i think its 1/2 the external clock crystal. also they have special optocouplers with a slot cut out of them so a slotted disc can be passed through. if you have old vcr's they are loaded with optocouplers, but the disc's not so much, but they can be easily made at home. these will do a better job, but im attempting this with the same emitter detector as the OP. i want to see if i can use them to clock a color stripe on a brushless dc outrunner. if it works ill post back some code.

... you might want to consider using the ISR (Interrupt Service Routine) for polling the detector. it will give far more uninterrupted samples over time, ...

What do you mean by the ISR?

Don

What resistor did you use for the IR detector and LED?

Hey,

I found your code and set up extremely useful in checking my own project that uses IR emission XD
Likely, I will keep a lot of the code around just so I can always read emission values for troubleshooting as I progress.
Can I credit you somehow in my code? Your name, a website, etc would be fine. Unless you don't care.
I ask because I do use a fritzing.org profile, create tutorials at one of my jobs, and post code for Arduino projects.

Thanks,
-Grace