PID——双环PID
单环PID只能对被控对象的一个物理量进行闭环控制,而当用户需要对被控对象的多个维度物理量(例如:速度、位置、角度等)进行控制时,则需要多个PID控制环路,即多环PID,多个PID串级连接,因此也称作串级PID
多环PID相较于单环PID,功能上,可以实现对更多物理量的控制,性能上,可以使系统拥有更高的准确性、稳定性和响应速度
PID 双环控制(通常为串级双环,如 “外环(如位置环)+ 内环(如速度环 / 电流环)”)是工业控制中常用的优化结构,其核心优势在于通过分层分工提升系统性能,尤其适用于电机控制、机械传动等需兼顾动态响应与稳态精度的场景。具体优点如下:
1.快速抑制内环扰动,提升抗干扰能力
双环控制中,内环(如速度环)直接与执行器(如电机)耦合,响应速度远快于外环(如位置环)。当系统受到内环扰动(如电机负载突变、电源电压波动、摩擦阻力变化等)时,内环能在扰动影响到外环目标(如位置)之前快速调整,大幅降低扰动对最终控制效果的影响。例如:电机负载突然增加时,速度环会立即检测到速度下降,快速增大输出以维持速度稳定,避免速度波动传递到位置环导致位置偏差扩大。
2. 分解控制任务,简化参数调试
双环控制将复杂的控制目标(如 “高精度位置控制”)分解为两个独立的子任务:
- 内环(如速度环)负责快速跟踪动态指令、抑制高频扰动,专注于 “快速响应” 和 “动态平稳性”;
- 外环(如位置环)负责最终目标的稳态精度,专注于 “消除静态误差”。这种分工使得参数调试更简单:先独立调试内环(让速度响应快速且稳定),再调试外环(基于稳定的速度环优化位置精度),避免单环控制中 “动态响应” 与 “稳态精度” 参数相互干扰的问题。
3. 提升系统稳定性与动态性能
内环可等效为一个 “快速响应的执行器模型”,对外环而言,内环的存在相当于 “简化了被控对象的动态特性”(降低了外环控制对象的阶次或延迟),从而提高外环的稳定性裕度。同时,内环可通过限幅(如速度限幅、电流限幅)限制执行器的最大动态输出(如电机最大转速、最大电流),避免系统因指令突变或扰动出现超调过大、震荡甚至失控(例如防止电机 “飞车”),兼顾动态响应速度与安全性。
4. 提高稳态控制精度
外环(如位置环)直接以最终控制目标(位置)为反馈,可通过积分环节(I)彻底消除稳态误差;而内环(如速度环)则确保动态过程中速度跟踪的精度,为外环提供稳定的 “速度基础”。两者结合,既能保证动态过程快速平稳,又能确保最终目标的高精度(如机械臂的定位精度、传送带的位置控制误差)。
5. 增强系统鲁棒性
实际系统中,执行器参数(如电机电阻、电感、转动惯量)可能随工况(温度、负载)变化,导致单环控制的性能下降。双环控制中,内环对执行器参数的变化更敏感,可通过快速调整补偿参数变化的影响,降低外环对执行器参数的依赖,使系统在参数波动时仍能保持稳定性能(即鲁棒性更强)。

我们把原来电机定位置改为双环

Count++;
if(Count > 40){
Count = 0;
Speed = Encoder_Get();
Location += Speed;
Outer.Actual = Location;
Inner.Actual = Speed;
PID_Update(&Outer);
Inner.Target = Outer.Out;
PID_Update(&Inner);
Motor_SetPWM(Inner.Out);
}
内环速度PID受外环位置PID调控,给外环输入位置,会计算出内环的目标速度,内环再转化为PWM。
#include "PID.h"
void PID_Update(PID_t *p)
{
p->Error1 = p->Error0; //获取上次误差
p->Error0 = p->Target - p->Actual; //获取本次误差,目标值减实际值,即为误差值
if (p->K_I != 0) //如果Ki不为0
{
p->ErrorInt += p->Error0;
}
else
{
p->ErrorInt = 0;
}
p->Out = p->K_P * p->Error0
+ p->K_I * p->ErrorInt
+ p->K_D * (p->Error0 - p->Error1);
if (p->Out > p->OutMax) {p->Out = p->OutMax;}
if (p->Out < p->OutMin) {p->Out = p->OutMin;}
}
void PID_Init(PID_t *p, float kp, float ki, float kd, float outMax, float outMin) {
p->Target = 0;
p->Actual = 0;
p->Out = 0;
p->K_P = kp;
p->K_I = ki;
p->K_D = kd;
p->Error0 = 0;
p->Error1 = 0;
p->ErrorInt = 0;
p->OutMax = outMax;
p->OutMin = outMin;
}
int16_t Speed,Location;
PID_t Inner,Outer;
static uint8_t Count;
int main(void){
Timer_Init();
Motor_Init();
Encoder_Init();
PID_Init(&Inner,0.3,0.2,0,100,-100);
PID_Init(&Outer,0.3,0,0.2,40,-40);
}
void TIM1_UP_IRQHandler(void){
if(TIM_GetITStatus(TIM1,TIM_IT_Update) == SET){
Count++;
if(Count > 40){
Count = 0;
Speed = Encoder_Get();
Location += Speed;
Outer.Actual = Location;
Inner.Actual = Speed;
PID_Update(&Outer);
Inner.Target = Outer.Out;
PID_Update(&Inner);
Motor_SetPWM(Inner.Out);
}
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);
}
}

浙公网安备 33010602011771号