增量式pid_关于PID公式实现的一点困惑。

查资料发现网上关于PID的实现方式有增量式PID和位置式PID两种。

struct _pid{
  float SetSpeed;//目标速度
  float ActualSpeed;//实测速度
  float err;//本次误差
  float err_1;//上次误差
  float err_2;//上上次误差
  float Kp,Ki,Kd;//比例、积分、微分系数
  float integral;//积分量
  float pwm;//执行器输出
}pid;
/*增量式实现*/
float pidcal(float speed)//输入实测速度,返回执行器PWM的数值
{
  pid.ActualSpeed = speed;
  pid.err = pid.SetSpeed - pid.ActualSpeed;//计算本次误差

  pid.pwm += pid.Kp*(pid.err-pid.err_1)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_1+pid.err_2);

  pid.err_2 = pid.err_1;
  pid.err_1 = pid.err;
  return pid.pwm;
}
/*位置式实现*/
float pidcal(float speed)//输入实测速度,返回执行器PWM的数值
{
  pid.ActualSpeed = speed;
  pid.err = pid.SetSpeed - pid.ActualSpeed;

  pid.pwm = pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_1);

  pid.integral += pid.err;//
  pid.err_1 = pid.err;
  return pid.pwm;
}

先说下,这两种代码勉强都是能工作的(效果一点都不好)。但是我认为这根本不属于PID。因为按我的理解PID中P是主要的,I和D起辅助作用。仅有P的情况,算法应该是能工作的,只是不能准确调整到位。但是仔细分析上面两种代码,在只有Kp情况下是不能工作的。

  1. 在只有Kp的情况下,增量式实现中假如当前速度与目标速度误差很大但是状态稳定,假如(pid.err-pid.err_1)一直等于0,那PID根本不起任何作用。
  2. 在只有Kp的情况下,pid.pwm = pid.Kp*pid.err。达到目标速度的时候pid.err=0,这时PID控制器输出pid.pwm=0,。这也是矛盾的。

我觉得正确的写法应该如下:

struct _pid{
  float SetSpeed;//目标速度
  float ActualSpeed;//实测速度
  float err;//本次误差
  float err_1;//上次误差
  float err_2;//上上次误差
  float Kp,Ki,Kd;//比例、积分、微分系数
  float integral;//积分量
  float pwm;//执行器输出
}pid;
struct err_queen{
  float errs[10];
  uint8_t num;
}err_queen;//定义一个存储过去误差值的环形数组,用于积分。
//因为电机响应速度很快,只取最新的10个值来影响本次输出

float pidcal(float speed)
{
  pid.ActualSpeed = speed;
  pid.err = pid.SetSpeed - pid.ActualSpeed;
  err_queen.errs[err_queen.num]=pid.err;
  pid.integral += err_queen.errs[err_queen.num]-err_queen.errs[(err_queen.num==9)?0:(err_queen.num+1)];
 //将最新的误差值加入积分值并减去最旧的数据
  pid.err_2 = pid.err_1;
  pid.err_1 = pid.err;
  err_queen.num ++ ;
  if(err_queen.num==10)
    err_queen.num=0;
  pid.pwm += pid.Kp*pid.err + pid.Ki*pid.integral +pid.Kd*(pid.err-pid.err_1);
  return pid.pwm;
}

pid.pwm +=pid.Kp*pid.err +pid.Ki*pid.integral +pid.Kd*(pid.err-pid.err_1);

这样的公式才能在电机稳定的情况下 pid.pwm输出一个大体稳定的值。电机速度如果有波动,产生pid.err,pid.pwm会在pid.err的作用下细微变化调整电机速度。其中pid.Kp起主要作用,pid.Ki,pid.Kd系数较小,视情况调整。

由于理解不了网上的代码,但是大家都在用应该没问题啊。我的代码实现实际上是将位置式的PID实现进行累加。而且这样的做效果最好。所以写在这里大家帮忙分析。到底怎么回事。

实验环境:

  1. 使用HALL传感器换向和测速,方波六步换向驱动。电机为2个磁极对。虽然电机转动一圈产生12个HALL边沿事件,但是由于HALL传感器的占空比做不到完全50%,因此6个边沿事件才能完成一次测速。即转动一圈更新2个速度值。
  2. PID控制频率为20Hz,(600r/min以下的速度不控制)。积分值只累加10个,因为电机响应很快,0.5s前的状态对现在意义不大。
  3. PWM频率28.8kHz,pwm周期值为2500,pwm=1000大概等于电机2000r/min。

实际效果:P=设定速度,S=实测速度,H=pwm值;,i=误差积分值(最新10个累加)。 视频最后h=2500为饱和状态。

可以看出转速波动不大

  pid.Kp=0.2;
  pid.Ki=0.005;
  pid.Kd=0.001;
2814784a26b69b628c1c3f451d2f9fc2.png
https://www.zhihu.com/video/1216026445711208448
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值