Newb here, so go easy on me...
The project I'm trying to implement involves driving a dc motor at rather high frequency (~230 rotations/second) for a specified number of complete rotations. It's important that the motor comes to rest at the same position where it began, because I'll subsequently trigger a DSLR camera to snap a photo of the object being rotated, and repeat this process multiple times.
I'm using this Pololu motor (gearbox removed): Pololu - 9.7:1 Metal Gearmotor 25Dx60L mm HP 6V with 48 CPR Encoder (No End Cap), which has an integrated 48 CPR quadrature encoder. I'm controlling the motor with an Arduino Uno, via the Pololu Simple Motor Controller.
As a starting point, I've written a sketch that runs the motor for a specified number of encoder changes (equal to 20 complete rotations) then stops:
#include <SoftwareSerial.h>
#define rxPin 10
#define txPin 13
SoftwareSerial smcSerial = SoftwareSerial(rxPin, txPin);
#define encoder0PinA 2
volatile unsigned int encPos = 0;
int pinIRLED = 9;
int pinIRLED_G = 8;
int pinENC = 11;
int pinENC_G = 10;
void exitSafeStart()
{
smcSerial.write(0x83);
}
void setup()
{
// Set pins for motor encoder power
pinMode(pinENC, OUTPUT);
pinMode(pinENC_G, OUTPUT);
digitalWrite(pinENC, HIGH);
digitalWrite(pinENC_G, LOW);
pinMode(encoder0PinA, INPUT);
attachInterrupt(0, EncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)
smcSerial.begin(19200);
Serial.begin(57600);
// the Simple Motor Controller must be running for at least 1 ms
// before we try to send serial data, so we delay here for 5 ms
delay(5);
smcSerial.write(0xAA); // send baud-indicator byte
exitSafeStart(); // clear the safe-start violation and let the motor run
}
void setMotorSpeed(int speed) // speed should be a number from -3200 to 3200
{
smcSerial.write(0x85); // motor forward command
smcSerial.write(speed & 0x1F);
smcSerial.write(speed >> 5);
}
void EncoderA()
{
encPos = encPos + 1; // Count encoder A changes
}
int speedo = 3100; // Motor speed
int rotations = 20; // Number of complete motor rotations
int multiplier = 24; // Number of encoder changes per rotation
int pulses = rotations*multiplier;
int N = 5; // cycle repeat
int count = 1;
void loop()
{
if (count <= N)
{
encPos = 0;
while (encPos < pulses)
{
setMotorSpeed(speedo); // CHARGE!
}
setMotorSpeed(0); // stop motor
delay(100); // Allow motor to come to rest
Serial.print(pulses); // # of changes I specified
Serial.print(":");
Serial.print(encPos); // # of changes measured
Serial.println();
count++; // iterate to next cycle
}
else
{
setMotorSpeed(0); // stop motor after last cycle
}
}
Of course, the motor can't stop on a dime, so it overshoots the number of encoder changes I've specified in my while loop. In a bit of wishful thinking, I thought that if the overshoot was at least consistent from trial to trial, I could just subtract that from my "pulses" variable, and have the motor come to rest at exactly 20 complete rotations. Not so much. The motor rotates for another 89 to 94 encoder changes at this frequency - so not consistent. Plus, I'm not even totally convinced that the interrupts are catching every encoder change at this frequency (any thoughts on this?)
So I'm not sure where to go from here. Is this even the right approach for this type of project? Should I be working with a PID controller instead? I have no experience with a PID controller, so am unfamiliar with their limitations and tuning challenges.
Many thanks for any thoughts!