Need guidance in calculating RPM if the PPR of a motor is known

I am using a GA12-N20-12V 1000 RPM ALL METAL GEAR MICRO DC ENCODER MOTOR How do I use the readings from the 2 channels to calculate real-time RPM? The PPR is 7 and the gear ratio is 1:30.

Lots of encoder using has been done. Google on "Your controĺler" + encoder.

Which Arduino?

Using the DUE

It will be more simple to just count the pulses on one channel for a period of time. Since there are 7 pulses per revolution with 30:1 gearing you will get 210 pulses per revolution of the output shaft.

You can either count the number of pulses in a given period of time, or find the time taken between pulses.

At your expected counts, this is best done with interrupts. There are tachometer and frequency measurement libraries available to use, although I'm not certain they will be valid for the Due.

Thank you for your reply, so After I count the pulse what do I do to count the RPM? I'm fairly new so I assumed the whole reason for having an encoder is so that it's easier to calculate the RPM, turns out its a mess. Can you point me to the right direction.

If one rotation = 7 counts, then
RPM = (counts/minute)/7

With 30:1 gearing and 7 counts per motor revolution one rotation = 210 counts.

rpm = #of counts in one minute / 210.

#include "CytronMotorDriver.h"
const int encoderPinA = 2; 
const int encoderPinB = 3;  
CytronMD motor(PWM_PWM, 11, 12);
const int PPR = 7;           
volatile unsigned long pulseCount = 0;   
unsigned long lastUpdateTime = 0; 
unsigned long interval = 60000; 

void setup() {
  Serial.begin(9600);

  pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);
  
  attachInterrupt(digitalPinToInterrupt(encoderPinA), countPulse, RISING); 
}

void loop() {
  motor.setSpeed(50);
  unsigned long currentTime = millis();

  if (currentTime - lastUpdateTime >= interval) {
    
    float ppm = (static_cast<float>(pulseCount) / interval) * 60000.0;
    Serial.print("Pulses Per Minute: ");
    Serial.println(ppm);


    float rpm = ppm / 210; 
    Serial.print("Revolutions Per Minute: ");
    Serial.println(rpm);
    

    pulseCount = 0;
    lastUpdateTime = currentTime;
  }
}

void countPulse() {
  if (digitalRead(encoderPinB) == HIGH) {
    pulseCount++; // Increment pulse count when rising edge on channel A occurs and B is high (forward direction)
  } else {
    pulseCount--; // Decrement pulse count when rising edge on channel A occurs and B is low (reverse direction)
  }
}

this is my code please let me know if I did anything wrong

When accessing a multibyte variable from within an interrupt, you want to read it when interrupts are disable to avoid reading a changing number.
https://gammon.com.au/interrupts

You use a transfer variable like in this simple example code


volatile unsigned long  count = 0;
unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");
  
  //interrupt on pin3
  pinMode(3,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(3),isrCount,RISING);
  //analogWrite(3,127); //uncomment to use as test signal
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
    //use copyCount for all calulations and actions in loop
    Serial.println(copyCount);
  }
}

void isrCount()
{
  count++;
}

You do not need any code related to pinB. Indeed, with the code you have you may be reading an negative number for rpm depending on the direction of rotation.

The ISR can be simplified to

void countPulse()
 {
   pulseCount++;
 }

You may want to use and interval of less than 60000 for more responsive tracking of the rpm.

Thank you so much kind stranger... i appreciate you all

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