问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32使用串级PID对编码器电机进行控制

创作时间:
作者:
@小白创作中心

STM32使用串级PID对编码器电机进行控制

引用
CSDN
1.
https://blog.csdn.net/2302_77915576/article/details/140894846

本文介绍了一种使用STM32单片机通过串级PID控制编码器电机的方法。通过详细讲解PID控制原理、参数调整方法、硬件接线图以及具体的代码实现,帮助读者掌握电机控制技术。

设计目标:使电机以目标速度达到目标位置

1. PID的作用

1.1 PID应用概述

PID控制器是一种广泛应用于工业控制系统的反馈控制器,其名称来源于其三种基本控制规律:比例(Proportional)、积分(Integral)和微分(Derivative)。其基本原理是通过反馈实现控制,反馈来源是电机上安装的编码器,编码器种类有很多,常见的是霍尔式还有光电式,本文中使用的电机使用的就是霍尔式编码器电机。

普通电机上电后即可进行旋转运动,运动方向可以通过调节控制器的高低电平翻转来实现,而调节输出的电压,则可实现对电机的速度调节。在一个周期内,反复调节输出电压,即可实现调速,这是目前最常见的调速方式,即调整同一周期内通电的时间,同一周期内通电时间越长,等效电压越大,而等效电压越大,电机速度越快,考虑到电机的机械特性,每个电机的机械特性都不尽相同,如果只是单纯改变占空比,输出PWM,电机难以实现较为准确的速度控制,且很多场景中,运行路径是固定的,这就需要电机拥有重复定位的精确性,这就需要使用到编码器。

通过STM32单片机开启定时器读取编码器值,这个代码来自江协科技。通过读取的值可以获取到电机的运动状态。

在获取到编码器值后,需要将其保留下来,这就需要使用定时器中断,代码中是用定时器2,每隔10ms进入一次中断,进行一次编码器值的获取。

1.2 PID参数调整

本文使用的是速度位置串级PID,在调节时,理论上应当先调节速度环,再调节外环,速度环作为内环,其响应速度通常要求比位置环快,以确保系统能够快速响应速度变化,

调整速度环的比例增益(Kp),使其具有足够的增益来快速响应速度偏差,同时避免系统过冲或振荡。

调整微调积分增益(Ki)以消除稳态误差,但要防止积分饱和。

调整微分增益(Kd)可以帮助减少超调和振荡,提高系统的稳定性和响应速度。

实际上调试时,我并没调整速度环,我的速度环PID值没有调整,只调整位置环的PID,首先使位置环先超调,再使得位置环逼近目标值,最后调整这两个PID区间值,最后实现的效果还算不错。

p1_p=0.074,p1_i=0.5,p1_d=0.05;//位置环PID
s1_p=1,s1_i=0,s1_d=1;//速度环PID

1.3 实物

实物效果,在输出PWM为50时,能准确的实现位置定位。基本的目标已经实现

2.代码部分

2.1 定时器采样周期计算

STM32F103C8T6的主频T1是72Mhz,即72x10^6hz,定时器每隔10ms需要进行一次编码器值获取,定时器的中断周期为
计数周期T=主频/(目标中断周期的倒数)=
后面计算预分频值Prescaler
这意味着预分频器应该设置为999,这样定时器的计数频率将变为:
定时器频率=72,000,000/1000=72,000
自动重载寄存器值设置为71(因为从0开始计数,所以实际计数值为72),以便在72,000个计数后溢出。
TIM_TimeBaseInitStructure.TIM_Period = 72-1;
TIM_TimeBaseInitStructure.TIM_Prescaler =1000-1;

2.2 编码器测速原理

选用的编码器为普通的霍尔编码器,减速比为30:1.当电机旋转一圈时,释放13个脉冲,STM32采用4倍频,因此,电机旋转一周,编码器读取的值为30x13x4=1560个脉冲数。
在知道旋转圈数使用的脉冲数后,可结合使用的轮子直径计算运行路程。

2.3 PID算法代码

#include "stm32f10x.h"                  // Device header
int16_t myabs(int a)
{ 		   
      int temp;
        if(a<0)  temp=-a;  
      else temp=a;
      return temp;
}
float pwm_control(float pwm) //pwm输出限幅
{
    if(pwm>99)
        pwm=99;
    else if(pwm<-99)
        pwm=-99;
    return pwm;
}
float position_xianfu(int16_t now_position,float tar_psoition)//位置式PID位置误差限幅
{
        if(tar_psoition-now_position<3)
        {
                now_position=tar_psoition;
        }
        return now_position;
}
float xianfu(float now,float tar)
{
    if(now>tar)
        now=tar;
    if(now<-tar)
        now=-tar;
    return now;
}
//位置式PID
float p1_Err=0,p1_last_err=0,Integral1=0,p1_pwm=0,p1_p=0.074,p1_i=0.5,p1_d=0.05;//位置环PID
float p1_pid(int16_t now_position1,float tar_position1)
{
    now_position1=myabs(now_position1);
    p1_Err=tar_position1-now_position1;
    p1_pwm=p1_p*p1_Err+p1_i*Integral1+p1_d*(p1_Err-p1_last_err);
    p1_pwm=pwm_control(p1_pwm);
    p1_last_err=p1_Err;
    return p1_pwm+50;
}
//增量式PID
float s1_pid(int16_t Speed,int16_t tar_speed1)
{
        float s1_Err,s1_p=1,s1_i=0,s1_d=1;//速度环PID
        static float s1_last_err,Integral_bias1;
        s1_Err=tar_speed1-Speed;
        Integral_bias1+=s1_Err;
        Speed=s1_p*s1_Err+s1_i*Integral_bias1+s1_d*(s1_Err-s1_last_err);
        s1_last_err=s1_Err;
        Speed=xianfu(Speed,tar_speed1);
    return Speed;		
}  

3.实物接线

OLED SCL PB8
OLED SDA PB9
TB6612
EN-12V电源正极 PWMA --- STM32--PA0
GND-12V电源负极 AIN1------ STM32--PB0
AO1-电机正极 AIN2------ STM32--PB1
AO2-电机负极 STBY-----STM32---VCC
TB6612 其他引脚悬空
Motor
电机正极-TB6612--AO1
GND-STM32--GND
B-STM32--PA6
A-STM32--PA7
VCC-STM32--5V
电机负极-TB6612--AO2

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号