Files
Raspi_Auto_Fan/fan_autopid.py
2026-05-09 16:31:36 +08:00

106 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pigpio
import time
PWM_PIN = 18
TACH_PIN = 23
TARGET_TEMP = 40.0
# 初始参数
Kp = 1.0
Ki = 0.0
Kd = 0.0
integral = 0
last_error = 0
last_temp = None
pulse_count = 0
last_time = time.time()
pi = pigpio.pi()
pi.set_PWM_frequency(PWM_PIN, 25000)
pi.set_PWM_range(PWM_PIN, 255)
def tach_cb(gpio, level, tick):
global pulse_count
pulse_count += 1
pi.set_mode(TACH_PIN, pigpio.INPUT)
pi.set_pull_up_down(TACH_PIN, pigpio.PUD_UP)
pi.callback(TACH_PIN, pigpio.FALLING_EDGE, tach_cb)
last_tem = 0
def get_temp():
global last_tem
with open("/sys/class/thermal/thermal_zone0/temp") as f:
temp_filtered = 0.8 * last_tem + 0.2 * int(f.read()) / 1000
last_tem = temp_filtered
return temp_filtered
def get_rpm():
global pulse_count, last_time
now = time.time()
dt = now - last_time
count = pulse_count
pulse_count = 0
last_time = now
return (count / 2) / dt * 60
def adaptive_pid(temp):
global Kp, Ki, Kd, integral, last_error, last_temp
error = temp - TARGET_TEMP
integral += error
integral = max(min(integral, 100), -100)
derivative = error - last_error
# ===== 自适应调参 =====
if last_temp is not None:
temp_rate = temp - last_temp
# 响应太慢 → 增大 Kp
if abs(error) > 5 and abs(temp_rate) < 0.1:
Kp += 0.001
# 震荡 → 降低 Kp提高 Kd
if abs(temp_rate) > 0.5:
Kp *= 0.95
Kd += 0.0005
# 长期偏差 → 增大 Ki
if abs(error) > 2:
Ki += 0.0001
last_temp = temp
last_error = error
output = Kp * error + Ki * integral + Kd * derivative
return output
try:
while True:
temp = get_temp()
rpm = get_rpm()
out = adaptive_pid(temp)
duty = max(10, min(255, int(out * 5)))
pi.set_PWM_dutycycle(PWM_PIN, duty)
print(f"\rT={temp:.1f}C RPM={rpm:.0f} PWM={duty} Kp={Kp:.2f} Ki={Ki:.2f} Kd={Kd:.2f} ", end="")
time.sleep(0.05)
except KeyboardInterrupt:
pass
finally:
pi.set_PWM_dutycycle(PWM_PIN, 0)
pi.stop()