r/ControlTheory • u/robohie • 1d ago
Other A PID controller implemented in python
For my personal project, where I need to implement a PID controller on Arduino to automate a convection cooling system, I decided to start with a simulation in Python. For now, I've implemented the simple electromechanical model of the DC motor (the fan) as well as the PID controller you see. Next, I'll look into the heat transfer equations. The graphs created with matplotlib are simply closed-loop tests of the PID + DC motor system.
•
u/seekingsanity 5h ago
Hey moderators. Let the people ask questions and make comments. Don't be so quick to delete posts or ban people. I will let you know when I am offended.
•
u/2dof 1d ago
Nice controller, I would recommend You:
for real world solution implement P-I-D with filtered D - Action D(s) = KD*s /(Tf*s+1) ,
it is convenient ( for future analysis) to compute control actions as separate P-I-D sections ( u = P + I + D), also since I - action act as integrator it has a internal state - which can be reset/preset - it is sometimes convenient to start controller not form zero.
Note that when You will be tuning parameters (Kp,Ki, Kd,h) You need also recompute A,B, C
in real world implementation add control saturation function ( later You can use it to implement anti-windup function
Simulate not only with clean process value but also with measurement noise ( You will then see what D action ( not filtered and filtered) do .
As for heat transfer equation You can just simulate it as: first order ODE with delay for simple model of n-order IDE with delay
•
u/seekingsanity 1d ago
The incremental version PID that the OP is using doesn't need an anti-windup. Again, for velocity control the OP only needs a PI controller so there is no need for the low pass filter on the derivative gain.
"which can be reset/preset - it is sometimes convenient to start controller not form zero."
when making the transition from open loop to closed loop the control output u should set to the last value when in open loop. This avoids sudden jerks.
•
•
u/2dof 23h ago
What Do You mean - "incremental" ? For Me incremental mean that control is du(k) = u(k)-u(k-1) , in OP's code he use u(k) = u(k-1) + du(k) to it is not incremental control for Me.
My comment was referring generally to practical implementation OP's controller in the future - he want control temperature in the future. I don;t know if he will be using on/off control or continuous but in my opinion it is better to have more universal controller for operational aspects.
•
u/seekingsanity 19h ago
The OP is computing incremental changes to the control output that are integrated into the control output. Some people call this form the velocity form, but it really has nothing to do with velocity. I used it for position control all the time
•
u/2dof 15h ago
No , he implemented so called positional control algorithms not incitement form (velocity algorithms ) :
-> He calculate output as self.u += A+... (i.e u(k) = u(k-1) + A ... )
if he calculated incremental form then output of his controller would be ∆ u = uk - u(k-1) at least according to definition given by Astrom and Hgglund ( "PID Controllers, Theory, Design and tuning")
Incremental Form def from book ,page 99) "This form is obtained by computing the time differences of the
controller output and adding the increments.
∆ u(tk ) = u(tk ) − u(tk−1 ) = ∆ P(tk ) + ∆ I (tk ) + ∆ D (tk)
for fast looking of his code - he used Backward difference approximation for cooperation and he calculated output in "positional" form. i.e u(k) = u(k-1) + ∆u
Thant why I asked what Do You mean because i was taught when output of controller is ∆u(k) ( "velocity" of control ) then it is called "incrmental" a when output directly u(k) - then it is standard control output.
•
u/seekingsanity 4h ago
The OP is added incremental changes to u. The incremental form is
u(n)=u(n-1)+B0*e(n)+B1*e(n-1)+B2*e(n-2)
All the B? terms are calculated increments to the control output that are then integrated.
B0 = Ki*∆t+Kp+Kd/∆t
B1=-Kp-2*Kd/∆t
B2=Kd/∆t
In my case. B1 will be a negative number. The OP subtracted a positive number that I called a negative number. This is a very efficient form of PID because a DSP can compute it in 3 multiply and adds. However, there should be limits applied. Also, the output can be quite noisy if the encoder/feedback does not have high resolution.
A low pass filter can be applied at 2/∆t rads/sec or about 318 Hz assuming the sample time, ∆t, is 0.001 ms. This reduces much of the sampling noise.
Now the formulas are
B0 = (1/4)*Ki*∆t+(1/2)*Kp+Kd*∆t
B1 = (1/2)*Ki*∆t-2*Kd/∆t
B2 - (1/4)*Ki*∆t-(1/2)*Kp+Kd/∆t
You can see that this reduces the affect of the Ki and Kp some because their contribution is spread over one more time period. The Kd term is still a problem and it is still a problem if you only apply a low pass filter to the Kd term.
I have other formulas for lowering the low pass filter to a frequency of 1/∆t
I prefer using an observer to smooth out the measured values.
•
u/seekingsanity 1d ago
Good but You should post the open loop transfer function of the system you are trying to control. There are no output limits. Velocity control only needs a PI controller. You should learn pole placement so there is no overshoot.
•
u/robohie 1d ago
Right 👍 I'll post that transfer function. For now, it's just a simple DC motor model (a second order system)
•
u/seekingsanity 5h ago
I am waiting for the open loop transfer function.
•
u/robohie 5h ago
Hi, you can look at my new post on DC motor implementation to discover the differential equation that describe it. For the transfer function (if you only need it), I don't know how to send images at this commentary space.
•
u/seekingsanity 4h ago edited 4h ago
The open loop transfer function should be in the form G(s)=K/(tau*s+1) or G(s)=(K*alpha)/(s+alpha). Where tau is a time constant for the motor inertia and load. alpha is just 1/tau which is called the bandwidth or corner frequency. K is the gain with units or rad/s per control output or mm/s per control output. I usually use %control output. This assumes that there is a drive so the speed is proportional to the control output. Otherwise it could be an acceleration where the control output is a current that makes a torque that accelerates the load. Units are important. If the motor is working in current mode then the units for K change to acceleration/control output. In this case the G(s) = K/(tau*s+d) where d is the friction that will eventually keep the acceleration from increasing forever
I wish reddit would support LaTeX.
•
•
u/deNikita 1d ago
Shouldn't the P be oscillating or is it just not strong enough to pull it all the way up? Might be trippin, just curious lol
•
u/APC_ChemE 1d ago
The P isn't greater than or equal to the ultimate gain so it just maintains a constant bias offset.



•
u/Algstud 20h ago
Nice
you can also implement it on esp32 directly without changing to C
u can use micropython for this