#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++;
}