IR tachometer, weird readings

Not yet. Stray light could be my problem as well. Going to try shielding it as best I can and see what the results are. I believe these sensors are extremely sensitive.

Debouncing in code would be difficult for me because of the range of rpm I’m measuring. Most values I would exclude with denounce code would be acceptable values at other RPM’s. What I could do is check for a percentage variance from the last reading and discard it if it was higher than x% difference. Even then however I have to take acceleration into account.

Well, it's not stray light. Hall sensor came in today and got it hooked up. I'm still seeing the same problem. Here's another copy of some console output...

currTime=302183396 prevTime=302083416 interval=99980 spindleRPM=600 rpmd=0
currTime=302283356 prevTime=302183396 interval=99960 spindleRPM=600 rpmd=0
currTime=302383316 prevTime=302283356 interval=99960 spindleRPM=600 rpmd=0
currTime=302483308 prevTime=302383316 interval=99992 spindleRPM=600 rpmd=0
currTime=302483308 prevTime=302383316 interval=99992 spindleRPM=600 rpmd=0
currTime=302583328 prevTime=302483308 interval=100020 spindleRPM=599 rpmd=-1
currTime=302683328 prevTime=302583328 interval=100000 spindleRPM=600 rpmd=1
currTime=302783284 prevTime=302683328 interval=99956 spindleRPM=600 rpmd=0
currTime=302883220 prevTime=302783284 interval=99936 spindleRPM=600 rpmd=0
currTime=302886808 prevTime=302883220 interval=3588 spindleRPM=16722 rpmd=16122
currTime=302983180 prevTime=302886808 interval=96372 spindleRPM=622 rpmd=-16100
currTime=303083176 prevTime=302983180 interval=99996 spindleRPM=600 rpmd=-22
currTime=303183220 prevTime=303083176 interval=100044 spindleRPM=599 rpmd=-1
currTime=303283256 prevTime=303183220 interval=100036 spindleRPM=599 rpmd=0
currTime=303283256 prevTime=303183220 interval=100036 spindleRPM=599 rpmd=0
currTime=303383236 prevTime=303283256 interval=99980 spindleRPM=600 rpmd=1
currTime=303483140 prevTime=303383236 interval=99904 spindleRPM=600 rpmd=0
currTime=303583056 prevTime=303483140 interval=99916 spindleRPM=600 rpmd=0
currTime=303683028 prevTime=303583056 interval=99972 spindleRPM=600 rpmd=0
currTime=303683028 prevTime=303583056 interval=99972 spindleRPM=600 rpmd=0
currTime=303783068 prevTime=303683028 interval=100040 spindleRPM=599 rpmd=-1
currTime=303883140 prevTime=303783068 interval=100072 spindleRPM=599 rpmd=0
currTime=303983188 prevTime=303883140 interval=100048 spindleRPM=599 rpmd=0

johnwasser still seems to be on to something. If you look at the two oddball intervals above, 3588 and 96372, they add up to 99,960 which would be right in line with the other intervals. I'm stumped as to what may be causing this.

I'm having an even harder time explaining these...

currTime=166339132 prevTime=166289152 interval=49980 spindleRPM=1200 rpmd=-1
currTime=166439184 prevTime=166389140 interval=50044 spindleRPM=1198 rpmd=-2
currTime=166539364 prevTime=166489260 interval=50104 spindleRPM=1197 rpmd=-1
currTime=166589480 prevTime=166539364 interval=50116 spindleRPM=1197 rpmd=0
currTime=166689708 prevTime=166639596 interval=50112 spindleRPM=1197 rpmd=0
currTime=166789832 prevTime=166739792 interval=50040 spindleRPM=1199 rpmd=2
currTime=166839816 prevTime=166791540 interval=48276 spindleRPM=1242 rpmd=43
currTime=166939668 prevTime=166889764 interval=49904 spindleRPM=1202 rpmd=-40
currTime=166989556 prevTime=166939668 interval=49888 spindleRPM=1202 rpmd=0
currTime=167089352 prevTime=167039448 interval=49904 spindleRPM=1202 rpmd=0
currTime=167189236 prevTime=167139276 interval=49960 spindleRPM=1200 rpmd=-2
currTime=167239228 prevTime=167189236 interval=49992 spindleRPM=1200 rpmd=0
currTime=167339328 prevTime=167289260 interval=50068 spindleRPM=1198 rpmd=-2

my units have a sensitivity pot, maybe you can adjust it's sensitivity?

maybe buy an oscilloscope to test your signal speed/s.

KrisKasprzak:
my units have a sensitivity pot, maybe you can adjust it's sensitivity?

Mine do as well. I currently have them set to the minimum sensitivity. Thing is, the problem occurs with the hall/proximity sensor as well.

Hi,
Time to get serious. :slight_smile:

Can you please post some pictures of your project so we can see your component layout?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Please not a fritzy picture circuit...

Thanks.. Tom.. :slight_smile:

Hi,
This is your sensor, it is not physically designed for tacho application, you need shrouds over both the emitter and sensor.
They will be sensitive to not just straight ahead range, but sideways as well.
irsensor.jpg

Tom.. :slight_smile:

irsensor.jpg

Hi Tom, you are correct. That’s the sensor I’m using. I’ve also tried this one...

Twidec/10mm Hall Effect Proximity Sensor Inductive Switch NPN NO(Normally Open) with Magnet DC5-30V NJK-5002C https://www.amazon.com/dp/B07P1GKQRM/ref=cm_sw_r_cp_api_i_C1oEDbTBHRNA7

I’m not in front of the setup at the moment but will be happy to post a picture later when I can.

I’m not sure what software I’d use to create the circuit diagram.

And I do have a scope but haven’t broken it out and hooked it up on this yet.

You said that IR sensor is not designed for a tach application. If you can point me to one that is I’ll be happy to order one.

travisr100:
Hi Tom, you are correct. That’s the sensor I’m using. I’ve also tried this one...

Twidec/10mm Hall Effect Proximity Sensor Inductive Switch NPN NO(Normally Open) with Magnet DC5-30V NJK-5002C https://www.amazon.com/dp/B07P1GKQRM/ref=cm_sw_r_cp_api_i_C1oEDbTBHRNA7

I’m not in front of the setup at the moment but will be happy to post a picture later when I can.

I’m not sure what software I’d use to create the circuit diagram.

And I do have a scope but haven’t broken it out and hooked it up on this yet.

Brake it out dude... lol

Hi,

I'm not sure what software I'd use to create the circuit diagram.

A picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

Sorry Tom, I've been busy and haven't had a chance. Will get to it however. This thing isn't even on a breadboard. The sensor is connected directly to the arduino, 5v, gnd, and signal. That's it.

Sorry this has taken me so long to get to. I got busy with some other stuff and also wanted to boil this down to basics to eliminate any other possibilities. Here is a pic...

Tach Circuit

This should suffice for a circuit diagram as well. As I said it's extremely basic. Signal pin from hall sensor to pin 2 on the nano. Other than that just power and ground. I got rid of the display and other components to get it down to basics. This is also a new board I'm trying it with. I previously had it on a Mega. Still getting the same results.

Here's some more console output...

period0=69216 rpm=866 rpmd=0 srpm=866
period0=69196 rpm=867 rpmd=1 srpm=866
period0=69200 rpm=867 rpmd=0 srpm=867
period0=69208 rpm=866 rpmd=1 srpm=867
period0=69184 rpm=867 rpmd=1 srpm=867
period0=69188 rpm=867 rpmd=0 srpm=867
discard period0=37648 rpm=1593 rpmd=726 srpm=978
discard period0=31532 rpm=1902 rpmd=309 srpm=1156
discard period0=69168 rpm=867 rpmd=1035 srpm=1191
period0=69152 rpm=867 rpmd=0 srpm=867
period0=69160 rpm=867 rpmd=0 srpm=867
period0=69168 rpm=867 rpmd=0 srpm=867
period0=69144 rpm=867 rpmd=0 srpm=867
period0=69156 rpm=867 rpmd=0 srpm=867
period0=69168 rpm=867 rpmd=0 srpm=867
period0=69156 rpm=867 rpmd=0 srpm=867
period0=69160 rpm=867 rpmd=0 srpm=867

Ther period0 line is the period between pulses. You can see the motor is running at a stead 867 RPM or approximately 69,160 microseconds between pulses. You'll see when the anomaly occurs it's like it's registering a pulse half way around the wheel. The two outlier pulses of 37,648 and 31,532 add up to 69,180 which is very close to all the normal pulse values.

I've tried this with the hall sensor, two different IR sensors, and two different arduino boards. It seems to be pretty consistent.

As I was reading my last post I was asking myself what other variables I had not tried changing. I figured it couldn't possibly make any difference but I went looking for a different USB cable. The one I've been using is about 5' long allowing the arduino to sit on my desk in front of my keyboard while the computer is on a shelf above. The only other cable I had was a little 6" cable. I tried that cable and the problem disappeared. In using the 6" cable I had to move the arduino right up next to the computer on the shelf.

This confuses me. I'm not sure if the difference is the cable or the fact that the arduino moved from the desk up next to the computer. i don't have a bunch of other electronic gear near the arduino that could be generating any interference I don't think. Although my keyboard and mouse next to the arduino are wireless.

I'll also mention that I tapped onto the signal wire and hooked it up to my scope. I know virtually nothing about using a scope. I was able to trigger on the signal from the hall and as I increased or decreased the motor speed I could see the pulse width changing on the scope. What I did not see were any sudden jumps in the pulse width on the scope like what I'm seeing in the output of the serial console. But it may be that it's happening so quickly that it's not really visible to the eye. I don't know enough to generate a single shot capture when the pulse width changes above or below a certain threshold. But what I'm seeing leads me to believe the pulse width isn't actually changing.

Very much scratching my head here.

I know this is a Band-Aid, but could you accept throwing out readings that aren't within, say 20% of the prior reading?

But, I am reluctant to do Band-Aids in my projects without knowing what is really happening.

Hi,
Thanks. OPs pic/circuit.


Tom. :slight_smile:

Tom, how did you get that image inline on the post? When I click the insert image button it's asking me for a URL. Doing it as an attachment?

Steve, I have considered throwing out the readings based on some criteria. You can see my console output says "discard" before several of the readings which is just me debugging to determine what to throw away. As you said, I hate doing that without knowing what's going on. In addition, kind of difficult to know what to throw away with this particular problem. My "discard" is looking at the length of the current period compared to last period and throwing it away if it's more than 2000. This won't catch it every time however. In addition there's the situation of acceleration. If I share this code someone else's motor parameters may be completely different than mine and what I use as a means to discard readings may not work for someone else's situation.

For any of you that want to see what the final code looks like here it is. Feel free to criticize at will.

volatile unsigned long period = 0; //time between pulses
volatile unsigned long prevTime = 0; //the last micros() we measured
volatile bool newMeasurementAvailable = 0;
unsigned long stablePeriod = 0; //
byte pointer = 0; //pointer to keep track of next position in array to store value
byte numPrevReadings = 0; //the number of readings to smooth, can be from 1 to 10, always starts at 1, dynamically changed based on period/RPM

unsigned long matrix[4][10] = {  //initialize the array with zeros
                              {0,0,0,0,0,0,0,0,0,0}, //stores the pulse period
                              {0,0,0,0,0,0,0,0,0,0}, //stores raw rpm
                              {0,0,0,0,0,0,0,0,0,0}, //stores smoothed rpm of current reading and numPrevReadingss
                              {0,0,0,0,0,0,0,0,0,0}  //not used just haven't decided if I'm going to or not
                              };

unsigned long total = 0;



void setup(){
  pinMode(21, INPUT);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), isr, FALLING); //Interrupts are called on Rise of Input
  Serial.println("Begin");
}

 
void loop(){
  if (newMeasurementAvailable) {
    noInterrupts();
    stablePeriod = period;
    interrupts();

    storeAndProcess();
    newMeasurementAvailable = 0;
    
    int rpmd = getRPM(0) - getRPM(1);  // rpm delta from the previous reading
    Serial.print(" period0=");
    Serial.print(getPeriod(0));
    Serial.print("\t rpm=");
    Serial.print(getRPM(0));
    Serial.print("\t rpmd=");
    Serial.print(abs(rpmd));
    Serial.print("\t srpm=");
    Serial.println(getSmoothedRPM(0));


  }
}

void storeAndProcess() {
  matrix[0][pointer] = stablePeriod;  //store the period
  matrix[1][pointer] = (60 * 1000000) / matrix[0][pointer];  //store the raw RPM

  //The next line determines the number of previous periods to use to calculate the average. As speed increases, number of previous readings will increase to a maximum of 9.
  //Using 125000 as a value below is a period of 1/8 of a second (1,000,000/125,000).  This equates to 480 RPM.  So up to 480 RPM it uses one reading.  At every multiple
  //of 480 RPM the number of values used for smoothing will increase by 1 up to 4800 RPM.  With an array of 10 elements as defined in this sketch that only gives us a max 
  //of the current value plus the 9 previous values.  The array could be defined with more than 10 elements if you wanted to change this.  Additionally instead of using
  //simple division as I've done you could use the map function to define the range of potential RPM's at which you want smoothing done.
  numPrevReadings = 125000 / stablePeriod;
  numPrevReadings = constrain(numPrevReadings, 0, 9);
  total = stablePeriod;  //start with the period we just measured
  if (numPrevReadings != 0) {
    for (int i = 0; i < numPrevReadings; i++) {  //add numPrevReadings previous periods
      total += getPeriod(i);
    }
   }
  matrix[2][pointer] = ((numPrevReadings + 1) * (60 * 1000000)) / total;  //store the smoothed RPM
  if (pointer++ >= 9) pointer = 0;  //increment the pointer to the position to store the next reading
  
}

unsigned long getPeriod(byte position) {
  //position  = 0 returns the last recorded value
  //position = 1 returns next oldest and so on
  int positionToGet = (pointer - 1 - position);
  if (positionToGet < 0) positionToGet += 10; 
  unsigned long value = matrix[0][positionToGet];
  return value;
}

unsigned long getRPM(byte position) {
  int positionToGet = (pointer - 1 - position);
  if (positionToGet < 0) positionToGet += 10; 
  unsigned long value = matrix[1][positionToGet];
  return value;
}

unsigned long getSmoothedRPM(byte position) {
  int positionToGet = (pointer - 1 - position);
  if (positionToGet < 0) positionToGet += 10; 
  unsigned long value = matrix[2][positionToGet];
  return value;
}

void isr(){
  newMeasurementAvailable = 1;
  period = micros() - prevTime;
  prevTime = micros();
}