control speed motor using PID arduino and processing

edited January 2014 in Arduino

Dear forum Need your advice I already programmed the PID code in arduino and ran into the processing but __the value output shows0 or 250. Secondly the set point didnt change value remain 100.Need your advice please I attach my code.

include <PID_v1.h>
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int inputPin=0, outputPin=3;
unsigned long serialTime;
//LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
#include <SoftwareSerial.h>
int ActPos = A1;    // select the input pin for feedback signal
int DesPos = A0;    // select the input pin for control signal

byte PWMOutput;
long Error[10];
long Accumulator;
long PID;
int PTerm;
int ITerm;
int DTerm;
byte Divider;
volatile int rpmcount = 0;//see http://arduino.cc/en/Reference/Volatile
int rpm = 0;
unsigned long lastmillis = 0;
int enablePin = 11;
int in1Pin = 10;
int in2Pin = 9;
int switchPin = 8;
int potPin = 1;



void setup()
{
  Serial.begin(9600);
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(enablePin, OUTPUT);
pinMode(switchPin, INPUT_PULLUP);
//lcd.begin(16, 2);
//lcd.print("rpm!");
Serial.begin(9600); 
Input = analogRead(inputPin);
Setpoint = 100;
attachInterrupt(0, rpm_fan, FALLING);//interrupt cero (0) is on pin two(2).
 myPID.SetMode(AUTOMATIC);
}


void GetError(void)
{
  byte i = 0;
  word ActualPosition = analogRead(ActPos);  
   word DesiredPosition = analogRead(DesPos);
    for(i=0;i<10;i++)
    Error[i+1] = Error[i];
    Error[0] = (long)DesiredPosition-(long)ActualPosition;
}
void CalculatePID(void)
{
   PTerm = 2000;
  ITerm = 25;
  DTerm = 0;
  Divider = 10;

// Calculate the PID  
  PID = Error[0]*PTerm;     // start with proportional gain
  Accumulator += Error[0];  // accumulator is sum of errors
  PID += ITerm*Accumulator; // add integral gain and error accumulation
  PID += DTerm*(Error[0]-Error[9]); // differential gain comes next
  PID = PID>>Divider; // scale PID down with divider
   if(PID>=127)
    PID = 127;
  if(PID<=-126)
    PID = -126;
 PWMOutput = PID + 127;
}
union {                // This Data structure lets
  byte asBytes[24];    // us take the byte array
  float asFloat[6];    // sent from processing and
}                      // easily convert it to a
foo;                   // float array
void SerialReceive()
{

  // read the bytes sent from Processing
  int index=0;
  byte Auto_Man = -1;
  byte Direct_Reverse = -1;
  while(Serial.available()&&index<26)
  {
    if(index==0) Auto_Man = Serial.read();
    else if(index==1) Direct_Reverse = Serial.read();
    else foo.asBytes[index-2] = Serial.read();
    index++;

}
}

  // if the information we got was in the correct format, 
  // read it into the system
  //if(index==26  && (Auto_Man==0 || Auto_Man==1)&& (Direct_Reverse==0 || Direct_Reverse==1))
 // {
   // Setpoint=double(foo.asFloat[0]);
    //Input=double(foo.asFloat[1]);       // * the user has the ability to send the 
                                          //   value of "Input"  in most cases (as 
                                          //   in this one) this is not needed.
   // if(Auto_Man==0)                       // * only change the output if we are in 
   // {                                     //   manual mode.  otherwise we'll get an
   //   Output=double(foo.asFloat[2]);      //   output blip, then the controller will 
   // /}                                     //   overwrite.

void loop()
{
  Input = analogRead(inputPin);
  myPID.Compute();
  analogWrite(outputPin,Output);
int speed = analogRead(potPin) / 4;
myPID.Compute();
boolean reverse = digitalRead(switchPin);
setMotor(speed, reverse);

 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_fan, FALLING); //enable interrupt
 if(millis()>serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime+=500;
  }
  }

}
void SerialSend()
{
  Serial.print("PID ");
  Serial.print(Setpoint);   
  Serial.print(" ");
  Serial.print(Input);   
  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");
}


void setMotor(int speed, boolean reverse)
{
analogWrite(enablePin, speed);
digitalWrite(in1Pin, ! reverse);
digitalWrite(in2Pin, reverse);
}

void rpm_fan(){ // this code will be executed every time the interrupt 0 (pin2) gets low.
  rpmcount++;
}

Answers

  • Dear forum Need your advice I already programmed the PID code in arduino and ran into the processing but __the value output shows0 or 250. Secondly the set point didnt change value remain 100.Need your advice please I attach my code.please ignore previous code its error this the latest.

    #include <PID_v1.h>
    double Setpoint, Input, Output;
    PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
    int inputPin=0, outputPin=3;
    unsigned long serialTime;
    //LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
    #include <SoftwareSerial.h>
    int ActPos = A1;    // select the input pin for feedback signal
    int DesPos = A0;    // select the input pin for control signal
    
    byte PWMOutput;
    long Error[10];
    long Accumulator;
    long PID;
    int PTerm;
    int ITerm;
    int DTerm;
    byte Divider;
    volatile int rpmcount = 0;//see http://arduino.cc/en/Reference/Volatile
    int rpm = 0;
    unsigned long lastmillis = 0;
    int enablePin = 11;
    int in1Pin = 10;
    int in2Pin = 9;
    int switchPin = 8;
    int potPin = 1;
    
    
    
    void setup()
    {
      Serial.begin(9600);
    pinMode(in1Pin, OUTPUT);
    pinMode(in2Pin, OUTPUT);
    pinMode(enablePin, OUTPUT);
    pinMode(switchPin, INPUT_PULLUP);
    //lcd.begin(16, 2);
    //lcd.print("rpm!");
    Serial.begin(9600); 
    Input = analogRead(inputPin);
    Setpoint = 100;
    attachInterrupt(0, rpm_fan, FALLING);//interrupt cero (0) is on pin two(2).
     myPID.SetMode(AUTOMATIC);
    }
    
    
    void GetError(void)
    {
      byte i = 0;
      word ActualPosition = analogRead(ActPos);  
       word DesiredPosition = analogRead(DesPos);
        for(i=0;i<10;i++)
        Error[i+1] = Error[i];
        Error[0] = (long)DesiredPosition-(long)ActualPosition;
    }
    void CalculatePID(void)
    {
       PTerm = 2000;
      ITerm = 25;
      DTerm = 0;
      Divider = 10;
    
    // Calculate the PID  
      PID = Error[0]*PTerm;     // start with proportional gain
      Accumulator += Error[0];  // accumulator is sum of errors
      PID += ITerm*Accumulator; // add integral gain and error accumulation
      PID += DTerm*(Error[0]-Error[9]); // differential gain comes next
      PID = PID>>Divider; // scale PID down with divider
       if(PID>=127)
        PID = 127;
      if(PID<=-126)
        PID = -126;
     PWMOutput = PID + 127;
    }
    union {                // This Data structure lets
      byte asBytes[24];    // us take the byte array
      float asFloat[6];    // sent from processing and
    }                      // easily convert it to a
    foo;                   // float array
    void SerialReceive()
    {
    
      // read the bytes sent from Processing
      int index=0;
      byte Auto_Man = -1;
      byte Direct_Reverse = -1;
      while(Serial.available()&&index<26)
      {
        if(index==0) Auto_Man = Serial.read();
        else if(index==1) Direct_Reverse = Serial.read();
        else foo.asBytes[index-2] = Serial.read();
        index++;
    
    }
    }
    
      // if the information we got was in the correct format, 
      // read it into the system
      //if(index==26  && (Auto_Man==0 || Auto_Man==1)&& (Direct_Reverse==0 || Direct_Reverse==1))
     // {
       // Setpoint=double(foo.asFloat[0]);
        //Input=double(foo.asFloat[1]);       // * the user has the ability to send the 
                                              //   value of "Input"  in most cases (as 
                                              //   in this one) this is not needed.
       // if(Auto_Man==0)                       // * only change the output if we are in 
       // {                                     //   manual mode.  otherwise we'll get an
       //   Output=double(foo.asFloat[2]);      //   output blip, then the controller will 
       // /}                                     //   overwrite.
    
    void loop()
    {
      Input = analogRead(inputPin);
      myPID.Compute();
      analogWrite(outputPin,Output);
    int speed = analogRead(potPin) / 4;
    myPID.Compute();
    boolean reverse = digitalRead(switchPin);
    setMotor(speed, reverse);
    
     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_fan, FALLING); //enable interrupt
     if(millis()>serialTime)
      {
        SerialReceive();
        SerialSend();
        serialTime+=500;
      }
      }
    
    }
    void SerialSend()
    {
      Serial.print("PID ");
      Serial.print(Setpoint);   
      Serial.print(" ");
      Serial.print(Input);   
      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");
    }
    
    
    void setMotor(int speed, boolean reverse)
    {
    analogWrite(enablePin, speed);
    digitalWrite(in1Pin, ! reverse);
    digitalWrite(in2Pin, reverse);
    }
    
    void rpm_fan(){ // this code will be executed every time the interrupt 0 (pin2) gets low.
      rpmcount++;
    }
    
Sign In or Register to comment.