help with measure speed of object. photo-interrupter

Hi,
I usually program VHDL in FPGAs, so im not too familiar with MCUs.
i thought i might give Arduino a try this time. Any help would be much appreciated.

i would like to measure the speed of a moving object.
the set up is going to be 2 optical sensors. and 2 laser pointers.
this will create 2 beams.
as the object pass, it will break the first beam. then the second.
the time taken to break the beams, will be stored.
with the known distance, and the measured time, the speed of the object can be calculated.

my questions are:

  1. how do i make a counter to measure the time taken to break beam1 and beam2?
  • do i simply make a “if-statement”, and a “count++” to measure the number of clock cycles?
  1. how do i detect “rising_edge” or “falling_edge” of beam1 and beam2?
    -interrupts?
    i cannot really use this because i am reading the sensors from the ADC.
    sadly this cannot be changed because i need an adjustable threshold.

  2. is it possible to store, letsay, 10 measurements in an array.

attached is a diagram of the set up.
any links to sample codes, or a description will be much appreciated. thanks.

photogates.png

The Arduino already has two time-keeping functions - millis() and micros(), depending on the accuracy you need.

  1. how do i make a counter to measure the time taken to break beam1 and beam2?
  2. do i simply make a "if-statement", and a "count++" to measure the number of clock cycles?

No.

  1. how do i detect "rising_edge" or "falling_edge" of beam1 and beam2? -interrupts?

Interrupts would work.

i cannot really use this because i am reading the sensors from the ADC. sadly this cannot be changed because i need an adjustable threshold.

Then you are using the wrong devices/technique.

thanks for the quick reply. i will look into it, and update this post.

You want to look at kinds of light detectors. http://en.wikipedia.org/wiki/Photodetector Look at phototransistors, specifically.

i should have mentioned this before. i am using photodiodes.
it produces voltage ranging from 0 to 5V, depending on light intensity.
hence, using the ADC to just make a threshold thats higher than ambient light, but less than laser pointer.

Then put the output of the photo diode through a voltage comparator first. This turns it into a digital signal and you can set a threshold with a pot on the other input of the voltage comparator.

i was hoping not to use too much additional hardware. but i guess that would make the programming alot easier.

You haven't said what sort of time you are expecting and what sort of resolution you need. Taking an analogue to digital conversion takes time that you might not have. Without proper information it is impossible to give good advice.

Seems like you don't need additional hardware. Assuming millisecond resolution would do, when you detect the object breaking beam #1, store the time using millis() and then store the time using millis() again when the object breaks beam #2. Subtract the two, divide by the distance between the beams and you've got the speed. I.e., something like:

#define BEAMDIST 1  // meters
#define SENSOR1 0   // ADC pin
#define SENSOR2 1 

int time1 ;
float deltaT ;

setup() {
}

loop() {
    if (analogRead(SENSOR1) > THRESHOLD) {
        time1 = millis() ;
    }

    if (analogRead(SENSOR2) > THRESHOLD) {
        deltaT = (millis() - time1)/1000.0 ;
        Serial.print("speed: ") ;
        Serial.println(deltaT/BEAMDIST) ;
        Serial.println(" m/sec") ;
    }
}

As Grumpy says though, without knowing the speed and resolution required all ideas are moot.


Rob

I agree with Grumpy_Mike here, a comparator will have a HIGH or LOW signal , which could be use at the input of the interrupt. The ATMega328 - Arduino UNO have 2 interrupt input. jmknapp got the method of calculated the result, but using polling in that case may or not work propely. Maybe using :

while ( !beam1)
{
  return;
{
do 
{
  // start counting...
}

while (!beam2)

[code] 

OK.. I may be wrong here...anyway, you have the idea... ( I do my best doing programming here )

[/code]

Polling is faster and more deterministic than interrupts (well at least if interrupts are used with Arduino functions).

However we're still waiting for the design brief :)


Rob

specs:
no. of objects = 10 (might change)
object length = 0.3 meters
max speed of object = 30 meters/s
min speed of object = 2.5 meters/s
sensor distance = 0.1 meters (apart)

hence, when the object passes the beams,
the photodiode signal will be LOW for 0.3 meters.
but all i need is the “falling_edge” of beam1 and beam2.

here is the code so far without additional hardware.
break beam1 calculate, break beam2, stop calculate.
store data somewhere.

int count={0,0,0,0,0};

void setup() {
Serial.begin(9600);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
}

void loop() {

int sensorValue1 = analogRead(A5);
int sensorValue2 = analogRead(A4);

if(sensorValue1>700)
{
digitalWrite(12, HIGH); // set the LED on
}
else
{
digitalWrite(12,LOW); // set the LED off
}

if(sensorValue2>700)
{
digitalWrite(13, HIGH); // set the LED on
}
else
{
digitalWrite(13,LOW); // set the LED off
}

if(digitalRead(13) == LOW & digitalRead(12) == HIGH){
//for (int i=0; i <= 6; i++){ //store data in an array
count[1]++; //count*++;[/color]*

  • // } *
  • }*
    _ Serial.println("---------------------------------------");_
    _ Serial.println(count[1]);_
    _ Serial.println(count[2]);_
    _ Serial.println(count[3]);_
    _ Serial.println(count[4]);_
    _ Serial.println(count[5]); _
    }
    [/quote]
    count[1] is time taken to break 2 beams.
    Problems:
    1. this is using polling method, which is not that accurate.
    2. i can only measure the first object. i cannot measure a second object with this code.
  • – i was thinking of storing results in something like an array.*

You have about 3mS between pulses then, not bad but not a lot of time either.

As the code stands though you haven’t got a chance, at the very least those Serial.prints will block the program forever.

You should separate the acquiring of data from the processing of it. Don’t Serial.print or play with LEDs, just get data, Then you can muck around.

Personally I think you’ll need the external comparators (or maybe just schmitt triggers), I doubt the analogRead() is fast enough (but maybe). Anyway do something like this.

#define N_OBJECTS 10
unsigned long times1 [N_OBJECTS];
unsigned long times2 [N_OBJECTS];
unsigned long * ptr1;
unsigned long * ptr2;
byte count;
byte  last_input1, last_input2;


ptr1 = times1;
ptr2 = times2;
count = 0;

do {
   if (input1 != last_input1 && input1 = HIGH) {
      // leading edge on 1
      *ptr1++ = micros();
      count++;
      last_input1 = input1;
   }

   if (input2 != last_input2 && input2 = HIGH) {
      // leading edge on 2
      *ptr2++ = micros();
      count++;
      last_input2 = input3;
   }
} while (count < N_OBJECTS * 2);

// now process time array

NOTE: Far from working code, just the idea.


Rob

You could do this to make the ADC clock faster:

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;

That will take down the time for an analogRead() from 111 usec to 16 usec. That’s only about 0.5% of the 3 msec fastest interval.

Using micros() instead of millis() gives 4 usec resolution on each measurement or 8 usec total. Each loop where the thresholds aren’t triggered would take a little more than 32 usec. Seems like you could get 97%+ accuracy pretty easy.

Not sure about your issue using an array. Why not just declare an array size 10 and stuff the results in there, incrementing a pointer each time? E.g., a circular buffer:

#define SIZE 10

int results[SIZE] ;  // speeds in mm/sec
int fptr = 0 ;

...

results[fptr] = measuredSpeed ;
fptr = (fptr + 1) % SIZE ;

...

That way the array will always contain the last SIZE measurements, after it fills up the first time anyway.

// print the last SIZE results
for (i = 0 ; i < SIZE ; i++)
	Serial.println(results[(i + fptr) % SIZE]) ;

Joe

Polling is faster and more deterministic than interrupts (well at least if interrupts are used with Arduino functions).

Care to elaborate on this? Polling requires that you happen to look at the pin just after (nanoseconds after) the signal change occurs.

With an interrupt, everything stops and the ISR is called. How you can get more deterministic or faster than that escapes me.

Now, easier to use? Yes, polling is much easier to use.

Polling requires that you happen to look at the pin just after (nanoseconds after) the signal change occurs.

Only if you do it like the OP was, as part of a massive function that twiddled everything else and it's brother.

If you do nothing else but look at a pin the code would look something like this (appolgies if it's not right, I haven't done much assembly lately)

loop:
    in     r16,PINB   // 1 cycle
        andi  r16,1       // 1 cycle
        breq  loop        // 1 cycle if false, 2 if true
// pin has gone high, we can do useful stuff here

so the worst case is when the pin goes high just on the "in" instruction, in this case the latency is 4 cycles or ~262nS. Now lets look at an interrupt,

// pin goes high
// indeterminate delay because we don't know what instructions were in progress
// then save context
push PC      // each push is 2 cycles
push r0
in   r0,SREG
push r0
push r1
push r2
push r3
push r4
push r5
push r6
push r7
push r9
push r10
push r11
push r12
push r13
push r14
push r15
push r16
push r17
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r28
push r29
push r30
push r31
jmp isr_func
// now we can do some useful work

The AVR has bugger-all hardware support for context switching so it has to push a lot of registers, in this case about 70 cycles or 4.5uS. OK I'm stretching it a bit here I suppose, the compiler probably doesn't push all the regs, but it's going to push a few and you have no idea how many.

I think you can reduce the latency (and certainly help the determinism) by having a do-almost-nothing loop

do {} while (myFlag);


ISR  xx () {
   myFlag = false;
}

And maybe add ISR_NAKED to the ISR definition and handle the regs yourself and probably other things that make sure there aren't too many registers being used.

I still don't think you'll get as fast as a tight polling loop.

Also I qualified my comment with

at least if interrupts are used with Arduino functions

If you use attachInterrupt() you add a whole new layer of code to the latency.


Rob

Thanks for taking the time to explain your reasoning. I can understand where you are coming from, if loop() is doing very little. If loop() has a lot do, then interrupts can be a lot faster - not to mention the fact that polling requires look at the pin WHILE it is HIGH (or LOW).

For very short duration signals, which I expect the "HIGH while a projectile is going by" signal to be, polling could (not will, just could) miss it altogether, if there is a lot going on in loop().

loop: in r16,PINB // 1 cycle andi r16,1 // 1 cycle breq loop // 1 cycle if false, 2 if true

The situation is even rosier - the AVR has sbis (skip if bit in IO register is set) and sbic (skip if bit in IO register is cleared) instructions, so the sequence can be even shorter than that - the AND operation isn't needed!

Yep, it depends on what else is going on, the approach used in any one application depends on a lot of things. I guess that's why we get the big bucks :)

SBIS/SBIC, I'd forgotten about them.


Rob