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:
- Kp(比例):从0开始逐步增大,观察响应速度。当系统出现轻微振荡时,取当前值的60%作为Kp。
- Ki(积分):从0开始缓慢增大,用于消除稳态误差。若出现低频振荡或超调增大,减小Ki。
- 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。
程序最终输出“判定: 通过”即表示参数满足要求。若未通过,按上述顺序调整参数后重新编译运行。
上图展示了调参完成后的预期响应形态:实际速度平滑上升至目标值,无超调,稳定时间约0.18s。实际曲线形态取决于电机模型与参数,但应保持“单调上升、无过冲”的特征。