Hey,

I have been trying to calculate the velocity for two motors, using encoder interrupts, which later would be used to apply PID control. Velocity Calculation code gives out correct velocity till a certain rpm (goes up as input voltage goes up), but then starts giving negative velocity (goes down as voltage goes up). Following is the code:

``````#define DirectionPin 3    // direction pin

int encoder0Pos = 0,oldPos = 0;  // encoder position
int dir = 0;
unsigned long oldTime, newTime, dt;
float vel;

void setup() {
Serial.begin(9600);            // set up Serial library at 9600 bps
pinMode(DirectionPin, INPUT);

// encoder pin on interrupt 0 (pin 2)
attachInterrupt(5, doEncoder, RISING);
oldTime = millis();
}

void loop() {
newTime = millis();              // read the current time stamp
dt = newTime - oldTime;           // compute delta time
oldTime = newTime;

vel = (float) ((encoder0Pos - oldPos) * 4.25) / (dt);  // velocity estimate in ms
int temp = encoder0Pos - oldPos;
oldPos = encoder0Pos;

Serial.println(vel);
}

// Interrupt routine
void doEncoder()
{
if (dir == HIGH) {encoder0Pos = encoder0Pos - 1;}
else {encoder0Pos = encoder0Pos + 1;}

}
``````

I need to connect three of these motors later in near future, but this code seems to have lot of interrupt overhead. Interrupt frequency is around 8000 ticks per second per motor.

You could get rid of the digitalRead in the ISR, and use the fast version instead.

I did the same. Following is the code.

``````#define DirectionPin 3    // direction pin

int encoder0Pos = 0,oldPos = 0;  // encoder position
int dir = 0;
unsigned long oldTime, newTime, dt;
float vel;

void setup() {
Serial.begin(9600);            // set up Serial library at 9600 bps
pinMode(DirectionPin, INPUT);

// encoder pin on interrupt 0 (pin 2)
attachInterrupt(5, doEncoder, RISING);
oldTime = millis();
}

void loop() {
newTime = millis();              // read the current time stamp
dt = newTime - oldTime;           // compute delta time
oldTime = newTime;

vel = (float) ((encoder0Pos - oldPos) * 4.25) / (dt);  // velocity estimate in ms
int temp = encoder0Pos - oldPos;
oldPos = encoder0Pos;

Serial.println(vel);
}

// Interrupt routine
void doEncoder()
{
dir = (PINE & 0b00100000) >> 5;
if (dir == HIGH) {encoder0Pos = encoder0Pos - 1;}
else {encoder0Pos = encoder0Pos + 1;}
}
``````

I could notice some improvement but, I finally need to implement this with three motors in parallel. Connecting two of them, I faced the same problem again. Any solutions?

That wasn't quite what I meant.
I see no reason here that "dir" should be global.
Either:

``````  if (digitalReadFast(DirectionPin) {encoder0Pos = encoder0Pos - 1;}
else {encoder0Pos = encoder0Pos + 1;}
``````

or

``````  if ((PINE & 0b00100000) >> 5) {encoder0Pos = encoder0Pos - 1;}
else {encoder0Pos = encoder0Pos + 1;}
``````

I will try that soon and post my results here !

I forgot: encoder0Pos should be declared "volatile"

Hey,

May I know the reason for declaring it 'volatile'?

By the way, forgot to mention, Interrupt frequency is around 12646 counts per sec per motor.
(1024 Counts per Rotation and 741 Rotations per Minute (RPM))

I tested my motor with your suggestions incorporated. It (two motors together) still gives erroneous velocity values.

Would you suggest me to consider following options?

• Analog PID Controller (using resistors, Op-Amp and Capacitors)
• Use of Motion Control Chip (PID Controller - LM629)