Arduino Mega missing encoder counts only when motor spins fast

Hi all,

I’m using a Mega with two maxon motors each equipped with an encoder (HEDL 5540 500 CPT, 3 Channels, with Line Driver RS 422). I am connecting the A and B signals from encoder 1 to pins 21 and 22 respectively (pin 21 is interrupt pin 2). Similarly I connect the A and B signals from encoder 2 to pins 20 and 23 (where pin 20 is interrupt pin 3).

I doubt this matters but I am using several other sensors connected to analog inputs and an SPI sensor as well. I’m also printing a string to serial so that I can interface with a Python program running in parallel which parses the serial string and then sends back a string to the arduino with updated variables.

I am using the Encoder.h library to handle the interrupt and count pulses. When I spin the motor slowly by hand through many revolutions the encoder works great and is very accurate. However, when I drive the motor (spinning at ~1000 rpm or higher) the motor count loses counts. I am able to verify this by twisting a string. I start with 0 twists in a string fixed to the motor shaft on one side and a plate on the other side. I spin the motor to say 50 revs and then unwind back to 0 revs. The encoder thinks it is at 0 revs but there are twists remaining in the string meaning it is missing counts somewhere. The mechanical setup of the string is accurate and I am sure nothing funny mechanically is happening. I have spent several weeks trying to figure out this issue. Is the Mega not able to process that many interrupts when the motor starts spinning fast?

I’ve attached some of my setup code below if that might help. Thank you in advance!!!

 #include <Encoder.h>
 #include <SPI.h>
 // Runtime Options
 bool DEBUGGER = true;    // if true python commands are NOT sent
 // Define Pin out
 #define encoder1PinA 21  
 #define encoder1PinB 22 // 22 
 #define encoder2PinA 20
 #define encoder2PinB 23 // 23
 #define motor1_A 2  // CW +
 #define motor1_B 3  
 #define motor2_A 5  // CCW +
 #define motor2_B 6  //   
 #define magEncPin 53
 #define pot1Pin 54   // analog pin 0
 #define pot2Pin 55   // analog pin 1
 #define fsr1Pin 56   // anolog pin 2
 #define fsr2Pin 57   // analog pin 3
 int CS_PIN = magEncPin;
 // Options and Parameters
 #define POT_MIN_VAL 10
 #define POT_MAX_VAL 1015
 #define BAUD_RATE 115200
 #define TIMEOUT 0  // timeout is for Serial.readString() timeout. If its large the control loop becomes very slow
 #define pauseTime 1  // (us microseconds) change this to increase feedback frequency on AMS5047 encoder
 #define PID_DELAY 500 // motor PD controller delay time in microseconds
 #define CPR 2000.0  // counts per turn for maxon motor encoders
 #define FSR_CALIBRATION_CONSTANT 2.0   //1.81
 #define MAX_FSR_FORCE 100 // max fsr force in N
 #define MAX_MAG_ENC_VAL 16383 //2^14 - 1
 #define MAX_NUM_TWISTS 150.0 // 144 (by hand), (115 @12V)
 #define MAX_PRELOAD 60.0
 #define Ks 10 // stiffness gain of twisted string actuator. stiffness of twisted string can be varied/tuned using potentiometer from: -(MAX_NUM_TWISTS)/(2*Ks) < 0 < (MAX_NUM_TWISTS)/(2*Ks). 
 // ...corresponds to the number of twists offset the actuator is from an ideal TSA where the antagonistic strings are perfectly inversed in length
 // Motor PD Gains
 #define kp 60.0    // at 12 V power supply to motor driver (40)
 #define kd -.10
 int POT_DEADZONE = 1;     // kp/2;
 float PRELOAD = 3.0;  // number of twists of preload
 // define motor encoder classes
 Encoder enc1(encoder1PinA, encoder1PinB);
Encoder enc2(encoder2PinA, encoder2PinB);

500 pulses per revolution * 1000 Revolutions per minute / 60 Seconds per minute = 8,333 pulses per second or a pulse every 120 uS. That is probably too fast to capture every pulse and do anything useful between interrupts.

Can you run the motor slower? Can you get an encoder with fewer pulses per rev?

You could put a counter between the encoder and the Arduino input so the board only sees a pulse every 10 or 32 or 100 or 500 pulses from the encoder. This could be done in hardware using logic chips or you could probably use one of the cheaper Arduino's as a counter. I think a 16MHz board could count pulses and toggle an output if you used fast reads and writes and did nothing else. Normal digitalRead() and digitalWrite() would probably be too slow.

Thank you for your feedback!!

Unfortunately, running the motor slower would defeat the purpose of my application. Can you suggest any logic chips I should try out? Is there anything from pololu or sparkfun that would work for solving this?

I am not familiar with what a 'fast read and write' are on arduino. Does this entail digging into the firmware?

Can you get an encoder with fewer pulses per revolution?

Search the forum for fast digitalRead and fast digitalWrite. Regular digitalRead() has a lot of overhead and checking to make sure everything is correct. The faster options use low level commands, nothing unusual or difficult.

I don't remember seeing anything from the usual suppliers that would do this, though I wouldn't be surprised if there is something deep in one of the catalogs.

The simplest for someone who knows Arduino but not electronics is to use another arduino to count the inputs pulses and every 100 input pulses change the output state, or whatever number works in your system. Use the fast digital read and write from your search of the forum.

If you want hardware that can do it, google "digital logic counter". There are a lot of binary or BCD counter IC. You might need to chain a few counters together to get the divisor you want.