Giter VIP home page Giter VIP logo

Comments (10)

Dlloydev avatar Dlloydev commented on May 28, 2024

Perhaps the heater power rating is too low for the quicker response you need.
If manually turning on the heater (full on), how long does it take for the temperature to reach 80C ?

Could you show the example code you're using?
What type of heater (PTC?) and SSR are you using?

from stune.

lpearl avatar lpearl commented on May 28, 2024

I ran a test and it took 3min 40sec to heat up to 80C full on. Even if I add another 190W heater it will still take at least a minute to heat up. I'm just trying it keep the temp around 80C during use.

Code used is below:
I have tried a few different outputSpan settings but haven’t had much luck.
Also tried setting debounce to 0

#include <max6675.h>
#include <sTune.h>
#include <QuickPID.h>

// pins
const uint8_t relayPin = 3;
const uint8_t SO = 12;
const uint8_t CS = 27;
const uint8_t sck = 26;

// user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 500;  // runPid interval = testTimeSec / samples
const uint16_t samples = 500;
const float inputSpan = 200;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 50;
float tempLimit = 150;
uint8_t debounce = 1;

// variables
float Input, Output, Setpoint = 80, Kp, Ki, Kd;

MAX6675 module(sck, CS, SO); //SPI
sTune tuner = sTune(&Input, &Output, tuner.ZN_PID, tuner.directIP, tuner.printOFF);
QuickPID myPID(&Input, &Output, &Setpoint);

void setup() {
  pinMode(relayPin, OUTPUT);
  Serial.begin(115200);
  delay(3000);
  Output = 0;
  tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
  tuner.SetEmergencyStop(tempLimit);
}

void loop() {
  float optimumOutput = tuner.softPwm(relayPin, Input, Output, Setpoint, outputSpan, debounce);

  switch (tuner.Run()) {
    case tuner.sample: // active once per sample during test
      Input = module.readCelsius();
      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.SetSampleTimeUs((outputSpan - 1) * 1000);
      debounce = 0; // ssr mode
      Output = outputStep;
      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 = module.readCelsius();
      myPID.Compute();
      tuner.plotter(Input, optimumOutput, Setpoint, 0.5f, 3);
      break;
  }
}

The heater is an AC cartridge heater similar to what you would find in a 3D printer, just bigger. The SSR is BRM-25DA that I got off amazon.

from stune.

lpearl avatar lpearl commented on May 28, 2024

Ah sorry I didn’t mean to do that

from stune.

Dlloydev avatar Dlloydev commented on May 28, 2024

Thank you for the details. Could you give this a try?

#include <max6675.h>
#include <sTune.h>
#include <QuickPID.h>

// pins
const uint8_t relayPin = 3;
const uint8_t SO = 12;
const uint8_t CS = 27;
const uint8_t sck = 26;

// user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 700;  // runPid interval = testTimeSec / samples
const uint16_t samples = 700;
const float inputSpan = 200;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 400;
float tempLimit = 150;
uint8_t debounce = 1;

// variables
float Input, Output, Setpoint = 80, Kp, Ki, Kd;

MAX6675 module(sck, CS, SO); //SPI
sTune tuner = sTune(&Input, &Output, tuner.ZN_PID, tuner.directIP, tuner.printOFF);
QuickPID myPID(&Input, &Output, &Setpoint);

void setup() {
  pinMode(relayPin, OUTPUT);
  Serial.begin(115200);
  delay(3000);
  Output = 0;
  tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
  tuner.SetEmergencyStop(tempLimit);
}

void loop() {
  float optimumOutput = tuner.softPwm(relayPin, Input, Output, Setpoint, outputSpan, debounce);

  switch (tuner.Run()) {
    case tuner.sample: // active once per sample during test
      Input = module.readCelsius();
      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);
      myPID.SetSampleTimeUs((outputSpan - 1) * 1000);
      debounce = 0; // ssr mode
      Output = outputStep;
      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 = module.readCelsius();
      myPID.Compute();
      tuner.plotter(Input, optimumOutput, Setpoint, 0.5f, 3);
      break;
  }
}

from stune.

lpearl avatar lpearl commented on May 28, 2024

It was doing good at first but started to throttle around 50C, it seems to be going up but significantly slower. I'm going to keep it running to see if it's able to get up to temp.

from stune.

Dlloydev avatar Dlloydev commented on May 28, 2024

It might help if the proportional gain is increased by using something like this
myPID.SetTunings(Kp * 2, Ki, Kd);

Could also try increasing the outputStep to 600.

Hopefully later this year I'll get some time to do some testing with non-ptc type heaters (like yours) and do some work on updated code, examples and documentation.

from stune.

lpearl avatar lpearl commented on May 28, 2024

It was able to get up to temp with an output step of 600. I couldn’t see if it was holding temp because the serial monitor stopped receiving data (loose cable). Is it supposed to print out pid values when it is done?

I couldn’t get the Kp * 2 working the error was about a float* multiplying with an int. I tried a float but it didn’t work either.

from stune.

Dlloydev avatar Dlloydev commented on May 28, 2024

With the example above, it will keep printing every 3rd sample as long as the PID is running.

from stune.

lpearl avatar lpearl commented on May 28, 2024

I just did some manual tuning using the QuickPID library. It is working well with some custom PWM code. I will close this for now since it seems auto-tunning is not the best method for systems with lots of lag.

You mentioned it prints every 3ed sample, but not the tuned kp, ki, kd values, only Output, Input, and Setpoint.

from stune.

matthew798 avatar matthew798 commented on May 28, 2024

Hello, I am also having some issues getting a system with significant lag to work.

I am using a toaster oven, a K type thermocouple wired to a MAX6675, and an esp32 controlling an SSR.

In my case, the test finishes after only 45 seconds (though the testTimeSec = 500). The calculated tunings don't work at all and result is the oven being on for less than 10% of the time (visually).

Here is the test:

 sec: 9.0000  out: 500.00  pv: 0.000  settling  ⤳⤳
 sec: 8.0000  out: 500.00  pv: 22.000  settling  ⤳⤳
 sec: 7.0000  out: 500.00  pv: 21.750  settling  ⤳⤳
 sec: 6.0000  out: 500.00  pv: 22.000  settling  ⤳⤳
 sec: 5.0000  out: 500.00  pv: 21.750  settling  ⤳⤳
 sec: 4.0000  out: 500.00  pv: 21.500  settling  ⤳⤳
 sec: 3.0000  out: 500.00  pv: 21.750  settling  ⤳⤳
 sec: 2.0000  out: 500.00  pv: 22.250  settling  ⤳⤳
 sec: 1.0000  out: 500.00  pv: 21.750  settling  ⤳⤳
 sec: 0.0000  out: 500.00  pv: 21.750  tan: 0.000 →
 sec: 1.0000  out: 750.00  pv: 21.750  tan: 0.000 →
 sec: 2.0000  out: 750.00  pv: 21.750  tan: 0.000 →
 sec: 3.0000  out: 750.00  pv: 21.500  tan: -0.021 ↘
 sec: 4.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 5.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 6.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 7.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 8.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 9.0000  out: 750.00  pv: 21.750  tan: -0.021 →
 sec: 10.0000  out: 750.00  pv: 22.250  tan: 0.021 ↗
 sec: 11.0000  out: 750.00  pv: 21.500  tan: 0.000 ↘
 sec: 12.0000  out: 750.00  pv: 22.000  tan: 0.021 ↗
 sec: 13.0000  out: 750.00  pv: 22.000  tan: 0.042 ↗
 sec: 14.0000  out: 750.00  pv: 21.750  tan: 0.292 ↗
 sec: 15.0000  out: 750.00  pv: 21.750  tan: 0.062 ↘
 sec: 16.0000  out: 750.00  pv: 21.750  tan: 0.062 →
 sec: 17.0000  out: 750.00  pv: 22.000  tan: 0.083 ↗
 sec: 18.0000  out: 750.00  pv: 22.000  tan: 0.104 ↗
 sec: 19.0000  out: 750.00  pv: 21.500  tan: 0.083 ↘
 sec: 20.0000  out: 750.00  pv: 21.750  tan: 0.083 →
 sec: 21.0000  out: 750.00  pv: 22.000  tan: -0.396 ↘
 sec: 22.0000  out: 750.00  pv: 22.000  tan: 0.333 ↗
 sec: 23.0000  out: 750.00  pv: 22.000  tan: -0.125 ↘
 sec: 24.0000  out: 750.00  pv: 21.500  tan: -0.167 ↘
 sec: 25.0000  out: 750.00  pv: 22.250  tan: 0.104 ↗
 sec: 26.0000  out: 750.00  pv: 21.750  tan: 0.104 →
 sec: 27.0000  out: 750.00  pv: 22.000  tan: 0.125 ↗
 sec: 28.0000  out: 750.00  pv: 22.000  tan: -0.104 ↘
 sec: 29.0000  out: 750.00  pv: 22.250  tan: -0.083 ↗
 sec: 30.0000  out: 750.00  pv: 22.250  tan: 0.437 ↗
 sec: 31.0000  out: 750.00  pv: 22.250  tan: 0.250 ↘
 sec: 32.0000  out: 750.00  pv: 22.250  tan: 0.042 ↘
 sec: 33.0000  out: 750.00  pv: 22.250  tan: 0.062 ↗
 sec: 34.0000  out: 750.00  pv: 22.750  tan: 0.125 ↗
 sec: 35.0000  out: 750.00  pv: 22.750  tan: 0.687 ↗
 sec: 36.0000  out: 750.00  pv: 22.750  tan: 0.042 ↘
 sec: 37.0000  out: 750.00  pv: 23.000  tan: 0.604 ↗
 sec: 38.0000  out: 750.00  pv: 22.750  tan: 0.437 ↘
 sec: 39.0000  out: 750.00  pv: 22.750  tan: 0.500 ↗
 sec: 40.0000  out: 750.00  pv: 23.000  tan: 0.333 ↘
 sec: 41.0000  out: 750.00  pv: 23.250  tan: 0.417 ↗
 sec: 42.0000  out: 750.00  pv: 23.500  tan: 0.521 ↗
 sec: 43.0000  out: 750.00  pv: 22.750  tan: 0.562 ↗
 sec: 44.0000  out: 750.00  pv: 23.000  tan: 0.625 ↗
 sec: 45.0000  out: 750.00  pv: 23.500  tan: 0.229 ↘

The results:

 Controller Action: directIP

 Output Start:      500.00
 Output Step:       750.00
 Sample Sec:        1.0000

 Pv Start:          21.750
 Pv Max:            25.998
 Pv Diff:           4.248

 Process Gain:      0.049
 Dead Time Sec:     32.000
 Tau Sec:           35.971

 Tau/Dead Time:     1.1 (easy to control)
 Tau/Sample Period: 36.0 (good sample rate)

 Tuning Method: NoOvershoot_PID
  Kp: 13.892
  Ki: 0.028  Ti: 499.703
  Kd: 0.062  Td: 222.269

Ideally, the oven should have an initial phase where it is 100% on, then slowly taper off as it reaches it's temp. Instead it completes the test and immediately reverts to such a small on-time that the oven actually cools while the PID loop is trying to heat it.

I will try to tune the oven manually but i'd really like to use autotuning as the thermal mass in the oven will vary greatly, and it would be amazing to have the oven calibrate itself to the contents every run.

Here is my code:

/ user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 200;  // runPid interval = testTimeSec / samples
const uint16_t samples = 200;
const float inputSpan = 350;
const float outputSpan = 1000;
float outputStart = 500;
float outputStep = 750;
float tempLimit = 150;
uint8_t debounce = 1;

// variables
float Input, Output, Setpoint = 100, Kp, Ki, Kd;

MAX6675 module(sck, CS, SO); //SPI
sTune tuner = sTune(&Input, &Output, tuner.NoOvershoot_PID, tuner.directIP, tuner.printALL);
QuickPID myPID(&Input, &Output, &Setpoint);


void setup() {
  pinMode(relayPin, OUTPUT);
  Serial.begin(115200);
  delay(3000);
  Output = 0;
  tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
  tuner.SetEmergencyStop(tempLimit);
}

void loop() {
  float optimumOutput = tuner.softPwm(relayPin, Input, Output, Setpoint, outputSpan, debounce);

  
  //Serial.print("Temp: ");
  //Serial.printf("%f", Input);
  //Serial.println("deg C");

  switch (tuner.Run()) {
    case tuner.sample: // active once per sample during test
      Input = module.readCelsius();
      //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.SetSampleTimeUs((outputSpan - 1) * 1000);
      debounce = 0; // ssr mode
      Output = outputStep;
      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 = module.readCelsius();
      Serial.printf("PV: %f deg C \r", Input);
      myPID.Compute();
      //tuner.plotter(Input, optimumOutput, Setpoint, 0.5f, 3);
      break;
  }
}

from stune.

Related Issues (20)

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.