I am working on a I.R detection program, and thanks to the help of quite a few others here on the forum, I have gotten to the point where I can detect objects however there is a problem.
When I place my hand in the path of the I.R. receiver/LED the program initially detects a break in the signal but then after only a few milliseconds it reverts back, meanwhile my hand is still obstructing the beam. I am thinking that there is something in my code that is unintentionally driving this?
Three other things that I have observed and that don't make sense to me are...
One, I can cut the power to the LED and the program still indicates that it is receiving a signal.
Two, I can completely black out the I.R. receiver and it also continues to indicate that it is receiving a signal.
Three, I can cut the power to the I.R receiver and it no longer indicates that it receives a signal.
Here is the code and a copy of the data sheet for the receiver that I am using...
/* Code to pulse pin 3 with a modulated signal
* Can be used to drive an IR LED to keep a TSOP IR reciever happy
* This allows you to use a modulated reciever and a continious beam detector
* By Mike Cook Nov 2011 - Released under the Open Source licence
*/
volatile byte pulse = 0;
ISR(TIMER2_COMPB_vect) // Interrupt Service Routine to pulse the modulated pin 3
{
pulse++;
if(pulse >= 10) // change number for number of modulation cycles in a pulse, was 8 on 7.5.14.
{
pulse = 0; // Re-set Pulse value to zero
TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off. TCCR2A register ^= Bitwise-shift (Compare Output Mode B, (Bit 5))
}
}
void setIrModOutput(){ // sets pin 3 going at the IR modulation rate
//pinMode(3, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS22);
OCR2A = 33; // defines the frequency 51 = 38.4 KHz, 54 = 36.2 KHz, 58 = 34 KHz, 62 = 32 KHz, 66 = 30KHz, 33 = 60 KHz
OCR2B = 16; // deines the duty cycle - Half the OCR2A value for 50%
TCCR2B = TCCR2B & 0b00111000 | 0x2; // select a prescale value of 8:1 of the system clock
}
void setup(){
setIrModOutput();
TIMSK2 = _BV(OCIE2B); // Output Compare Match B Interrupt Enable
Serial.begin(9600); // initialize serial communication:
pinMode(03, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
pinMode(07, INPUT); // I. R. Reviever pin
}
void loop()
{
//pinMode(03, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
int Dect = digitalRead(07);
//Serial.println (Dect);
if (Dect == HIGH)
{
Serial.println ("Object Detected");
}
else
{
Serial.println ("Scanning");
}
}
TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off. TCCR2A register ^= Bitwise-shift (Compare Output Mode B, (Bit 5))
A comment is useless if it explains what you are doing. A comment is useful if it explains WHY you are doing it.
This one falls into the useless category.
Long comments go on their own line. Having to scroll forever to read a comment is stupid.
int Dect = digitalRead(07);
Speaking of stupid, using octal constants to define pin numbers falls into that category.
//pinMode(03, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
That code does NOT do that. Do not comment out code posted here. DELETE IT if you don't need it.
If you are not getting consistent readings from the pin, it suggests to me that you have a floating pin condition. You need to provide a schematic. I suspect that you are missing a pulldown resistor between the digital pin.and ground.
IR receivers present a logical HIGH when idle and note receiving. They present a logical LOW when receiving the mark of a signal. (=modulated signal).
So just change the HIGHs to LOWs in your code, and it may get better.
Another problem you may encounter, is that many IR receivers will reject signals if they are constantly ON or ON/OFF for a certain amount of time (not really that long). Some models are designed for continuous rx.
You will get some idea by checking the data sheet for the IR receiver you are using.
Another thing is that the model of IR receiver you quoted is tuned to 30kHz modulation & in your code you have set modulation to 60kHZ. (assuming your comments are correct ) So make sure the frequencies match, for better performance.
oops....just realised that you need double the frequency because of the way you are configuring it....sorry....
I read your blog on the 10 common I.R. mistakes hoping that I missed something obvious, but no luck.
IR receivers present a logical HIGH when idle and note receiving. They present a logical LOW when receiving the mark of a signal. (=modulated signal).
So just change the HIGHs to LOWs in your code, and it may get better.
I had initially assumed that the receiver would go low when receiving a signal and I did try "LOW" but this made it worse actually. By worse I mean that it constantly detected a signal even when I cut the power to the LED. I read the data sheet and figured that it would confirm this one way or the other, but I found nothing concrete. I will do some more digging and hopefully something will turn up.
This is my first Arduino program so could you explain this statement a bit...
Another problem you may encounter, is that many IR receivers will reject signals if they are constantly ON or ON/OFF for a certain amount of time (not really that long). Some models are designed for continuous rx.
Currently I pulse for 10 and then rest for 10, according to the data sheet this is the minimum. I have tried 15 as well but did not notice a difference. I can't find anything in the data sheet about rejecting or requiring a constant signal.
First, read this page (and other articles in IR) and then post back with questions you need answered.
A mark is when the modulated signal is being sent and a space is when nothing is being sent.
IR receivers are designed for specific tasks. If you are plannig on sending a continuous signal with this Ir receiver you may hit problems (after you solve your initial problems)
In your code you are making life difficult for yourself....try out the Timer1 library instead, its much easier to use.
It looks like you are setting up Timer2 to interrupt at 60kHz and toggling the output pin every 10 times, which means you are producing 6kHz.
However, I am not really sure because I havent spent the time verifying the register setting you configured.
I looked at the fist link and everything I read fit with my understanding of I.R. systems thus far.
I am not running a constant signal and I am producing 30 KHz, see attached.
I looked at Timer1 as well but I need to look at it again because it was not obvious to me how to employ it the first time that I looked at it. I feel that I am close to understanding how to fix the code that I have, but then again...
One more thing that I noticed is that the voltage across pin 1 or the receiver measures 1.5 Volts when a signal is detected and drops briefly when I break the beam with my hand, but them immediately recovers despite my hand still blocking the signal. (Electrically it seems that the receiver thinks it is actually seeing a signal.) This seems to suggest a circuit problem. I tried a pull up resistor circuit (floating pin issue?) but this did not help.
the image you posted seems to be exactly 30kHz modulation. ON for 8 periods (266.66 uSecs) and off for 8 periods(266.66 uSecs). So if that is a capture of your signal then things are working OK....with the following caveats:
The signal output from the IR receiver should be inverted - from what you have displayed. (5V when modulated IR detected & 0V when no Ir detected). Also the image doesnt look like standard output from an IR Receiver...is the a copture of the IR Led emitter signal?
266 is a bit short for a Mark...try changing this to 600 or 1000 instead.
As per my previous post the circuit with the IR receiver will start rejecting this signal after less than 1 second as it needs longerpauses between full signals.
If you want to reliably detect a signal like the one you are generating, then you will need an IR receiver like the TSOP4038 (they are only available with 38kHz modulation, but could work at 30kHz modulation)
Regarding the 1.5V...are you sure you have a TSOP34830. How do you know? The numbers are usually in very small print on top of receiver (I usually need a strong maginfying glass to read it).
IF using a DMM to measure, you should see 2.5V when a signal is being received because half the time the output is HIGH and half the time the output is LOW, which averages out to 50% of 5V =2.5V. Of course if your power supply is 3.3V then you would get 1.65V.
Otherwise, please post how you have wired the IR receiver & connected to the Arduino.
The signal output from the IR receiver should be inverted - from what you have displayed. (5V when modulated IR detected & 0V when no Ir detected). Also the image doesn't look like standard output from an IR Receiver...is the a capture of the IR Led emitter signal?
Correct, it is actually a plot of the LED pulse. Originally I was working with 8 on then 8 off. I have since bumped it to 10 obviously, but I forgot that the image was of the shorter pulse. Would it be beneficial to have a plot of what the receiver is producing? The voltage readings are a constant 1.596 volts accept for brief drops (~0.9 volts) when my hand initially breaks the beam.
266 is a bit short for a Mark...try changing this to 600 or 1000 instead.
I have tried 10, 15, 20, 30 & 50 for marks and the longer the mark the worse it gets?
As per my previous post the circuit with the IR receiver will start rejecting this signal after less than 1 second as it needs longerpauses between full signals.
I need more time on this as right now I am not sure how to increase the length between marks...
If you want to reliably detect a signal like the one you are generating, then you will need an IR receiver like the TSOP4038 (they are only available with 38kHz modulation, but could work at 30kHz modulation)
I can certainly try this but in my research prior to purchasing parts I ended up with the TSOP34830 because I need to stay away from 38 KHz because 38 KHz is used by the main circuit/program to actually steer the robot. 30 KHz is dedicated to the robot's vision system.
Regarding the 1.5V...are you sure you have a TSOP34830. How do you know? The numbers are usually in very small print on top of receiver (I usually need a strong maginfying glass to read it).
Yes, I have a TSOP34830. I confirmed it on the packing slip and I also read it off the receiver itself as you described.
IF using a DMM to measure, you should see 2.5V when a signal is being received because half the time the output is HIGH and half the time the output is LOW, which averages out to 50% of 5V =2.5V. Of course if your power supply is 3.3V then you would get 1.65V.
It seems to be a constant 1.596 volts. (I am using it with a Fio V2: 3.3 volt microcontroller.)
Otherwise, please post how you have wired the IR receiver & connected to the Arduino.
I will post a proper schematic but for now know that I have a limiting resistor on the LED and everything else is wired directly to the Fio with jumper clips. I reviewed the TSOP34830 data sheet and this seems to be all that is required.
The 1.596 is correct, because you are sending marks and spaces 3.3/2 = 1.65V which ic close enough to the 1.596V ( allowing for slight difference between the lenght of your marks & spaces). So maybe there is no problem with your circuit.
You may well (probably will) get crosstalk between the 38kHz & 30kHz receivers unless the IR beams are physically isolated from each other.
Looking at the plot of the output of the IR receiver should be your first(-ish) step in troubleshooting for you. Please post an image.
Overall it sounds like the circuit is working & that you may be confusing the (inverted) way the output of the IR receiver works, as per my earlier posts.
You may well (probably will) get crosstalk between the 38kHz & 30kHz receivers unless the IR beams are physically isolated from each other.
While I am developing the vision system I'll stick with the 30 KHz signal, if I end up getting crosstalk it should be easy to convert it up to 58 KHz if needed.
Here is the plot of the receiver output. It is a square wave which was not what I expected. In addition I tried to capture the voltage into the receiver and it came in at just above 0 volts while the volt meter reads 3.253?
BTW: you may still get the same issues of interference @ 58kHz, unless only one LEd is transmitting at the same time& in the same area. (standard IR receivers are available @ 30,33,36,38,40 & 56kHz only AFAIK. 455kHz are no longer available)
Okay now that we know that the TSOP seems to be preforming as it should it looks like I have to look into increasing the space between the marks. I have looked into the the mark/space relation ship and it seems to be the same thing as the duty cycle, but this does not seem to agree with my understanding of your statement below...
As per my previous post the circuit with the IR receiver will start rejecting this signal after less than 1 second as it needs longerpauses between full signals.
Now that I read this I am thinking that you mean the space after one pulse and not 10 as I had assumed? Please confirm.
Thanks for sticking with this thread. I learn best by example and so I knew that there was a chance that I would bite off more than I could chew, but I had now idea that I would struggle on this level.
For starters, I would increase the duration of the mark to between 600 and 1000uSecs in duration. The same for the space - maybe make the space twice the duration of the mark.
Most IR receivers are designed to reject noise. They treat continuous marks/spaces as noise. However, depending on your situation you may get away with it. Playing around with the duration of the marks and spaces will help. The closer the ir receiver is to the emitter the better, as it may overload the internal rejection circuitry. A read of the datasheet will also help by telling you how long of a gap you need after marks & maybe the typical mark length it is designed for.
Normally a complete IR signal will last say around 60->100 ms. Depending on the the specs of the IR receiver it may start rejecting the signal as noise if it lasts longer than 500->1000 ms.
There seems to be some confusion between mark/space and modulation pulse.
Typically a mark is a series of modulated pulses. A space is when no modulated IR is being sent.
A modulated IR signal, is usually at a fixed frequency - say 40kHz. If you repeatedly turn the IR on for 25 usSecs and of for 25 uSecs then you have a modulated IR signal 40kHz @ 50% duty cycle.
A modulated IR signal of say 600uSecs total duration is a a mark of 600uSecs.
The most important fact is that you are trying to use the IR receiver for a use it was not intended. You would be better swithing to the model I mentioned earlier and using the 30kHz for the alternative funcion.
Have you figured out how both systems will not be transmitting at the same time?
I can get the mark down to 600 uSec but I am stuck on how to increase the space. How is this achieved? I tried adding a delay statement just to see what happened and it did not work. I am assuming that there is a registry setting?
/* Code to pulse pin 3 with a modulated signal
* Can be used to drive an IR LED to keep a TSOP IR reciever happy
* This allows you to use a modulated reciever and a continious beam detector
* By Mike Cook Nov 2011 - Released under the Open Source licence
*/
volatile byte pulse = 0;
ISR(TIMER2_COMPB_vect) // Interrupt Service Routine to pulse the modulated pin 3
{
pulse++;
if(pulse >= 18) // change number for number of modulation cycles in a pulse.
{
pulse = 0; // Re-set Pulse value to zero
TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off. TCCR2A register ^= Bitwise-shift (Compare Output Mode B, (Bit 5))
}
}
void setIrModOutput(){ // sets pin 3 going at the IR modulation rate
TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS22);
OCR2A = 33; // defines the frequency 51 = 38.4 KHz, 54 = 36.2 KHz, 58 = 34 KHz, 62 = 32 KHz, 66 = 30KHz, 33 = 60 KHz
OCR2B = 16; // deines the duty cycle - Half the OCR2A value for 50%
TCCR2B = TCCR2B & 0b00111000 | 0x2; // select a prescale value of 8:1 of the system clock
}
void setup(){
setIrModOutput();
TIMSK2 = _BV(OCIE2B); // Output Compare Match B Interrupt Enable
Serial.begin(9600); // initialize serial communication:
pinMode(03, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
pinMode(07, INPUT); // I. R. Reviever pin
}
void loop()
{
//pinMode(03, OUTPUT); // Just enable output on Pin 3 and disable it on Pin 11
int Dect = digitalRead(07);
//Serial.println (Dect);
if (Dect == LOW)
{
Serial.println ("Object Detected");
}
else
{
Serial.println ("Scanning");
}
}
The most important fact is that you are trying to use the IR receiver for a use it was not intended. You would be better switching to the model I mentioned earlier and using the 30kHz for the alternative function.
Where was this? Are you referring to your Timer1 comment? Also, why is it not correct to use the receiver in this manner?
Have you figured out how both systems will not be transmitting at the same time?
No, I tested my theory and you are correct, the 30 KHz receiver does indeed pick up the 38 KHz signal. How is it then that typically I.R. toys operate at both 38 KHz and 56 KHz and they do not interfere with each other?
Did you check the output with your LA? You should be getting 600uSecs Mark followed by 600uSec space repeating.
So in your ISR, you should be getting both the mark & space equal because you are using one check for 18 and toggling on/off every time pusle hit 18.
So add in some more logic/code. to get 600 mark use 18 ; to get 1000uSec space add in additional IF statments for a count of 30 = (18/600*1000). One time check for 18 (mark) the next time check for 30(space)
(FYI: if I was designing this from scratch I wouldn't be doing this stuff in an ISR, but in the main loop using a delay)
Delay won't work within the ISR, which is probably why it failed for you. Your code should never spend much time executing in the ISR either.
Before I change direction answer this please... How will your approach allow Arduino emit a signal and detect it without interrupts? I am all for a more straight forward approach, I just can see what you are seeing.
From my previous post.......
Did you confirm the behaviour with your LA & did you try my suggestion about 18/30 within the ISR. If so what did you see on your LA in both cases?
Regarding change of direction, I wasnt really suggesting that you change, merely pointing out that I would approach it differently...like using existing libraries,that have alredy solved issues in advance & using the main loop in preference to the ISR. The 18/30 suggestion should work for you using the existing approach. You just need to write the code yourself.
18 pulses produced a 600 uSec mark verified by the scope. I have not worked out how two write the code which doubles the space. I am thinking that I should take advantage of the toggle feature and tie it to that. I just have not had time to write it.
Not sure if this is relevant but 18 pulses produces what seems to be garbage in that the receiver delivers a steady stream of 0s & 1s. It actually functions (somewhat) if I set the mark to 70 pulses?!
I understand what you mean about the existing libraries however when I looked at them initially nothing jumped out at me. I am am wondering, is it less work to finished what I started or figure out how to incorporate the library code?
Is a 58 KHz frequency going to relieve my cross talk issue?
58kHz....I am only aware of 56kHz receivers. You are likely to have crosstalk at all standard frequencies. In general, 56 &38 would be better than 30&38.
However, if you can make the beams directional by physically screening them from each other, it may work. Will need a bit of trial and error on your part. IR signals will bounce off walls, ceilings and any reflective surface like glass etc. Putting your IR emitters inside 6mm pipes 3cm long would help - as long as you can get away with pointing at the targets.
It will also be important to use the minimum possible current thru each emitter.
Would RF or ultrasound work for either of your sensors?