3. 前馈-反馈复合控制在伺服系统中的应用

{'id' 学习卡片

任务定义

伺服系统位置跟踪中,传统PID反馈控制存在固有滞后,当输入轨迹连续变化时会产生跟随误差。本案例设计一个前馈-反馈复合控制器:前馈通道基于参考轨迹的加速度信息提供补偿力矩,反馈通道采用PID修正残余误差,目标是使电机实际位置对给定参考轨迹的跟踪误差显著小于纯PID控制。

系统模型与控制结构

被控对象为直流伺服电机,简化为二阶模型:J·θ'' + b·θ' = Kt·u,其中J=0.01 kg·m²为转动惯量,b=0.1 N·m·s/rad为粘性阻尼系数,Kt=1 N·m/A为力矩常数,u为控制输入(电流),θ为电机角度。控制结构如下:

θ_ref(t) 前馈补偿器 G_ff(s)=J·s²+b·s + − 测量反馈 θ(t) PID反馈控制器 Kp+Ki/s+Kd·s + 伺服电机模型 1/(J·s²+b·s) θ(t) 前馈通道(加速度补偿) 反馈通道(误差修正)

前馈补偿器取被控对象模型的逆:G_ff(s) = J·s² + b·s,其输入为参考轨迹θ_ref,输出为前馈电流u_ff。反馈PID根据跟踪误差e=θ_ref−θ输出u_pid。总控制量为u = u_ff + u_pid。理想情况下,前馈通道单独即可实现零误差跟踪,反馈通道仅用于抑制模型失配和外部扰动。

Python实现

以下代码在Python中完成复合控制器仿真,并与纯PID控制对比。仿真采用梯形速度轨迹作为参考输入,离散化步长1ms。

import numpy as np
import matplotlib.pyplot as plt

# ---------- 系统参数 ----------
J = 0.01      # 转动惯量 kg·m²
b = 0.1       # 粘性阻尼 N·m·s/rad
Kt = 1.0      # 力矩常数 N·m/A
dt = 0.001    # 采样周期 1ms
T = 3.0       # 仿真时长 3s
t = np.arange(0, T, dt)
N = len(t)

# ---------- 参考轨迹:梯形速度曲线 ----------
v_max = 2.0           # 最大速度 rad/s
a_acc = 5.0           # 加速度 rad/s²
t_acc = v_max / a_acc # 加速时间 0.4s
t_const = 1.0         # 匀速时间
t_dec = t_acc         # 减速时间
t_total = t_acc + t_const + t_dec  # 1.8s

theta_ref = np.zeros(N)
vel_ref = np.zeros(N)
acc_ref = np.zeros(N)

for i in range(1, N):
    ti = t[i]
    if ti < t_acc:
        acc_ref[i] = a_acc
        vel_ref[i] = a_acc * ti
    elif ti < t_acc + t_const:
        acc_ref[i] = 0
        vel_ref[i] = v_max
    elif ti < t_total:
        acc_ref[i] = -a_acc
        vel_ref[i] = v_max - a_acc * (ti - t_acc - t_const)
    else:
        acc_ref[i] = 0
        vel_ref[i] = 0
    theta_ref[i] = theta_ref[i-1] + vel_ref[i] * dt

# ---------- 控制器参数 ----------
Kp, Ki, Kd = 50.0, 100.0, 0.5   # PID参数

# ---------- 仿真函数 ----------
def simulate(use_ff):
    theta = 0.0
    omega = 0.0
    integral = 0.0
    prev_error = 0.0
    theta_hist = np.zeros(N)
    err_hist = np.zeros(N)
    
    for i in range(N):
        # 跟踪误差
        error = theta_ref[i] - theta
        integral += error * dt
        derivative = (error - prev_error) / dt
        prev_error = error
        
        # PID输出
        u_pid = Kp * error + Ki * integral + Kd * derivative
        
        # 前馈输出(使用参考加速度和速度)
        u_ff = 0.0
        if use_ff:
            u_ff = J * acc_ref[i] + b * vel_ref[i]
        
        # 总控制量
        u = u_pid + u_ff
        
        # 电机模型更新(欧拉法)
        alpha = (Kt * u - b * omega) / J
        omega += alpha * dt
        theta += omega * dt
        
        theta_hist[i] = theta
        err_hist[i] = error
    
    return theta_hist, err_hist

# ---------- 运行两种控制 ----------
theta_pid, err_pid = simulate(use_ff=False)
theta_ff, err_ff = simulate(use_ff=True)

# ---------- 计算最大误差和RMS误差 ----------
max_err_pid = np.max(np.abs(err_pid))
max_err_ff = np.max(np.abs(err_ff))
rms_err_pid = np.sqrt(np.mean(err_pid**2))
rms_err_ff = np.sqrt(np.mean(err_ff**2))

print(f"纯PID:   最大误差={max_err_pid:.4f} rad, RMS误差={rms_err_pid:.4f} rad")
print(f"前馈+PID: 最大误差={max_err_ff:.4f} rad, RMS误差={rms_err_ff:.4f} rad")

# ---------- 绘图 ----------
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))

ax1.plot(t, theta_ref, 'k--', label='参考轨迹', linewidth=1.5)
ax1.plot(t, theta_pid, 'b-', label='纯PID', alpha=0.7)
ax1.plot(t, theta_ff, 'r-', label='前馈+PID', alpha=0.7)
ax1.set_ylabel('位置 (rad)')
ax1.legend()
ax1.grid(True, alpha=0.3)

ax2.plot(t, err_pid, 'b-', label='纯PID误差', alpha=0.7)
ax2.plot(t, err_ff, 'r-', label='前馈+PID误差', alpha=0.7)
ax2.set_xlabel('时间 (s)')
ax2.set_ylabel('跟踪误差 (rad)')
ax2.legend()
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('servo_tracking.png', dpi=100)
plt.show()

运行与验证

依赖:numpy、matplotlib。运行命令:python servo_control.py。

验证方法:程序执行后,终端输出两种控制器的最大误差和RMS误差数值;同时生成servo_tracking.png图像,包含位置跟踪对比和误差对比两个子图。

判定标准:满足以下条件即验证通过:

  1. 程序无异常退出,输出两组误差指标;
  2. 前馈+PID的最大误差和RMS误差均小于纯PID对应值;
  3. 误差曲线图中,前馈+PID的误差幅值明显低于纯PID,尤其在加速和减速阶段(0~0.4s和1.4~1.8s)差异显著。

预期输出(由代码逻辑直接推出):纯PID在加减速阶段因积分滞后产生较大跟踪误差;加入前馈补偿后,由于前馈项直接提供加速所需力矩,误差大幅减小。匀速段两者误差均趋近于零。