STM32 PID速度环 PID输出的速度总是达不到我设定的速度值

2019-12-20 21:41发布

移植的PID算法,现在遇到一个砍了,我是首次接触PID,本着敬畏的态度来学习。关于STM32采用PID算法控制直流有刷电机有几个疑问,希望前辈们能屈尊给新人一些建议。
疑问1:STM32 PID速度环中使用编码器来获取速度的速度单位是什么?(并且这个编码器每次中断服务程序中是什么含义?)关于编码器取到的速度如何使用再PID算法上?

编码器相关代码:

typedef struct
{
        unsigned short V;    //speed
        unsigned short cnt;
        unsigned short rcnt;
        unsigned short CNT;
}EncoderType;

void TIM3_ENC_Init(void)     
{
  GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_ICInitTypeDef  TIM_ICInitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  
                                                                                              
        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);                                 
        GPIO_WriteBit(GPIOA, GPIO_Pin_6,Bit_SET);
        GPIO_WriteBit(GPIOA, GPIO_Pin_7,Bit_SET);

  TIM_TimeBaseStructure.TIM_Period = 20000;
        TIM_TimeBaseStructure.TIM_Prescaler = 0;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;   
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
       
        //?????3??????  IT1 IT2??????
        TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge);
        TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 6;      
  TIM_ICInit(TIM3, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM3, TIM_FLAG_Update);      
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  TIM3->CNT = 0;
        TIM_Cmd(TIM3, ENABLE);
}


void TIM3_IRQHandler(void)
{

  if (TIM3 -> CR1 & 0X0010)                 
   {
    GetEncoder.rcnt -= 1;
   }
   else GetEncoder.rcnt += 1;

   TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}




void Get_Encoder(void)
{
  s32 CNT3_temp,CNT3_last;

  GetEncoder.cnt = TIM3 -> CNT;
  CNT3_last = GetEncoder.CNT;
  CNT3_temp = GetEncoder.rcnt * 2000 + GetEncoder.cnt;  // #define prd     ECDPeriod
  GetEncoder.V = CNT3_temp - CNT3_last;               
  
  while ((int)(GetEncoder.V)>1000)                                 
  {                                                             
   GetEncoder.rcnt--;                                             
   CNT3_temp = GetEncoder.rcnt * 2000 + GetEncoder.cnt;
   GetEncoder.V = CNT3_temp - CNT3_last;                 
  }                                                             
  while ((int)(GetEncoder.V)<-1000)                           //Vbreak  ECDPeriod/2
  {                                                             
   GetEncoder.rcnt++;                                             
   CNT3_temp = GetEncoder.rcnt * 2000 + GetEncoder.cnt;
   GetEncoder.V = CNT3_temp - CNT3_last;                 
  }
  GetEncoder.CNT = CNT3_temp;                                                 
  
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
9条回答
pillar2060
1楼-- · 2019-12-21 00:28
疑问2:关于我的位置PID算法有什么问题?导致我的设定值和PID输出值一直不能一致。

float RM_Kp=4;     
float RM_Ki=0;     
float RM_Kd=0;     
float RM_Lim=100.0;

typedef struct
{

float kp;   
float ki;   
float kd;   
float errILim;

float errNow;
float ctrOut;


float errOld;
float errP;
float errI;
float errD;
}PID_AbsoluteType;

void PID_AbsoluteMode(PID_AbsoluteType* PID)
{
         if(PID->kp      < 0.0)    PID->kp      = -PID->kp;
         if(PID->ki      < 0.0)    PID->ki      = -PID->ki;
         if(PID->kd      < 0.0)    PID->kd      = -PID->kd;
         if(PID->errILim < 0.0)    PID->errILim = -PID->errILim;

         PID->errP = PID->errNow;

         PID->errI += PID->errNow;

         if(PID->errILim != 0)          
         {
                if(     PID->errI >  PID->errILim)    PID->errI =  PID->errILim;
                else if(PID->errI < -PID->errILim)    PID->errI = -PID->errILim;
         }
         
         PID->errD = PID->errNow - PID->errOld;
         PID->errOld = PID->errNow;       
         PID->ctrOut = PID->kp * PID->errP + PID->ki * PID->errI + PID->kd * PID->errD;

}


void PidSpeedControl(int Speed)   //入口参数 设定的速度值  100
{
   SpeedNow = GetEncoder.V;             //get Encoder speed   it is real speed

  SpeedTag = Speed;                    //this speed is set speed

   PidSpeedType.errNow  = SpeedTag - SpeedNow;          //get  speed Difference

   PidSpeedType.kp      =RM_Kp;   //get main.c RM_Kp value                 
   PidSpeedType.ki      = RM_Ki;   //get main.c RM_Ki value                     
   PidSpeedType.kd      =RM_Kd;   //get main.c RM_Kd value                     
   PidSpeedType.errILim = RM_Lim;   //get main.c RM_Lim value                  
   PID_AbsoluteMode(&PidSpeedType);                       
   SpeedControl = PidSpeedType.ctrOut;  //输出速度值
   printf("%d ",SpeedControl );
   MotorSpeedSet(SpeedControl);   //           PWM占空比 = SpeedControl / ARR     (ARR=719)  PWM 频率14Khz
}
djkc
2楼-- · 2019-12-21 04:39
速度PID比较难调,主要是靠采集时间间隔然后按脉冲数计算转速,不是那么 精准。PID参数调整时,我建议先开环调速度PID参数,调好后加入位置环,位置快到的时候速度减速,那样位置环就比较好调了。
pillar2060
3楼-- · 2019-12-21 07:43
djkc 发表于 2018-3-21 09:51
速度PID比较难调,主要是靠采集时间间隔然后按脉冲数计算转速,不是那么 精准。PID参数调整时,我建议先开 ...

谢谢前辈,PID速度调总是有振荡。我这里还有一个疑问就是为什么我的速度不是从零开始的,而是从KP*100(100为我设定的速度的值)往下降呢?
su33691
4楼-- · 2019-12-21 08:18
 精彩回答 2  元偷偷看……
zhenhuajiang
5楼-- · 2019-12-21 11:38
关注学习中;
whatcanitbe
6楼-- · 2019-12-21 11:50
晚上回去有时间帮你看看

一周热门 更多>