Motor speed controller, PID won't slow down.

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
 }

Please post your debugging output.

How do you mean debugging output?

The serial test I ran for the RPM sensor was with a different simple sketch, This only outputs to an LCD screen, I can maybe take a video of it?

I've just swapped out a new opto-coupler for the Zero cross, and I read 50hz on the cold side so I know thats working,

Its weird it just will not slow down no matter how I play with the tuning parameters now, i'm confused because you would think the PID library would handle the switching of the Triac but it is in the main code.

I think my failure has something to do with the RPM variable.

Oh, OK, I saw the lcd.print and mistook it for Serial.print.

Still it might be interesting to add some Serial.print lines that show the variables. That is a standard technique for working out what the program is "thinking".

I've used the original v2 PIDSPINO code and tested my IR sensor, the connections wern't great and were intermittant, its better now The motor is actually hunting for the right RPM but the signal values from my IR are not clean, It gets the odd reading in a very high range and it cuts the power and stops turning and dosn't restart (when motor is stopped on with the reflector infront of the IR sensor.) I need to add some software or hardware filtering to clean up the signal I think.

Thanks for your help tho Nick, Don't think I would have got here as I was thinking it was all software and wouldn't have rechecked.

Many thanks.

The PID is using Input as its input variable. Clearly this is intended to contain the current rpm, but you never assign the calculated rpm value to the Input variable (the assignment is commented out). Since the PID never sees the speed change in response to its Output, it will keep trying to correct it.