Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose integral for user-space anti-windup access #132

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions PID_v1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ void PID::SetMode(int Mode)
inAuto = newAuto;
}

/* GetIntegral(...)*************************************************************
* Get Integral term for user access to anti-windup schemes
******************************************************************************/
double PID::GetIntegral(){
return outputSum;
}

/* SetIntegral(...)*************************************************************
* Set Integral term for user access to anti-windup schemes
******************************************************************************/
void PID::SetIntegral(double Integral){
outputSum = Integral;
}

/* Initialize()****************************************************************
* does all the things that need to happen to ensure a bumpless transfer
* from manual to automatic mode.
Expand Down
2 changes: 2 additions & 0 deletions PID_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class PID
// once it is set in the constructor.
void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which
// the PID calculation is performed. default is 100
void SetIntegral(double); // * sets the internal Integral term, in output units



Expand All @@ -59,6 +60,7 @@ class PID
double GetKd(); // where it's important to know what is actually
int GetMode(); // inside the PID.
int GetDirection(); //
double GetIntegral(); //

private:
void Initialize();
Expand Down
108 changes: 108 additions & 0 deletions examples/PID_SimulatedHeater/PID_SimulatedHeater.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/********************************************************
PID Basic simulated heater Example
Reading analog input 0 to control analog PWM output 3
********************************************************/
// This simulates a 20W heater block driven by the PID
// Vary the setpoint with the Pot, and watch the heater drive the temperature up
//
// Simulation at https://wokwi.com/projects/358122536159671297
//
// Based on
// Wokwi https://wokwi.com/projects/357374218559137793
// Wokwi https://wokwi.com/projects/356437164264235009

#include <PID_v1.h> // https://github.com/br3ttb/Arduino-PID-Library

//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
double Kp = 17, Ki = 0.3, Kd = 2; // works reasonably with sim heater block
//double Kp = 255, Ki = .0, Kd = 0; // works reasonably with sim heater block
//double Kp = 2, Ki = 5, Kd = 1; // commonly used defaults
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, P_ON_E, DIRECT);

const int PWM_PIN = 3; // UNO PWM pin
const int INPUT_PIN = -1; // Analog pin for Input (set <0 for simulation)
const int SETPOINT_PIN = A1; // Analog pin for Setpoint Potentiometer
const int SETPOINT_INDICATOR = 6; // PWM pin for indicating setpoint
const int INPUT_INDICATOR = 5; // PWM pin for indicating Input

void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
myPID.SetOutputLimits(-4, 255);
if (SETPOINT_INDICATOR >= 0) pinMode(SETPOINT_INDICATOR, OUTPUT);
if (INPUT_INDICATOR >= 0) pinMode(INPUT_INDICATOR, OUTPUT);
Setpoint = 0;
//turn the PID on
myPID.SetMode(AUTOMATIC);
if(INPUT_PIN>0){
Input = analogRead(INPUT_PIN);
}else{
Input = simPlant(0.0,1.0); // simulate heating
}
Serial.println("Setpoint Input Output Watts");
}

void loop()
{
// gather Input from INPUT_PIN or simulated block
float heaterWatts = (int)Output * 20.0 / 255; // 20W heater
if (INPUT_PIN > 0 ) {
Input = analogRead(INPUT_PIN);
} else {
float blockTemp = simPlant(heaterWatts,Output>0?1.0:1-Output); // simulate heating
Input = blockTemp; // read input from simulated heater block
}

if (myPID.Compute())
{
analogWrite(PWM_PIN, (int)Output);

Setpoint = analogRead(SETPOINT_PIN) / 4; // Read setpoint from potentiometer
if (INPUT_INDICATOR >= 0) analogWrite(INPUT_INDICATOR, Input);
if (SETPOINT_INDICATOR >= 0) analogWrite(SETPOINT_INDICATOR, Setpoint);
}
report();
}

void report(void)
{
static uint32_t last = 0;
const int interval = 1000;
if (millis() - last > interval) {
last += interval;
// Serial.print(millis()/1000.0);
Serial.print(Setpoint);
Serial.print(' ');
Serial.print(Input);
Serial.print(' ');
Serial.print(Output);
Serial.print(' ');
Serial.print(myPID.GetIntegral());
Serial.print(' ');
Serial.println();
}
}

float simPlant(float Q,float hfactor) { // heat input in W (or J/s)
// simulate a 1x1x2cm aluminum block with a heater and passive ambient cooling
// float C = 237; // W/mK thermal conduction coefficient for Al
float h = 5 *hfactor ; // W/m2K thermal convection coefficient for Al passive
float Cps = 0.89; // J/g°C
float area = 1e-4; // m2 area for convection
float mass = 10 ; // g
float Tamb = 25; // °C
static float T = Tamb; // °C
static uint32_t last = 0;
uint32_t interval = 100; // ms

if (millis() - last >= interval) {
last += interval;
// 0-dimensional heat transfer
T = T + Q * interval / 1000 / mass / Cps - (T - Tamb) * area * h;
}
return T;
}