- PID控制(Proportional-Integral-Derivative Control)是一种常用的反馈控制算法,广泛应用于自动控制系统中。PID控制器通过对比例、积分和微分三项的计算,生成控制输出来调节系统的行为,以使其达到期望的目标值。
PID控制器的三个组成部分
-
比例控制(P - Proportional Control):
- 比例控制部分根据当前误差值
e
(
t
)
e(t)
e(t) 进行调节。它产生的控制输出与误差成正比:
P ( t ) = K p ⋅ e ( t ) P(t) = K_p \cdot e(t) P(t)=Kp⋅e(t) - K p K_p Kp 是比例增益,决定了系统对误差的响应速度和幅度。
- 优点:能够快速响应误差变化。
- 缺点:仅使用比例控制可能导致稳态误差,即系统可能无法完全达到目标值。
- 比例控制部分根据当前误差值
e
(
t
)
e(t)
e(t) 进行调节。它产生的控制输出与误差成正比:
-
积分控制(I - Integral Control):
- 积分控制部分根据误差的累积来调节控制输出,目的是消除稳态误差:
I ( t ) = K i ⋅ ∫ 0 t e ( τ ) d τ I(t) = K_i \cdot \int_0^t e(\tau) d\tau I(t)=Ki⋅∫0te(τ)dτ - K i K_i Ki 是积分增益,决定了系统对累积误差的修正力度。
- 优点:可以消除稳态误差,使系统达到目标值。
- 缺点:积分控制可能导致系统反应过慢或产生积分饱和(即积分项积累过多,导致输出过大)。
- 积分控制部分根据误差的累积来调节控制输出,目的是消除稳态误差:
-
微分控制(D - Derivative Control):
- 微分控制部分根据误差的变化率来调节控制输出,主要用于预测误差的变化趋势并进行提前修正:
D ( t ) = K d ⋅ d e ( t ) d t D(t) = K_d \cdot \frac{de(t)}{dt} D(t)=Kd⋅dtde(t) - K d K_d Kd 是微分增益,决定了系统对误差变化速度的响应程度。
- 优点:可以提高系统的稳定性,减小振荡和过冲。
- 缺点:对噪声敏感,如果误差信号中存在噪声,微分控制可能会放大这些噪声,导致不稳定。
- 微分控制部分根据误差的变化率来调节控制输出,主要用于预测误差的变化趋势并进行提前修正:
PID控制器的总体公式
将比例、积分和微分控制结合起来,PID控制器的控制输出为:
u
(
t
)
=
K
p
⋅
e
(
t
)
+
K
i
⋅
∫
0
t
e
(
τ
)
d
τ
+
K
d
⋅
d
e
(
t
)
d
t
u(t) = K_p \cdot e(t) + K_i \cdot \int_0^t e(\tau) d\tau + K_d \cdot \frac{de(t)}{dt}
u(t)=Kp⋅e(t)+Ki⋅∫0te(τ)dτ+Kd⋅dtde(t)
其中:
- u ( t ) u(t) u(t) 是控制器的输出,用于调节系统。
- e ( t ) = r ( t ) − y ( t ) e(t) = r(t) - y(t) e(t)=r(t)−y(t) 是系统的误差, r ( t ) r(t) r(t) 是目标值, y ( t ) y(t) y(t) 是实际输出。
调节PID控制器的参数
-
K
p
K_p
Kp(比例增益):
- 增大 K p K_p Kp会使系统对误差更加敏感,响应更快,但可能导致系统不稳定和振荡。
-
K
i
K_i
Ki(积分增益):
- 增大 K i K_i Ki 可以消除稳态误差,但可能导致系统过调,反应变慢。
-
K
d
K_d
Kd(微分增益):
- 增大 K d K_d Kd 可以减小系统的振荡和过冲,但对噪声敏感,需要谨慎设置。
c语言代码实现
- PID控制器的C代码示例
#include <stdio.h>
// 定义PID结构体
typedef struct {
float Kp; // 比例增益
float Ki; // 积分增益
float Kd; // 微分增益
float prev_error; // 上一次的误差
float integral; // 误差的积分
} PIDController;
// 初始化PID控制器
void PID_Init(PIDController *pid, float Kp, float Ki, float Kd) {
pid->Kp = Kp;
pid->Ki = Ki;
pid->Kd = Kd;
pid->prev_error = 0;
pid->integral = 0;
}
// 计算PID控制输出
float PID_Compute(PIDController *pid, float setpoint, float measured_value, float dt) {
// 计算误差
float error = setpoint - measured_value;
// 计算比例项
float P_out = pid->Kp * error;
// 计算积分项
pid->integral += error * dt;
float I_out = pid->Ki * pid->integral;
// 计算微分项
float derivative = (error - pid->prev_error) / dt;
float D_out = pid->Kd * derivative;
// 保存当前误差以供下次使用
pid->prev_error = error;
// 计算最终的控制输出
float output = P_out + I_out + D_out;
return output;
}
int main() {
// 创建一个PID控制器
PIDController pid;
// 初始化PID控制器参数(Kp, Ki, Kd)
PID_Init(&pid, 1.0, 0.1, 0.01);
// 设定目标值(setpoint)
float setpoint = 100.0;
// 当前测量值
float measured_value = 90.0;
// 时间步长(假设为0.1秒)
float dt = 0.1;
// 计算PID控制器的输出
float output = PID_Compute(&pid, setpoint, measured_value, dt);
// 输出结果
printf("PID Output: %f\n", output);
return 0;
}
python仿真
# 代码来自:https://ethanr2000.medium.com/using-pid-to-cheat-an-openai-challenge-f17745226449
# 系统建模方程 https://ctms.engin.umich.edu/CTMS/index.php?example=InvertedPendulum§ion=SystemModeling
# sudo apt-get install python-opengl
# pip install gym==0.16.0
# pip install pillow==9.0.0 原因:https://github.com/MannLabs/alphapept/issues/561
# pip install imagio # 用于保存结果,使用的numpy版本为1.20.1
import imageio
import gym
env = gym.make("CartPole-v1")
observation = env.reset()
Kp = 135
Ki = 96.5
Kd = 47.5
force = 0
integral = 0
writer = writer = imageio.get_writer('output.gif', mode='?') # https://imageio.readthedocs.io/en/stable/reference/userapi.html
for _ in range(100):
img = env.render(mode = "rgb_array") # 捕捉当前帧的图像
writer.append_data(img)
env.render()
observation, reward, done, info = env.step(force)
velocity = observation[1]
angle = observation[2]
angular_velocity = observation[3]
integral = integral + angle
F = Kp*(angle) + Kd*(angular_velocity) + Ki*(integral)
force = 1 if F > 0 else 0
if done:
observation = env.reset()
integral = 0
env.close()
writer.close()
效果
- 实际运行比这个gif展示的更稳定,摆动速度也是不同的
CG
- https://github1s.com/m-lundberg/simple-pid/blob/master/simple_pid/pid.py#L101-L161
- pip install mujoco # mujoco是和gym同类的仿真工具
- https://mujoco.readthedocs.io/en/latest/python.html
- https://github.com/openai/mujoco-py?tab=readme-ov-file