LM393 speed sensor returns double value

Hi,

I'm trying to implement PID controller to my first robot car. To do so I've installed 2 lm393 optical speed sensor to read the rpm and consequently the speed of the wheels.
The problem is that the value that I read is the double of correct value. After checking the code I've tried to move manually one disk lot and it return a value of 2 instead of 1. It's like in the interrupt I use CHANGE instead of RISING. The last attempt was to copy a guy's code on Youtube and in my case it return the double of his value of rpm.
Now I'm suspecting the problem is in my sensor:

even if when i try to block the light with a simple paper seem to work well.
Someone else had the same problem???
This is my code:

#include "TimerOne.h"

// Dichiaro PIN:
#define pin_step_sx 2
#define pin_step_dx 3
#define in3 4
#define in4 8
#define in1 7
#define in2 9
#define enA 6
#define enB 11

volatile unsigned long step_sx=0;
volatile unsigned long step_dx=0;
volatile unsigned long num_sx_prec=0;
volatile unsigned long num_dx_prec=0;

void setup() {
// Dichiaro Input/Output
pinMode(pin_step_sx,INPUT);
pinMode(pin_step_dx,INPUT);
pinMode(in3,OUTPUT);
pinMode(in4,OUTPUT);
pinMode(in1,OUTPUT);
pinMode(in2,OUTPUT);
pinMode(enA,OUTPUT);
pinMode(enA,OUTPUT);

Timer1.initialize(1000000);
Timer1.attachInterrupt(calcolo);
attachInterrupt(digitalPinToInterrupt(pin_step_sx),conta_step_sx,RISING);
attachInterrupt(digitalPinToInterrupt(pin_step_dx),conta_step_dx,RISING);
Serial.begin(9600);
}

void loop() {
avanti();
}

void conta_step_sx(){
   step_sx++;
  }

void conta_step_dx(){
  step_dx++;
  }

void calcolo(){
  Timer1.detachInterrupt();
  float step_disco=20;
  unsigned long num_sx=step_sx;
  unsigned long num_dx=step_dx;
  unsigned long diff_step_sx=num_sx-num_sx_prec;
  unsigned long diff_step_dx=num_dx-num_dx_prec;
  float rpm_sx=diff_step_sx/step_disco*60;
  float rpm_dx=diff_step_dx/step_disco*60;
  Serial.print(num_sx);
  Serial.print("  ");
  Serial.print(num_dx);
  Serial.print("  ");
  Serial.print(rpm_sx);
  Serial.print("  ");
  Serial.println(rpm_dx);
  num_sx_prec=num_sx;
  num_dx_prec=num_dx;
  Timer1.attachInterrupt(calcolo);
}

void avanti() {
digitalWrite(in3,LOW);
digitalWrite(in4,HIGH);
analogWrite(enB,250);
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
analogWrite(enA,250);  
}

Thanks in advance if someone can help me.

LM393 is a comparator chip, not a sensor. Your link points to some H2010 sensors modules that happen to have
comparators.

It may well be your sensors giving multiple edges for some reason - you'd need an oscilloscope to know for sure.

Possibly you need to declare your pinMode as INPUT_PULLUP for these sensors (this is normally the case for
comparator outputs and encoders).

You are calling Serial methods within an interrupt function - this can freeze the processor.

Thank u Mark for your reply.
I tried declaring pinMode as INPUT_PULLUP but nothing.
As i wrote, the strange thing is that even copying another sketch only to verify the comparator returns a double value.
I read of a guy somewhere on internet that has the same problem. He solved by using a small capacitor but there weren't much details.

Add an RC filter, small timeconstant like 10µs perhaps, ie 1k in series and 10nF to ground.

The board in your link, if it's what I think it is, uses a H 2010 photo-transistor in conjunction with a LM 393 comparator IC. It should be counting pulses from a slotted wheel or whatever you have. When powered with 5.0 volts the LM 393 reference level is set at about 2.5 volts and it gets triggered by the photo-transistor. The output of the LM 393 is open collector but a 10K pull up should be on your board. The board should have a LED power on and a LED for pulses out. Blocking the slot of the sensor should trigger the latter LED.

If you want to try a quick and simple diagnostic try the following simple tachometer code sample:

int encoder_pin = 2; // pulse output from the module
unsigned int rpm; // rpm reading
volatile byte pulses; // number of pulses
unsigned long timeold;
// number of pulses per revolution
// based on your encoder disc
unsigned int pulsesperturn = 12;
void counter()
{
   //Update count
   pulses++;
}
void setup()
{
   Serial.begin(9600);
   pinMode(encoder_pin, INPUT);
   //Interrupt 0 is digital pin 2
   //Triggers on Falling Edge (change from HIGH to LOW)
   attachInterrupt(0, counter, FALLING);
   // Initialize
   pulses = 0;
   rpm = 0;
   timeold = 0;
}
void loop()
{
   if (millis() - timeold >= 1000) {
      //Don't process interrupts during calculations
      detachInterrupt(0);
      rpm = (60 * 1000 / pulsesperturn )/ (millis() - timeold)* pulses;
      timeold = millis();
      pulses = 0;
      Serial.print("RPM = ");
      Serial.println(rpm,DEC);
      //Restart the interrupt processing
      attachInterrupt(0, counter, FALLING);
   }
}

In this sample modify the number 12 to fit your pulses per turn or revolution. Running that code right now and applying a 1.0 KHz symmetrical square wave to pin 2 I am seeing 1200 RPM. If you are seeing double the correct speed it leads me to believe based on pulses per revolution something is wrong in the code.

Ron

Ron I dont't have an oscilloscope but i used your piece of code and it however returns the double of correct value.
I also tried the RC filter of Mark the values changed a little, but are still incorrect.

Somehow this thing is triggering twice as much as it should. Two different codes and the same symptom. I mean you could just /2 in your code but that really does not address the actual problem. What are you using? Slotted wheel or similar? Maybe it is seeing a glint off of it. Just plain strange. The schematics of the board itself pretty much show the LM393 comparator has a two 10K resistor divider for the Vref making Vref 2.5 volts. I have seen a few versions with a pot allowing the user to set sensitivity. I don't know what to suggest as a solution.

Ron

I suspect the comparator simply doesn't have nearly enough hysteresis for this use - I'd expect at least 10 to 20% hysteresis is needed for an optical sensor to deal with noise and reflection artifacts, and even 50% is reasonable.

Its a cheap sensor, maybe they've not even considered this?

Hysteresis? :slight_smile: The circuit of these modules looks just like this but uses a slightly different photo transistor. The LM 393 reference is set using a pair of 10K resistors in series. So powered with 5 volts Vref is about 2.5 volts. The slightly improved module uses a pot so the user can set sensitivity, not that it matters much.

Ron

Probably the easiest thing is to simply divide by 2 in the code making sure that it's good for all range of speed.
The strange thing is that manually using a paper to block the light stream it works well.
Probably when connected to motor shaft the frequency is too high and cause problems.
But however sounds so strange.