Mastering MicroPython PID Control

In the realm of embedded systems and automation, the Proportional - Integral - Derivative (PID) controller stands as a cornerstone technology. It is a control algorithm that calculates an error value as the difference between a desired setpoint and a measured process variable. By using proportional, integral, and derivative terms, it computes a corrective output to minimize the error over time. MicroPython, a lean and efficient implementation of the Python 3 programming language that is optimized to run on microcontrollers, provides a convenient platform for implementing PID control algorithms. This blog post aims to provide a comprehensive guide to understanding and using PID controllers in MicroPython.

Table of Contents#

  1. Fundamental Concepts of PID
  2. MicroPython and PID
  3. Usage Methods
  4. Common Practices
  5. Best Practices
  6. Conclusion
  7. References

Fundamental Concepts of PID#

A PID controller consists of three main components:

Proportional (P) Term#

The proportional term is directly proportional to the current error. It calculates the output as a product of the error and the proportional gain (KpK_p). A higher KpK_p value will cause the controller to respond more aggressively to errors, but too high a value can lead to instability and oscillations.

P=Kp×e(t)P = K_p \times e(t)

where e(t)e(t) is the error at time tt.

Integral (I) Term#

The integral term accumulates the error over time. It helps to eliminate steady - state errors by integrating the error over a period. The integral gain (KiK_i) is used to scale the accumulated error.

I=Ki×0te(τ)dτI = K_i \times \int_{0}^{t} e(\tau) d\tau

Derivative (D) Term#

The derivative term is based on the rate of change of the error. It predicts future error trends and helps to dampen oscillations. The derivative gain (KdK_d) is used to scale the rate of change of the error.

D=Kd×de(t)dtD = K_d \times \frac{de(t)}{dt}

The total output of the PID controller is the sum of these three terms:

u(t)=Kpe(t)+Ki0te(τ)dτ+Kdde(t)dtu(t)=K_p e(t)+K_i \int_{0}^{t} e(\tau) d\tau + K_d \frac{de(t)}{dt}

MicroPython and PID#

MicroPython allows us to implement PID controllers in a more accessible and readable way compared to traditional low - level programming languages. It provides high - level data types, functions, and libraries that simplify the development process. With MicroPython, we can easily interface with sensors to measure the process variable and actuators to apply the corrective output.

Usage Methods#

Basic PID Class in MicroPython#

class PID:
    def __init__(self, Kp, Ki, Kd):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.prev_error = 0
        self.integral = 0
 
    def compute(self, setpoint, current_value):
        error = setpoint - current_value
 
        # Proportional term
        P = self.Kp * error
 
        # Integral term
        self.integral += error
        I = self.Ki * self.integral
 
        # Derivative term
        derivative = error - self.prev_error
        D = self.Kd * derivative
 
        output = P + I + D
        self.prev_error = error
 
        return output

Using the PID Class#

# Initialize the PID controller
Kp = 1.0
Ki = 0.1
Kd = 0.01
pid = PID(Kp, Ki, Kd)
 
# Set the setpoint
setpoint = 50
 
# Simulate a current value
current_value = 20
 
# Compute the PID output
output = pid.compute(setpoint, current_value)
print(f"PID output: {output}")

In this example, we first define a PID class with an __init__ method to initialize the gains and internal variables. The compute method calculates the PID output based on the setpoint and the current value.

Common Practices#

Tuning the PID Gains#

Tuning the PID gains (KpK_p, KiK_i, KdK_d) is a crucial step. One common method is the Ziegler - Nichols method, which involves setting KiK_i and KdK_d to zero and increasing KpK_p until the system starts to oscillate. Then, based on the critical gain and the oscillation period, the optimal gains can be calculated.

Anti - Windup#

Integral windup can occur when the integral term accumulates a large value during periods when the actuator is saturated. To prevent this, we can limit the integral term or use conditional integration.

class PID:
    def __init__(self, Kp, Ki, Kd, integral_limit):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.prev_error = 0
        self.integral = 0
        self.integral_limit = integral_limit
 
    def compute(self, setpoint, current_value):
        error = setpoint - current_value
 
        # Proportional term
        P = self.Kp * error
 
        # Integral term with anti - windup
        self.integral += error
        if self.integral > self.integral_limit:
            self.integral = self.integral_limit
        elif self.integral < -self.integral_limit:
            self.integral = -self.integral_limit
        I = self.Ki * self.integral
 
        # Derivative term
        derivative = error - self.prev_error
        D = self.Kd * derivative
 
        output = P + I + D
        self.prev_error = error
 
        return output

Best Practices#

Sampling Time#

The sampling time should be carefully chosen. A too short sampling time may lead to unnecessary computational load, while a too long sampling time may cause the controller to respond slowly.

Filtering the Input#

Noise in the sensor readings can affect the performance of the PID controller. Using a low - pass filter on the input can help to reduce the noise.

import math
 
class LowPassFilter:
    def __init__(self, alpha):
        self.alpha = alpha
        self.prev_value = 0
 
    def filter(self, value):
        filtered_value = self.alpha * value + (1 - self.alpha) * self.prev_value
        self.prev_value = filtered_value
        return filtered_value
 
# Example usage
alpha = 0.5
filter = LowPassFilter(alpha)
noisy_value = 10
filtered_value = filter.filter(noisy_value)

Conclusion#

MicroPython provides a powerful and accessible platform for implementing PID controllers. By understanding the fundamental concepts of PID, using the appropriate usage methods, following common practices, and adopting best practices, we can develop effective PID control systems. Whether it is for temperature control, motor speed regulation, or other automation tasks, MicroPython PID controllers can play a vital role.

References#

  • Åström, K. J., & Hägglund, T. (2006). PID Controllers: Theory, Design, and Tuning. Instrument Society of America.
  • MicroPython official documentation: https://docs.micropython.org/