I've built the PIDSPINO open source PID board and got it all working except for the PID tunings I think,
The program takes inputs from a potentiometer, a TCRT5000 photo diode and reciever, and a zero crossing detection opto-isolater, which via an interrupt tells the arduino when the AC wave is crossing zero so it can fire the Triac at the right time.
I've the tested the RPM sensor and it works, the serial monitor changes values when I rotate the motor. (refective aluminium tape the shaft in the housing).
when I run the program I can't get the thing to slow down, it just goes flat out and only slows very little when adjusting the pot, I think its related to my program, The LCD also displays the desired output rpm and it too will not come down, It seems that it is tied to the PID function because when I change the tuning parameters, the LCD displays different numbers and jumps large r small amounts on turning of the pot. This program is typically set up for fast router spindels, around 20,000rpm My application requires a much lower RPM, like from 300 -2000rpm.
// TRIAC
#define triac_control 5 // Triac control - pin
//RPM control
#define sensorPin A0 // potentiometer or MACH3 0-5V PWM - pin
//Power
#define powerOn 4 // Power switch - pin
#define powerIndicator 1 // indicator GREEN LED -pin
#define powerOn2 12 // external On/Off from cnc controller
//Zero Detect
#define zero_detect 2 //Zero detect - pin
// when using values in the main routine and IRQ routine must be volatile value
volatile byte zero_bit = LOW; // declare IRQ flag
// HIGH = 1, LOW = 0
// HALL SENSOR
#define hallsensor 3 //- pin
unsigned int rpmcount;
unsigned int rpm;
unsigned long timeold;
//LCD
//LiquidCrystal::LiquidCrystal(rs, enable, d0, d1, d2, d3)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LiquidCrystal lcd(13, 11, 7, 8, 9, 10);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// PID
#include <PID_v1.h>
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Define the aggressive and conservative Tuning Parameters
//double consKp=0.05, consKi=0.73, consKd=0.5; //Original for fast motor consKp=0.05, consKi=0.73, consKd==0.03;
double aggKp=1, aggKi=0.2, aggKd=1;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, DIRECT);
int analogValue = 0;
int analogmin = 80;
int analogmax = 1000;
float kDev = 1; // rpm to analog - exp: max rpm = 22000 , analogmax = 1023 : rpm/analogmax = kDev = 21.5
void setup()
{
//Triac control setup
pinMode(triac_control, OUTPUT);
digitalWrite(triac_control, 0); // LED off
//Power switch
pinMode(powerIndicator, OUTPUT);
digitalWrite(powerIndicator, 0); // LED off
pinMode(powerOn, INPUT);
digitalWrite(powerOn, 1); // pull up
pinMode(powerOn2, INPUT);
digitalWrite(powerOn2, 0);
//Zero detect
pinMode(zero_detect, INPUT);
attachInterrupt(0, zero_fun, RISING); // interrupt 0 digital pin 2 connected ZeroCross circuit
// Hall sensor
pinMode(hallsensor, INPUT);
attachInterrupt(1, rpm_fun, RISING); // interrupt 1 digital pin 3 connected hall sensor
rpmcount = 0;
rpm = 0;
timeold = 0;
// LCD detect
lcd.begin(16,2); // initialize the lcd
lcd.home (); // go home
lcd.print("Hello, ARDUINO ");
lcd.setCursor ( 0, 1 ); // go to the next line
lcd.print (" vSpindel-3.0 ");
delay(3000);
lcd.clear();
//PID
Input = rpm;
Setpoint = analogValue;
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(100, 9980); // limit are set to be delay in microseconds for triac fiering ( 8333 for 60hz, 10000 for 50hz line )9980 to limit max power.
// we realy dont need full speed of 36000
}
void loop()
{
//Power switch and indicator = ON/OFF
if ((!digitalRead(powerOn))||(digitalRead(powerOn2)== 1))
{
digitalWrite(powerIndicator, 1);
}
else
{
digitalWrite(powerIndicator, 0);
}
//RPM counter and show on LCD
if (rpmcount >= 80)
{
//Update RPM every 20 counts, increase this for better RPM resolution,
//decrease for faster update
//rpm = 60*1000/(millis() - timeold)*rpmcount;
unsigned long time = millis() - timeold;
float time_in_sec = (float)time / 1000;
float impuls_time = (float)rpmcount / time_in_sec;
rpm = (int)impuls_time*60;
// rpmcount = 0; //reset
// timeold = millis(); //set time
if (rpm < 10000)
{
lcd.setCursor ( 0, 0 );
lcd.print ("RPM:");
lcd.setCursor ( 4, 0 );
lcd.print (" ");
lcd.setCursor ( 5, 0 );
lcd.print (rpm);
}
else
{
lcd.setCursor ( 0, 0 );
lcd.print ("RPM:");
lcd.setCursor ( 4, 0 );
lcd.print (rpm);
}
lcd.setCursor ( 0, 5 );
lcd.print (rpm); //displaying actual speed on tool shaft motor/shaft=1/2
rpmcount = 0; //reset
timeold = millis(); //set time
}
//PID
analogValue = analogRead(sensorPin); // we are reading pot value
//Input = rpm;
if (analogValue*kDev <300) //check if speed is to low
{
Setpoint = 0;
}
else
{
Setpoint = analogValue*kDev; // setpoint converted to rpm
}
myPID.Compute();
lcd.setCursor ( 0, 1 );
lcd.print ( Output ); // print output for easy pid tunings
//TRIAC delay control
if ((zero_bit == 1) && ((digitalRead(powerOn)== 0)||(digitalRead(powerOn2)== 1))) // checking zero bit and power on/off from switch or cnc controller
{
delayMicroseconds(10000-Output); // delay for triac fiering in reverse, we need smaler delay for more power
digitalWrite(triac_control, 1); //triac on
delayMicroseconds(10); // triac On propogation delay
digitalWrite(triac_control, 0); //triac off
zero_bit = 0; // clear flag
}
}
void zero_fun() // set bit
{
zero_bit = 1;
// if zero detect set bit == 1
}
void rpm_fun() // rpm sensor interrupt
{
rpmcount++;
//Each rotation, this interrupt function is run twice
}