I recently purchased an arduino leonardo board, and a DC geared motor(131:1 gear drive) with a hall sensor encoder(from DFRobot). I chose a DC gear motor out of cost and the hope to achieve reasonable positional control while maintaining full motion(not limited to 180* or 360* like a servo). I only need the motor to rotate in one direction so that simplifies things a bit. I've been having a lot of fun tinkering but I've hit a road-block.
I'm driving the motor with a TIP120 darlington circuit for a simple PWM power-supply. Arduino allows me to set 0-255 values to adjust the speed of the motor essentially. That part works great. Now I calculated the theoretical amount of encoder pulses that should occur for a full 360* rotation. Should be 131(gear enlargement) * 16 pulses per revolution = 2096 pulses per revolution of motor shaft.
If I write the code to cut power to the motor via the PWM once it achieves 2096 pulses at full power(255 on the TIP120 PWM) I end up running more like 1.25 revolutions.
If I write the code to cut the power to the motor via PWM once it achieves 2096 pulses at say 'less' power(110) on the TIP120 PWM I end up running more like 0.75 revolutions.
Shouldn't the motor speed have nothing to do with the pulse count on the encoder. Unless of course the motor is running too quickly for the encoder/microcontroller to handle. So I'm not sure what is actually going on I suspect the Interrupt code I have written is sub-par. I borrowed most of it from a tutorial written about the motor&encoder.
Should I be looking into PID control for this? I assumed the problem was inertia at first but it doesn't seem to be the case. I could be wrong.
//PIN Constants
const byte tip120PIN = 6;
const byte encoderPinA = 2;//A pin -> the interrupt pin 0
const byte encoderPinB = 4;//B pin -> the digital pin 4
//Program Constants
const int oneRevolutionPulseCount = 2096;//Theoretical number of pulses per revolution of pinion gear
//Global Program variables
byte encoderPinALast;
int pulseCount;//the number of the pulses
boolean Direction;//the rotation direction
boolean driveMotor;
void setup() {
Serial.begin(57600);//Initialize the serial port for 57600 baud
Serial.println("Initializing...");
//Initialize PWM control for motor
pinMode(tip120PIN, OUTPUT);//Set pin to be output
analogWrite(tip120PIN, 110);//0 to 255 to control motor speed
driveMotor = true;
//Initialize Encoder
encoderInitialization();//prepare encoder interrupt
}
void encoderInitialization() {
Direction = true;//default -> Forward
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
attachInterrupt(0, rotorPulsed, CHANGE);
}
void loop() {
//If the motor is turned off then run this routine to wait a while and turn back on
if(!driveMotor){
delay(6000);
driveMotor = true;
analogWrite(tip120PIN, 111);// 0 to 255 to control motor speed
pulseCount = 0;
}
delay(100);
}
void rotorPulsed() {
//If pulse count is greater then the theoretical one revolution Stop the motor and use the logic block in the Loop
if(pulseCount >= oneRevolutionPulseCount) {
driveMotor = false;
pulseCount = 0;
analogWrite(tip120PIN, 0);//Turn motor off
}
if(driveMotor) {
int lastState = digitalRead(encoderPinA);
//if Last Pin A state was Low, and New Pin A state is High
if((encoderPinALast == LOW) && (lastState == HIGH)) {
int val = digitalRead(encoderPinB);
//If Pin B is low and direction is Forward
if(val == LOW && Direction) {
Direction = false;//Change Direction to Reverse
}
//If Pin B is High and direction is Backward
else if(val == HIGH && !Direction) {
Direction = true;//Change Direction to Forward
}
}
//Update the number of pulses that have occured if there was a change of state
if(encoderPinALast != lastState) {
if(!Direction)
{pulseCount++;}
else
{pulseCount--;}
}
encoderPinALast = lastState;
}
}
The wiring schematic is essentially the same as in this tutorial - 12V_DC_Motor_251rpm_w_Encoder_(SKU__FIT0186)-DFRobot . Only with a simple PWM circuit on a half-size breadboard with a wall-wart supply feeding into the motor.
Any help would be greatly appreciated :).