I am trying a simple test to turn a wheel attached to a Pololu 29:1 Metal Gearmotor 37Dx52L mm with 64 CPR Encoder (product #1443) one rotation using an Arduino UNO. (This means the motor shaft would turn 29 times.) I am using only encoder channel A. The program below uses an interrupt to look for a falling signal on the encoder channel. The program spins the wheel until the encoder position reaches 464 (ie 16 times 29). Then it waits five seconds and spins another rotation.
Here’s the problem: On the wheel’s first rotation, the wheel overshoots its mark by about 25%. Then on subsequent rotations, it undershoots its mark by about 5%, but sometimes more. To try to see what’s going on, I modified the program to store the time that each interrupt was triggered in an array. Generally speaking, the times between triggers are consistent, although it takes a few turns of the motor shaft to get up to speed, so the time between the initial readings is longer. If the motor were consistently overshooting its mark, I would guess it’s coasting at the end, but it only overshoots on the first rotation.
Note, that if you run the code, you will need to start the motor by typing something in the serial window. There will then be a five second delay before the motor spins.
Any help would be appreciated.
[code]/*
RotaryEncoder sketch
This sketch: (1) rotates a wheel one rotation, (2) prints the value of encoder A, (3) delays the program 5 seconds, and (4) repeats
Hardware: (1) Pololu 29:1 Metal Gearmotor 37Dx52L mm with 64 CPR Encoder (#1443) and (2) Arduino UNO
Note… the program reads only encoder A and uses just the falling edge of the channel.
Using just a single edge of one channel results in 16 counts per revolution of the motor shaft.
Thus, the frequency of the A output is 16 times the motor rotation frequency (ie 16 times 29 = 464).
*/
#define CH_1_DIR_PIN 6 //pin to set the direction of roatation
#define CH_1_PWM_PIN 9 // pin to set the speed of rotation
const int encoderPinA = 2; //encoder A output to pin 2
const int encoderStepsPerRevolution = 464; // 16 times 29 (motor frequency)
int Pos = 0, oldPos = 1;
volatile int encoderPos = 0; // variables changed within interrupts are volatile
void setup()
{
pinMode(CH_1_DIR_PIN, OUTPUT); // motor direction pin is output
pinMode(CH_1_PWM_PIN, OUTPUT); // pwm pin is output
pinMode(encoderPinA, INPUT); // encoder pin is input
digitalWrite(encoderPinA, HIGH); //enable pullup resitor
Serial.begin(9600);
digitalWrite(CH_1_DIR_PIN, HIGH); // motor direction is clockwise
while (!Serial.available()){ //don’t start motord until a key on the keyboard is hit.
}
attachInterrupt(0, doEncoder, FALLING); // encoder pin on interrupt 0 (pin 2)
}
void loop()
{
analogWrite(CH_1_PWM_PIN, 100); // start motor turning
/********************
The following code turns off the interrupts while getting data from encoderPos /
uint8_t oldSREG = SREG; //save status register
cli(); //turn off interrupts while getting data from encoderPos
Pos = encoderPos; //get data
SREG = oldSREG; //restore status register and turn interrupts back on
/********************/
if(Pos != oldPos){ // See if encoder A has changed value
if (Pos % encoderStepsPerRevolution == 0){ // See if the wheel has turned one revolution
analogWrite(CH_1_PWM_PIN, 0); //turn motors off
float angle = (Pos % encoderStepsPerRevolution)(360/(float)encoderStepsPerRevolution); // calculate angle (which should be zero)
Serial.print(Pos, DEC);
Serial.print (" ");
Serial.println (angle);
delay(5000);
}
oldPos = Pos;
}
}
void doEncoder()
{
encoderPos++; // count up if both encoder pins are the same
}
[/code]