Introduction: Cheap Sensors: RPR220

About: All you need to know is I exist......

Sensors are an integral part of any robot, automation project, or anything involving mechatronics. Unfortunately they are normally quite expensive. This series of instructables aims to provide information about cheap sensors for whatever project you like. I'll be providing information on how to use them, some example code for Arduino, and what I think the sensor would be good for.

Sensors Tested So Far:

One type of range-sensor is the reflective optocoupler, where an LED shines, and an LDR measures the brightness. Often these sensors are used for line following robots, as a black piece of paper reflects less light than a white one. However, you can also use them to detect range. If you shine a torch at a wall, you can approximate how far away the wall is based on how bright the light appears. This is my main interest in these sensors, as traditional ranged sensors (ultrasonic and sharp infared) are quite large (and expensive).

There are three reflective optocouplers I could get my hands on:

  1. RPR220 (~$0.40 each)
  2. TCRT5000 (~$0.13 each)
  3. CNY70 (~ $0.52 each)

I couldn't find a comparison of them so I bought a couple of each. I'll be writing up on each of these so that in future, people won't have to buy all of them to evaluate which to use. (Note that prices are for buying them from China, Digikey has them at about $1.50 each).

So, without further exposition, let's get to it.

Step 1: Physical Description and Datasheet

As with any new part, the first thing to do is to get the datasheet, and then look at it.

The datasheet is here, and you can look at the image on this post to see what it actually looks like. The grid is 1cm. I was a little confused by the datasheets drawing of the sensor, trying to figure out what all the pins were. So I've also put in a picture that will hopefully make this easier for other people.

What else can we learn from the datasheet?

  1. The phototransistor limits the current from 0.5uA (dark) to 0.8mA (light).
  2. The LED can handle up to 50mA

These will come in handy when designing a drive circuit.

Step 2: Drive Circuit

So we have to do two things:

  1. Turn on and off the IR LED
  2. Measure current through the phototransistor

The reason we want to be able to turn the IR LED on and off is so that we can measure ambient light levels and remove those from our final distance estimation.

So, to drive an LED we need to plug it in to a digital pin on a microcontroller. For this project I've used an Arduino Pro Micro, but you could use anything from a Basic Stamp to an ARM micro. The important thing to note is that while the LED can withstand 50mA, the Arduino can't supply that from a digital pin. I couldn't find an exact number for the Pro Micro, so to be safe, I drove the LED at 20mA. Plugging this information into a LED calculator (or using Ohms law if you're motivated) we discover that we need a 200 ohm resistor.

How do we measure current? Well, we have some ADC (Analog to Digital Converter) pins on our Arduino. They won't measure current, but if we use a resistor, ohms law tells us voltage (which we can measure) will be proportional to current.

The phototransistor will allow through it up to 0.8mA, and we want this to be 5V on the ADC. Thus, in theory we need a 6K2 resistor. BUT - there is a trick. The reflectivity of our target is not going to reflect 100% of the light back onto the sensor, so it will never reach 0.8mA. Indeed, the datasheet says a typical value at 6mm is 0.3mA. I want my robot's sensor to measure even longer distances, up near half a meter. So I multiplied the resistance by 10 to give me 10 times gain.

As it turns out, I didn't have a 68K (the nearest standard value to 62K), but I didn't have one. I used a dodgy 100K resistor that read 80K on a multimeter. All that the resistor value changes is the amplification - so pick one that gives good performance at the range you want the sensor to work at. (higher resistor values for longer range)


This results in the schematic shown in the pictures, which was then built on a breadboard.

Step 3: Arduino Test Code

Now we need some code to drive the sensor.

Because we want to be able to use the sensor when there are external sources of IR light present, we need to take two readings and compare. I used the following code:

#define IR_INPUT_PIN A0
#define IR_LED_PIN 16 void setup(){ Serial.begin(9600); pinMode(IR_INPUT_PIN, INPUT); pinMode(IR_LED_PIN, OUTPUT); } void loop(){ int ambient = 0; int lit = 0; int value = 0; digitalWrite(IR_LED_PIN, LOW); delay(5); //To give ADC and LED transition time ambient = analogRead(IR_INPUT_PIN); digitalWrite(IR_LED_PIN, HIGH); delay(5); lit = analogRead(IR_INPUT_PIN); value = lit - ambient; Serial.println(value); }

Step 4: Tests

Well, it was time to do some actual tests: set a target, measure some distances and see what values I got.

After half-an-hour or so I had enough data to draw a graph.

Step 5: Linearization and More Arduino Code

This sensor is non-linear. You can tell that by looking at the graph.

To linearize it, I used the formula:

dist = 900/(RAW - 12)

This worked well enough for a black target, though white is of course quite different. Building up a better model is definitely possible, but would be material specific. If you want accurate values, you'll have to calibrate it anyway.

The arduino code I ended up with to use these sensors is:

void initRPR220(int ledPin, int detectorPin){
//Initialises an RPR220 on specified pins pinMode(detectorPin, INPUT); pinMode(ledPin, OUTPUT); } int readRPR220(int ledPin, int detectorPin){ //Returns an approximately linearized distance (mm) for an RPR on specified pins. //Note: Designed for black materials int val = 0; digitalWrite(ledPin, LOW); delay(5); val = analogRead(detectorPin); digitalWrite(ledPin, HIGH); delay(5); val = analogRead(detectorPin) - val; return 9000/(val - 12); }

Step 6: Summary

So the RPR220 is a cheap sensor costing only $0.40 each. To drive it requires two resistors, a digital output and an analog input.

It can tell the difference between a black and white surface at up to 20cm or so, and if you know the target color (or can calibrate it in situ) can provide between 1cm precision at 20cm (black) to 2mm precision at 20cm. At short ranges the accuracy is much greater - up to 300 units per cm (0.03mm per unit).

The time to measure the distance is about 10ms, not sure why, but reducing it reduced the accuracy.

And this is driving the IR LED at about half it's intended current. Driving it at full current would likely need a slight change in resistor values to cover the whole range.



This sensor is very sensitive to range, but unless the target color is known, and the sensor calibrated for it, the actual distance will not be accurate. It is plenty good enough to let a small robot know when something is close, and prevent it bumping into walls or falling off tables.

While it could be used for greyscale color detection, it's extreme sensitivity to distance may be prohibitive.