This blog serves as a memorial for the project titled “A genetic-algorithm optimized PID controller” to keep notes of why i started and what i learned from it.

Background and Motivation

I came across an advert for Sous vide cooker, which is popular for preparing juicy steak. I happened to have an electronic kettle to be replaced. Not very happy with its condition, and a new one was already in my shopping list. Bingo! A natural idea came to me that this kettle can be repurposed to mimic what a Sous vide cooker could do - maintaining a fixed temperature of a body of water for a relatively long time. I knew immediately that this requires a good PID controller just like what I have in a cryostat for stabilizing the sample chamber temperature slightly above the absolute zero. As one may know, the brain of the PID controller is a simple feedback loop governed by three parameters: proportional gain (P), integral gain (I) and derivative gain (D). In practice, in a narrow range of goal temperature, these parameters do not need to be dynamically adapted to a different goal if the external environment is stable. However, it is not guaranteed to always achieve the best stabilization for a wide range of goal temperature for the same set of parameters. That means these parameters also need to be changed if the goal temperature varies. On top of the PID feedback loop, we also need to add another layer of feedback loop to optimize parameters P, I and D. Then the genetic algorithm seems to be useful here for generating the best choice of parameters. Here is a definition for genetic algorithm from MathWorks:

A genetic algorithm (GA) is a method for solving both constrained and unconstrained optimization problems based on a natural selection process that mimics biological evolution. The algorithm repeatedly modifies a population of individual solutions. At each step, the genetic algorithm randomly selects individuals from the current population and uses them as parents to produce the children for the next generation. Over successive generations, the population “evolves” toward an optimal solution.

This experiment with genetic algorithm would at least guarantee me an enjoyable exploration if not a ready-to-use Sous vide cooker. Not too bad at the worst situation. Let’s go on the journey.

How to Implement This Idea

How to Stablize the Temperature in General

Before moving into the actual implementation, I would like to first compare a few ideas side-by-side for stablizing temperature, ranging from the most intuitive but also naive one to the less intuitive but more practical ones. I do not intend to specify programming language at this stage thus choose to illustrate in pseudo-code.

  • Idea0 (without a PID controller):
    if measured (actual) temperature < the goal temperature:
      turn on the heater 
    else:
      turn off the heater
    

It is the most intuitive approach but not practical at all in achieving stabilization due to overshooting the temperature and a lack of mechanism to balance this out.

  • Idea1 (with a PID controller configured with a fixed set of parameters):
    Kp, Ki, Kd = x, x, x
    error = measured temperature - set temperature
    integral = error + integral
    derivative = (lasterror-error)/dt
    output = Kp*error+Ki*integral+Kd*derivative
    if output > 0:
      turn on the heater
    else:
      turn off the heater
    

    The PID controller will determine when to turn off and on the heater. However, we need to manually set the PID parameters Kp, Ki, Kd according to prior knowledge.

  • Idea2 (Train the genetic algorithm in actual data): We use the genetic algorithm to predict the best parameters for a goal temperature. The genetic algorithm needs data to provide feedback in the closed loop of training. These data can be generated by traversing the PID parameter space in hundreds and thousands of experiments. Clearly, this approach is time-consuming and not practical if not involving automation process.

  • Idea3 (Train the algorithm in a physical model): Thanks to the law of physics, we can first build up a physical model in which we can train the genetic algorithm in seconds. The implementation is then constituted by three steps: 1. Build a physical model as realistic as possible 2. Train the genetic algorithm in a physical model; 3. Deploy the optimized PID parameters to control hardware.

Physical Modeling

Heat transfer can take place in four different ways : Advection, thermal conduction, convection and radiation. Here we only consider thermal conduction as the major contributor. We also consider metallic walls of the kettle to be perfectly transparent in terms of thermal conduction. Therefore, the hot water directly interfaces the cold air outside. Then we can start to do some calculations of relevant physical properties. According to Fourier’s law: heater transfer per $meter^2/sec$ = - thermal conductivity * gradient of temperature ~ 540 $Watt/meter^2$. The surface area of the kettle is estimated to be about 700 $cm^2$. Then the rate of heat dissipation is thus 37.8 W. The thermal conductivity of air is about 27 mW/m K. The heater power is 1000 Watt according to its manufacturer. Here is my sketch to illustrate the idea and some necessary math along the way: By knowing the heat capacity of water to be 4.184 Joule/gram/deg and 0.8L (800 gram) water inside, we can estimate that the temperature goes up at a rate of 0.3 deg/sec when the heater is on and decreases at a rate of 0.012 deg/sec when the heater is off. Note that this estimate is not a function of temperature. So far, we have finished the physical modeling part.

Training Process of the Genetic Algorithm

In the training process, the simulated temperature is programmed to goes up by 0.32 degree in each heating cycle and decreases by 0.012 degree in each natural cooling cycle according to the results of physical modelling by assuming 1 cycle = 1 second.

To evaluate each set of PID parameters, a cost function is defined by L_mae= sum(abs(set temp - measured temp)) or L_mse=sum((set temp - measured temp)^2). At each generation, we select the set of parameters minimizing the cost function, and directly pass its properties onto the next generation (The principle of elitism) . Then we also provide a mechanism to mutate the “worst” set of parameters with the highest cost function value by pid_mutation, i.e., to fully randomize its values of Kp, Ki, Kd. For the rest, we would like to let them hybridize with neighbors to produce the next generation by pid_hybrid. This step helps to remain some good genetic properties the system, which are not fully manifested but potentially useful for later generations.
The code implementation is:

def pid_hybrid(pid1, pid2):
    dice = rand() * 3
    if 0 <= dice < 1:
        pid1_new = np.array([pid1[0], pid2[1], pid2[2]])
        pid2_new = np.array([pid2[0], pid1[1], pid1[2]])
    elif 1 <= dice < 2:
        pid1_new = np.array([pid2[0], pid1[1], pid2[2]])
        pid2_new = np.array([pid1[0], pid2[1], pid1[2]])
    else:
        pid1_new = np.array([pid2[0], pid2[1], pid1[2]])
        pid2_new = np.array([pid1[0], pid1[1], pid2[2]])
    return pid1_new, pid2_new

def pid_mutation():
    return 100 * random_sample(3)

Starting from the 99th generation (iteration), we find that all winners’ descendants collapse in a smaller volume in (Kp, Ki, Kd) parameter space. That means the model has already been trained or optimized, thus ends the optimization process.

Hardware components and wiring

Functional parts Models
Microcontroller Raspberry Pi Pico/ Ardurio Nano
Temperature sensor MAX6675
220V control Relay
User interface ICD 1602
User input rotary potentiometer

Software

The source code of this open-source project is hosted by Github

Algorithm Training Process

For Python users, use pidtrain.py to train your PID controller in simulation. For C++ users, use pidtrain.cpp to train your PID controller instead. C++ code is 50 times faster than its Python counterpart. .

Deploy to Microcontroller

The Micropython code for microcontroller unit (MCU) is stored in mpython folder. Please include the libraries in lib as well. The Arduino code for MCU is stored in Arduino folder and please include the libraries folder

User Interface Design for the Microcontroller

The LCD is only 16 by 2, so we have to fully exploit the limited screen space and the switch button of the rotary potentiometer.

screen 0

This is the main screen to display setting temperature and reading. Press button to go next.

screen 1

This is the second screen (screen1) to monitor the PID paramters in use and the calculated output value in real time. Press button to go next and roll to the left to go back to screen0.

From left to right, screen 2, screen 3, screen 4

Above three screens (screen2 to screen4) to modify the PID parameters one by one manually. Use the rotary potentiometer. Press button to go next.

screen 5

This is the last screen screen5. Roll left to adapt Auto mode (default setting) and press button to accept the manually set PID parameters and go to screen0.

Performance Test

Results of Algorithm Training

After training for 100 generations and a population size of 20 in each, a set of parameter (Kp = 88, Ki = 4.4, Kd = 18) is the final winner for a goal temperature of 56 degree Celsius.

Algorithm-optimized PID Controller and Its Performance

We configure our PID controller by this set for following experiments. Here we show the actual temperature curve (labelled as real) and the simulation result (labelled as simulation). In the first 2000 seconds, the simulation matches quite well with the actual curve real in both trend of temperature (upper) and output (Kp*error+Ki*integral+Kd*derivative) of the PID system (lower). That means our physical model gives accurate predictions of temperature change rates used here. After 2000 seconds, the temperature in simulation stabilizes within 0.32 degree. In reality, the temperature continues to fluctuate in a much narrowed window ~ 5 degrees. This fluctuation seems to be overshooting, which may be due to the fact that the heater is still much hotter than water and continues to heat water even after being powered off. This may be the bottleneck to achieve better performance.

Concluding remarks

In the end, not surprisingly, there is still a lot to improve in many aspects for this combination of software and hardware to perform as good as a commercial cooker. For myself, it is thrilling to go through this exploration and broaden my knowledge in genetic algorithm and microcontrollers. I hope this is also some sort of entertaining for you to go with me in this journey.