<< Click to Display Table of Contents >>

Navigation:  »No topics above this level«

Infrared Reflective Sensor TCRT5000 · 2025.04.17

Return to chapter overview

IR reflective sensors have a IR LED and an IR transistor sensor which senses the reflected infrared from the LED. A typical very low cost sensor is the TCRT5000. I bought 50 of these for $10, that's about half the price of a single time-of-flight sensor.

These are a very low-cost way of implementing limit switches, measuring RPM, proximity sensing, crude distance measurement, etc. Note that there are far more accurate ways to measure distance, with the latest 'time-of-flight' sensors, or IR sensors specifically designed for distance measurement such as the Sharp GP2Y0A21YK0F, but these are many times more expensive.

The major drawback of the TCRT5000 is that they misbehave if someone points an infrared remote control at them and presses a button. IR distance sensors with built-in controllers do not have this problem (I think).

 

Digital output circuit with LM393 comparator

Our application is for detecting the distance of objects using the sensor in analogue mode. It is not for measuring rotation speed or for interrupt-driven proximity switches. For that you should incorporate a comparator chip like the LM393 which provides a digital output, then you can use this to generate an interrupt. Many cheap off-the-shelf modules are available, like this one:

tcrt5000-2

Warning: Some of these modules don't have 'hysteresis', so the switching can be very noisy and the signal must be 'debounced'. There's some code to do this at the end of this page. A noisy signal should not be used for interrupts.

Alternatively, use this improved inverting comparator circuit which has a 100K feedback resistor R3 to provide hysteresis (you can use values between 47K and 220K to adjust the hysteresis period, which is also affected by R5, so experiment a bit). The LM393 output goes high when a reflective object moves close to the sensor. R5 adjusts the sensitivity (use any multi-turn pot 5K..500K), measure the threshold voltage on pin 3. The LM393 compares the voltage from the TCRT5000 with the threshold voltage on pin 3.

tcrt5000-lm393-small

 

Very simple analogue output circuit

A minimal circuit can be used for our purposes, with no opamps or comparators. The IR LED is turned on/off by a digital output and the transistor IR sensor value is read via an analogue input.

tcrt5000-3

The analogue input gets typical readings in the range 0..900 when connected to a 10-bit analogue input (0..1023), which corresponds to a reflector distance of 150mm..10mm. The closer it is, the higher the reading.

R2 (330Ω) limits the current through the IR LED to about 10mA at 5V so you don't overload the microcontroller output.

 

Improved accuracy and stability

The influence of ambient infrared light and ambient temperature is removed by subtracting the value read when the IR LED is off from the value read when it's on. This makes the readings more accurate and reduces drift dramatically.

The sensor has a built-in "daylight blocking filter", but this doesn't seem to work very well. Just drawing the curtains changes the reading by 10%, and God knows what bright sunlight would do (but we don't have any sun at the moment). The sensor does not compensate for drift caused by temperature changes either, and the IR LED itself causes heating. Compensation by subtracting the reading when the IR LED is off solves all the problems.

 

Methods in the IrReflectiveSensor class

In the source code at the end of this page, you will find two analogue read routines:
int read() : Blocks until the reading is complete, takes just over 800µS.
bool poll(int* reading) : A non-blocking version which returns immediately with 'true' if a new reading is ready. Call this regularly from loop().

One digital routine:
bool readSwitch(bool* state, int level, int hysteresis) : A proximity switch with hysteresis, which calls poll(). You can use this for end-stop sensors etc. For readSwitch(), the constructor's 'readingsToAverage' can be zero (the default) because the switch has hysteresis, so averaging is not needed. (For a limit switch application it may be better to use a module with a comparator, because the digital output could be used to generate an interrupt, which is faster than polling the sensor.)

And a routine you must code yourself to calculate the reflector distance from the reading according to your calibration table (see 'Calculating the reflector's distance' below). This returns INFINITY if there is no reflection.
float calculateDistance(int reading)

 

Why use delays?

Being cheap, the TCRT5000 is not very fast. The waveform below shows the IR LED on/off control signal in orange, and the value from the IR sensor in blue.
You can see that it takes about 400µS until the IR sensor reaches the correct value. That's why there's a 400µS delay after the LED is turned on until the sensor is read.

tcrt5000-trace

 

Calculating the reflector's distance

The sensor reading depends on the reflectivity and size of the target object, and any other reflective objects in the vicinity. Even the wires of the prototype will affect the reading, so keep them out of the way. The reading should be 0 if there's no reflection.

If you need the sensor to measure something like weight or tension by moving an armature, the best setup is to house the sensor and a matt-white movable reflector in a non-reflective enclosure (line the enclosure with black antistatic foam), then calibrate it as described below. The exponential curve is steep at long distances and flattens out as the distance approaches zero. The closer the reflector, the more accurate the reading will be (but not closer than 10mm).

The TCRT5000 detects distances from 10..150mm. Resolution can be better than 1mm up to 100mm distance, and 0.1mm at 10-30mm distance. Accuracy depends on the surrounding reflections and the calibration curve.

To convert the reading to a distance (or tension in grams etc), you must create a calibration table, enter it into an Excel spreadsheet, then use Excel's 'Trendline' feature to create the exponential curve equation for converting the IR reading to the desired units.

 

How to use Excel to determine the equation for distance calculation

1) Mount the sensor and reflector, and write some code to display the readings from the sensor's analogue input using calls to read() or poll().

2) Create a data set of readings vs. distances in mm, with as many points as possible between 10 and 150mm distance. The more points you have, the more accurate the equation will be.

3) Enter the points into two vertical columns in an Excel spreadsheet, with the analogue readings in the first column A (high to low) and the matching mm distances in the second column B (low to high). This ensures you'll get the correct axes on the scatter chart.

4) Select all the data values in the two columns and do 'Insert -> Charts -> Scatter chart with smooth lines and markers'. You should see a chart with the distances on the vertical Y axis and the analogue readings on the horizontal X axis, with a nice exponential curve.

5) Right-click on the curve to select it and show the context menu. Choose 'Add Trendline'. You should see the 'Format Trendline' properties window on the right.

6) On the 'Trendline Options' properties page, select the 'Logarithmic' or 'Polynomial' radio button. Choose the one that shows the trend line curve with the closest match to your data points.

7) Select the 'Display Equation on Chart' checkbox. This shows the equation that matches the curve. Copy this equation and paste it somewhere safe, e.g. y = -29.72ln(x) + 210.68

8) Code this equation in the calculateDistance() method. For ln(x), use logf((float)reading).

9) Is it bedtime yet?

Alternatively, you could use MATLAB's 'Curve Fitting Toolbox' to create a polynomial equation which might have an even better fit to your data. But you have to pay for that.

 

Here's a basic Excel calibration spreadsheet (with only 8 calibration points), showing the Scatter chart and dotted Trend Line:

excel-tcrt5000-calibration

 

Source code

  IrReflectiveSensor.h   [Click to expand]

an optimized "rolling averager" is used to smooth the analogue readings.

  RollingAverage.h   [Click to expand]

 

Various utility functions. The floating-point-to-string conversion routines are smaller and faster than the Arduino's dtostrf().

  Utils.h   [Click to expand]

  Utils.cpp   [Click to expand]

 

Code to debounce a noisy digital input. Use this for pushbuttons, microswitches, and naughty comparators without hysteresis.

  Debouncer.cpp   [Click to expand]

 

Fun

For your amusement, I made some AI-generated images of insects enhanced with TCRT5000 sensors. These MattLabs CyberSect™ products are currently under development! ;-)

insect-wearing-tcrt5000 insect-wearing-led-1 insect-wearing-mattlabs-1