Go Down

Topic: Interrupt Overhead (Read 1 time) previous topic - next topic

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:

Code: [Select]


#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 = digitalRead(DirectionPin);     // read the direction of motor
  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.

AWOL

You could get rid of the digitalRead in the ISR, and use the fast version instead.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

I did the same. Following is the code.

Code: [Select]


#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?

AWOL

That wasn't quite what I meant.
I see no reason here that "dir" should be global.
Either:
Code: [Select]
  if (digitalReadFast(DirectionPin) {encoder0Pos = encoder0Pos - 1;}
  else {encoder0Pos = encoder0Pos + 1;}
or
Code: [Select]
  if ((PINE & 0b00100000) >> 5) {encoder0Pos = encoder0Pos - 1;}
  else {encoder0Pos = encoder0Pos + 1;}

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Cool ! Thanks a lot for your reply.

I will try that soon and post my results here !

AWOL

I forgot: encoder0Pos should be declared "volatile"
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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)



Thanks in advance !

AWOL

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

Sometimes, the reference material is a little deficient.
Not in this case, however:
http://arduino.cc/en/Reference/Volatile
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Jack Christensen


I forgot: encoder0Pos should be declared "volatile"


And should be accessed atomically in loop() ?
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Go Up