没有一种控制算法比PID调节规律更有效、更方便的了。现在一些时髦点的调节器基本源自PID。甚至可以这样说:
PID调节器是其它控制调节算法的妈
为什么PID应用如此广泛、又长久不衰?
因为PID解决了自动控制理论所要解决的最基本问题,
系统的稳定性 | 系统的快速性 | 系统的准确性 |
- 1 调节PID的参数,可实现在系统稳定的前提下,兼顾系统的带载能力和抗扰能力,
- 2 在PID调节器中引入积分项,系统增加了一个零积点,使之成为一阶或一阶以上的系统,这样系统阶跃响应的稳态误差就为零。
由于自动控制系统被控对象的千差万别,PID的参数也必须随之变化,以满足系统的性能要求。这就给使用者带来相当的麻烦,特别是对初学者。
下面简单介绍一下调试PID参数的一般步骤:
1.负反馈
自动控制理论也被称为负反馈控制理论。首先检查系统接线,确定系统的反馈为负反馈。例如电机调速系统,输入信号为正,要求电机正转时,反馈信号也为正(PID算法时,误差=输入-反馈),同时电机转速越高,反馈信号越大。其余系统同此方法。
2.PID调试一般原则
- a.在输出不振荡时,增大比例增益P。
- b.在输出不振荡时,减小积分时间常数Ti。
- 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