CIM motor RPM too high?

Hi everybody.
My robotics team has been working on a device that tests the efficiency of old CIM motors we have so we don't match motors with different RPM.
Though, we've run into a bit of a road block.
On the datasheet of the motor we have hooked up, it states that the RPM on a free load is 5310 RPM.
Though, when we test it with our setup, it gives off from 6,000 RPM to 7,000. Here is the data sheet for the Motor. Here is the encoder. This is the setup:

The gear ratio is 12:125 from what I can tell, but mechanical is not my forte.

Here's the code:

/*Gear Ratio is 10.416666667 to 1
 *   The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 7
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 * 
 * 
 * 
 * 
 */
#define buttonLeft A2 //right button
#define buttonCenter A1 //center button
#define buttonRight A0 //left button
int pageNum = 0;
int pageMax = 2;
int pageOld = 5;

#include <LiquidCrystal.h>
#include <Servo.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 7);
int passes = 0;
double Time;
double oldTime;
double rpm = 0;
double a = 0;
double ticks;
double percentage;
double average;
Servo victor;
void setup() {
  // put your setup code here, to run once:
  PageSetup();
  lcd.begin(16, 2);
  lcd.clear();
  pinMode(8, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), addInt, CHANGE);
  Serial.begin(9600);
  victor.attach(9);
  Calculations();
  
}

void addInt(){
  a++;
}
void loop() {
  //PageSystem();
  //delay(50);
  }

//Ignore this.. this is a work in progress for a UI.

/*void PageSetup(){
  pinMode(buttonLeft, INPUT_PULLUP);
  pinMode(buttonCenter, INPUT_PULLUP);
  pinMode(A0, INPUT_PULLUP);
}
*/
/*void PageSystem(){
  if((digitalRead(buttonLeft) == LOW) && (pageNum >0)){
    pageNum--;
    Serial.println(pageNum);
    delay(100);
  }else if((digitalRead(buttonRight) == LOW) && (pageNum <2)){
    pageNum++; 
    Serial.println(pageNum);
    delay(100);
  }

  if((pageNum == 0) &&(pageOld != 0)){
    pageOld = pageNum;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Final RPM:");
    lcd.setCursor(0, 1);
    lcd.print("RPM = ");
    lcd.setCursor(6, 1);
    lcd.print(average);
   
  }else if((pageNum == 1) &&(pageOld != 1)){
    pageOld = pageNum;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Test 2");
  }else if((pageNum == 2) &&(pageOld != 2)){
    pageOld = pageNum;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Test 3");
  }
}
*/

void Calculations(){
 // pageNum = 0;
  
  
  victor.writeMicroseconds(2000);//    Writes to the Motor controller
  lcd.clear();
  Time = millis();
  oldTime = Time;
  a = 0;
  while(millis() < 5000){//            Calculates RPM over 5 seconds
    if(millis() - oldTime == 1000){//  Calculate rpm every second
      lcd.clear();
      oldTime = millis();
      rpm = (a/360)*60;//     ticks over 360 equals one rotation, times 60 equals per minute.
      rpm *= 10.416666667;//  multiply times gear ratio
      average = average + rpm;// to calculate average
      passes++;//                again, to calculate average
      a = 0;//                   reset ticks
      lcd.print(rpm);//          display the RPM, while loop is running.
    }
  }
  victor.writeMicroseconds(1500);
  average /= passes;//           calculate average
  lcd.clear();//                 lcd stuff below
  lcd.setCursor(0,0);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Final RPM:");
  lcd.setCursor(0, 1);
  lcd.print("RPM = ");
  lcd.setCursor(6, 1);
  lcd.print(average);
  
  

  
  
}

Thanks in advance.
Any response is greatly appreciated.

Who wrote this code ? What was their reference source ?

Have you tried reading the RPM value and writing it to a variable and then printing it to the serial port after reading it with all the LCD code commented out ? (to eliminate LCD code effect on RPM code timing ?

 rpm = (a/360)*60;//     ticks over 360 equals one rotation, times 60 equals per minute.

I don't believe this can be correct. The E4P comes in the following Counts per Revolution 100/108/120/125/128/200/250/256/300/360.

You are reading one output with a CHANGE interrupt.

attachInterrupt(digitalPinToInterrupt(2), addInt, CHANGE);
void addInt(){
  a++;
}

That algorithm only reads half the quadrature transitions available, and in effect will give 2X the counts per revolution, and there is no 180 cpr version.

Can you verify the counts per revolution of the encoder you have? With the quadrature, you can read 1x,2x, and 4x the counts available.

As an additiional matter, the variable count "a" needs to be declared as volatile since it changes within the ISR and is referenced by the program.

Thanks so much for quick response!

You are reading one output with a CHANGE interrupt.

As an additiional matter, the variable count "a" needs to be declared as volatile since it changes within the ISR and is referenced by the program.

Both of these seemed to fix it. It's now giving off a more reasonable RPM, between 4950 and 5340.
I changed a to be volatile and set the interrupt to be HIGH instead of CHANGE.

I don't believe this can be correct. The E4P comes in the following Counts per Revolution 100/108/120/125/128/200/250/256/300/360.

The E4P we have has 360 counts, as we tested that before we started. The RPM was (a/360), amount of complete rotations, times 60, to change it to revolutions per minute, as this takes place every second:

if(millis() - oldTime == 1000){// Calculate rpm every second

Who wrote this code ? What was their reference source ?

I wrote this code, and the only reference source I used was a previous post on getting a victor to work with arduino.

Have you tried reading the RPM value and writing it to a variable and then printing it to the serial port after reading it with all the LCD code commented out ? (to eliminate LCD code effect on RPM code timing ?

We tested on the serial port before we added the LCD and after, and there seemed to be no difference.

Thanks so much for the help. We finally got it working; we would've been stuck for a long time. :slight_smile:

Thanks so much for the help. We finally got it working; we would've been stuck for a long time

Cattledog nailed it. He earned a karma point.

Sorry I'm back.
It worked for like the first 6 or 7 times we tested it. After that, it went back to it's old problem of spitting out around 6000. I had believed Cattledog fixed it, but apparently that was not the issue. we had rewrote the code a different way with the same result. Here's what we came up with:

#include <LiquidCrystal.h>

#include <Servo.h>

double Time;
volatile double a = 0;
double ticks = 0;
double rpm;

Servo victor;
void setup() {
  
  // put your setup code here, to run once:
  victor.attach(9);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), addInt, HIGH); 
  victor.writeMicroseconds(2000);
  delay(1000);
  a = 0;
  delay(5000);
  ticks = a;
  victor.writeMicroseconds(1500);
  rpm = ((a/360)/5) * 60;
  rpm *= 10.416666667;
  Serial.println(rpm);
  
}
void addInt(){
  a++;
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(3000);
  Serial.println("Reset to Continue");
}

Simpler, but still not working. I really do not know what to do.

 attachInterrupt(digitalPinToInterrupt(2), addInt, HIGH);

That is not correct. The interrupt condition should be RISING or FALLING.
HIGH is not a valid interrupt mode except on the Due. I think you are using a UNO, and HIGH defaults to CHANGE. You will be triggering on each edge for 2x the counts you want.

Here is some very simple and well tested tachometer code. Note that it makes a protected copy of the interrupt count data. I have also shown how to use tone() as a test function to generate pulses so that you can test the calculations in your sketch without running the motor. I wasn't sure of your counts per second, so I typed it as long.

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

unsigned long lastRead = 0;
unsigned long interval = 1000;

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

  pinMode(2, INPUT_PULLUP); //external interrupt on pin2
  attachInterrupt(0, isrCount, RISING);
  
 // tone(2, 1250); //1250 hz square wave on pin 2 45Kmax
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval; //millis();
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();

    Serial.println(copyCount); //raw counts in time period
  }
}

void isrCount()
{
  count++;
}

Wow, you're a real life saver. After redoing the code basically from scratch (I really wanted to get rid of the fluff) and doing some research (I've never worked with interrupts before, surprisingly), Your solution worked. Setting it to RISING and manually turning the shaft, I found out it was a 200 count encoder. Thanks so much, its now giving off a stable 5300(ish) RPM. :slight_smile: