A few days ago, a friend came over to talk about some microcontroller related projects. One of the topics was distance sensing, or rather proximity/movement sensing with low technical effort.
The basic idea was to detect movement of an object or person within a short distance to trigger events. Typical sensors for this kind of application would be passive infrared (PIR) modules, radiowave sensors (microwave or radar) or active infrared distance sensors. All of these can be quite pricey, perhaps with the exception of the PIR, which cannot detect objects very well.
So, I thought about how the goal could be accomplished with standard parts. Active infrared is the most simple choice.
The demands:
- Detection of objects, not only persons/pets.
- Ranging if possible.
- High immunity agains disturbance signals.
From (3) I can already define that pulsed IR will be needed. Well, no problem so far. Detection has also been done: Take the standard TSOP17xx IR receiver block and some kind of modulated IR source, make sure they don’t see each other while pointing in the same direction, and you are good to go. This principle has the benefit of being dead simple, because the TSOP chip has all the fancy stuff like AGC and disturbance filters integrated – just watch the output go low and you have just detected a reflecting object.
But how to do the ranging? The best idea would be to send out a sequence of pulses that become weaker and weaker until no signal can be received anymore. By comparison of the power needed for sufficient reception, one can then draw a conclusion about the presence of reflectors. But this means that the LED current would need to be modulated, too, which makes things more complex. I wanted to use a standard Atmel AVR microcontroller with no external parts.
At this point I had an idea: What if I not the LED current but rather the sensitivity of the TSOP receiver were the variable? A look in the datasheet confirmed my thoughts: Filters almost never have infinitely steep transition bands (which is where the “pass” to “no pass” transistion occurs), especially analog ones like the bandpass filter inside the TSOP17xx receiver. The sensitivity vs. absolute frequency curve is given in the datasheet. My thought was that by frequency-modulating the transmission signal, I could change the sensitivity of the receiver in a way that lets me make a decision about the reflected IR power without having to change the LED current at all.
[1] TSOP1736 datasheet rev. 10, published by Vishay Semiconductor. Page 4, figure 1. See http://www.alldatasheet.com/datasheet-pdf/pdf/26588/VISHAY/TSOP1736.html for details.
So we set up a test circuit: An ATMega8 controller generates an 1:1 PWM signal to feed the IR LED. As for the receiver, we used an TSOP1738 type sensitive to 38kHz. The datasheet specifies a drop in sensitivity of 80-90% for a frequency deviation of 8kHz, which means we will sweep over the range from 30 to 38 kHz.The microcontroller does exactly that, sending out 1 millisecond of signal before turning off the IR LED and examining the TSOP output for response. If the TSOP has received something, the sequence is aborted and an index value about the frequency is returned to the main loop, where the decision about proximity or no proximity is made.
The AVR is configured to use its TIMER1 as a modulator in CTC mode, toggling the OC1A pin for each compare match while resetting the timer. Using an 11.059.200 Hz quartz as the main clock source, we needed a frequency divider of 145.51 (38 kHz) to 184.32 (30kHz), which can be reached by setting the OCR1A registers to the divider value corresponding to the desired frequency. Without the fractionals, of course, but that doesn’t matter much.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | const uint8_t lim_up = 145; // 38 kHz const uint8_t lim_dn = 184; // 30 kHz ... uint8_t measure( void ) { uint8_t k = 40; for (uint8_t i = lim_dn; i--; i >= lim_up) { // Set frequency divider OCR1AL = i & 0xFF; OCR1AH = (i >> 8) & 0xFF; // Enable transmitter for 1ms TCCR1A |= (1 << COM1A0); _delay_ms(1); TCCR1A &= ~(1 << COM1A0); // TSOP output low now? Output has certain lag, so it // will still be active, even if TX is off! if (!(PIND & (1<<PD2))) return k; k--; } // Aww, no signal returned at all. return 0; } |
(For this code example, the TSOP output is connected to PD2 and the LED to the OC1A pin of an ATMEGA32 processor.)
After setting up the threshold value and switching an indicator LED according to the results, this method proved very usable.
There IS one problem though: The TSOP contains an AGC (auto gain control) stage that changes sensitivity according to ambient light. If the ambient light levels change during operation, the overall sensitivity of the sensor and therefore the meaning of the index value are likely to change. This means that the sensor will operate much better at night than at day, but it also depends on the electrical and mechanical properties of sensor and sensed object.
For the future, I plan to add some other routines that allow live sensor calibration and tracking of the values over time, so that slow changes will not trip the sensor while fast changes will. Precise distance sensing will be pretty much impossible, because the response of the sensor depends on reflectivity of the object in range. It will, however, be sufficient for a aeparation of moving/not moving.
Another possibility is to use more than one transmitting LED and switch them between sequences. This way, multiple sensing zones could be created, while only one receiver is needed.
Fantastic Idea. But how do to get immunity from obstacle COLOUR. Dark and Light colour will reflect different intensity ?
That problem also occured to me when I tried this. Actually, it’s not so much of a problem for most applications where you’d try to sense differently painted objects because paints are made to please humans. Most of them look bland in infrared, pretty much the same brightness value all over ;-)
For surface types like transparent, plastic, metal, etc. the reflection magnitude will cause trouble indeed.
For my application it was more of a “there is something” and “it’s coming closer”, which means I’d sample the average reflection value and then try to get a reading of the rate of change. If it stops, I’d still see an offset from the average value.