0基础STM32 | PID(基于智能车电机控制)一

没有一种控制算法比PID调节规律更有效、更方便的了。现在一些时髦点的调节器基本源自PID。甚至可以这样说:

PID调节器是其它控制调节算法的妈

为什么PID应用如此广泛、又长久不衰?

因为PID解决了自动控制理论所要解决的最基本问题,

系统的稳定性系统的快速性系统的准确性
  1. 1 调节PID的参数,可实现在系统稳定的前提下,兼顾系统的带载能力和抗扰能力,
  2. 2 在PID调节器中引入积分项,系统增加了一个零积点,使之成为一阶或一阶以上的系统,这样系统阶跃响应的稳态误差就为零。

由于自动控制系统被控对象的千差万别,PID的参数也必须随之变化,以满足系统的性能要求。这就给使用者带来相当的麻烦,特别是对初学者。

下面简单介绍一下调试PID参数的一般步骤:

1.负反馈

自动控制理论也被称为负反馈控制理论。首先检查系统接线,确定系统的反馈为负反馈。例如电机调速系统,输入信号为正,要求电机正转时,反馈信号也为正(PID算法时,误差=输入-反馈),同时电机转速越高,反馈信号越大。其余系统同此方法。

2.PID调试一般原则

  1. a.在输出不振荡时,增大比例增益P。
  2. b.在输出不振荡时,减小积分时间常数Ti。
  3. c.在输出不振荡时,增大微分时间常数Td。

3.一般步骤

a.确定比例增益P
    确定比例增益P 时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0(具体见PID的参数设定说明),使PID为纯比例调节。输入设定为系统允许的最大值的60%~70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%~70%。比例增益P调试完成。
b.确定积分时间常数Ti
    比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。
c.确定积分时间常数Td
    积分时间常数Td一般不用设定,为0即可。若要设定,与确定 P和Ti的方法相同,取不振荡时的30%。
d.系统空载、带载联调,再对PID参数进行微调,直至满足要求。

19届全国大学生智能汽车电磁组PID代码

PID.c

#include "PID.h"

/************************************************
º¯ÊýÃû£ºIncPIDInit(PID *sptr)
¹¦  ÄÜ£ºPID²ÎÊý³õʼ»¯
²Î  Êý£º
·µ»ØÖµ£ºvoid
************************************************/
void IncPIDInit(PID *sptr)
{
    sptr->SumError=0;
    sptr->LastError=0;
    sptr->LLastError=0;

    sptr->Kp=0;
    sptr->Ki=0;
    sptr->Kd=0;
}

/**********************##**************************
º¯ÊýÃû£ºIncPIDCalc(PID *sptr,int16 Setpoint,int16 Turepoint)
¹¦  ÄÜ£ºÔöÁ¿Ê½PID¿ØÖÆ
²Î  Êý£ºPID *sptr,int16 Setpoint,int16 Turepoint
·µ»ØÖµ£ºint32 iIncpid
************************************************/
int16 IncPIDCalc_L(PID*sptr,int16 Setpoint,int16 Turepoint)
{
    int16 iError,iIncpid;
    //µ±Ç°Îó²î
    iError=Setpoint-Turepoint;      //Æ«²î
    //ÔöÁ¿¼ÆËã
    iIncpid =sptr->Kp*(iError-sptr->LastError)+sptr->Ki*iError;
    sptr->LastError=iError; 
	  
    return(iIncpid);
}
int16 IncPIDCalc_R(PID*sptr,int16 Setpoint,int16 Turepoint)
{
    int16 iError,iIncpid;
    //µ±Ç°Îó²î
    iError=Setpoint-Turepoint;      //Æ«²î
    //ÔöÁ¿¼ÆËã
    iIncpid =sptr->Kp*(iError-sptr->LastError)+sptr->Ki*iError;
    sptr->LastError=iError; 
	  
    return(iIncpid);
}
/************************************************

/*******************##*****************************
º¯ÊýÃû£ºPID_Turn_DT(PID*sptr,int16 Error,int16 Gory_z)
¹¦  ÄÜ£º¶¯Ì¬PID¿ØÖÆ£¬¼ÓÁËÍÓÂÝÒÇ
²Î  Êý£ºPID*sptr,int16 Error,int16 Gory_z
·µ»ØÖµ£ºfloat 
************************************************/
float PID_Turn_DT(PID*sptr,float Error,float Gory_z)
{
    float iError,dError,gory_z;
	  float KP;            //¶¯Ì¬P£¬×¢ÒâÓëKpÇø·Ö
    float output;

    iError=Error;  //Æ«²î
	  gory_z=Gory_z;
	
	  KP = (iError*iError)*sptr->Ki + sptr->Kp;    //¶¯Ì¬PµÄ¼ÆËãabs
	
    dError=(iError-(sptr->LastError));     //΢·Ö
	
    output=KP*iError               //±ÈÀýÏî(¶¯Ì¬p)
          +sptr->Kd*dError         //΢·ÖÏî
	        +sptr->K_gory*gory_z;    //ÍÓÂÝÒÇÐÞÕý
	
	  sptr->LastError=iError;
	
    return(output);
}

PID.h

#ifndef __PID_H__
#define __PID_H__

#include "headfile.h"

typedef struct 
{
    float SumError;  //Îó²îÀÛ»ý

    float Kp;      //±ÈÀýϵÊý
    float Ki;      //»ý·ÖϵÊý
    float Kd;      //΢·ÖϵÊý
	  float K_gory;

    float LastError;  //ÉÏÒ»´ÎÎó²î
    float LLastError; //ÉÏÉÏ´ÎÎó²î
}PID;

//½á¹¹Ìå±äÁ¿ÉêÃ÷
extern PID TurnPID;
extern PID SpeedPID;
extern PID L_SpeedPID;
extern PID R_SpeedPID;

//º¯ÊýÉùÃ÷
void IncPIDInit(PID *sptr);
int16 IncPIDCalc_L(PID *sptr,int16 Setpoint,int16 Turepoint);//ÔöÁ¿Ê½PID¿ØÖÆ
int16 IncPIDCalc_R(PID *sptr,int16 Setpoint,int16 Turepoint);//ÔöÁ¿Ê½PID¿ØÖÆ
//float PID_Turn(PID*sptr,float Error,float Gory_z);
float PID_Turn_DT(PID*sptr,float Error,float Gory_z);
#endif

头文件headhile.h

#ifndef __HEADFILE_H_
#define __HEADFILE_H_




#include "isr.h"
#include <string.h>
#include <stdio.h>
#include "intrins.h"
#include <math.h>
//------STC32G SDKµÈ
#include "STC32Gxx.h"
#include "board.h"
#include "common.h"


#include "zf_uart.h"
#include "zf_gpio.h"
#include "zf_iic.h"
#include "zf_adc.h"
#include "zf_spi.h"
#include "zf_tim.h"
#include "zf_pwm.h"
#include "zf_nvic.h"
#include "zf_exti.h"
#include "zf_delay.h"
#include "zf_eeprom.h"
#include "zf_fifo.h"


#include "SEEKFREE_FONT.h"
#include "SEEKFREE_18TFT.h"

#include "SEEKFREE_ICM20602.h"
#include "SEEKFREE_TSL1401.h"
#include "SEEKFREE_IPS114_SPI.h"
#include "SEEKFREE_MPU6050.h"
#include "SEEKFREE_OLED.h"
#include "SEEKFREE_ABSOLUTE_ENCODER.h"
#include "SEEKFREE_WIRELESS.h"
#include "SEEKFREE_PRINTF.h"
#include "SEEKFREE_AT24C02.h"
#include "SEEKFREE_BLUETOOTH_CH9141.h"
#include "SEEKFREE_WIRELESS_CH573.h"
#include "SEEKFREE_CONFIG.h"
#include "SEEKFREE_IMU660RA.h"
#include "SEEKFREE_IMU963RA.h"
#include "SEEKFREE_DL1A.h"
#include "SEEKFREE_VIRSCO.h"
#include "SEEKFREE_DL1B.h"




#include "seekfree_assistant.h"


#include "fuse.h"
#include "ADC.h"
#include "PID.h"
#include  "speed.h"
#include "debug.h"
#include "park.h"




//MOTOR_MODE 
#define MOTOR_MODE_SELECT  0

#define Left_Z_Pin      PWMA_CH3P_P64 //
#define Left_F_Pin      PWMA_CH4P_P66 //
#define Right_Z_Pin     PWMA_CH1P_P60 //
#define Right_F_Pin     PWMA_CH2P_P62 //

#define Left_PWM_Pin   PWMA_CH3P_P64    //
#define Left_DIR_Pin   P66              //
#define Right_PWM_Pin  PWMA_CH1P_P60    //
#define Right_DIR_Pin  P62            //



#define Right_Ecoder_Pin1     CTIM0_P34  //
#define Right_Ecoder_Pin2     P35        //
#define Left_Ecoder_Pin1    CTIM3_P04   //
#define Left_Ecoder_Pin2    P53          //


#define UART_User    UART_4          //
#define UART_TX_Pin  UART4_TX_P03   //
#define UART_RX_Pin  UART4_RX_P02  //


#define BUZZPin     P67


#define Left_ADC_Pin       ADC_P00
#define LeftXie_ADC_Pin    ADC_P01
#define RightXie_ADC_Pin  ADC_P05
#define Right_ADC_Pin       ADC_P06


#define Reed_Switch_Pin P26  



#endif

PID算法仿真基于PYTHON

//pid算法仿真
#text.py
import PID #导入上面的PID算法
from time import sleep
#导入绘图
import matplotlib.pyplot as plt
import numpy as np
 
def test_pid(Kp, Ki , Kd, target, time):
    #位置式PID
 
    pid = PID.Positional_PID(Kp, Ki, Kd, target)
 
    #增量式PID
 
    #pid = PID.Incremental_PID(Kp, Ki, Kd, target)
    
    feedback = 0
    feedback_list = []
    time_list = []
    target_list = []
    
    for i in range(1, 50):
        
        output = pid.PID_OUT(feedback)
        feedback +=output #PID控制系统的函数
        
        feedback_list.append(feedback)
        target_list.append(target)
        time_list.append(i)
        #时间间隔实际没有作用,有时间再加上哈哈
        sleep(time)
 
    feedback_list[0]=0
    target_list[0]=1.1
    #显示输出曲线
    plt.plot(time_list,feedback_list)
    #显示目标对比折线
    plt.plot(time_list,target_list,color='red',linewidth=1,linestyle='--')
    plt.grid(True)
    plt.show()
 
if __name__ == "__main__":
    Kp = 1.5
    Ki = 0.002
    Kd = 0.03
    target_value = 100
    time = 0.01
test_pid(Kp, Ki, Kd, target_value, time)

import time
#位置式PID
class Positional_PID(object):
    
    def __init__(self, P, I, D, Target):
        #对参数值初始化
        self.Target_value = Target  #目标值
        self.last_error = 0.0       #上一次误差
        self.Integral_value_min = -4000  #累积误差的最小限幅
        self.Integral_value_max = 4000   #累积误差的最大限幅
        self.Output_value = 0.0          #输出值
        self.Integral_value = 0.0        #累计值
        self.Kp = P                      #比例常数
        self.Ki = I                      #积分常数
        self.Kd = D                      #微分常数
        
    def PID_OUT(self, Feedback_value):
        #根据给定值和返回值求出偏差
        error = self.Target_value - Feedback_value  
        #求偏差累积值
        self.Integral_value  += error 
        #对累积值进行限幅
        if (self.Integral_value <= self.Integral_value_min):
            self.Integral_value = self.Integral_value_min
        if (self.Integral_value >= self.Integral_value_max):
            self.Integral_value = self.Integral_value_max
        #输出值等于比例部分 + 积分部分 + 微分部分
        self.Output_value=self.Kp * error + self.Ki * self.Integral_value +self.Kd * (error - self.last_error)
        #传递上一次误差
        self.last_error = error
        
        return self.Output_value
 
#增量式PID
class Incremental_PID(object):
    
    def __init__(self, P, I, D, Target):
        self.Target_value = Target
        self.last_error = 0.0            
        self.last_last_error = 0.0       #上上次误差
        self.Output_value = 0.0
 
        self.Kp = P
        self.Ki = I
        self.Kd = D
        
    def PID_OUT(self, Feedback_value):
        #根据给定值和返回值求出偏差
        error = self.Target_value - Feedback_value  
 
        #输出值等于比例部分 + 积分部分 + 微分部分
        self.Output_value +=self.Kp * (error - self.last_error) + self.Ki * error +self.Kd * (error - 2 * self.last_error + self.last_last_error)
        self.last_last_error = self.last_error
        self.last_error = error
        #print(self.Kp * error)
        
        return self.Output_value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值