Hello, I'm trying to build a system that can detect a BB (6mm diameter ball) moving through a barrel at the speed of ~100m/s.
I decided to use an IR (940nm) Led and an IR phototransistor aligned perpendicular to the barrel (a 3d printed support holds them aligned in place) so that when the ball moves through them, blocking the light, it can be detected. If my math is correct the sensor have 0.059 ms or less to detect it.
The system is wired to an Arduino Nano like in the diagram.
The following bit is part of a longer code that checks other sensor continuously, but here is the important part:
//Pin Names
const int photoGatePin = A0; //the IR Led and IR phototransistor are connected here
void setup() {
Serial.begin(9600);
}
void loop() {
//PHOTO GATE
if(analogRead(photoGatePin) > 200) { //if a BB passed through the Photo Gate
Serial.println("BB passed");
}
}
The IR couple is working properly and detects normally when an object blocks the light, however it isn't able to detect the BB moving through the barrel and I'm thinking that the problem is the speed of the BB.
How can I solve the problem?
If the BB is too fast how can I detect it? In some threads I read to use interrupts but from my understanding the Arduino have first to detect the BB anyway.
analogRead() is too slow to detect the passage of the ball. You need to be able detect beam blockage by using digitalRead().
For that to work, you need full range of response (HIGH to LOW) from the photosensor. You may have to adjust the load resistor on the phototransistor to get full range of output (blocked/unblocked). You may also have to eliminate stray light from the beam path and adjust the IR LED intensity by changing the current limiting resistor.
The fastest way to read a digital input is by polling, for example as follows:
while(PIND&4); //blocking wait for LOW on PortD, pin 2
do_something(); //start timer?
while (!(PIND&4)); //blocking wait for HIGH on PortD, pin 2
Quick and wrong? Here's the hastily composed code:
unsigned long time1;
unsigned long time2;
int a;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
}
void loop() {
time1 = micros();
a = analogRead(0),
time2 = micros();
Serial.print(time2);Serial.print(" ");
Serial.print(time1);Serial.print(" ");
Serial.println(time2-time1);
while(1){};
// put your main code here, to run repeatedly:
}
I have been working on a project recently where there was a problem with reaction time of opto slot detectors. What I read indicates that they are slow. Really slow. Surprisingly slow. One doc suggested that 8ms or more is common.
That's a catastrophic loss of accuracy for my project and quite possibly means that in this case, the BB will not be noticed at all. Check the data sheet to see what the story is for your particular detector.
With the default setting on a 16 MHz Uno, analogRead() takes about 110 microseconds to obtain a sample (roughly 9600 measurements per second).
I tried the posted sketch modified to take several readings by replacing the while(1) with delay(), 208uS on the first reading, then anywhere from 108 to 116 uS on subsequent readings. Possibly some setup code for the analog ports is run the first time, reading any of the analog ports in setup() eliminates the extra time for the first read of port A0.
@david_2018
Thanks! Interesting. How to read several analog inputs in sequence? Adding a "setup" (dummy read) for each "new" channel would bring down performance.
unsigned long time1;
unsigned long time2;
unsigned long time3;
int a;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
}
void loop() {
a = analogRead(0);
time1 = micros();
a = analogRead(0);
time2 = micros();
a = analogRead(1);
time3 = micros();
Serial.print(time2);Serial.print(" ");
Serial.print(time1);Serial.print(" ");
Serial.println(time2-time1);
Serial.print(time3);Serial.print(" ");
Serial.print(time2);Serial.print(" ");
Serial.println(time3-time2);
while(1){};
// put your main code here, to run repeatedly:
}
Railroader: @david_2018
Thanks! Interesting. How to read several analog inputs in sequence? Adding a "setup" (dummy read) for each "new" channel would bring down performance.
There doesn't seem to be any additional delay when switching between ports, just with the first initial read. ~~ I'm not sure where the source code for analogRead() is located, but there is likely some setup involved with the first read, such as setting the voltage reference source.~~ Looks like the source is in wiring_analog.c, but I don't see any initialization code on the first call.
If one wants to view the BB's travel through the barrel. I recommend using industrial X-Ray and a Industrial strength X-ray imaging system. You'll want to develop a remote firing system, as you'd not want to be in the room when the X-ray ramps up the KV to penetrate the metal of the gun barrel. I'd tie the firing sequence into the X-Ray on signal for synchronization. Fun project.
Lets see if we can speed this up ... how about 4.8µs? (using digital read as per reply#2) or near instantaneous using an interrupt (FALLING - see circuit).
From another thread: IR LED is 940nm and 60° angle
Let's use the most common one with the same specs at Digi-Key: OED-EL-1L2 (119,240 in stock)
These are rated for up to 100mA continuous.
You have 100ohm in series for (5-1.3)/100 = 37mA.
OPTIONAL: Let's boost the brighness using 47ohm for (5-1.5)/47 = 74mA
OP asked a question and 14 replies are present. Is this topic turning into "speculating genius's"?
I know, I contributed.
Maybe OP should have time to evaluate the replies?
208uS on the first reading, then anywhere from 108 to 116 uS on subsequent readings. Possibly some setup code for the analog ports is run the first time
That is about right. As the data sheet states, the first cycle of analog input takes 25 clock cycles and subsequent reads take 13 clock cycles.
how about 4.8µs? (using digital read as per reply#2) or near instantaneous using an interrupt
DigitalRead() is NOT used in reply #2, just 3 machine cycles (188 nanoseconds) are required for PIND, bit test and branch. This method is quite a bit faster than using an interrupt, which has to store/restore registers and the machine state.
DigitalRead() is NOT used in reply #2, just 3 machine cycles (188 nanoseconds) are required for PIND, bit test and branch. This method is quite a bit faster than using an interrupt, which has to store/restore registers and the machine state.
Yes, that'll work, but its not faster than an interrupt at detecting the pulse. For a 16MHz Arduino, it only takes a 62.6ns pulse to set an interrupt flag ... a 4.6mm BB moving at 100m/s will create a 46µs pulse. If the time it takes to enter the interrupt and get the timestamp is critical, then there's always input capture at hand. Anyways, using an interrupt is non-blocking and there's an eternity to process the data.
On the slow end of things, this 26µs analog read function should also work if used in a blocking while loop. Could even get a plot of the waveform using Serial Plotter.
Your math is correct. 60 µs is also what I have calculated.
PT334 is a photocell that has a rise time of 15µs and a fall time of the same so PT334 is a photocell with visible light that could do the job.
Then it depends on what your goal is: If you simply want to know if the bb passed, you can extend the signal using electronics or you can use interrupts.
As far as interrupts and speed are concerned:
Hardware interrupt processing on the nano = about 4 clock cycles to see an interrupt (synchronizer chain...), then @16 MHz you should be able to trigger an interrupt with a 0.25µs signal pulse, as your pulse is much longer 60µsec and as the rise and fall time of the PT334 is 15µsec, it should be possible to do but at the limit.
Hi, i think your problem is not related only to math, but mainly to hardware ... phototransistors are quick, but not all are so quick, better use a photodiode instead ... usually phototransistors have rise and fall times from 5 to 50 uS, except some model, where instead photodiodes works in nS ranges ... as example, BPV10NF have rise and fall times of 2.5nS ...
Also, may be better to use interrupts instead analog or digital read commands