Skip to content

Navigation Menu

Sign in
Sign up

Trying to figure out tuning values for PolyFormer #17

Answered by Dlloydev
alextrical asked this question in Q&A
Discussion options

Firstly, thank you for an amazing library, and continuing to improve the PID_V1 library.

I'm hoping to use this library to control a hot-end in a PullStruder called the PolyFormer.
To get the temperature in Celsius from from thermistor I'm using the NTC_Thermistor library and passing the reading to the "Input" variable in the TCLab_Thermal_PWM/sTune_QuickPID example.
However I cannot seem to get the example to set the output to full power, or avoid a large overshoot. I know its a PBCAK, but not sure how to configure this.

The simplified schematic for the control circuit is here. The thermistor being used is a 3950
image

The desired setpoint is 220C using a FQP30N06L or AO3400 MOSFET

The test code I'm trying to use is the following

 sTune QuickPID Example
 This sketch does on-the-fly tunning and PID Digital Output control
 of a thermal heater (TIP31C). Tunning parameters are quickly
 determined and applied during the temperature ramp-up to setpoint.
 Open the serial plotter to view the graphical results.
 *****************************************************************/
#include <sTune.h>
#include <QuickPID.h>
#include <Thermistor.h>
#include <NTC_Thermistor.h>
#define SENSOR1_PIN PA2
#define REFERENCE_RESISTANCE 4700
#define NOMINAL_RESISTANCE 100000
#define NOMINAL_TEMPERATURE 25
#define B_VALUE 3950
#define STM32_ANALOG_RESOLUTION 65535 //16 Bit resolution
Thermistor* thermistor1;
// pins
//const uint8_t inputPin = 0;
const uint8_t relayPin = PA7;
// user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 500;
const uint16_t samples = 500;
const float inputSpan = 50;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 300;
float tempLimit = 280;
// variables
float Input, Output, Setpoint = 220, Kp, Ki, Kd;
sTune tuner = sTune(&Input, &Output, tuner.ZN_PID, tuner.directIP, tuner.printOFF);
QuickPID myPID(&Input, &Output, &Setpoint);
void setup() {
 pinMode(relayPin, OUTPUT);
 Serial.begin(9600);
 analogReadResolution(16); //Set Resolution of ADC to 16 bit, this will pad any lower resolution values, giving us future flexability
 thermistor1 = new NTC_Thermistor(
 SENSOR1_PIN,
 REFERENCE_RESISTANCE,
 NOMINAL_RESISTANCE,
 NOMINAL_TEMPERATURE,
 B_VALUE,
 STM32_ANALOG_RESOLUTION // <- for a thermistor calibration
 );
 while (!Serial) delay(10);
 delay(3000);
 tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
 tuner.SetEmergencyStop(tempLimit);
}
void loop() {
 tuner.softPwm(relayPin, Input, Output, 0, outputSpan, 1);
 switch (tuner.Run()) {
 case tuner.sample: // active once per sample during test
 Input = thermistor1->readCelsius();
 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 = thermistor1->readCelsius();
 myPID.Compute();
 tuner.plotter(Input, Output, Setpoint, 0.1f, 3);
 break;
 }
}

Any advice is greatly appreciated

You must be logged in to vote

Thanks for the test results.

Yes, sTune will complete its test early (at the inflection point if set to tuner.directIP.
sTune doesn't try to reach any setpoint ... it just determines how a system responds to a step change in power. There's no PID control while using sTune.

Note that the outputStep was set to 50. Since the outputSpan is 1000, this is only 5% power and the temp only increased about 4C during the test. I suggest trying outputStep of 500 (50% power). The temp doesn't need to reach 90C, but if the sTune test could bring it up to at least 50C, then the results would be much better.

You could also try using tuner.direct5T which is much slower, but might give better results:
sTun...

Replies: 6 comments 4 replies

Comment options

I'm also not sure why its setting the output to 1/10th the Output step value. This looks to result in steps being 30/1000 outputSpan and causing a slow heat up.
image
image

You must be logged in to vote
0 replies
Comment options

Thanks for the detailed information. In your example, the plotter was scaled to 0.1, but this doesn't affect the actual output which would go to 1000 max.

In the following updated example, I've changed the input span to 280 as this was set too low.

The output scale is now 0.2 so it will show 1/5th of the true output. The output at 1000 max will show 200, but it won't re-scale the overall plot and make the Input graph smaller.

Also, since the desired setpoint is quite high, I've changed the outputStep to 500.

/******************************************************************
 sTune QuickPID Example
 This sketch does on-the-fly tunning and PID Digital Output control
 of a thermal heater (TIP31C). Tunning parameters are quickly
 determined and applied during the temperature ramp-up to setpoint.
 Open the serial plotter to view the graphical results.
*****************************************************************/
#include <sTune.h>
#include <QuickPID.h>
#include <Thermistor.h>
#include <NTC_Thermistor.h>
#define SENSOR1_PIN PA2
#define REFERENCE_RESISTANCE 4700
#define NOMINAL_RESISTANCE 100000
#define NOMINAL_TEMPERATURE 25
#define B_VALUE 3950
#define STM32_ANALOG_RESOLUTION 65535 //16 Bit resolution
Thermistor* thermistor1;
// pins
//const uint8_t inputPin = 0;
const uint8_t relayPin = PA7;
// user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 500;
const uint16_t samples = 500;
const float inputSpan = 280;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 500;
float tempLimit = 280;
uint8_t debounce = 1;
// variables
float Input, Output, Setpoint = 220, Kp, Ki, Kd;
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);
 analogReadResolution(16); //Set Resolution of ADC to 16 bit, this will pad any lower resolution values, giving us future flexability -------------------------------------------------
 thermistor1 = new NTC_Thermistor(
 SENSOR1_PIN,
 REFERENCE_RESISTANCE,
 NOMINAL_RESISTANCE,
 NOMINAL_TEMPERATURE,
 B_VALUE,
 STM32_ANALOG_RESOLUTION // <- for a thermistor calibration
 );
 while (!Serial) delay(10);
 delay(3000);
 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 = thermistor1->readCelsius();
 tuner.plotter(Input, Output, Setpoint, 0.2f, 3); // output scale 0.2, 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 = thermistor1->readCelsius();
 myPID.Compute();
 tuner.plotter(Input, optimumOutput, Setpoint, 0.2f, 3); // output scale 0.2, plot every 3rd sample
 break;
 }
}
You must be logged in to vote
0 replies
Comment options

Thank you so much for getting back to me so quickly, I have tried the modified code that you sent, but still seem to be having issues with throttling the power to the heater before it reaches the setpoint. Do you know what I may be doing wrong?
image

You must be logged in to vote
0 replies
Comment options

Looking at the red input, the graph begins with the input temperature still cooling from a previous test. You'll need to make sure the input temperature has settled (stable) prior to starting a new test. (you may need to wait up to 15 minutes between tests).

Also, try increasing outputSpan to 2000 (2 seconds) and testTimeSec to 750.

You must be logged in to vote
1 reply
Comment options

the changes you mentioned resulted in the following output, after making sure the input temperature was stable by not using it for a few hours.
Is there a way to make it reach the setpoint faster my forcing the output to a higher output percentage until its closer to the setpoint?
image

I'm going to see if using Analogue write makes any difference to the output, but it looks like the output starts at the "outputStep" value, and slowly moves from there. Is that the expected outcome?

image

Comment options

Yes, after sTune completes, the PID output starts at the outputStep value to allow "on-the-fly tuning.

I suppose you could speed things up by boosting the proportional gain by using something like this
myPID.SetTunings(Kp * 2, Ki, Kd);

It might be helpful to see the serial print of the Get_All_Tunings example that uses your settings.

You must be logged in to vote
1 reply
Comment options

I ran the following code

/****************************************************************************
 sTune Get All Tunings Example (TCLab - Thermal Heater using digital output)
 ****************************************************************************/
#include <sTune.h>
#include <Thermistor.h>
#include <NTC_Thermistor.h>
#define SENSOR1_PIN PA2
#define REFERENCE_RESISTANCE 4700
#define NOMINAL_RESISTANCE 100000
#define NOMINAL_TEMPERATURE 25
#define B_VALUE 3950
#define STM32_ANALOG_RESOLUTION 65535 //16 Bit resolution
Thermistor* thermistor1;
// pins
//const uint8_t inputPin = 0;
const uint8_t relayPin = PA7;
// user settings
uint32_t settleTimeSec = 10;
uint32_t testTimeSec = 500;
const uint16_t samples = 500;
const float inputSpan = 150;
const float outputSpan = 1000;
float outputStart = 0;
float outputStep = 50;
float tempLimit = 90;
// variables
float Input, Output;
sTune tuner = sTune(&Input, &Output, tuner.ZN_PID, tuner.directIP, tuner.printALL);
void setup() {
 // analogReference(EXTERNAL); // 3.3V
 pinMode(relayPin, OUTPUT);
 Serial.begin(9600);
 analogReadResolution(16); //Set Resolution of ADC to 16 bit, this will pad any lower resolution values, giving us future flexability
 thermistor1 = new NTC_Thermistor(
 SENSOR1_PIN,
 REFERENCE_RESISTANCE,
 NOMINAL_RESISTANCE,
 NOMINAL_TEMPERATURE,
 B_VALUE,
 STM32_ANALOG_RESOLUTION // <- for a thermistor calibration
 );
 while (!Serial) delay(10);
 delay(3000);
 Output = 0;
 tuner.Configure(inputSpan, outputSpan, outputStart, outputStep, testTimeSec, settleTimeSec, samples);
 tuner.SetEmergencyStop(tempLimit);
}
void loop() {
 tuner.softPwm(relayPin, Input, Output, 0, outputSpan, 1);
 switch (tuner.Run()) {
 case tuner.sample: // active once per sample during test
 Input = thermistor1->readCelsius(); // get degC
 break;
 case tuner.tunings: // active just once when sTune is done
 Output = 0;
 tuner.SetTuningMethod(tuner.TuningMethod::DampedOsc_PID);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::NoOvershoot_PID);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::CohenCoon_PID);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::Mixed_PID);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::ZN_PI);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::DampedOsc_PI);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::NoOvershoot_PI);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::CohenCoon_PI);
 tuner.printTunings();
 tuner.SetTuningMethod(tuner.TuningMethod::Mixed_PI);
 tuner.printTunings();
 break;
 }
}

It resulted in the serial output attached
SerialOutput1.txt

It looks like its maxing out at 1 step of power, and timing out before it reaches the intended setpoint of 90C.
The output is a 40W heater attached to a 3d printer hot end if that's of any help to track down the issue

Thank you for all of your help

Comment options

Thanks for the test results.

Yes, sTune will complete its test early (at the inflection point if set to tuner.directIP.
sTune doesn't try to reach any setpoint ... it just determines how a system responds to a step change in power. There's no PID control while using sTune.

Note that the outputStep was set to 50. Since the outputSpan is 1000, this is only 5% power and the temp only increased about 4C during the test. I suggest trying outputStep of 500 (50% power). The temp doesn't need to reach 90C, but if the sTune test could bring it up to at least 50C, then the results would be much better.

You could also try using tuner.direct5T which is much slower, but might give better results:
sTune tuner = sTune(&Input, &Output, tuner.ZN_PID, tuner.direct5T, tuner.printALL);

You must be logged in to vote
2 replies
Comment options

Ah, ok, so it just runs at 5% power for the full test. It feels odd that it isn't seeing any oscillation to work out the PID tuning, but some amazing maths must be going on in the background ^_^
I'm going to test the 50% power output now

Comment options

I tried 100% power, and got the following serial output. I think this is for a range of 109C
SerialOutput2.txt

I will try the "tuner.direct5T" setting once the system cools back down for a stable temperature.

Answer selected by alextrical
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /