# A simple analog proximity sensor with digital interface (for Raspberry Pi) [last update: Feb 7, 2014]

Raspberry Pi has a Broadcom BCM2835 chip, which controls 26 GPIO (general purpose input/output) pins. There are C library or RPi.GPIO python package available online that can be used to control the pins. The RPi.GPIO package is by default included in most Raspberry Pi system, such as Raspbian, a RPi version of Debian linux system.

One drawback of RPi, compared to arduino, is that it doesn’t have any analog pin. All the GPIO pins are purely digital. For example, if pin A is an output pin, it can only output LOW (0V) or HIGH (3.3V), represented as 0 or 1. If pin A is an input pin, for any voltage below 0.8V applied on pin A, it takes it as LOW or 0; for any voltage above 1.3V (surprisingly low actually!), it takes it as HIGH or 1 [ref: RPi GPIO].
In real world, however, purely 0 or 1 rarely happens. We always get information that can have continuous value in its range. For example, temperature can be 10C or 50F, or 100C or 212F. These number contains more information than simply “cold” or “hot”. A distance can be 2 cm or 10 m, and it is not enough to only know “close” or “far away”.

There are some methods to overcome this drawback. RPi does support SPI or I2C interface, so that we can use some external analog to digital converter (ADC) and use SPI or I2C interface to get quasi-analog signal through these ADCs, such as MCP3008, TLC549, MCP23017, etc. These chips usually cost several bucks. However, with additional commercial sensors, the whole part can cost more than $20 to$30, and it is difficult to make the system compact. For robotic project one usually need more than one sensor, and the cost can add up easily.

In fact, in many situations, it is actually possible to avoid using these external devices, and still able to get analog signals through the digital pins!

The key is to convert analog signal to time duration. Because time is always analog!

I build a simple infrared proximity sensor using several infrared LEDs, one phototransistor, one 2N3904 NPN transistor, a 100nF ceramic capacitor and several low power resistors. And I am able to get some analog reading.

All the elements are among the cheapest in the electronic market.

It doesn’t really matter what LEDs, phototransistor or NPN transistors are being used. They are pretty much the same.

The only thing that might matter a little bit is the 100nF (0.1uF) capacitor. I used a low profile ceramic one, which is probably not the best choice. A class 1 ceramic, or film capacitor, will be more suitable here.

Connect the +5V and GND wires to an external 5V power supply, also connect the GND wire to the ground of the Raspberry Pi GPIO pins. Choose one GPIO pin, say, Pin A as the trigger and connect it to the Trigger wire. Choose another GPIO pin, say, Pin B, as the signal input/output and connect it to the OUT wire.

To measure the distance of an object, we send a trigger signal to activate the infrared LEDs. The light emitted by these LEDs are then reflected by the object in front of the sensor. The phototransistor in the middle collects the reflected light and generates a proportional current. This current is used to integrate the voltage across the capacitor (I=CdV/dt). By monitoring the time it takes the capacitor voltage to reach some certain threshold, we have a sense of how much current was generated by the phototransistor, or equivalently, how much light got reflected. Apparently, closer the object is, more the reflected light is. By carefully calibrating the timing of the sensor, we should be able to get a pretty precise measurement of the distance.

Here is the detailed sequential of operations.1. Zero the capacitor

First set Pin B to be an output pin and set it to be zero.

GPIO.setup(PIN_B,GPIO.OUT)
GPIO.output(PIN_B,0)
time.sleep(0.01)

This will discharge any residual voltage on the capacitor. Note that the RC time for discharging the capacitor is t=RC=500ohm * 100nF = 50 us = 0.00005 sec. By maintaining zero volt at pin B for 200RC time, we make sure the capacitor is fully discharged (the residual voltage should be e200=1087 times the original residual voltage).2. Set Pin B as Input

Now we use Pin B as an input pin to get data from the phototransisto.
GPIO.setup(PIN,GPIO.IN)

3. Light up the LEDs

It’s time to turn on the infrared LEDs.

GPIO.setup(PIN_A,GPIO.OUT)
GPIO.output(PIN_A,1)

This will set the voltage of trigger pin to be 3.3V. Since the BE node of 2N3904 drops 0.7V, the voltage across R1 is 2.6V. The current through R1 is then I=2.6V/4.3kΩ=0.6mA. 2N3904 then amplifiers this current by ~150 times, resulting a ~ 100mA current from its collector to emitter. Each of the LEDs will conduct about 50mA for a short time period.4. Timing the duration of Pin B remaining LOW

Start to measure how long it takes the capacitor to reach RPi’s threshold so Pin B becomes HIGH

counter=0
t1=time.clock()*1000
while(GPIO.input(PIN_B)==0)&(counter<1e4):
counter = counter+1
deltat=time.clock()*1000-t1

deltat is the time duration of Pin B remaining LOW. Since deltat is proportional to the reciprocal of phototransistor current (or amount of reflected light), and phototransistor current is roughly proportional to the reciprocal of the distance, deltat is roughly proportional to the distance.
deltat1I1lightdistance

The (counter<1e4) term is to prevent the situation that it takes too long to integrate the capacitor due to extremely low phototransistor current, or equivalently, infinite distance.

Scroll to Top
##### LEGO MINDSTORMS Motors with Raspberry Pi (BrickPi 0.1)

Since we first got the Raspberry Pi, we have wanted to make a robot out of it.  There aren’t many...

Close