PID Control DC Motor Speed

Hi forum

I had done my own code to control dc motor speed using PID. The code could calculate the speed of rpm unfortunately not giving a correct number. Secondly when the encoder disc of the motor attached to the optical sensor the disc rotate only once and then stop then continue rotate once and stop. Can you check my code and please advice me .

#include <PID_v1.h>
double Setpoint, Input, Output;
volatile int rpmcount = 0;
double rpm = 0;
unsigned long lastmillis = 0;
int outputPin = 9; // motor connected to digital pin 9 output
// Tuning parameters
float Kp=0; //Initial Proportional Gain 
float Ki=10; //Initial Integral Gain 
float Kd=0; //Initial Differential Gain 

// Specify the links and initial tuning parameters
PID myPID(&rpm, &Output, &Setpoint,Kp,Ki,Kd, DIRECT);
const int sampleRate = 1;
unsigned long lastMessage = 0;
unsigned long serialTime;


void setup()
{
Setpoint = 100;
Serial.begin(9600); 
 attachInterrupt(0, rpm_motor, FALLING);//interrupt cero (0) is on pin two(2).
 myPID.SetMode(AUTOMATIC); // Turn on the PID loop as automatic control
  myPID.SetSampleTime(sampleRate); // Sets the sample rate
  lastMessage = millis(); // timestamp

}



void loop()
{

 myPID.Compute(); // Run the PID loop
Output= 200;
analogWrite(outputPin, Output); 
 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;  // Convert frecuency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use rpmcount * 30.
                        //input pid
 Serial.print("RPM =\t"); //print the word "RPM" and tab.
 Serial.print(rpm); // print the rpm value.
 Serial.print("\t Hz=\t"); //print the word "Hz".
 Serial.println(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_motor, FALLING); //enable interrupt
  }
 
}
void rpm_motor(){ // this code will be executed every time the interrupt 0 (pin2) gets low.
  rpmcount++;
}

 
void SerialSend()
{
  Serial.print("PID ");
  Serial.print(Setpoint);   
  Serial.print(" ");
  Serial.print(rpm);   
  Serial.print(" ");
  Serial.print(Output);   
  Serial.print(" ");
  Serial.print(myPID.GetKp());   
  Serial.print(" ");
  Serial.print(myPID.GetKi());   
  Serial.print(" ");
  Serial.print(myPID.GetKd());   
  Serial.print(" ");
  if(myPID.GetMode()==AUTOMATIC) Serial.print("Automatic");
  else Serial.print("Manual");  
  Serial.print(" ");
  if(myPID.GetDirection()==DIRECT) Serial.println("Direct");
  else Serial.println("Reverse");
}

[code]

[/code]

 detachInterrupt(0);    //Disable interrupt when calculating


 rpm = rpmcount * 60;  // Convert frecuency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use rpmcount * 30.
                        //input pid
 Serial.print("RPM =\t"); //print the word "RPM" and tab.
 Serial.print(rpm); // print the rpm value.
 Serial.print("\t Hz=\t"); //print the word "Hz".
 Serial.println(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_motor, FALLING); //enable interrupt

You are doing an awful lot with the interrupt handler detached. What really needs to happen with the interrupt handler detached? You need to make a copy of rpmcount and reset rpmcount to 0.

There's a good reason that function names on the Arduino use camelCase naming conventions. Variables should, too.

 Serial.print("RPM =\t"); //print the word "RPM" and tab.

Really? Is that what that code is doing? I'd have never guessed.

The code could calculate the speed of rpm unfortunately not giving a correct number.

Then why are you doing anything with PID? You need to fix this problem FIRST.

hi forum

At first I used this code to calculate speed of motor with rpm and frequency. The code was working properly but when I modify the code by adding PID it doesnt give proper reading of the speed . Thats why seek your advice. This is my first code calculate speed of motor using rpm.

volatile int rpmcount = 0;
int rpm = 0;
unsigned long lastmillis = 0;
int motorPin = 9; // motor connected to digital pin 9
int analogPin = 0; // potentiometer connected to analog pin 0
int val = 0; // variable to store the read value


void setup()
{
pinMode(motorPin, OUTPUT); // sets the pin as output
Serial.begin(9600); 
 attachInterrupt(0, rpm_motor, FALLING);//interrupt cero (0) is on pin two(2).
}



void loop()
{
val = analogRead(analogPin); // read the input pin
//analogWrite(motorPin, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 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;  // 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.print(rpm); // print the rpm value.
 Serial.print("\t Hz=\t"); //print the word "Hz".
 Serial.println(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_motor, FALLING); //enable interrupt
  }
}
void rpm_motor(){ // this code will be executed every time the interrupt 0 (pin2) gets low.
  rpmcount++;
}[code]

[/code]