用电机进行简单的PID参数整定

最近一直在学习PID的相关知识,网上有很多心得和口诀,看完过后感觉自己好像是懂了一些,但让自己实践一下又感觉无从下手,举手无措。所以今天我决定,直接上手一个简单的电机速度PID试试。

准备阶段

  1. 一块主控板子 我这里刚好有一块原子的mini开发板,所以就用它了。其实任何一块最简单的STM32核心板都能完成功能。
    用电机进行简单的PID参数整定_第1张图片

  2. 一个电机 我这里用的是平衡小车之家的减速比30:1的直流减速电机,需要注意的是需要带编码器作为位置反馈
    用电机进行简单的PID参数整定_第2张图片

  3. 一块电机驱动

电机驱动这里用的是L298N,使用非常简单。方向控制,其中一个高电平一个低电平就能控制电机转了,假设左边高是正转,那么右边高便是反转,同时为高或同时为低则不转。实际我们是输入两个脉冲波进行控制,脉冲的占空比决定转速。
用电机进行简单的PID参数整定_第3张图片

  1. 电源供给

我这里用的是12V的航模电池,其实学生电源也行,不过单片机是需要3.3伏的电压,没有降压模块的同学可以用usb给板子供电(usb是5伏,不过板子上有降3.3伏的芯片),然后注意和航模电池共地就好了
用电机进行简单的PID参数整定_第4张图片

  1. USB转TTL模块
    用电机进行简单的PID参数整定_第5张图片
    (图片来自淘宝)这个用于单片机通过串口向电脑反馈数据,然后通过上位机软件显示波形,便于观察和调试。上位机我这里用的是匿名的科创地面站v4.34。软件可以在他们的官网下载。 地址
    嫌麻烦的也可以直接看运动效果(~ ^_ ^~)
    用电机进行简单的PID参数整定_第6张图片

电路搭建

用电机进行简单的PID参数整定_第7张图片
电路搭建比较简单,简单说一下,航模电池引出两路,一路通过降压模块给开发板和编码器供电,一路连接电机驱动L298N。开发板通过PA9,PA10连接USB转TTL模块。要注意的是电机的接口有6根线,两根是电机+和电机-,两根是编码器电源和地,两根是编码器A相B相。AB相连接PA6和PA7。然后电机驱动的方向控制连接PA0和PA1(图中还没连)。这里的电机+ -,方向的控制引脚,和编码器的AB连接引脚不用固定。只要后面软件设定的正转是你想要的正转就行了,不对就交换下引脚好了。

软件搭建

  1. PWM初始化 这些就没必要贴了,原子例程里一堆
  2. 编码器初始化
static void TIM3_Mode_Config(void)//TIM3编码器模式
	//PA6 ch1 
    //PA7 ch2
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;   	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//- 正交编码器输入引脚  // PA6 A  Pa7 B
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;         
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);                           

	/*- TIM4编码器模式配置 -*/
	TIM_DeInit(TIM3);
	TIM_TimeBaseStructure.TIM_Period = 65535;//设定计数器自动重装值
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);              
                 
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,
	 TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);
 	//配置编码器模式触发源和极性4倍频
	TIM_ICStructInit(&TIM_ICInitStructure);	//配置滤波器
	TIM_ICInitStructure.TIM_ICFilter = 6;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
		
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能或者失能指定的TIM中断
	
	TIM3->CNT = 0;//初始值为0

	TIM_Cmd(TIM3, ENABLE);   //启动TIM3定时器
}
  1. 串口初始化

串口初始化比较简单,不过串口通信协议需要按照匿名上位机的写,这个在上位机里有相关协议和例程。

  1. 定时器初始化

    假定10ms控制一次

  2. 简单的PID程序
    这大概是最简单的PID了
    用电机进行简单的PID参数整定_第8张图片
    ``

PID控制里一定要考虑的(重点)

网上的教程,原理讲的很透,但是实际运用起来,有些东西是必须要说明的

1 PWM的重装载值

这个值选择100或者10000,同一个函数运行起来,效果绝对是不一样的,本文选择1000(随缘取的,感觉不错,大家也可以选择100,10000,或者其他的~ ^ ^ ~),记住这个值,我们的PID控制输出最高值就应向这个值看齐
2 控制周期

这个值也非常重要,它既影响了控制效果(10ms控制一次和1s控制一次是不一样的),也影响了速度反馈的数值。我的速度反馈算法是最简陋的,算一个控制周期里编码器反馈的脉冲数。控制周期我选择 10ms,所以这里速度的单位为( cnt/10ms

3 期望值的范围

本文的的期望值就是希望得到的速度,这个值不是随便给的,粗略计算一下,假设我们的电机一秒最多能5圈,假设1圈1560个脉冲,那么1s反馈的脉冲数为1560*5=7800,在10ms里最多78个脉冲,所以我们的期望值应设在 -78到78(小数就不考虑了) 之间(单位 cnt/10ms

4 输出值的范围

因为我们的pwm最大值为1000,那么我希望我的PID控制在(0——1200)之间比较合适,略微超出的限下幅就很舒服,假如输出范围为(0——10000),这就不太合理,超过1000的值都被限幅了,相当于整个电机大部分时间都在满转速运动(就变成了开环控制),控制效果就不好了。
假如如我期望速度为30,而刚开始的速度反馈为0,那么第一次控制的偏差error就为30,一开始我们确实是希望电机能满电压运行,然后当速度提到7左右的时候,电机加速度就应该慢慢减弱,最后让速度能够平滑地变成10。那么这个Kp值大概多少比较好呢,首先Kp=1.0是没用的,30的pwm连电机都动不了~ … ~,那么10呢,初始输出为300,电机应该处于刚起转的地步,理论上的Kp值应该是10的数倍,不过我也是刚上手,先设个10.0看看效果

参数整定

东西已经弄好了,我们来试试效果吧

试试P=10,i=0,d=0的效果(期望速度为30cnt/10ms)
以下部分还待编辑
用电机进行简单的PID参数整定_第9张图片
从图中我们可以看到看到,电机在转过3000后往回减了一点,然后就不动了,这说明存在静差。然后计算下时间,从哪开始动到稳定,2305-2168=137(看横坐标),就是1370ms,这便是调整时间。下一步,我们应该按照网上给的口诀,先调整P大到接近等幅震荡。

由于时间关系,先写这么多,明天再继续

你可能感兴趣的:(嵌入式开发)