Making my own PID library #10180
Replies: 9 comments 22 replies
-
Maybe I2C clock stretching causing problems? |
Beta Was this translation helpful? Give feedback.
-
I wonder if it's related to #10067? |
Beta Was this translation helpful? Give feedback.
-
My guess is that this is electrical. Thermocouples are sensitive beasts. On the left hand side of the plot, presumably the PWM is fully on, and at the RHS it is fully off. Only in the transition region around the setpoint is there a pulse waveform. If that can be confirmed with a scope, then the cause is very likely electrical interference between the PWM output and the thermocouple input. |
Beta Was this translation helpful? Give feedback.
-
edit: To make conclusions easier You should plot control output not as pwm clock value as (roundPWMOUT = Output / 1000) but
edit: in any problem with performing tuning - let as know, we will help, better explanation of step response tuning method : https://yilinmo.github.io/EE3011/Lec9.html 3.What Do You control ? |
Beta Was this translation helpful? Give feedback.
-
Bye default i consider your process as first order with delay , it also be considered as higer order it depends of physical construction, by default first order for Your is good ( see https://www.electricalengineeringinfo.com/2017/05/transfer-function-mathematical-model-thermal-system.html ) about my "stupid" simulation: I just done a step response of Your PID controller - Your code but with: Setpoint and Input fixed values (no sensor reading), (at first I was supriced that control signal is saturated also "donky blinded" by "lack of" sampling time and just not even noticed a transient behavior ( electric issue noticed by pererhinch) which is most importnant issue. In typical numerical simulation i usually use from odeint (from scipy.integrate python ) with digital controllers implementation ), when numerical proces identification is needed then I use mentioned z Ziegler–Nichols for first order or scipy.optimize lib for more advanced. |
Beta Was this translation helpful? Give feedback.
-
Time to show the setup. I solved the problem by putting an optocoupler in between the Pi Pico PWM output and the input of the TC 427. By doing this, I have separated the noisy switching GND entirely from the Pi Pico and the thermocouple. Also, shortening the PWM line and by that lowering the inductance of the trace (no ringing on the PWM line). As for the integral windup, one of the ways to solve it was also to make the Ki constant small in retrospect to the Kp component of the PID. My initial parameters were Kp = 0.1, Ki = 6.0 and Kd = 1.5. When I made the Kp much larger, like Kp = 1000 and Ki = 1.6, the system started behaving as expected with no overshoot. Here are some pictures at 100 C. |
Beta Was this translation helpful? Give feedback.
-
Good work. My control system theory is decidedly rusty and I'm happy to be told that the following is nonsense but I'll stick my neck out anyway... As has been mentioned above, heating a thermal mass approximates to a single pole system. Say your control system has a large proportional (P) term, and zero integral (I) and derivative (D) terms. On power up it will approach the setpoint on an exponential curve, stabilising at the setpoint with no overshoot. It sounds to me as if this is very nearly what you have, although you haven't mentioned D. Clearly this behaviour can be improved, but the question arises as to what needs to be bettered? The time from power up to getting within a given tolerance of the setpoint or the response to external disruption when the setpoint is reached? If the former you can use a nonlinear approach: turn the PWM to 100% until within tolerance, then switch to P==1000. That achieves the fastest possible outcome. It's really only in the case where you need a rapid response to external disturbances that you need optimised PID control. |
Beta Was this translation helpful? Give feedback.
-
This is the fully functional version of code. from machine import Pin, I2C, PWM, UART
import time
pwm0 = PWM(Pin(8)) # create PWM object from a pin
pwm0.freq(200) # set frequency
i2c1 = machine.I2C(1, sda=Pin(14), scl=Pin(15), freq=50000) #Error 5 change CLK speed
#or wrog value CLK
Setpoint = 180.0
#Original param
# Kp = 0.10
# Ki = 6.0
# Kd = 1.50
Kp = 1000.0
Ki = 10.60
Kd = 1.0
outMin = 0.0
outMax = 65000.0
IoutMin = -65000.0
IoutMax = 65000.0
dt =0.1
Iout = 0.0
Input = 0.0
lastinput = 0.0
uart = UART(0, baudrate=230400, tx=Pin(0), rx=Pin(1))
i2c1.writeto_mem(0b01100110, 0x06, bytearray(0x20))
i2c1.writeto_mem(0b01100110, 0x05, bytearray(0x04))
valueK = [0x00,0x00]
temperatureK = []
while True:
valueK = i2c1.readfrom_mem(0b01100110, 0x00, 2)
temperatureK = (valueK[0] * 16.0 + valueK[1] /16.0)
Input = temperatureK
error = Setpoint - Input
Pout = Kp * error
Iout = Iout + (Ki * error * dt)
if (Iout > IoutMax):
Iout = IoutMax
if (Iout <= IoutMin):
Iout = IoutMin
Dout = ((Input - lastinput ) /dt)
Dout = Kd * Dout
Output = Pout + Iout + Dout
if (Output > outMax):
Output = outMax
Iout = Iout - (Ki * error * dt) # anti-reset windup
if (Output <= outMin):
Output = outMin
Iout = Iout - (Ki * error * dt) # anti-reset windup
PWMOUT = int(Output)
pwm0.duty_u16(PWMOUT)
roundPWMOUT = Output / 1000
strPWMOUT = str(roundPWMOUT)
strSETPOINT = str(Setpoint)
strINPUT = str(Input)
uart.write(strSETPOINT+' '+strINPUT+' '+ strPWMOUT +'\n')
lastinput = Input
print(Input)
time.sleep(0.1) |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello everyone, I am trying to make a simple PID controller for a heater using MicroPython, Pi Pico and a MCP9600 Thermocouple Reader.
I have based it around the standard PID Arduino Library(http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/), which is also used for MicroPython simple-pid library (https://micropython-simple-pid.readthedocs.io/en/latest/#), (https://github.com/gastmaier/micropython-simple-pid/blob/master/simple_pid/PID.py#:~:text=%23%20Compute%20integral%20and%20derivative%20terms,output%2C%20self.output_limits)).
Now, the main problem that I have is quite interesting.
Until the circuit reaches the desired Setpoint (100 C), the program and the I2C bus work just fine. The moment that the Setpoint is overshoot, the readings of the temperature go all over the place (random values all of a sudden). I have tried multithreading, longer delays, lowering the I2C clock but nothing helps to make the problem go away. At the end I am printing the data via UART and using a FTDI chip just for an easier display on the Arduino Ploter (you can see on the screen shoot the behaviour of the input (red), output (green) and setpoint (blue)).
Here is the code:
All ideas are welcome, my only guess is that somehow the math of the program is interfering with the I2C bus (input)?
Thank you so much for your time reading this!
Beta Was this translation helpful? Give feedback.
All reactions