Giter VIP home page Giter VIP logo

dlloydev / stune Goto Github PK

View Code? Open in Web Editor NEW
79.0 5.0 15.0 95 KB

Open loop PID autotuner using a novel s-curve inflection point test method. Tuning parameters are determined in about ½Tau on a first-order system with time delay. Full 5Tau testing and multiple serial output options are provided.

License: MIT License

C++ 100.00%
arduino pid autotune tuner fopdt process control step sopdt tuning

stune's People

Contributors

dlloydev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

stune's Issues

Relay Heater sTune

Hello and thank u for both the QuickPID and sTune, they are both great tools to have.

I am having an issue with trying to auto tune my Silicon Heater, i am using a mosfet to control a 24v 200watt heater and use the mosfet in pseudo PWM mode (as a ON/OFF relay) to do so with 1 second intervals.

My issue is that i got no idea how to proceed with sTune since it supports PWM values of 0 to 255 and my heater will not turn on with values below 129 and will turn fully on with values above 130.

Running the tune with the following settings:

const uint32_t testTimeSec = 300;
const float outputStart = 0;
const float outputStep = 255;
const uint16_t samples = 500;
const uint32_t settleTimeSec = 30;

Problem is heater is ON for a long period of time and i am forced to hard stop the tune cause otherwise it will burn out.

Any possible solutions?

Thank u in advance for ur hard work.

output always nan

First of all, great library and thank you for the effort.

I'm using an ESP32 Arduino.

I have an implementation where a user can create any number of thermSystems which is represented as a class for me.
In every thermSystem there is it's own set and measured temperature coming from different sensors.
For every thermSystem there is only one boiler with it's own input which controlls if it has to start to heat or not.
For me, the esp can not directly set a pin to high or low, so i modified your library a little bit in the following ways:

sTune.h

float softDigit(boolean &heatControllBit, float input, float output, float setpoint, uint32_t windowSize, uint8_t debounce);

sTune.cpp

float sTune::softDigit(boolean &heatControllBit, float input, float output, float setpoint, uint32_t windowSize, uint8_t debounce) {

  // software PWM timer
  uint32_t msNow = millis();
  static uint32_t  windowStartTime, nextSwitchTime;
  if (msNow - windowStartTime >= windowSize) {
    windowStartTime = msNow;
  }
  // SSR optimum AC half-cycle controller
  static float optimumOutput;
  static bool reachedSetpoint;

  if (input > setpoint) reachedSetpoint = true;
  if (reachedSetpoint && !debounce && setpoint > 0 && input > setpoint) optimumOutput = output - 8;
  else if (reachedSetpoint && !debounce && setpoint > 0 && input < setpoint) optimumOutput = output + 8;
  else  optimumOutput = output;
  if (optimumOutput < 0) optimumOutput = 0;

  // PWM relay output
  static bool relayStatus;
  if (!relayStatus && optimumOutput > (msNow - windowStartTime)) {
    if (msNow > nextSwitchTime) {
      nextSwitchTime = msNow + debounce;
      relayStatus = true;
      heatControllBit = true;
    }
  } else if (relayStatus && optimumOutput < (msNow - windowStartTime)) {
    if (msNow > nextSwitchTime) {
      nextSwitchTime = msNow + debounce;
      relayStatus = false;
      heatControllBit = false;
    }
  }
  return optimumOutput;
}

As you can see i have added a modification to the softpwm function to be able to set a boolean variable by value instead of a digitalWrite. This is to ensure that no pin is changed in my setup and controlls only at software level.

So with that in mind, i have the following controll functions for the auto tune PID.

/* PID DETAILS */
const uint8_t inputPin = 0;

uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 1000;
const uint16_t samples = 500;
const float inputSpan = 150;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 300;
float tempLimit = 350;

// variables
float Input, Output, Setpoint = 50, Kp, Ki, Kd;
sTune *tuner;
QuickPID *myPID;

void pidInit();
void pidLoop();
/* PID DETAILS */

/*
*     This function is called at startup of the thermSystem
*/
void thermSystem::pidInit() {
    tuner = new sTune(&Input, &Output, tuner->ZN_PID, tuner->directIP, tuner->printOFF);
    myPID = new QuickPID(&Input, &Output, &Setpoint);
    tuner->Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
    tuner->SetEmergencyStop(tempLimit);
}

/*
*     This function is called in every iteration of the loop()
*/
void thermSystem::pidLoop() {
    tuner->softDigit(shouldStartHeat, Input, Output, 0, outputSpan, 1);

    switch (tuner->Run()) {
        case tuner->sample:  // active once per sample during test
            Input = currentTemp;
            //Input = analogRead(inputPin) * 0.322265625 - 50.0;  // get degC (using 3.3v AREF)
            tuner->plotter(Input, Output * 0.1, Setpoint, 1, 3);
            break;

        case tuner->tunings:                       // active just once when sTune is done
            tuner->GetAutoTunings(&Kp, &Ki, &Kd);  // sketch variables updated by sTune
            myPID->SetOutputLimits(0, outputSpan);
            myPID->SetSampleTimeUs(outputSpan * 1000 - 1);
            myPID->SetMode(myPID->Control::automatic);  // the PID is turned on
            myPID->SetProportionalMode(myPID->pMode::pOnMeas);
            myPID->SetAntiWindupMode(myPID->iAwMode::iAwClamp);
            myPID->SetTunings(Kp, Ki, Kd);  // update PID with the new tunings
            break;

        case tuner->runPid: // active once per sample after tunings
            //Input = analogRead(inputPin) * 0.322265625 - 50.0;  // get degC (using 3.3v AREF)
            Input = currentTemp;
            myPID->Compute();
            tuner->plotter(Input, Output, Setpoint, 0.1f, 3);
            break;
    }
}

I have the following output on the serial monitor:

Setpoint:150.00, Input:197.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:230.00, Input:0.00, Output:nan,
Setpoint:150.00, Input:198.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:230.00, Input:0.00, Output:nan,
Setpoint:150.00, Input:198.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:230.00, Input:0.00, Output:nan,
Setpoint:150.00, Input:199.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:230.00, Input:0.00, Output:nan,
Setpoint:150.00, Input:199.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:210.00, Input:0.00, Output:nan,
Setpoint:230.00, Input:0.00, Output:nan,
Setpoint:150.00, Input:199.00, Output:nan,
Setpoint:225.00, Input:0.00, Output:nan,

And my heating can not turn off.
It is always on but the current set temperature is 15.5 celsius which is represented as 155 decimal and the current temperature is 20 celsius which is 200 decimal.

current temperature value is coming in Serial modbus communication which sample rate is roughly equal to the loop iteration in my setup.

What could be the problem?

EDIT

If i restart the system with 155 set temperature and 200 measured temperature the pid is turning on and off my boolean variable for a while, even if the set temperature never exceeds the measured.

At the start of the system it looks like this:

Setpoint:225.00, Input:0.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:41.23,
Setpoint:210.00, Input:0.00, Output:40.47,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:58.07,
Setpoint:210.00, Input:0.00, Output:56.18,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:74.91,
Setpoint:210.00, Input:0.00, Output:71.89,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:91.75,
Setpoint:210.00, Input:0.00, Output:87.60,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:100.00,
Setpoint:210.00, Input:0.00, Output:100.00,
Setpoint:230.00, Input:0.00, Output:30.00,
Setpoint:150.00, Input:202.00, Output:30.00,
Setpoint:210.00, Input:0.00, Output:30.00,
Setpoint:225.00, Input:0.00, Output:100.00,
Setpoint:210.00, Input:0.00, Output:100.00,
Setpoint:230.00, Input:0.00, Output:30.00,

Also there is valve open time which i have to wait before i start the boiler. I don't know how to integrate it into the PID, since it can vari between 1 min to 5 or 10 min while the valve is opening.

Example sTune QuickPID Example dont work

Hello,

i use the example Code https://github.com/Dlloydev/sTune/blob/main/examples/MAX6675_PTC_SSR/sTune_QuickPID/sTune_QuickPID.ino without changing anything. I got the Arduino Mega 2560, PTC heater, Max6675 Thermo Couple and a SSR.
This is my Output.

Setpoint:80.00, Input:25.50, Output:25.00,
Setpoint:80.00, Input:26.25, Output:25.00,
Setpoint:80.00, Input:27.50, Output:25.00,
Setpoint:80.00, Input:28.50, Output:25.00,
Setpoint:80.00, Input:30.00, Output:25.00,
Setpoint:80.00, Input:31.75, Output:25.00,
Setpoint:80.00, Input:34.25, Output:25.00,
Setpoint:80.00, Input:36.50, Output:25.00,
Setpoint:80.00, Input:38.50, Output:25.00,
Setpoint:80.00, Input:41.00, Output:25.00,
Setpoint:80.00, Input:44.25, Output:25.00,
Setpoint:80.00, Input:47.50, Output:25.00,
Setpoint:80.00, Input:50.25, Output:25.00,
Setpoint:80.00, Input:53.50, Output:25.00,
Setpoint:80.00, Input:57.00, Output:25.00,
Setpoint:80.00, Input:60.50, Output:25.00,
Setpoint:80.00, Input:64.25, Output:25.00,
Setpoint:80.00, Input:67.50, Output:25.00,
Setpoint:80.00, Input:71.75, Output:25.00,
Setpoint:80.00, Input:75.75, Output:25.00,
Setpoint:80.00, Input:79.75, Output:25.00,
Setpoint:80.00, Input:84.00, Output:25.00,
Setpoint:80.00, Input:88.00, Output:25.00,
Setpoint:80.00, Input:93.50, Output:25.00,
Setpoint:80.00, Input:98.00, Output:25.00,
Setpoint:80.00, Input:103.25, Output:25.00,
Setpoint:80.00, Input:108.50, Output:25.00,
Setpoint:80.00, Input:113.75, Output:25.00,
Setpoint:80.00, Input:119.25, Output:25.00,
Setpoint:80.00, Input:125.00, Output:25.00,
Setpoint:80.00, Input:131.00, Output:25.00,
Setpoint:80.00, Input:136.75, Output:25.00,
Setpoint:80.00, Input:143.25, Output:25.00,
Setpoint:80.00, Input:149.50, Output:25.00,
ABORT: pvInst > eStop

What did i wrong?

optimumOutput from softPwm looks incorrect

SoftPwm for SSR (delay == 0) looks like it is trying to deal with the extra time due to turn off at a zero crossing when computing optimumOutput.
Since we don't know where our window started in a cycle we will get anywhere from 0 to 0.5 extra cycle of output.
Unless we know where we start, I think the best we could do is make it so we get +/- 0.25 of a cycle by subtracting 0.25 of a cycle.
For 60 Hz that would be 4 mS or 4.1666667 mS, for 50 Hz that would be 5 mS.
I think this is true whether we are above or below the set point.

So

if (input > setpoint) reachedSetpoint = true;
if (reachedSetpoint && !debounce && setpoint > 0 && input > setpoint) optimumOutput = output - 8;
else if (reachedSetpoint && !debounce && setpoint > 0 && input < setpoint) optimumOutput = output + 8;
else optimumOutput = output;
if (optimumOutput < 0) optimumOutput = 0;

would become:

if (input > setpoint) reachedSetpoint = true;
if (reachedSetpoint && !debounce && setpoint > 0 && input > setpoint) optimumOutput = output - 4;
else optimumOutput = output;
if (optimumOutput < 0) optimumOutput = 0;

In reality, if the PID has an "I" component it will correct for the offset so this all may be a moot point.

Big overshoot in tuning with NoOvershoot_PID

Hi,

i use a relay to power a heater but it seems that the relay is never turned off.

I tried it with various settings at the moment following (not really sure what the best values would be):

// user settings
uint32_t Pid::settleTimeSec = 10;
uint32_t Pid::testTimeSec = 200;  // runPid interval = testTimeSec / samples
const uint16_t Pid::samples = 1000;
const float Pid::inputSpan = 1000;
const uint32_t Pid::outputSpan = 10;
float Pid::outputStart = 0;
float Pid::outputStep = 1000;
float Pid::tempLimit = 100;
uint8_t Pid::debounce = 0;

// variables
float Pid::Input;
float Pid::Output;
float Pid::SetPoint = 80;
float Pid::Kp;
float Pid::Ki;
float Pid::Kd;

//setup
    tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
    tuner.SetEmergencyStop(tempLimit);

//loop
        tuner.softPwm(PIN_RELAY, Input, Output, SetPoint, outputSpan, debounce);
        status = tuner.Run();

        switch (status) {
            case tuner.sample: // active once per sample during test
                Input = Sensors::temp_1; // get degC (using 3.3v AREF)
                break;
            case tuner.tunings: // active just once when sTune is done
                tuner.GetAutoTunings(&Kp, &Ki, &Kd); // sketch variables updated by sTune
                quickPid.SetOutputLimits(0, outputSpan);
                quickPid.SetSampleTimeUs((testTimeSec * 1000000) / samples);
                Output = 0;
                quickPid.SetMode(QuickPID::Control::automatic); // the PID is turned on
                quickPid.SetProportionalMode(QuickPID::pMode::pOnMeas);
                quickPid.SetAntiWindupMode(QuickPID::iAwMode::iAwClamp);
                quickPid.SetTunings(Kp, Ki, Kd); // update PID with the new tunings
                break;
            case tuner.runPid: // active once per sample after tunings
                Input = Sensors::temp_1; // get degC (using 3.3v AREF)
                quickPid.Compute();
                break;
            default:
                break;
        }

Even when the emergency stop heat is reached the relay is still on.

sec: 105.2992  out: 1000.00  pv: 90.200  pvPk: 76.317  pvPkCount: 0  ipCount: 1  tan: 14.517 ⚠ ↘

 sec: 106.5091  out: 1000.00  pv: 90.600  pvPk: 76.797  pvPkCount: 0  ipCount: 1  tan: 14.497 ⚠ ↘

 sec: 107.7191  out: 1000.00  pv: 91.000  pvPk: 77.275  pvPkCount: 0  ipCount: 1  tan: 14.475 ⚠ ↘

 sec: 108.9292  out: 1000.00  pv: 91.500  pvPk: 77.753  pvPkCount: 0  ipCount: 1  tan: 14.553 ⚠ ↗

 sec: 110.1392  out: 1000.00  pv: 91.800  pvPk: 78.230  pvPkCount: 0  ipCount: 1  tan: 14.430 ⚠ ↘

 sec: 111.3492  out: 1000.00  pv: 92.300  pvPk: 78.705  pvPkCount: 0  ipCount: 1  tan: 14.405 ⚠ ↘

softPwm --> ledcWrite

Hi.

In my application I am using a ESP32 driving a thrystor using 8 bit PWM. According to the manufacturer the minimum PWM frequency should be 1kHz. Using softPwm, this would mean the windowSize should be < 1 (since millis is used). Since in the .cpp, time variables are uint32_t, the maximum frequency using softPwm would be 1kHz, right?

Then what I don't understand is what would happen with the following MAX31856 example:
`void loop() {
float optimumOutput = tuner.softPwm(relayPin, Input, Output, Setpoint, outputSpan, debounce);

switch (tuner.Run()) {
case tuner.sample: // active once per sample during test
if (!digitalRead(drdyPin)) Input = maxthermo.readThermocoupleTemperature();
tuner.plotter(Input, Output, Setpoint, 0.5f, 3); // output scale 0.5, plot every 3rd sample
break;

case tuner.tunings: // active just once when sTune is done
  tuner.GetAutoTunings(&Kp, &Ki, &Kd); // sketch variables updated by sTune
  myPID.SetOutputLimits(0, outputSpan * 0.1);
  myPID.SetSampleTime(outputSpan - 1);

...`

because when I set outputSpan = 1 (to get the necesarry 1kHz frequency of the PWM) then the PID output will be limited to a max of 0.1.

Would using a function like ledcWrite, which allows frequency to be specified, help solve this issue?

Noisy thermocouple input

Not sure if this is a real issue, but I thought that in any case you would be interested in more data.

I'm building a hot plate for SMD soldering with a k-type thermocouple connected to a MAX6675 and a plate heater controlled by a SSR. I use a relay-like control for the SSR, with 2 sec window and the SSR on for a fraction of that time. I built an Arduino program to auto tune my physical setup.

Unfortunately the MAX6675 output is very noisy, due to the thermocouple limitations. The output can easily change by a degree centigrade just due to noise. When looking at Brett's old autoune library, there was a specific note about noise http://brettbeauregard.com/blog/2012/01/arduino-pid-autotune-library/. The library had a setting for dealing with noise SetNoiseBand()

You are clearly using a different algorithm, and I'm not sure how impacted it is by noise. I also mentioned in another issue that it's very hard for a setup like mine to reach steady state. So even if I'm trying to use always the same conditions (5% output stepping up to 20%, but since I use a 2000 msec PWM window, the values you will see are 100 and 400), the actual values change quite a lot.

I modified your library to also print the thermocouple input value, not just the average, so you can see how noisy the system is. I'm attaching 4 different runs with identical settings but different starting conditions. The suggested K values are actually very consistent, considering the noise and starting conditions

//user settings
const uint32_t testTimeSec = 600;
float outputStart = 100; // 5% start
float outputStep = 400; // 20% step
const uint16_t samples = 600;
const uint32_t settleTimeSec = 300; //5 minutes to settle

pid2.log
pid3.log
pid4.log
pid5.log

PTC Heater Requires Using `direct5T` Test

If running sTune and using a PTC heater, the much quicker directIP test appears to produce good results for everything except for its ability to accurately determine PV max ... this also results in process gain and Kp being inaccurate (process gain too low, Kp too high).

Presently I'm using a thermal calculation to get PV Max which doesn't account for the positive temperature coefficient of the PTC, so I'll need to investigate. I may need to add a new IP test mode for PTC because the IP test is just so fast (240 sec vs 1122 sec) and so close to being ready for PTC testing to ignore. See comparison in image below:

image

PID does not work properly on my environment.

First of all, thank you for this library. It is really a piece of art.
Probably Iam just stupid and can't use it properly.

My setup

  • ESP32-Wrover-E ( 16mb flash, 8mb psram )
  • Arduino environment
  • Quick PID
  • sTune
  • Modbus

The esp32 hosts a webpage where a user can create it's own zones ( rooms ) and can put heating controller inside it.
The user can pick which thermostat to use for which room and can select separate pins for the boiler start, valve open and pump circulation. He can also set how much time it takes for the valve to be opened fully, so the heating can begin and the pumps can circulate the water across the tubes.

This system is represented as separate classes in code.

  • A class for the thermostat which gets the measured temperature via modbus from the physical modul and contains the set temperature which a user can controll
  • A class for the boiler which will controll the boiler on/off state
  • A class for the pump(s) which will controll the pump start/stop and watches for the post circulation time expiration
  • A class for the valve(s) which will controll the valve open/close state and watches for the open time expiration
  • A heating which will controll the flow of the heating on a particular room

So it goes like this:

Heating loop will periodically checks if we can start to heat or not. For this it will ask the thermostat class which will decide based on the measured and set temperature. If it says we can heat, the heating system will start the process.

  • Starts to open the valves
  • After the valves are opened ( not known time, can take from 0 to 600sec ) gives a signal to the boiler to start to heat and starts the pumps

Meanwhile the heating system will periodically checks if the temp is on the set temp. If it is, ( +- hysteresis ) it will start the stop process

  • Takes away the boiler start signal
  • Wait for the defined amount of time to do a post circulation
  • After the post circulation done, it will stop the pump(s) and closes the valve(s)

It is working good, but now i want to give the user the option to be able to controll it with PID
For this i have created a wokwi project which tries to simulate my environmnet and for the life of me i can't figure out why it does not work.

Here is the wokwi simulation: https://wokwi.com/projects/357187661998047233

Do you have any suggestions? ( sorry for the long issue )

( meanwhile I will try to create a more representative simulation at wokwi )

Here is a more detailed simulation of my system.
https://wokwi.com/projects/357256912224692225
If you let the usePID variable false it will do a normal heating controll and controlls the temperature fine.
If you set it to true it will use the PID for temp controll.

Relay heater example

Hello and thank you for the great library and project.
Would it be possible to add example on how to tune relay output pid. I have mosfet switching heater. Or would you suggest some better way then using the mosfet as relay.
I know this thread has been opened before, but I quite don't understand how is was solved.
Thank you very much.
Also this is my first time with github so sory if this is not the proper way to do this.

After PID has run the heater doesn't reach it's setpoint

After a succesfull run of the Stune PID code i get PID. When i put these PID values into my quickPID code the heater doesn't even reach it's Setpoint. It usually overschoots i tiny amount(0.5-1 degrees) and then it wont stay stable and is usually off by -2 degrees celcius. So i wonder if I have coded the stune config right so that i get good PID values.

Or is it that i have to tune the PID values myself to get perfect values? I have already verified that the system's ADC and everything around it is stable enough to get accurate readings.

I have added the two arduino files, one with your Stune code and one where I implemented it with QuickPID.
https://drive.google.com/drive/folders/1xJyZ1f-AH9hoV89mOSyx0aYwIFUbGc3g?usp=sharing

The system that i am using it on is a stm32f411ceu which is reading a 10kthermistor. The output is handled by a IRFz44n Mosfet which is controlled with a PWM signal. This controls the 12VDC towards the heater.

So can you help me and/or have a look at the stune code so that i get the best possible PID values.
Thanks in advance!

"outputStep" is not working correct

Hi
I recently used sTune library for a MAX6675 Furnace... it was hard to tune it manually as temperature changes very slow.
So I decided to use sTune, and tried to edit configuration numbers as best as i can... but, my problem is on "outputStep"...
this parameter is so weird. its default value is 50, and system will start with 50/1000 of heater output. this is so weak to even make my furance a little warm! so i increased it to 700, and test started and finished (but unfortunately every time it gaves a different p-i-d numbers.. anyway).. so:
it is expected that sTune find best "outputStep" automatically; and do no need to be changed by user...
and an IMPORTANT notice, if your setpoint is below current temprature (by mistake, running sTune in midde of work, etc) it wont notice that setpoint is below input and starts with adjusted "outputStep" value, makes your furnace over heated and makes burnings/etc..
please take a look on "outputStep". i think it needs a revision.
Thanks

How to use sTune. (Doc issue? PBCAK?)

I just ported a project from the old PID_v1 library to QuickPID, and everything works well (thanks for all your work!) But my system in unstable (was unstable even with PID_v1), so I want to use sTune.

I looked at the examples for sTune, in particular the QuickPID one, and I'm struggling to understand when the code exits, so that I can retrieve the Kp, Ki and Kd parameters for future use. I looked at the Run method, and I see a similar state machine with some of the same values used in the switch statement in the example (inOut, tunings and runPid). It looks as if the loop() will keep running forever

I'm pretty sure I'm missing something (https://acronyms.thefreedictionary.com/PBCAK), but I think that a couple of extra explanation lines in the readme would help other people as well

SSR High Mass System

I'm using the MAX6675 sTune QuickPID example.

I'm using a 25A SSR to control a 190W heater, it's heating up a plate of aluminum (with Max6675 k type probe). I've tried a few different settings but it doesn’t seem to heat up fast enough, it struggles to maintain heat.

Temp is set at 80C

Thanks!

Can't compile Autotune_PID_v1 example.

Trying to compile Autotune_PID_v1 example returns this error in Arduino IDE 1.8.15 and 2.0.0-beta12:

sketch_jan18a:33:85: error: no matching function for call to 'sTune::sTune(double*, double*, sTune::TuningMethod, sTune::Action, sTune::SerialMode)' sTune tuner = sTune(&Input, &Output, tuner.Mixed_PID, tuner.directIP, tuner.printALL); ^ In file included from E:\Testes Arduino\sTune\sketch_jan18a\sketch_jan18a.ino:6:0: C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:16:5: note: candidate: sTune::sTune(float*, float*, sTune::TuningMethod, sTune::Action, sTune::SerialMode) sTune(float *input, float *output, TuningMethod tuningMethod, Action action, SerialMode serialMode); ^~~~~ C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:16:5: note: no known conversion for argument 1 from 'double*' to 'float*' C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:15:5: note: candidate: sTune::sTune() sTune(); ^~~~~ C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:15:5: note: candidate expects 0 arguments, 5 provided C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:5:7: note: candidate: constexpr sTune::sTune(const sTune&) class sTune { // Inflection Point Autotuner ^~~~~ C:\Users\Rodrigo\Documents\Arduino\libraries\sTune\src/sTune.h:5:7: note: candidate expects 1 argument, 5 provided exit status 1 no matching function for call to 'sTune::sTune(double*, double*, sTune::TuningMethod, sTune::Action, sTune::SerialMode)'

Reset() doesn't properly re-initialize internal variables

I'm building a hot plate for SMD soldering with a k-type thermocouple and a plate heater controlled by a SSR. I use a relay-like control for the SSR, with 2 sec window and the SSR on for a fraction of that time. I built an Arduino program to auto tune my physical setup. Here's the simplified version

//user settings. PWM cycle is 2 seconds, 0-100% is 0-2000
const uint32_t testTimeSec = 600;
float outputStart = 200;     // 10% start
float outputStep = 400;   // 20% step
const uint16_t samples = 600;
const uint32_t settleTimeSec = 300; //5 minutes to settle

float Input = 0, Output = 0, Setpoint = 30, Kp = 0, Ki = 0, Kd = 0;

void setup()
{
sTune tuner = sTune(&Input, &Output, tuner.zieglerNicholsPID, tuner.directIP, tuner.printALL);
  tuner.Configure(outputStart, outputStep, testTimeSec, settleTimeSec, samples);
  reflowStatus = REFLOW_STATUS_ON;
  Output = outputStart;
  /*while (true)
  {
    lcd.setCursor(0, 1);
    lcd.print(analogRead(A0));
    lcd.print("    ");
  }*/
}

void loop()
{
  // Current time
  unsigned long now;

  switch (tuner.Run())
  { // active while sTune is testing (non-blocking)
  case tuner.inOut:
    // Time to read thermocouple?
    if (millis() > nextRead)
    {
      // Read thermocouple next sampling period
      nextRead += SENSOR_SAMPLING_TIME;
      // Read current temperature
      Input = thermocouple.readCelsius();
    }
    break;

  case tuner.tunings:                                         // active just once when sTune is done
    tuner.SetAutoTunings(&Kp, &Ki, &Kd);                      // sketch variables are updated by sTune
    outputStart += 200;
    outputStep += 200;
    if (outputStep > 2001)
    {
      digitalWrite(ssrPin, LOW);
      Serial.println("end");
      while (true) {}
    }
    Output = outputStart;

    tuner.Reset();
    tuner.Configure(outputStart, outputStep, testTimeSec, settleTimeSec, samples); // restart autotune
    break;
  }

  // SSR control 
    now = millis();
    if ((now - windowStartTime) > windowSize)
    {
      // Time to shift the Relay Window
      windowStartTime += windowSize;
    }
    if (Output > (now - windowStartTime))
      digitalWrite(ssrPin, HIGH);
    else
      digitalWrite(ssrPin, LOW);
  }
}

As it's now. the loop runs once, and when I try to reset the autotuner to create a step response for different PWM value, it exits immediately without a settling period nor a full analysis.

In order to make it work for me, I need to change the Reset function into

void sTune::Reset() {
  _Ku = 0.0f;
  _Tu = 0.0f;
  _td = 0.0f;
  _kp = 0.0f;
  _ki = 0.0f;
  _kd = 0.0f;
  _tunerStatus = inOut;
  usPrev = micros();
  settlePrev = micros();
  pvTangentPrev = 0;
  dtCount = 0;
  ipCount = 0;
  plotCount = 0;
  sampleCount = 0;
  pvPkCount = 0; 
}

I'm not sure if all of those are needed, but there are a lot of internal variables that are initialized to 0 only when declared, so the second time sTune is invoked, those have the previous values. I didn't want to fully unravel all your code to see which ones really needed to be changed, so I simply reset to 0 (or the right values) all the internal variables that are declared = 0 in your code (lazy, I know :)

Also, your example code only works if the Arduino is restarted and sTune is called before a long enough time has elapsed, since it assumes that usPrev and settlePrev are close enough to 0 when sTune is called. By adding usPrev = micros(); and settlePrev = micros(); in the Reset() function, it works even as part of a cycle like in my case. Otherwise, if those are not initialized properly on reset(), this line of code simply skips the settling time if (settleElapsed >= _settlePeriodUs) { // if settling period has expired

Use of 0-10V instead of relay

Hi,
I onder how I could use a 0-10 volt to control an oven instead of a relay which switches on or off.
Your help is appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.