|
| 1 | +/******************************************************** |
| 2 | + PID Basic simulated heater Example |
| 3 | + Reading analog input 0 to control analog PWM output 3 |
| 4 | + ********************************************************/ |
| 5 | +// This simulates a 20W heater block driven by the PID |
| 6 | +// Vary the setpoint with the Pot, and watch the heater drive the temperature up |
| 7 | +// |
| 8 | +// Code at https://wokwi.com/projects/357409124554569729 |
| 9 | +// |
| 10 | +// Based on |
| 11 | +// Wokwi https://wokwi.com/projects/357374218559137793 |
| 12 | +// Wokwi https://wokwi.com/projects/356437164264235009 |
| 13 | + |
| 14 | +//#include <PID_v1.h> // https://github.com/br3ttb/Arduino-PID-Library |
| 15 | +#include <PID_v1_bc.h> // https://github.com/drf5n/Arduino-PID-Library |
| 16 | + |
| 17 | +//Define Variables we'll be connecting to |
| 18 | +double Setpoint, Input, Output; |
| 19 | + |
| 20 | +//Specify the links and initial tuning parameters |
| 21 | +//double Kp = 17, Ki = .1, Kd = 2; // works reasonably with sim heater block |
| 22 | +//double Kp = 255, Ki = .0, Kd = 0; // works reasonably with sim heater block |
| 23 | +double Kp = 2, Ki = 5, Kd = 1; // commonly used defaults |
| 24 | +PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, P_ON_E, DIRECT); |
| 25 | + |
| 26 | +const int PWM_PIN = 3; // UNO PWM pin |
| 27 | +const int INPUT_PIN = -1; // Analog pin for Input (set <0 for simulation) |
| 28 | +const int SETPOINT_PIN = A1; // Analog pin for Setpoint Potentiometer |
| 29 | +const int SETPOINT_INDICATOR = 6; // PWM pin for indicating setpoint |
| 30 | +const int INPUT_INDICATOR = 5; // PWM pin for indicating Input |
| 31 | + |
| 32 | +void setup() |
| 33 | +{ |
| 34 | + Serial.begin(115200); |
| 35 | + Serial.println(__FILE__); |
| 36 | + myPID.SetOutputLimits(0, 255); |
| 37 | + if (SETPOINT_INDICATOR >= 0) pinMode(SETPOINT_INDICATOR, OUTPUT); |
| 38 | + if (INPUT_INDICATOR >= 0) pinMode(INPUT_INDICATOR, OUTPUT); |
| 39 | + Setpoint = 0; |
| 40 | + //turn the PID on |
| 41 | + myPID.SetMode(AUTOMATIC); |
| 42 | + if(INPUT_PIN>0){ |
| 43 | + Input = analogRead(INPUT_PIN); |
| 44 | + }else{ |
| 45 | + Input = simPlant(0); // simulate heating |
| 46 | + } |
| 47 | + Serial.println("Setpoint Input Output Watts"); |
| 48 | +} |
| 49 | + |
| 50 | +void loop() |
| 51 | +{ |
| 52 | + // gather Input from INPUT_PIN or simulated block |
| 53 | + float heaterWatts = (int)Output * 20.0 / 255; // 20W heater |
| 54 | + if (INPUT_PIN > 0 ) { |
| 55 | + Input = analogRead(INPUT_PIN); |
| 56 | + } else { |
| 57 | + float blockTemp = simPlant(heaterWatts); // simulate heating |
| 58 | + Input = blockTemp; // read input from simulated heater block |
| 59 | + } |
| 60 | + |
| 61 | + if (myPID.Compute()) |
| 62 | + { |
| 63 | + analogWrite(PWM_PIN, (int)Output); |
| 64 | + |
| 65 | + Setpoint = analogRead(SETPOINT_PIN) / 4; // Read setpoint from potentiometer |
| 66 | + if (INPUT_INDICATOR >= 0) analogWrite(INPUT_INDICATOR, Input); |
| 67 | + if (SETPOINT_INDICATOR >= 0) analogWrite(SETPOINT_INDICATOR, Setpoint); |
| 68 | + } |
| 69 | + report(); |
| 70 | +} |
| 71 | + |
| 72 | +void report(void) |
| 73 | +{ |
| 74 | + static uint32_t last = 0; |
| 75 | + const int interval = 1000; |
| 76 | + if (millis() - last > interval) { |
| 77 | + last += interval; |
| 78 | + // Serial.print(millis()/1000.0); |
| 79 | + Serial.print(Setpoint); |
| 80 | + Serial.print(' '); |
| 81 | + Serial.print(Input); |
| 82 | + Serial.print(' '); |
| 83 | + Serial.print(Output); |
| 84 | + Serial.print(' '); |
| 85 | + Serial.println(20.0 * (int)Output/255); |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +float simPlant(float Q) { // heat input in W (or J/s) |
| 90 | + // simulate a 1x1x2cm aluminum block with a heater and passive ambient cooling |
| 91 | + // float C = 237; // W/mK thermal conduction coefficient for Al |
| 92 | + float h = 5 ; // W/m2K thermal convection coefficient for Al passive |
| 93 | + float Cps = 0.89; // J/g°C |
| 94 | + float area = 1e-4; // m2 area for convection |
| 95 | + float mass = 10 ; // g |
| 96 | + float Tamb = 25; // °C |
| 97 | + static float T = Tamb; // °C |
| 98 | + static uint32_t last = 0; |
| 99 | + uint32_t interval = 100; // ms |
| 100 | + |
| 101 | + if (millis() - last >= interval) { |
| 102 | + last += interval; |
| 103 | + // 0-dimensional heat transfer |
| 104 | + T = T + Q * interval / 1000 / mass / Cps - (T - Tamb) * area * h; |
| 105 | + } |
| 106 | + return T; |
| 107 | +} |
| 108 | + |
0 commit comments