1、该系列教程是基于stm32f103c8t6最小系统板的hal库开发,用最通俗易懂的方式手把手带你学会使用Pid算法的速度环、位置环以及速度位置串级pid。
2、出这一期Pid系列教程的想法是前段时间我参加了一个比赛,要用到串级Pid的功能,可是我发现网上的教程要么是零零散散的,没有集中一起讲解这三个功能的,要么就是写的内容不够简单直接,基础没那么好的同学学起来会很吃力。为了用最直观的步骤和最简单的代码带大家一起掌握使用pid控制电机的能力,我打算出一期完整的、通俗易懂的系列教程,同时也作为对我前段时间学习内容的总结。
3、Pid算法涉及到的内容很多,值得我们去深入地研究去发现它的美,pid算法的学习不仅仅是理论上的理解,要去实践,实现把速度、位置控制好的功能。移植好pid算法以后的调参也是一门学问呢!哈哈哈,所以掌握pid并不是一件容易的事情,不过我已经把串级pid实现了,请相信我会带着大家一起从头到尾一点一点实现!
1、本章节要实现的功能是使用串级pid控制电机,最终达到的效果是:电机可以以指定的速度转动到特定的位置,要求速度、位置准确,抗干扰能力强(转到目的角度以后,用手很难转动电机,并且电机在转动时以一定阻力难阻止电机运动,电机在受到干扰后会及时补充速度)。
2、大家会学会:使用串级PID(位置环与速度环)控制电机;注意:位置环与速度环都要先单独调好以后再合并为串级pid,一般来说合成后的串级pid是能用的,如果不准,也可以再调一下参数,先调速度环,将位置环注释掉,调好速度环后,取笑位置环注释,再继续调位置环,调到自己需要的效果。
3、学习本章前建议大家先学习完:【手把手带你用pid算法控制电机】——(1)编码器电机和0.96寸OLED显示屏的使用
【手把手带你用pid算法控制电机】——(2)PID速度环
【手把手带你用pid算法控制电机】——(3)PID位置环
在掌握使用速度环与位置环以后,串级PID控制就很简单了。
速度位置串级PID顾名思义,是速度环与位置环两个环串联一起使用;内环是速度环,外环是位置环,位置pid的输出作为速度pid的输入,把位置pid的输出作为速度pid的目标值去控制。
控制框图如下所示:
本教程的代码是基于【手把手带你用pid算法控制电机】——(2)PID速度环
不需要再写代码,只需要在那篇文章的代码中改一些地方就行。
改成串级PID的代码。
/* USER CODE BEGIN PV */
int16_t speed,encoder_counter;
float Position_KP=0.18,Position_KI=0.002,Position_KD=0; //位置PID系数
float Velocity_KP=4.5,Velocity_KI=0.1,Velocity_KD=0; //速度PID系数
int Encoder,Target_Velocity=30;
int Moto,Position_Moto;//电机PWM变量
int limit_a;
int Position,Target_Position=850; //位置和目标位置自己设定
/* USER CODE END PV */
/* USER CODE BEGIN 0 */
/**
* @function: void GET_NUM(void)
* @description: 使用STM32编码器模式,读取编码器产生的脉冲值
* @param {*}
* @return {*}
*/
void GET_NUM(void)
{
encoder_counter=(short) __HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COUNTER(&htim3,0);//将编码器模式的定时器清零
}
/**
* @function:void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
* @description: 定时器中断回调函数,0.1S中断一次并计算转速,将电机转速以及编码器产生的脉冲数显示在OLED屏上
* @param {TIM_HandleTypeDef *htim}
* @return {*}
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim1)
{
GET_NUM();//得到所记录的脉冲数
Position+=encoder_counter;//脉冲数积累
Position_Moto = Position_PID(Position,Target_Position);
limit_a=Xianfu(Position_Moto,myabs(Target_Velocity));
Moto = Incremental_PI(encoder_counter,limit_a);
//Moto = Incremental_PI(encoder_counter,Target_Velocity);
//Moto =Xianfu(Position_Moto,(这里填PWM满幅));
Set_Pwm(Moto);
//speed=(float)encoder_counter/2040/0.1;//转速为n,r/s 脉冲数转化为速度
//OLED_Showdecimal(0,4,speed,2,2,12,0);//在特定位置显示2位整数+2位小数的电机转速
}
}
/*串口重定向*/
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int _io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__*/
/******************************************************************
*@brief Retargets the C library printf function to the USART.
*@param None
*@retval None
******************************************************************/
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1,0xFFFF);
return ch;
}
/* USER CODE END 0 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
printf("%d,%d\n",Position,Target_Position); //输出编码器的值(实际值)和目标值到vofa软件
}
显示实际位置与目标位置的图像,观察图线是不是以一定的斜率上升到一个值就不变化了;原理:位置的导数就是速度,所以位置图像的斜率就表示速度的大小;
斜率不变代表速度大小不变,即速度环效果可以;
脉冲值达到一定值以后不上升,表示位置环效果可以;
同时有这两个现象表示串级PID效果可以。
(1)我们要先调整速度内环,保证有阶跃响应的稳定,快速,准确性。
(2)速度环要调到的效果:从速度0到收到一个控制目标,速度迅速达到20;从速度20收到一个控制目标,速度迅速到达0。
(3)±1的偏差为编码器的最小量级,PID控制器是作用于偏差,有偏差后它才能生效,所以属于正常控制范围。
因为位置环的输出要作为速度环的速度目标值,所以注意整定位置环参数时,位置环的输出要接近速度环的量级,这样理解:速度环的量级指的就是速度环的目标值指的是每个中断周期内捕捉到的脉冲数值,例如每10ms内电机的脉冲数值是比较小的,所以速度目标值也比较小,所以位置环的参数就也可能比较小。
总之:要根据速度环的需求去整定位置环的参数,并且还要对位置环限幅才能达到应该好的效果。
串级pid效果如下:横坐标为时间,纵坐标有两个,分别是位置目标值和位置实际值,其中实际速度值可以通过实际位置曲线的斜率得以体现,斜率恒定,表示实际速度值恒定。
理论上,把速度环和位置环单独调好以后,整合起来,串级pid的效果是比较好的,如果内外环参数单独调的时候都是正常的,整合以后电机乱转(没有按理想情况转),十有八九你现在是已经磨了很长一段时间了,你脑袋已经昏了,绝对是你代码写错了,注意位置环和速度环控制函数里输入的参量不要搞错,我就是凌晨3点还在调,没调好,第二天发现是自己函数的输入参量搞错了。
我是速度环的两个参量填错了,导致电机总是乱转,搞得我莫名其妙的。
所以大家移植代码的时候一定要从上到下仔细分析一下代码逻辑,理清楚,避免出现低级错误。
说到最后,想到前言我说了是我本人最近做了一个用到了串级pid的项目,到了本系列教程的最后一节了,也该告诉大家我做的是项目具体是什么。我做了一个智能化电梯,用n20电机正反转模拟电梯的上下行,电机以恒定速度正反转不同圈数代表电梯上升或下降到不同的楼层,并且可以反复持续工作,电机运行都正常,每次误差也不会太大。通过这个项目对速度环,位置环,串级Pid都有了初步的认识。
后面在很多地方都再次用到了速度环、位置环、串级控制等操作,每次实操,我都感觉自己对pid控制算法有新的理解和体会,所以我觉得想一次就把一个知识完全掌握,或者说是掌握的较为全面,是不太可能的;初步学了一个知识以后,一定要在其他项目里多实操,以达到对知识更全面更可靠的理解,而不是只停留在会用,只是对知识一知半解。要知道,往往上爬,真正的高手过招,那都拼的是基础知识和能力!与众君共勉!
行文至此,此系列教程已经初步完稿,后续有新的体会与理解以后会不定时对文章进行改进,但是会确保每次发布的文章都是没有错误的,大家放心学习!
码字不易,希望喜欢的小伙伴别忘了点赞+收藏+关注,你们的肯定就是我创作的动力。
欢迎大家积极交流,本文未经允许谢绝转载!!!