项目介绍
项目功能介绍
该项目使用PID算法对温度进行控制,使用按键和拨轮对目标温度进行控制,同时在LCD屏幕上显示对应的P值,I值,D值,目标温度以及实时温度。
设计思路
设计思路分为三部分,分别是温度采集、算法调节、加热控制。
温度采集
通过I2C向SHT30发送命令以启动温度转换。等待SHT30完成温度转换,然后从传感器的数据寄存器中读取温度值。转将转换后的温度值用于所需的应用程序,显示在LCD屏幕上、对获取到的温度使用PID算法。
PID算法
通过PID算法进行调节,将参数进行更新。
加热控制
使用PWM模式,对加热电阻进行控制。
硬件框图
主控硬件框图
温度传感器原理图
加热电阻原理图
软件流程图
成品展示
主要代码片段及原理说明
PID控制器的算法公式和原理如下:
PID控制器的公式
PID控制器的输出由以下三个部分组成:
1. 比例 (P)
- 比例控制器的输出与当前误差成正比。
- 公式:
- 其中,是比例增益,e(t) 是当前时刻的误差(设定值减去实际值)。
2. 积分 (I)
- 积分控制器输出与误差的累积(即积分)成正比。
- 公式:
- 其中,K_i 是积分增益, 是从时间0到当前时间t的误差积分。
3. 微分 (D)
- 微分控制器输出与误差的变化率(即微分)成正比。
- 公式:
- 其中, 是微分增益, 是误差的变化率。
将这三个部分结合起来,PID控制器的总输出为:
PID控制器的原理
PID控制器的工作原理基于以下概念:
1. 比例控制:减少当前误差。比例增益决定了控制器对误差的敏感程度。增大可以提高系统的响应速度,但过高的可能导致系统不稳定和振荡。
2. 积分控制:消除稳态误差。积分作用随着时间的累积而增加,直到系统能够精确地跟踪设定值。积分增益决定了积分作用的大小。增大可以提高系统的稳态精度,但过高的可能导致系统的响应变得缓慢和振荡。
3. 微分控制:预测误差的变化趋势,并提前调整控制作用以减少超调。微分增益决定了微分作用的大小。增大可以减少系统的超调和振荡,但过高的可能导致系统对噪声敏感。
PID控制器的目标是找到一个合适的,,组合,使系统既能够快速响应变化,又能够精确地跟踪设定值,同时保持稳定和不受噪声影响。
在单片机系统中常采用离散化PID,在离散时间系统中,PID控制器需要使用离散化的公式。离散化PID控制器的公式通常基于以下变换:
1. 比例 (P) 部分:与连续时间相同,直接与当前误差成正比。
2. 积分 (I) 部分:使用数值积分,通常使用前向欧拉法或梯形法。
3. 微分 (D) 部分:使用数值微分,通常使用向后欧拉法或中点法。
离散化PID控制器的标准公式如下:
其中:
- u[k] 是第k个采样时刻的控制输出。
- e[k] 是第k个采样时刻的误差,即 e[k] = setpoint - process_variable[k]。
- K_p,K_i,K_d 分别是比例增益、积分增益和微分增益。
- T_s 是采样时间,即控制器两次计算之间的时间间隔。
- 是从第0个采样时刻到第k个采样时刻的误差累加和,即积分项。
在实际应用中,为了防止积分饱和(即积分项过大导致控制器输出过大),通常会引入积分限制。
根据上边的公式推导,编写的对应代码如下:
class PIDController:
def __init__(self, Kp, Ki, Kd, setpoint):
self.kp = Kp
self.ki = Ki
self.kd = Kd
self.setpoint = setpoint
self.last_error = 0.0
self.integral = 0.0
self.last_time = time.ticks_ms()
def update(self, current_value):
# 计算时间间隔
current_time = time.ticks_ms()
delta_time = time.ticks_diff(current_time, self.last_time) / 1000.0
self.last_time = current_time
# 计算误差
error = self.setpoint - current_value
# 积分项
self.integral += error * delta_time
# 微分项
derivative = (error - self.last_error) / delta_time
# 计算 PID 控制输出
output = self.kp * error + self.ki * self.integral + self.kd * derivative
# 保存本次误差用于下次计算
self.last_error = error
return output
sht30测量温湿度代码
函数逻辑:
1. 发送命令并读取数据:
self.send_cmd(SHT30.MEASURE_CMD, 6)
: 调用类的另一个方法send_cmd
,向SHT30传感器发送测量命令,并指定要读取的数据长度为6字节。
2. 处理原始数据(如果raw
为True):
- 直接返回一个包含6个字节的
bytearray
,这是传感器直接测量的原始数据。
3. 解析温度和湿度(如果raw
为False):
- 温度解析:从原始数据中提取温度值(前两个字节),进行位操作和数学运算,转换为摄氏度。公式为:
(((data[0] << 8 | data[1]) * 175) / 0xFFFF) - 45 + self.delta_temp
。这里的self.delta_temp
可能是用于校准的温度偏移量。 - 湿度解析:从原始数据中提取湿度值(中间两个字节),进行位操作和数学运算,转换为百分比。公式为:
(((data[3] << 8 | data[4]) * 100.0) / 0xFFFF) + self.delta_hum
。这里的self.delta_hum
是用于校准的湿度偏移量。
4. 返回结果:
- 如果
raw
为False,则返回一个包含两个浮点数的元组(t_celsius, rh)
,分别代表温度(摄氏度)和湿度(百分比)。
这个函数的作用是简化SHT30传感器的数据读取过程,用户可以根据需要选择返回原始数据还是解析后的温湿度值。
def measure(self, raw=False):
"""
If raw==True returns a bytearray(6) with sensor direct measurement otherwise
It gets the temperature (T) and humidity (RH) measurement and return them.
The units are Celsius and percent
"""
data = self.send_cmd(SHT30.MEASURE_CMD, 6)
if raw:
return data
t_celsius = (((data[0] << 8 | data[1]) * 175) / 0xFFFF) - 45 + self.delta_temp
rh = (((data[3] << 8 | data[4]) * 100.0) / 0xFFFF) + self.delta_hum
return t_celsius, rh
遇到的主要难题及解决方法
主要遇到参数较难调节的问题,解决方法:经查找百度以及各类博客,总结出如下方法:
1. 比例系数Kp的调节:Kp是PID控制器中最重要的参数,它决定了系统的响应速度和稳定性。增大Kp可以加快系统响应,减小静态误差,但同时也可能增加系统的超调量和振荡。因此,需要仔细调节Kp,以平衡响应速度和稳定性。
2. 积分系数Ki的调节:Ki主要用于消除静态误差。增大Ki可以减少超调量,提高系统的稳定性,但如果Ki过大,可能会导致系统响应变慢,甚至引起振荡。通常在调节Ki时,需要从零开始逐渐增加,直到达到满意的消除静态误差的效果。
3. 微分系数Kd的调节:Kd用于预测系统的未来行为,对抗超调。在噪声较大的系统中,Kd的调节尤其重要。增加Kd可以加快系统响应,减少超调量,但过大的Kd可能导致系统对噪声过于敏感,引起不稳定。因此,调节Kd时也需要谨慎,通常在比例和积分调节之后进行。
4. 调试顺序:一般的调试顺序是先调节比例(从中间值开始,逐渐调整),然后是积分(从零开始逐渐增加),最后是微分(也是从零开始逐渐增加)。
5. 系统延迟的影响:控制系统中的延迟可能会导致调节困难。比例控制系数过小会导致调节力度不够,过大则可能导致系统振荡。需要根据系统的具体特性来调整比例系数。
未来的计划或建议
为这个恒温控制器设计更精美的GUI界面,以及后续进一步优化控制算法,例如模糊控制等算法。