Hello,
using one of the dc motor with inbuilt rotary encoder, i am trying to rotate the shaft with required rpm giving the suitable PWM value. i have written the code to get the exact rpm which is as follows:
volatile int rpmcount = 0;
float rpm = 0;
unsigned long lastmillis = 0;
int pwm=5;
int dir1 = 11;
int dir2=12;
float rotation = 0.00;
int pwm_val= ;
void setup(){
Serial.begin(9600);
attachInterrupt(0, rpm_fan, RISING);//interrupt cero (0) is on pin two(2)
pinMode(pwm,OUTPUT);
pinMode(dir1,OUTPUT);
pinMode(dir2,OUTPUT);
}
void loop(){
digitalWrite(dir1,HIGH);
digitalWrite(dir2,LOW);
analogWrite(pwm_val,255);
if (millis() - lastmillis == 1000){ /*Uptade every one second, this will be equal to reading frecuency (Hz).*/
detachInterrupt(0); //Disable interrupt when calculating
rpm = (rpmcount * 60.0)/135.0 ; /* Convert frecuency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/
//Serial.print("RPM =\t"); //print the word "RPM" and tab.
Serial.println(rpm); // print the rpm value.
//Serial.print("\t Hz=\t"); //print the word "Hz".
//Serial.println(pid/*rpmcount*/); /*print revolutions per second or Hz. And print new line or enter.*/
rpmcount = 0; // Restart the RPM counter
lastmillis = millis(); // Uptade lasmillis
attachInterrupt(0, rpm_fan, RISING); //enable interrupt
}
now the problem here is. i am unable to understand how should i apply PD controller in such way that i get the exact pwm value required to achieve the rpm i want as my rpm ranges from 0 to 270 but it does not vary linearly with the PWM value? so how can i write the code to get the exact pwm value so that i can achieve the required rpm?
It doesn't matter that the relationship between PWM and RPM is not linear.
You will first need to download the PID library or otherwise incorporate PID code into your program.
Study on line tutorials to learn how to choose the constants Kp, Ki and Kd (google "PID tuning").
Then choose setpoint = desired RPM, process value = current RPM, and start tuning.
i know the working of PID and its coding but the problem is i dont understand how the calculated PID value will change the PWM of the motor accordingly to reach the required RPM.
volatile int rpmcount = 0;
float rpm = 0;
unsigned long lastmillis = 0;
int pwm = 5;
int dir1 = 11;
int dir2 = 12;
float rotation = 0.00;
float kp=2.5;
float kd=2.0;
float setp = 200.00;
float error =0 ;
float last = 0;
float derr = 0;
float pid = 0;
float mult=8;
void setup(){
//setp = setp*(255.00/262.22);
Serial.begin(9600);
attachInterrupt(0, rpm_fan, RISING);//interrupt cero (0) is on pin two(2)
pinMode(pwm,OUTPUT);
pinMode(dir1,OUTPUT);
pinMode(dir2,OUTPUT);
}
void loop(){
digitalWrite(dir1,HIGH);
digitalWrite(dir2,LOW);
if(c==0)
{
analogWrite(pwm_initalval,);
}
if (millis() - lastmillis == 1000){ /*Uptade every one second, this will be equal to reading frecuency (Hz).*/
detachInterrupt(0); //Disable interrupt when calculating
rpm = (rpmcount * 60.0)/135.0 ; /* Convert frecuency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use rpmcount * 30.*/
//Serial.print("RPM =\t"); //print the word "RPM" and tab.
Serial.println(rpm); // print the rpm value.
//Serial.print("\t Hz=\t"); //print the word "Hz".
//Serial.println(pid/*rpmcount*/); /*print revolutions per second or Hz. And print new line or enter.*/
rpmcount = 0; // Restart the RPM counter
lastmillis = millis(); // Uptade lasmillis
error = (setp - rpm);
derr = last - error;
pid = mul*((kp*error)+(kd*derr)) ;
last = error;
if (pid <255 && pid >0){
analogWrite(pwm,(int)pid); //set motor speed
}
else{
if (pid>255){
//pid = 255;
analogWrite(pwm,255);
}
if(pid<0){
//pid = 0;
analogWrite(pwm,0);
}
attachInterrupt(0, rpm_fan, RISING); //enable interrupt
}
}
}
void rpm_fan(){ /* this code will be executed every time the interrupt 0 (pin2) gets low.*/
rpmcount++;
}
i have written the complete code above, but i am not able to achieve the required RPM correctly. what's wrong in this? is there somehting missing which i am not getting?
what's wrong in this?
You tell us. What does the program do?
How did you choose Kp and Kd and why do you think those values should work properly?
Put some print statements in the program to make sure that the error term and the PID-derived corrections are in the correct direction and are reasonable values.
Finally, it is a mistake to repeatedly use attachInterrupt() and detachInterrupt(). There is no need at all to use detachInterrupt().
i will tune the PID by changing the kp and kd correctly. but will you please tell me that if my code written is correct and am i going in right direction because tuning th epid will be worthless if the code written is wrong.
drocobeth:
now the problem here is. i am unable to understand how should i apply PD controller in such way that i get the exact pwm value required to achieve the rpm i want as my rpm ranges from 0 to 270 but it does not vary linearly with the PWM value? so how can i write the code to get the exact pwm value so that i can achieve the required rpm?
Might need to consider the PWM frequency being used. And may need to consider what wire resistances etc you have between your voltage supply and your motor terminals etc.
will you please tell me that if my code written is correct
No, that is not possible. We don't have your motor/encoder/setup to test it. That is your job.
However, I have already pointed out an error. Have you corrected it?
Finally, it is a mistake to repeatedly use attachInterrupt() and detachInterrupt(). There is no need at all to use detachInterrupt().