Speed sensor values

Hello, im using arduino uno with lm393 speedometer. And getting rpm values like 2000 rpm or so from 250 rpm robot is this normal?
here is my code

#include <SoftwareSerial.h>
#include<Servo.h>
#include "TimerOne.h"
SoftwareSerial bt_iletisim(9, 8);
float sure = 0, distance = 0;
int pin1 = 4;
int pin2 = 5;
int pin3 = 6;
int pin4 = 7;
const byte MOTOR1 = 2;  // Motor 1 Interrupt Pin - INT 0
const byte MOTOR2 = 3;  // Motor 2 Interrupt Pin - INT 1
unsigned int counter1 = 0;
unsigned int counter2 = 0;
float diskslots = 20.00;
// Interrupt Service Routines
// Motor 1 pulse count ISR
void ISR_count1()
{
counter1++;  // increment Motor 1 counter value
 }
// Motor 2 pulse count ISR
void ISR_count2()
{
  counter2++;
  // increment Motor 2 counter value
}
void ISR_timerone()
{
  Timer1.detachInterrupt();  // Stop the 
  Serial.print("Motor Speed 1: ");
  float rotation1 = (counter1 / diskslots) *60;  // calculate RPM for Motor 1
  Serial.print(rotation1);
  Serial.print(" RPM - ");
  counter1 = 0;  //  reset counter to zero
  Serial.print("Motor Speed 2: ");
  float rotation2 = (counter2 / diskslots) * 60;  // calculate RPM for Motor 2
  Serial.print(rotation2);
  Serial.println(" RPM");
  counter2 = 0;  //  reset counter to zero
  Timer1.attachInterrupt( ISR_timerone );  // Enable the timer
}
void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  Timer1.initialize(1000000); // set timer for 1sec
  attachInterrupt(digitalPinToInterrupt (MOTOR1), ISR_count1, RISING);  // Increase counter 1 when speed sensor pin goes High
  attachInterrupt(digitalPinToInterrupt (MOTOR2), ISR_count2, RISING);  // Increase counter 2 when speed sensor pin goes High
  Timer1.attachInterrupt( ISR_timerone );
  Serial.begin(9600);
  bt_iletisim.begin(9600);
}
void sol() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
}
void sag() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
}
void geri() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin4, LOW);
}
void ileri() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
}
void loop() {
  if (bt_iletisim.available())
  {
    char data = bt_iletisim.read();
    String stringOne = String(data);
    switch (data) {
      case 'w':
        Serial.print(data);
        ileri();
        break;
      case 's':
        Serial.print(data);
        geri();
        break;
      case 'a':
        Serial.print(data);
        sol();
        break;
      case 'd':
        Serial.print(data);
        sag();
        break;
      case 'q':
        Serial.print(data);
 break;
      default:
        break;
    }
  }
  ileri();
}

is that normal?

Since we cannot see your circuit or how the speedometer is implemented, there is no way to know what "normal" is.

It is not a good idea to use Serial print in an ISR. Interrupts are disabled in an ISR and print needs interrupts.

The counter variables used in the ISRs should be declared volatile.

1 Like

Hello
Make the ISR coding as short possible.
It is deeply recommended to use function calls like Serial.println inside a ISR never.
Use flags declared as 'volatile' to forward a signal to the loop().
Have a nice day and enjoy coding in C++.

1 Like

I change my code like your directives and it like that

#include <SoftwareSerial.h>
#include<Servo.h>
#include "TimerOne.h"

SoftwareSerial bt_iletisim(9, 8);

float sure = 0, distance = 0;


int pin1 = 4;
int pin2 = 5;
int pin3 = 6;
int pin4 = 7;

const byte MOTOR1 = 2; 
const byte MOTOR2 = 3;  

volatile float rotation1 = 0;
volatile float rotation2 = 0;
volatile unsigned int counter1 = 0;
volatile unsigned int counter2 = 0;

float diskslots = 20.00;

void ISR_count1()
{
  counter1++; 
}
void ISR_count2()
{
  counter2++;
}

void ISR_timerone()
{
  Timer1.detachInterrupt();
  rotation1 = (counter1 / diskslots) * 60; // calculate RPM for Motor 1
  counter1 = 0;  //  reset counter to zero
  rotation2 = (counter2 / diskslots) * 60;  // calculate RPM for Motor 2
  counter2 = 0;  //  reset counter to zero
  Timer1.attachInterrupt( ISR_timerone );  // Enable the timer
}

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  Timer1.initialize(); // set timer for 1sec
  attachInterrupt(digitalPinToInterrupt (MOTOR1), ISR_count1, RISING);
  attachInterrupt(digitalPinToInterrupt (MOTOR2), ISR_count2, RISING);
  Timer1.attachInterrupt( ISR_timerone );
  Serial.begin(9600);
  bt_iletisim.begin(9600);

}
void sol() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
}
void sag() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
}
void geri() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin4, LOW);
}
void ileri() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
}
void loop() {
  if (bt_iletisim.available())
  {
    char data = bt_iletisim.read();
    String stringOne = String(data);
    switch (data) {
      case 'w':
        Serial.print(data);
        ileri();
        break;
      case 's':
        Serial.print(data);
        geri();
        break;
      case 'a':
        Serial.print(data);
        sol();
        break;
      case 'd':
        Serial.print(data);
        sag();
        break;
      case 'q':
        Serial.print(data);

        break;
      default:
        break;
    }
  }
  ileri();
  Serial.print(rotation1);
  Serial.print(" ");
  Serial.print(rotation2);
  Serial.print("\n");
}

but still getting the same values.

Do you get 0 when the wheels aren't moving?

Do you get different values on the two wheels when only one is moving?

Are you sure your wheels are turning at 250 RPM? That's about 4 turns per second so it shouldn't be too hard to tell.

Write a small sketch to copy the speed sensor input to the built-in LED. Does the LED blink 20 times when you turn the wheel manually?

ye i get 0 when wheels aren moving. When i turn it manually it counts 20 by only quarter turn. Motors can get max 250 rpm but it says 2000 rpm isnt that bit too much. If i block two column of sensors by sheet of paper it counts twice when i unblock that it counts twice again even isr on falling or rising.

That's not good. It is counting four times as fast as expected on a slow turn?

even if i divide by 4 it still missin actual values by nearly 200 time

You do not need to detach/reattach interrupts inside your Timer1 ISR. Interrupts are off during that call. You do, however, need to disable interrupts, and make a copy of your volatile variables, and then use that copy in your calculations.

I also bumped your Serial up to a modern speed...

#include <SoftwareSerial.h>
#include<Servo.h>
#include "TimerOne.h"

SoftwareSerial bt_iletisim(9, 8);

float sure = 0, distance = 0;


const int pin1 = 4;
const int pin2 = 5;
const int pin3 = 6;
const int pin4 = 7;

const byte MOTOR1 = 2;
const byte MOTOR2 = 3;

volatile unsigned int counter1 = 0;
volatile unsigned int counter2 = 0;
volatile unsigned int current1;
volatile unsigned int current2;

const unsigned int diskslots = 20;

void ISR_count1()
{
  counter1++;
}

void ISR_count2()
{
  counter2++;
}

void ISR_timerone()
{
  current1 = counter1;
  counter1 = 0;  //  reset counter to zero
  current2 = counter2;
  counter2 = 0;  //  reset counter to zero
}

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  Timer1.initialize(); // set timer for 1sec
  attachInterrupt(digitalPinToInterrupt (MOTOR1), ISR_count1, RISING);
  attachInterrupt(digitalPinToInterrupt (MOTOR2), ISR_count2, RISING);
  Timer1.attachInterrupt( ISR_timerone );
  Serial.begin(115200);
  bt_iletisim.begin(9600);
}

void sol() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
}

void sag() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, LOW);
}

void geri() {
  digitalWrite(pin2, HIGH);
  digitalWrite(pin4, HIGH);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
  delay(1000);
  digitalWrite(pin2, LOW);
  digitalWrite(pin4, LOW);
}

void ileri() {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, LOW);
  digitalWrite(pin3, HIGH);
  digitalWrite(pin4, LOW);
  delay(1000);
  digitalWrite(pin1, LOW);
  digitalWrite(pin3, LOW);
}

void loop() {
  float rotation1, rotation2;
  unsigned int value1, value2;
  
  if (bt_iletisim.available())
  {
    char data = bt_iletisim.read();
    switch (data) {
      case 'w':
        Serial.print(data);
        ileri();
        break;
      case 's':
        Serial.print(data);
        geri();
        break;
      case 'a':
        Serial.print(data);
        sol();
        break;
      case 'd':
        Serial.print(data);
        sag();
        break;
      case 'q':
        Serial.print(data);
        break;
      default:
        break;
    }
  }
  ileri();

  noInterrupts();
  value1 = current1;
  value2 = current2;
  interrupts();

  rotation1 = value1 * 60.0 / diskslots; // calculate RPM for Motor 1
  rotation2 = value2 * 60.0  / diskslots;  // calculate RPM for Motor 2
  Serial.print(rotation1);
  Serial.print(" ");
  Serial.print(rotation2);
  Serial.print("\n");
}

thanks for the help but nothing changed still getting same values.

Here is a simple sketch to blink the LED once for each rising edge from the sensor. See if you count 20 blinks per turn. If not, you probably have a hardware problem.

const byte SpeedSensorPin = 2;

boolean PreviousInputState = false;

unsigned PulseCount = 0;

boolean LEDState = false;
unsigned long PreviousBlinkTime = 0;
unsigned BlinkRate = 300;

void setup()
{
  pinMode(SpeedSensorPin, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  boolean currentInputState = digitalRead(SpeedSensorPin) == HIGH;

  if (currentInputState != PreviousInputState)
  {
    PreviousInputState = currentInputState;

    // Count only rising edges
    if (currentInputState)
      PulseCount++;
  }

  // Play out the pulses at a rate slow enough to read.
  if (PulseCount > 0 && currentMillis - PreviousBlinkTime > BlinkRate)
  {
    PreviousBlinkTime = currentMillis;
    LEDState = !LEDState; // Toggle
    digitalWrite(LED_BUILTIN, LEDState ? HIGH : LOW);
    // When LED turns off, decrement the pulse count
    if (!LEDState)
      PulseCount--;
  }
}

Many of the low cost hobby sensors have comparators based on the LM393 without any hysteresis feedback, and it is not uncommon to experience multiple interrupts/noise troubles with these basic lm393 comparator modules.

Performance is often improved with a cap between D0 and ground. That solution and other possible circuit mods for hysteresis improved response are discussed here

Arduino Forum – 18 Aug 15

FC-03 and attachInterrupt() problems!?!?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.