Detecting a small and fast object

jremington:
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.

Phototransistors may be too slow, but will be fastest with a low value load resistance on the
collector, such as 1k or less, which means fairly intense illumination.

You could use a photodiode for greater intrisic speed, but that requires a transimpedance amplifier and
comparator to generate a logic signal. If you go to these lengths its a no-brainer to add a pulse-stretcher
as well to make it easier for the software on the Arduino - for instance a 7555 monostable.

jremington:
analogRead() is too slow to detect the passage of the ball. You need to be able detect beam blockage by using digitalRead().

Ok, so I just wire the system to a digital pin instead of an analog one? The IR couple gives me a full response from 0 to 1023 and they are slotted in a 3d printed support inside the barrel, so no stray light.
I never read of polling as a function in Arduino, I'll document myself on this one.

dlloyd:
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).

4.8”s? How? I just wire the system as it is on a digital pin? What do you mean by "Falling"? Am I wrong or the 47ohm resistor should be before the LED? Also dlloyd thank you very mych for bearing with me along my posts.

dlloyd:
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.

int analogReadFast(int ADCpin) {

byte ADCregOriginal = ADCSRA;
ADCSRA = (ADCSRA & B11111000) | 5; //32 prescaler
int adc = analogRead(ADCpin);
ADCSRA = ADCregOriginal;
return adc;
}

I don't need timestamps, I just need to know if the BB passed or not and count it, after that that's not a problem if the Arduino takes longer to process the data as long as it's faster than a second BB passing (and I think that's way faster with 20-30 BB/s). Referring to the code you posted I barely understand it (cause of my ignorance), if the digital pin route is simpler and gives me what I want I think I'll follow that.

MarkT:
Phototransistors may be too slow, but will be fastest with a low value load resistance on the
collector, such as 1k or less, which means fairly intense illumination.

You could use a photodiode for greater intrisic speed, but that requires a transimpedance amplifier and
comparator to generate a logic signal. If you go to these lengths its a no-brainer to add a pulse-stretcher
as well to make it easier for the software on the Arduino - for instance a 7555 monostable.

I can try reducing the resistor then, given I have enough light to trigger the PT.
From what you are saying it seems I need more external hardware, but that is a problem for me space-wise, sorry

Hi,
What you are trying to build is a "Chronograph".

Try googling..

chronograph arduino

If you can get the response from the phototransistor to go from a voltage level below the voltage threshold for a digital LOW to above the voltage threshold for a digital HIGH, you will not need to use an ADC which is relatively slow compared to using a digital input.

Tom... :slight_smile:

TomGeorge:
Hi,
What you are trying to build is a "Chronograph".
Try googling..

That's half right, a chronograph is composed of two sensor to measure the speed, but the configuration and use-logic is the same.
I have to try the digital route

4.8”s? How?

This is just the speed of Arduino's digitalRead() function, but it doesn't account for the rise/fall time of the TEFT4300 phototransistor signal (2”s/2.3”s typical with 100 load) or any additional processing time that might be relevant. I recommend using an interrupt pin on your Arduino.

Here's a circuit update where I changed the 10K phototransistor resistor to 1K for faster response. If the signal level doesn't change enough, may need to increase this resistor to 1.5K, 2.2K, 2.7K etc until it works properly ... then use the next higher value.

Am I wrong or the 47ohm resistor should be before the LED?

It makes no difference.

EDIT: The analogReadFast() function I provided is just so you could use the Serial Plotter as an oscilloscope to partially see what the signal looks like

Balistic chronograph ... in 2018 we had a similar discussion in the Ita forum, and i published a "principle schematic" about a standalone unit (using photodiodes) ... you can take example from it if you want ... CRONOGRAFO BALISTICO - #341 by Etemenanki - Software - Arduino Forum

its not faster than an interrupt at detecting the pulse.

You should actually look into this topic!

The method shown in reply #2 is about 10x faster than using, say, the INT0 interrupt, because you have to do something with the result of the detection. The minimal INT0 ISR is about 30 machine cycles end to end.

jremington:
...
The method shown in reply #2 is about 10x faster than using, say, the INT0 interrupt...

Sorry, i'm not a programmer, but isn't this always related to the speed of your loop() ?

I mean, not the speed of the reading itself, but if in the loop you have a lot of other things, don't they interfere with your reading speed, while instead an interrupt acts immediately at trigger, stopping all the rest ? ... or those instructions you mentioned stops all the rest like an interrupt ?

You should actually look into this topic!

Huh? I'm referring to the guaranteed time it takes to "detect" a pulse (flip a bit in the interrupt register). You're referring to the time it takes to enter and leave the interrupt ... apples and oranges. To me, what's important is detecting the pulse ... we have essentially eternity in time to completely process an interrupt (and some code) prior to arrival of the next BB. DISCLAIMER: I'm not a programmer, so I'll be very interested to know there's something amiss here.

I'm referring to the guaranteed time it takes to "detect" a pulse (flip a bit in the interrupt register)

What you are missing is that to be at all useful, the program has to detect that bit flip and DO something with it.

Taking that fact into account, in any practical application, interrupts turn out to be significantly slower than polling.

Sorry, i'm not a programmer, but isn't this always related to the speed of your loop() ?

No, because the method shown in reply#2 is blocking. It is an extremely tight loop that waits for a PORT bit to flip, so the Arduino can't be doing anything else.

Here is the machine code corresponding to a similar line of code (Atmel Studio 7)

   while ((PIND&4) == 0);
  80:	4a 9b       	sbis	0x09, 2	; skip if bit 2 is set, I/O register 9
  82:	fe cf       	rjmp	.-4      	; jump back to 0x80 <main>

jremington:
...
No, because the method shown in reply#2 is blocking. ...

Oh, ok, i was just thinking about a "free-running" program ... that instead enter in "shoot waiting" and do nothing other til the shoot ...

What you are missing is that to be at all useful, the program has to detect that bit flip and DO something with it.

Not missing, treating it separately. At 30 BBs/sec, there's 33.333ms of time to DO something. That's 533,333 CPU cycles ... I just rounded this off to "eternity". Have to be careful with polling pulses of short duration ... the loop duration needs to be less than the duty cycle of the pulse (not period), otherwise pulses will be randomly missed. That's why I think using an interrupt is more "useful". We don't yet know the resulting waveform ... an oscilloscope trace would be nice.

I'm not saying the method shown in reply#2 won't work ... it will providing the pulse has adequate width.

It could look something like this (or inverted) and be only 100ns width (for example).

Just saying that an interrupt is faster at detection, is non-blocking and that there's more than ample time for processing.

You are still missing the point. The same considerations and timing apply to flipping a bit in an interrupt register and a port input register.

The difference in the two approaches is how long it takes the user program to do something useful with the bit flip.

Feed LED with 40kHz.
Tv remote control working frequency 40 kHz , 0.059 ms17 kHz make it 20 kHz, so bullet is blocking 2 pulses, then google for missing pulse detector.

The same considerations and timing apply to flipping a bit in an interrupt register and a port input register.

I have to say that I don't understand why the same timing is applicable. I always like to break down the timing into its specific details. Its mentioned somewhere (I don't have a link) that the interrupt signal needs only last longer than one MCU cycle (lets say 62.6ns) to reliably set the interrupt flag. It can also trigger with less duration but will be less reliable). Also, this can happen while already servicing an interrupt, so I just clear the flag(s) at the end of the routine.

From Gammon's link, it says:

Can interrupts occur while interrupts are disabled?
Interrupts events (that is, noticing the event) can occur at any time, and most are remembered by setting an "interrupt event" flag inside the processor. If interrupts are disabled, then that interrupt will be handled when they are enabled again, in priority order.

I'm glad that there is so much discussion about this topic. IMHO the most interesting routes are dlloyd's and jremington's one, but I still don't know what of the two is the most efficient.
That said, given I'm not particularly educated in electronics, I'll try to rewire the sistem to a digital pin using interrupts and see if it is reliable at detecting it. I'll post here the results when I'll get to do it, and then we'll see how to move from there

EDIT: I'm documenting myself on interrupts and I'm reading that all variables edited in the interrupt function need to be declared as volatile but, from arduino reference:

int or long volatiles

If the volatile variable is bigger than a byte (e.g. a 16 bit int or a 32 bit long), then the microcontroller can not read it in one step, because it is an 8 bit microcontroller. This means that while your main code section (e.g. your loop) reads the first 8 bits of the variable, the interrupt might already change the second 8 bits. This will produce random values for the variable.

My thought is: can I just write in the interrupt function to call another function? So that it just calls an external function that increase a number and then it ends, keeping on with the loop.

UPDATE: I rewired the system on the digital pin 2 but it still wasn't enough fast.
I introduced the interrupt and my code is this one now (stripped down to the important bit), but it still doesn't detect the BB reliably, only randomly just as before:

//Pin Names
const int photoGatePin = 2; //the IR Led and IR phototransistor are connected here

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, photoGateCheck, RISING );
}

void photoGateCheck() {
  Serial.println("OK");
}

void loop() {
  }

Now I'll decide if I should switch to a 1k ohm on the phototransistor or follow jremington advice. I think I'll try jremington route first just because is software-way.
On this purpose, jremington can you please elaborate on this?

  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

Does this code block my loop? I need the arduino to keep checking other things.
What does "PIND&4" represents?

When you're ready to test using interrupts, its best to keep an interrupt function as simple as possible and do everything else in the main loop. Here's some pseudo code to get started:

const interruptPin = 2;
volatile bool bbCountFlag = false;
volatile unsigned int bbCount = 0;
unsigned int bbCountCopy = 0;

void setup() {
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), nextBB, FALLING); // or RISING
}

void loop() {

  if (bbCountFlag) {
    noInterrupts();
    bbCountCopy = bbCount;
    interrupts();
    bbCountFlag = false;
  }
  // do something using bbCountCopy
}

void nextBB() {
  bbCount++;
  bbCountFlag = true;
  EIFR = bit (INTF0);  // clears flag for interrupt 0 (adds minimal debounce)
}

Then why not place only the flag in the ISR, and do all the rest outside ? ... :wink:

Then why not place only the flag in the ISR, and do all the rest outside ?

Yeah, I did say as "simple as possible", but there is some time available. For instance, in order to prevent overloading other code using interrupts like using the serial library, a higher baudrate allows less time to spend in an ISR function. If printing is at 115,200 baud, then there's about 86.8”s per character or about 1388 MCU cycles available.

Most of the newer MCUs have a "glitch and debounce filter" feature for digital inputs. I think the time spent in an ISR can partially emulate this by ignoring glitches or bounce about the first edge of the pulse by re-clearing the interrupt flag at the end of the ISR function. This wouldn't filter/debounce when the pulse returns to steady-state, but if the pulse is noisy only at one end of the pulse, then one of the 2 circuits should work (normally low or normally high signal).

I'm not so good in coding, i'm mainly an hardware person ... will tend to always take care of debouncing contacts with hardware systems ...