pid_control.py代码
python
"""
PID Motor Control Simulation
Author: Bochra Oudha
Date: October 2025
Description:
This simulation demonstrates how a PID controller (Proportional, Integral, Derivative)
can control the speed of a DC motor. The system starts with zero speed and tries to
reach a target (setpoint) speed using feedback control.
"""
import numpy as np
import matplotlib.pyplot as plt
# PID parameters
Kp = 0.8 # Proportional gain
Ki = 0.4 # Integral gain
Kd = 0.05 # Derivative gain
# Simulation parameters
dt = 0.01 # Time step
time = np.arange(0, 10, dt) # 10 seconds
setpoint = 1.0 # Desired speed (normalized)
speed = 0.0 # Initial motor speed
integral = 0.0
previous_error = 0.0
speeds = []
controls = []
# Simulation loop
for t in time:
# Calculate error
error = setpoint - speed
# Integrate error
integral += error * dt
# Derivative of error
derivative = (error - previous_error) / dt
# PID control law
control = Kp * error + Ki * integral + Kd * derivative
# Simple motor model (speed response)
speed += (control - 0.2 * speed) * dt
# Save data
previous_error = error
speeds.append(speed)
controls.append(control)
# Plot results
plt.figure(figsize=(10, 6))
# Speed vs Time
plt.subplot(2, 1, 1)
plt.plot(time, [setpoint]*len(time), 'r--', label='Setpoint')
plt.plot(time, speeds, 'b', label='Motor Speed')
plt.title('PID Motor Speed Control Simulation')
plt.xlabel('Time [s]')
plt.ylabel('Speed')
plt.legend()
plt.grid()
# Control signal
plt.subplot(2, 1, 2)
plt.plot(time, controls, 'g', label='Control Signal')
plt.xlabel('Time [s]')
plt.ylabel('Control Effort')
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
代码目的:让电机转速从 0 开始,慢慢追到目标速度 1.0。
feedback control(反馈控制)= 根据当前输出和目标的差距,不断修正输入。
PART1-PID参数
python
# PID parameters
Kp = 0.8 # Proportional gain
Ki = 0.4 # Integral gain
Kd = 0.05 # Derivative gain
Kp = 0.8------比例项增益。意思是误差越大,现在施加的控制就越大。
Ki = 0.4------积分项增益。把过去一直存在的误差累积起来,再进行补偿。它主要解决的问题是**稳态误差。**也就是系统看起来快到了,但总差一点点,长期到不了目标值。这时候积分项就会慢慢把那点残余误差补掉。
Kd = 0.05------微分项增益。微分项看的是误差变化得快不快。如果误差变化太猛,说明系统可能冲得太快了,容易超调,这时候 D 项会起到一种"刹车"或者"预判"的作用。
PART2-仿真参数
python
# Simulation parameters
dt = 0.01 # Time step
time = np.arange(0, 10, dt) # 10 seconds
setpoint = 1.0 # Desired speed (normalized)
speed = 0.0 # Initial motor speed
integral = 0.0
previous_error = 0.0
这一段是在初始化系统。
dt = 0.01 时间步长
time = np.arange(0, 10, dt) 生成从 0 到 10 秒的时间序列,步长是 0.01。本质是一个数组(类似列表)
setpoint = 1.0 目标速度
speed = 0.0 初始电机速度是 0
integral = 0.0 积分项初始值
previous_error = 0.0 上一时刻误差
PART3-保存结果的列表
python
speeds = []
controls = []
这两个列表用来记录每一步的数据,最后画图就靠它们。
speeds:存每个时刻的电机速度
controls:存每个时刻的控制量
PART4-主循环
python
# Simulation loop
for t in time:
对每一个时间点,都做一次控制计算。也就是在每个离散时刻,控制器都重新看一下现在的情况,然后决定下一步怎么调。
1.算误差
python
error = setpoint - speed
误差 = 目标值 - 当前输出
2.积分误差
python
integral += error * dt
把当前这一步的误差累积到总误差里
3.计算误差变化率
python
derivative = (error - previous_error) / dt
这就是微分项
4.PID控制律
python
control = Kp * error + Ki * integral + Kd * derivative
控制量 = 比例项 + 积分项 + 微分项
PART5-电机模型
python
speed += (control - 0.2 * speed) * dt
可以拆解为speed = speed + (control - 0.2 * speed) * dt
意思是 新的速度 = 旧速度 + 速度变化量,而 (control - 0.2 * speed) 相当于"速度变化趋势"。
control 是控制器给电机的驱动力**,**它会让速度上升。
- 0.2 * speed 是阻尼项 / 损耗项,速度越大,这个阻碍越大。
对应 dspeed/dt = control - 0.2 * speed
PART6-更新和保存数据
python
previous_error = error
speeds.append(speed)
controls.append(control)
previous_error = error 把当前误差保存下来,给下一次循环算微分项用。
speeds.append(speed) 把当前速度保存到列表。
controls.append(control) 把当前控制量保存到列表。
PART7-画图部分
1.建图窗口
python
plt.figure(figsize=(10, 6))
创建一个图窗,尺寸是 10×6。
2.第一张图:速度响应
python
plt.subplot(2, 1, 1)
plt.plot(time, [setpoint]*len(time), 'r--', label='Setpoint')
plt.plot(time, speeds, 'b', label='Motor Speed')
plt.title('PID Motor Speed Control Simulation')
plt.xlabel('Time [s]')
plt.ylabel('Speed')
plt.legend()
plt.grid()
这部分是在画上面的图。
plt.subplot(2, 1, 1)
表示整张图分成 2 行 1 列,现在画第 1 个子图。
plt.plot(time, [setpoint]*len(time), 'r--', label='Setpoint')
画目标速度线,也就是红色虚线。因为目标始终是 1.0,所以它是一条水平线。
这里 len(time) 是1000,那么 [setpoint] * 1000 就是 [1.0, 1.0, 1.0, ..., 1.0] 。这样写是因为
因为 plt.plot(x, y) 要求x 和 y 必须一样长。
plt.plot(time, speeds, 'b', label='Motor Speed')
画真实电机速度,也就是蓝线。这条线会从 0 开始,逐渐逼近 1.0,可能有一点超调。
3.第二张图:控制信号
python
plt.subplot(2, 1, 2)
plt.plot(time, controls, 'g', label='Control Signal')
plt.xlabel('Time [s]')
plt.ylabel('Control Effort')
plt.legend()
plt.grid()
这部分画的是控制量。
PART8-最后两句
python
plt.tight_layout()
plt.show()
plt.tight_layout() 自动调整子图间距,防止标签重叠。
plt.show() 把图显示出来。
PART8-讲一讲Kd
Kd重点在于derivative的符号(正负号),
python
derivative=(error -previous_error) / dt
情况1:误差在减小(好现象),比如
python
previous_error = 1.0
error = 0.5
那么
python
derivative = (0.5 - 1.0)/dt = 负数
代入控制
python
control = ... + Kd * (负数)
control 会变小,这意味着 系统在接近目标 → D项帮你"踩刹车"
误差增大时候同理。