Accuracy of MOCH22A based Infrared Speed Sensor Module

Back in May I did use TCST 2103 infrared light barrier to measure real rpm numbers of a micromotor. The measurements did make sense (14700rpm was measurable), and putting something between the forks and removing it resulted in exactly one interrupt.

Yesterday I did test with new Infrared Speed Sensor Module I got from aliexpress. That module has the beauty of only 4 connection lines (GND, VCC, D0 and A0), with all supporting electronic on the module itself. Also the 2nd LED besides the power LED goes off when something is between the forks.

I glued a paperboard stripe on a motor wheel and was surprised that PWM=80 was enough to get 0 interrupts from the module -- with slower speed I did get interrupts:

Next I did single measurements whithout the wheel:

What I cannot explain and ask you for an explanation are the following observations:

  • if I move a cent from top beteen the forks and remove back to top, I get 4 interrupts
  • if I move a cent from left beteen the forks and remove it to the right, I get 5 interrupts

I tried RISING, FALLING, CHANGE -- all with the same result on single measurement.

So today I thought maybe the battery I glued the module on can have some bad connection to the module and influence the measurements. After I removed the battery, the repeated measurements did not show any difference.

Is the module just bad?
What can be done to get a single interrupt for a single test?

(The A0 values are <50 or >900)
When back at home on weekend I can try the other module, I bought two of them (1.15$/pc).

Forgot to mention that I did connect pin D0 of module (digital line) to pin D3 of Arduino Uno and used "attachInterrupt(digitalPinToInterrupt(3), incVarA, RISING);" to attach ISR

Hermann,

I have used something similar (probably the same) but have not encountered accuracy problems. Could it be a faulty sensor perhaps?

Perhaps, I will check with 2nd same type module on weekend.

This is the bare minimum program I used:

int cnt=0;

void incVarA(void) {
        ++cnt;
}

void setup(void) {
	Serial.begin(57600);
        pinMode(3, INPUT);

        attachInterrupt(digitalPinToInterrupt(3), incVarA, FALLING);
}

void loop(void) {
	Serial.println(cnt);
}

What I cannot explain is why the counter gets increased by 2 already when moving a cent between the forks (DO is 0 if space between forks is empty, and 1 if not). How can a transition from 0 to 1 trigger 2 FALLING interrupts?

Hermann.

OMG!

I thought about my setup and asked, what might be wrong with my setup if the sensor is NOT broken.

I was pretty sure that my code was correct, and I cannot change the VCC and GND connections.
So I tried to connect sensor module A0 (analog) pin to digital pin 3 of Arduino Uno — and everything WORKED!

Counter increases

  • when removing cent between the forks for FALLING
  • when putting cent between the forks for RISING
  • in both cases for CHANGE

Now that ISR (Interrup Service Routine) worked with single tests I went back to motor.
And I did work with bitlash again (http://bitlash.net/), a programmable command shell for Arduino.
Since bitlash does not allow to attach interrupts in its minimal command set, I did start with bitlash demo userfunctions.pde and ended up with code at bottom of this posting.

I did use super glue again to attach the sensor to 9V battery at just the height needed to measure the paperboard rotating with the 20mm diameter wheel:

First I did turn on motor at very slow speed, did reset conter variable by re function, and did count for 50 or 100 turns of the wheel. Then I did use ra function to print the counter value and it matched to what I have counted ±1.

Then I increased motor speed to PWM=60 and again no single interrupt was detected (too fast).

So I went back to PWM=55 and did count with command line defined function pa:

> function pa { print millis(), "ms ", ra(); }; 
saved
> pa
498231 ms  25960
> pa
500438 ms  26166
> pa
501723 ms  26286
> pa
502792 ms  26387
> pa
503726 ms  26474
> pa
504643 ms  26559
> pa
505434 ms  26633
> pa
506550 ms  26736
> pa
507444 ms  26818
>

Since the speed was really constant we see a linear function:

Then I determined the interrupt counts per second:
(26633-26166)/(505434-500438)*1000 = 93.4

This translates to 93.4rps or 5608rpm at motor shaft, not too bad for PWM=55.

Here is the bitlash code with ISR:

#include "bitlash.h"

int cnt=0;

void incVarA(void)    { ++cnt; }
void resetVarA(void)  { cnt=0; }
numvar readVarA(void) { return cnt; }

void setup(void) {
    initBitlash(57600);		// must be first to initialize serial port

    addBitlashFunction("ra", (bitlash_function) readVarA);
    addBitlashFunction("re", (bitlash_function) resetVarA);

    attachInterrupt(digitalPinToInterrupt(3), incVarA, FALLING);
}

void loop(void) {
    runBitlash();
}

Hermann.

A colleague gave me the answer to "why the counter gets increased by 2 already when moving a cent between the forks" question. It is just jitter and the falling edges of jitter triggered interrupt even on wrong side (moving cent between forks with FALLING).

He also told me that a Schmitt trigger is a simple counter measure for avoiding jitter interrupt triggers, and that my infrared speed sensor module does not have the needed feedback of Schmitt trigger.

I thought what I can do with software and found a solution eliminating jitter interrupts. Just let ISR "change()" be triggered on CHANGE, check whether on FALLING edge and whether enogh time has passed (more than dt) since last (typically RISING) interrupt:

void change(void) { 
    t = micros();
    
    if ( !digitalRead(3) && (t-tl > dt) ) {
        ++cnt;
    }
        
    tl = t;
}

I did use the speed sensor module to measure high speed robot. Because its easier and maximum speed did trigger interrupts in single digit or low 2-digit number range per second I just used the A0 measuremnts from previous posting in this thread (that allows for more than 90 interrupts per second).

This forum posting details how an Arduino Uno with infrared speed module is used to measure speed of radially running (Arduino Pro Mini/Namo) robot:
http://forum.arduino.cc/index.php?topic=331722.msg2411534#msg2411534

With speeds greater than 40km/h or 11m/s it is important that what you pass through the module forks really passes and does not hit the module. I did experience complete destruction (speed sensor, lost wheel, cables, ...) not stopping before the end of the video because I was not carefully enough:

But using infrared speed module turned out to very useful because it allows to get detailed insight into a run:

And after having eliminated most of vibration it is not dangerous anymore to use the module for high speed fork passing:

Hermann.

Using the digital infrared speed sensor pin with suppression as described in previous posting (with dt=50 microseconds) did completely remove the "0" spikes.

Giving the infrared speed sensor enough "interrupted" time is needed to correctly trigger interrupt each time:

Now a good curve without spikes is the result, and a new speed record of 13.6m/s or 48.9km/h got measured. For details see this posting:
http://forum.arduino.cc/index.php?topic=331722.msg2412902#msg2412902

Hermann.

I do not use fork type light barriers for speed measurements in Motor test station anymore. Instead I do 90fps 640x480 videos with Raspberry Pi Zero from above and count the number of frames per round by single frame stepping the taken video. Knowing the robot diameter speed can be calculated easily from that.

Recently I found a fidget spinner for less than 1$ with free shipping and ordered it:

I wanted to know what that is, and do some measurements with it. I remembered the sensor this thread is about, and found it still superglued to the 9V block battery as in times of Motor Test Station. I superglued a little piece of white plastic to the spinner so that interrupts get generated:

Next I modified the code posted here before a bit:

#include "bitlash.h"

#define mx 10

int cnt=0;
unsigned long t0, tl=0, t; // board start
unsigned long dt=50;  // minimal dt for rising->falling

void change(void) {
  if (cnt<mx)
  {
    t = micros();
    
    if ( !digitalRead(3) && (t-tl > dt) ) {
        cnt++;
        if (cnt==mx) {
          tl = t;
          Serial.println( 1000000.0*cnt/(tl-t0) );
        }
    }
        
    tl = t;
  }
}

void resetVarA(void) {
    t0=micros();
    cnt=0;
}

void setup(void) {
    initBitlash(57600);		// must be first to initialize serial port

    addBitlashFunction("re", (bitlash_function) resetVarA);

    attachInterrupt(digitalPinToInterrupt(3), change, CHANGE);
}

void loop(void) {
    runBitlash();
}

I did run the fidget spinner several times, record was 25.09rps or 1505.4rpm:

bitlash here! v2.0 (c) 2013 Billbitlash here! v2.0 (c) 2013 Bill Roy -type HELP- 916 bytes free
> 10.20
re
> 11.19
re
> 11.46
re
> 9.67
re
> 19.59
re
> 25.09
re
> 16.57

Now knowing that rps value is below 90 would have allowed to measure with 90fps Raspberry video as well. But the spinner sounded as if much more speed was possible (maybe it is and I don't have the best technique to kick the spinner).

Hermann,