当前正在备战第十八届智能车,记录一下学习和实践的过程,这一篇主要是讲pid算法以及调试。
PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。
PID是经典的闭环控制算法,具有原理简单,易于实现,适用面广,控制参数相互独立,参数的选定比较简单等优点。
在智能车闭环中,pid算法起到了关键作用,他可以保证车辆行驶的速度按照你所设定的目标速度执行,提高了车辆行驶的稳定性。
首先在main函数中对pid进行初始化。
PID_init(&Motor_pid_r);
PID_init(&Motor_pid_l);
PID_Set(&Motor_pid_r,10,10,4);
PID_Set(&Motor_pid_l,10,10,4);
这是所调用的pid函数。
//初始化PID
void PID_init(PID_TypDef* sptr)
{
sptr->Kp = 0.0; // 比例常数 Proportional Const
sptr->Ki = 0.0; // 积分常数 Integral Const
sptr->Kd = 0.0; // 微分常数 Derivative Const
sptr->Bias = 0.0;
sptr->Integral = 0.0;
sptr->Last_Bias = 0.0;
sptr->Pre_Bias = 0.0;
}
//PID设置
void PID_Set(PID_TypDef *PID,float Kp,float Ki,float Kd)
{
PID->Kp = Kp;
PID->Ki = Ki;
PID->Kd = Kd;
}
这是在中断中调用来计算pwm的函数
pwm_r += IncPID(r_speed,target_speed_r,&Motor_pid_r);
pwm_l += IncPID(l_speed,target_speed_l,&Motor_pid_l);
这是增量式PID和位置式PID,具体用那一个要看实际应用情况
typedef struct
{
float Kp; // 比例常数 Proportional Const
float Ki; // 积分常数 Integral Const
float Kd; // 微分常数 Derivative Const
float Integral;
float Bias;
float Last_Bias;
float Pre_Bias;
}PID_TypDef;
PID_TypDef Motor_pid_r; //右电机PID
PID_TypDef Motor_pid_l; //左电机PID
//PID设置
void PID_Set(PID_TypDef *PID,float Kp,float Ki,float Kd)
{
PID->Kp = Kp;
PID->Ki = Ki;
PID->Kd = Kd;
}
//增量式PID
float IncPID(int Encoder,int Target,PID_TypDef* sptr)
{
float Pwm;
sptr->Bias = Target - Encoder; // 计算当前误差
Pwm = sptr->Kp * (sptr->Bias-sptr->Last_Bias) // P
+sptr->Ki * sptr->Bias // I
+sptr->Kd * (sptr->Bias-2*sptr->Last_Bias+sptr->Pre_Bias); // D
sptr->Pre_Bias=sptr->Last_Bias; // 存储误差,用于下次计算
sptr->Last_Bias=sptr->Bias;
return(Pwm); // 返回增量值
}
//位置式PID
float PstPID(float Angle, float Target,PID_TypDef* sptr)
{
float Pwm;
// if(around==2)
// {
sptr->Bias = 30 ;
// }else
// {
sptr->Bias = Target -Angle ;
// }
sptr->Integral += sptr->Bias;
Pwm = sptr->Kp * sptr->Bias // P
+sptr->Ki * sptr->Integral // I
+sptr->Kd * (sptr->Bias-sptr->Last_Bias); // D
sptr->Last_Bias=sptr->Bias;
return(Pwm);
}
比例P : e(k)-e(k-1) 当前误差 - 上次误差
积分I : e(i) 当前误差
微分D : e(k) - 2e(k-1)+e(k-2) 当前误差 - 2*上次误差 + 上上次误差
增量式PID中不需要累加,控制增量Δu(k)的确定仅与最近3次的采样值有关,容易通过加权处理获得比较好的控制效果,并且在系统发生问题时,不会出现突变的情况,增量式不会严重影响系统的工作。
e(k): 用户设定的值(目标值) - 控制对象的当前的状态值
比例P : e(k)
积分I : ∑e(i) 误差的累加(包括e(k))
微分D : e(k) - e(k-1) 这次误差-上次误差
因为有误差积分一直累加,也就是当前的输出u(k)与过去的所有状态都有关系,用到了误差的累加值;(误差e会有误差累加),输出的u(k)对应的是执行机构的实际位置,,一旦控制输出出错(控制对象的当前的状态值出现问题 ),u(k)的大幅变化会引起系统的大幅变化
并且位置式PID在积分项达到饱和时,误差仍然会在积分作用下继续累积,一旦误差开始反向变化,系统需要一定时间从饱和区退出,所以在u(k)达到最大和最小时,要停止积分作用,并且要有积分限幅和输出限幅
所以在使用位置式PID时,一般我们直接使用PD控制
而位置式 PID 适用于执行机构不带积分部件的对象,如舵机和平衡小车的直立和温控系统的控制
(详细的位置式pid与增量式pid可以看原文链接https://blog.csdn.net/u014453443/article/details/100573722)
这是我使用的上位机软件
这是上位机软件所看到的双电机上电后粗调的效果
基本上实现了pid闭环控制,用手施加外部持续稳定的阻力,电机依旧可以保证稳定的转速,效果比较理想。
我最近发了一篇文章里面包含了常用的功能函数以及常用的模块底层驱动函数封装库,大家感兴趣的可以收藏一下,需要的时候就不用到处找代码,一篇就够用,我会持续更新。
常用模块函数封装库(持续更新中。。。。。。)-CSDN博客