trouble with encoder and sending out Serial data

I would like to read a quadrature encoder and print out the rpm and total revolutions to a serial LCD.

Code is working, but only at slow speeds. When I turn the motor by hand, the LCD populates just fine.

When I power the motor, the system loses track of itself. I tried bumping my serial speeds up to baud:38400, although that did not fix the issue.

The encoder library says that there are actually 4 counts per "encoder hole". Two sensors and a rising / falling edge event on each.

Encoder: 512 counts per revolution (CPR). Motor gear ratio: 10.0625:1. Encoder is on motor shaft (not output shaft). Output shaft (OS) speed ~ 200 RPM at minimal load.

So, 200 / 60 * 512 * 10.0625 * 4 = 68693 interrupts per second (correct me if I am wrong here)

Tried just writing to serial monitor (with software serial disabled). Tried writing to just LCD. Both work ok by hand, but powering the motor causes the code to choke. Serial monitor (or LCD) populate sporadically.

Is this more than the arduino can handle? How might I capture my precious data? Let me know if you need any more info.

#include <SoftwareSerial.h>
#include <Encoder.h>

// pin assignments
#define encA 2
#define encB 3

// preprocessor directives
Encoder myEnc(encA, encB); 
SoftwareSerial LCD = SoftwareSerial(8,9); //pin 9 = TX, pin 8 = RX (RX unused)

// Variables
int motor_pos;
long revs = 0;
float rpm = 0;
int timeonerev;
int timelastrev;



void setup() {
  Serial.begin(38400);
  LCD.begin(38400);
  delay(500);                    // wait for display to boot up
  clear_lcd();                    
  myEnc.write(0);
  // LCD.write(0x7C); LCD.write(0x10); // change serial lcd baud to 38400. Do once
}

void loop() {
  
  // counts per "encoder hole": 4, counts per rev: 512, gear ratio: 10.0625. (4*512*10.0625 = 20608)
  if (myEnc.read() > 20608) { 

    timeonerev = millis() - timelastrev;
    rpm = 1 / (timeonerev / 1000.0 / 60.0 );
    revs++;
    
    char buffer1 [32];
    itoa (revs, buffer1, 10);
    char buffer2 [32];  
    itoa (rpm, buffer2, 10);

    // write values to LCD
    LCD.write(0xFE); LCD.write((0 + 0*64 + 128)); // go to cursor position. 
    write_lcd( "Revs: " ); write_lcd( buffer1 );
    LCD.write(0xFE); LCD.write((0 + 1*64 + 128)); // go to cursor position. 
    write_lcd( "RPM: " ); write_lcd( buffer2 );

    // write values to serial monitor
    Serial.print( "Revs: " ); Serial.println( buffer1 );
    Serial.print( "RPM: " ); Serial.println( buffer2 );

    myEnc.write(0);
    timelastrev = millis();

  }
}

void clear_lcd() { // clear display and place cursor at beginning of first line
  LCD.write("                "); 
  LCD.write("                ");
  LCD.write(254); // cursor to 1st position on first line
  LCD.write(128);
}

void write_lcd(char* msg) { // asterisk makes everything ok.
  LCD.write(msg);
}

Don't write the values to the LCD on every iteration of loop. It would probably be sufficient to update the LCD once per second. Same thing for the Serial Monitor.

...R

I tried to send LCD / serial data once every 3, 5, 10 rotations of the motor by only entering the send loop whenever the encoder count is equal to or greater than the corresponding number of counts. This still does not work completely. I think the revolution count is accurate, although the rpm is not working.

Might this have to do with the fact that I am interrupting so often and interrupts prevent millis() from updating properly?

Is it a rule of thumb that high-resolution encoders and anything involving timing do not work well together?

How many encoder pulses are there per second?
Do you know how efficiently the Encoder library handles them?

...R

So, 200 / 60 * 512 * 10.0625 * 4 = 68693 interrupts per second.

The library seems to be very good at handling these. It looks like interrupts interfere with the ATMega's ability to update its internal counter used for millis().

I tried hooking up a real-time clock for the timing, but I find out after the fact that the DS1307 does not provide resolution greater than 1 second. This will not work for the rpm resolution I need. RTC's with greater than one second resolution do not seem to be readily available. I believe this is for power efficiency.

So I come back to my original question: Is the Arduino incapable of being able to read this quadrature encoder and doing anything that deals with timing (or at least timing that relies on the internal millis() function)?

Sorry, I see now that you had the number of counts in your first post.

69000 per second means one every 14 microsecs. That does not leave a lot of spare capacity for other stuff.

Is it the motor shaft or the output shaft that is rotating at 200 rpm? And which is th encoder attached to?

I wonder if that encoder and program are really intended for rpm measuring. You only need a single pulse per revolution to measure RPM and revolutions.

...R

Motor gear ratio: 10.0625:1. Encoder is on motor shaft (not output shaft). Output shaft (OS) speed ~ 200 RPM at minimal load.

Ideally, I would only measure one pulse per rev, but this encoder is built onto the motor. It seems to be a question of what hardware is replaced or added. The encoder library (referenced in OP) seems to perform 4X counting by default and it does not seem adjustable.

I am wondering if anyone has worked with high precision encoders with the Arduino. Am I in a situation where nothing I do will make the Arduino capable of reading all these encoder pulses and dealing with timing on-board?

If you don't use the encoder.h library you can write your own routine for reading the pulses, and write it, for example, so the interrupt is only on one pin rising which will give you 1/4 of your current counts.

In the ISR you read the state of the other pin to determine direction. If you don't need direction, the code is even more trivial.

Code for these quadrature encoders is relatively simple and I'm not sure what the benefits of using a library are.

brian15co:
Ideally, I would only measure one pulse per rev ...

Not my best performance at reading the question - sorry again.

I agree with what @cattledog has said.

...R