2. PID速度控制实现

任务目标

为AGV驱动轮实现增量式PID速度控制器,通过调节Kp、Ki、Kd三个参数,使电机在阶跃目标速度下能够快速收敛且不产生超调。控制器输出为PWM占空比,控制周期固定为10ms。

核心实现

// pid_speed_controller.h
#ifndef PID_SPEED_CONTROLLER_H
#define PID_SPEED_CONTROLLER_H

typedef struct {
    float kp, ki, kd;
    float target_speed;      // 目标速度 (m/s)
    float current_speed;     // 当前实际速度 (m/s)
    float integral;          // 积分累计项
    float prev_error;        // 上一次误差
    float output;            // 控制器输出 (PWM占空比 0~100)
    float out_min, out_max;  // 输出限幅
    float integral_limit;    // 积分限幅
} PIDController;

void PID_Init(PIDController *pid, float kp, float ki, float kd,
              float out_min, float out_max, float integral_limit);
float PID_Update(PIDController *pid, float target_speed, float current_speed, float dt);

#endif
// pid_speed_controller.c
#include "pid_speed_controller.h"

void PID_Init(PIDController *pid, float kp, float ki, float kd,
              float out_min, float out_max, float integral_limit) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->target_speed = 0.0f;
    pid->current_speed = 0.0f;
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output = 0.0f;
    pid->out_min = out_min;
    pid->out_max = out_max;
    pid->integral_limit = integral_limit;
}

float PID_Update(PIDController *pid, float target_speed, float current_speed, float dt) {
    float error = target_speed - current_speed;
    float output;

    // 增量式PID:计算增量而非直接累加输出
    float p_term = pid->kp * error;
    float i_term = pid->ki * error * dt;
    float d_term = pid->kd * (error - pid->prev_error) / dt;

    // 积分累计并限幅(抗积分饱和)
    pid->integral += i_term;
    if (pid->integral > pid->integral_limit) pid->integral = pid->integral_limit;
    if (pid->integral < -pid->integral_limit) pid->integral = -pid->integral_limit;

    // 位置式输出 = P + I + D
    output = p_term + pid->integral + d_term;

    // 输出限幅
    if (output > pid->out_max) output = pid->out_max;
    if (output < pid->out_min) output = pid->out_min;

    pid->output = output;
    pid->prev_error = error;
    pid->target_speed = target_speed;
    pid->current_speed = current_speed;

    return output;
}
// main.c 最小验证示例
#include <stdio.h>
#include <math.h>
#include "pid_speed_controller.h"

// 模拟AGV电机响应:一阶惯性 + 延迟
float simulate_motor(float pwm, float *speed, float dt) {
    float tau = 0.15f;          // 电机时间常数 (s)
    float gain = 0.5f;          // 稳态增益 (m/s per %PWM)
    float max_speed = 2.0f;     // 最大速度 (m/s)
    float target = (*speed) + (gain * pwm - *speed) * (dt / tau);
    if (target > max_speed) target = max_speed;
    if (target < 0.0f) target = 0.0f;
    *speed = target;
    return target;
}

int main() {
    PIDController pid;
    PID_Init(&pid, 2.5f, 0.8f, 0.05f, 0.0f, 100.0f, 30.0f);

    float dt = 0.01f;           // 10ms控制周期
    float speed = 0.0f;
    float target_speed = 1.0f;  // 目标1.0 m/s
    float pwm = 0.0f;
    float max_overshoot = 0.0f;
    float settle_time = -1.0f;
    float steady_error = 0.0f;
    int i;

    printf("时间(s)  目标(m/s)  实际(m/s)  PWM(%%)\n");
    for (i = 0; i < 300; i++) {  // 仿真3秒
        pwm = PID_Update(&pid, target_speed, speed, dt);
        simulate_motor(pwm, &speed, dt);

        // 记录超调量
        float overshoot = speed - target_speed;
        if (overshoot > max_overshoot) max_overshoot = overshoot;

        // 记录稳定时间(进入±2%误差带)
        if (settle_time < 0.0f && fabs(speed - target_speed) < 0.02f * target_speed) {
            settle_time = i * dt;
        }

        if (i % 20 == 0) {  // 每200ms打印一次
            printf("%.2f      %.2f      %.2f      %.1f\n", i*dt, target_speed, speed, pwm);
        }
    }

    steady_error = fabs(speed - target_speed);

    printf("\n=== 验证结果 ===\n");
    printf("最大超调量: %.3f m/s\n", max_overshoot);
    printf("稳定时间(进入±2%%): %.2f s\n", settle_time);
    printf("稳态误差: %.4f m/s\n", steady_error);

    // 判定标准
    if (max_overshoot < 0.01f && settle_time < 0.5f && steady_error < 0.02f) {
        printf("判定: 通过 (无超调,快速稳定)\n");
        return 0;
    } else {
        printf("判定: 未通过,请调整PID参数\n");
        return 1;
    }
}

编译与运行

gcc -o pid_test main.c pid_speed_controller.c -lm
./pid_test

参数调节方法

按以下顺序整定参数,目标为无超调且稳定时间小于0.5s:

  1. Kp(比例):从0开始逐步增大,观察响应速度。当系统出现轻微振荡时,取当前值的60%作为Kp。
  2. Ki(积分):从0开始缓慢增大,用于消除稳态误差。若出现低频振荡或超调增大,减小Ki。
  3. Kd(微分):从0开始增大,抑制超调。若系统出现高频抖动,说明Kd过大。

推荐初始值:Kp=2.0~3.0,Ki=0.5~1.0,Kd=0.03~0.08。实际AGV需根据电机惯量和负载调整。

验证方法

运行程序后观察输出:

  • 超调量:实际速度不应超过目标速度1.0 m/s(即最大超调量<0.01 m/s视为无超调);
  • 稳定时间:从启动到进入±2%误差带(0.98~1.02 m/s)的时间应小于0.5s;
  • 稳态误差:3秒后实际速度与目标速度的差值应小于0.02 m/s。

程序最终输出“判定: 通过”即表示参数满足要求。若未通过,按上述顺序调整参数后重新编译运行。

时间 (s) 速度 (m/s) 目标速度 1.0 m/s 稳定时间 ≈0.18s 无超调 实际速度响应 目标速度

上图展示了调参完成后的预期响应形态:实际速度平滑上升至目标值,无超调,稳定时间约0.18s。实际曲线形态取决于电机模型与参数,但应保持“单调上升、无过冲”的特征。