Hello
I've been trying to find a way to implement pid speed control of a dc motor using timerone library. so the interrupt should happen every 0.25s for my case and then count the number of encoder counts withing that interval and use it to calculate current rpm and send it to computePID() for error correction.
Up till now the program successfully computes,returns and displays the currentrpm, however, when I send that rpm to computePID() the output is not as desired, the motor starts to jack while rotating(its unable to roatate properly, here's the code.
#include <TimerOne.h>
const int encoderPinA = 2;
const int pwmPin = 4; // Motor PWM
const int dirPin = 53; // Motor DIR
float counter=0; // Counter variable for counting pulses
int RPM, currentRPM;
unsigned long currentTime, previousTime;
double elapsedTime;
// PID declaration
double kp = 0.06; //proportional gain
double ki = 0.1; //integral gain
double kd = 0.082; //derivative gain
double error;
double lastError;
double input, output;
int setPoint;
double cumError, rateError;
void setup() {
Serial.begin(115200);
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(pwmPin, OUTPUT);
pinMode(dirPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(encoderPinA), encoder, RISING);
Timer1.initialize(250000); // takes microseconds-Set timer interrupt interval to 0.25s
Timer1.attachInterrupt(computerpm); // Attach timer interrupt service routine
digitalWrite(dirPin, LOW); //set direction
}
void loop() {
setPoint = 80;
currentRPM = RPM;
Serial.println(currentRPM); // Print RPM value
output = computePID();
analogWrite(pwmPin, output); //write new pid output to pin
}
void encoder() {
counter++;
//Serial.println(counter);
}
double computerpm() {
RPM = (counter / 96)*240; // Calculate RPM from counter value
counter = 0;
return RPM;
}
double computePID() {
currentTime = millis(); //get current time
elapsedTime = (double)(currentTime - previousTime); //compute time elapsed from previous computation
error = setPoint - RPM; // determine error
cumError += error * elapsedTime; // compute integral
rateError = (error - lastError) / elapsedTime; // compute derivative
double out = kp * error + ki * cumError + kd * rateError; //PID output
lastError = error; //remember current error
previousTime = currentTime; //remember current time
//Serial.println(error);
return out; //return PID output - PWM
}
//end of program
pid values are correct as i'm able to acheive the speed control with using pulsin() but I no longer wana use that, here's my previous code that works with pid:
void loop() {
setPoint = 121;
currentRPM = computerpm();
output = computePID();
analogWrite(pwmPin, output);
}
void encoder() {
interrupted = true;
}
double computerpm() {
noInterrupts();
rps_Ton = pulseIn(encoderPinA, HIGH); // calculate ON time of RPus pulse input
rps_Toff = pulseIn(encoderPinA, LOW); // calculate OFF time of RPus pulse input
rps_time = rps_Ton + rps_Toff; // calculate total time(microseconds)
rps = rps_time / 1000; // calculate frequency that is RPms
RPM = 60000 * (1 / (96 * rps)); // Update current RPM
//Serial.print("currentRPM; ");
Serial.println(rps);
interrupted = false;
interrupts();
return RPM;
}
But as said, I no longer wana use interrupts() and pulse in like that because there's more i wana do and the interupt part is causing trouble.
So can anyone point out what's wrong in my current code using timerone?
Thanks