增量式PID的整型算法
PID算法通俗讲解知识讲解
P I D算法通俗讲解总所周知,PID算法是个很经典的东西。
而做自平衡小车,飞行器PID是一个必须翻过的坎。
因此本节我们来好好讲解一下PID,根据我在学习中的体会,力求通俗易懂。
并举出PID的形象例子来帮助理解PID。
一、首先介绍一下PID名字的由来:P:Proportion(比例),就是输入偏差乘以一个常数。
I :Integral(积分),就是对输入偏差进行积分运算。
D:Derivative(微分),对输入偏差进行微分运算。
注:输入偏差=读出的被控制对象的值-设定值。
比如说我要把温度控制在26度,但是现在我从温度传感器上读出温度为28度。
则这个26度就是”设定值“,28度就是“读出的被控制对象的值”。
然后来看一下,这三个元素对PID算法的作用,了解一下即可,不懂不用勉强。
P,打个比方,如果现在的输出是1,目标输出是100,那么P的作用是以最快的速度达到100,把P理解为一个系数即可;而I呢?大家学过高数的,0的积分才能是一个常数,I就是使误差为0而起调和作用;D呢?大家都知道微分是求导数,导数代表切线是吧,切线的方向就是最快到至高点的方向。
这样理解,最快获得最优解,那么微分就是加快调节过程的作用了。
二、然后要知道PID算法具体分两种:一种是位置式的,一种是增量式的。
在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明显没有必要。
而且小车的PID控制器的输出并不是绝对数值,而是一个△,代表增多少,减多少。
换句话说,通过增量PID算法,每次输出是PWM要增加多少或者减小多少,而不是PWM的实际值。
所以明白增量式PID就行了。
三、接着讲PID参数的整定,也就是PID公式中,那几个常数系数Kp,Ti,Td等是怎么被确定下来然后带入PID算法中的。
如果要运用PID,则PID参数是必须由自己调出来适合自己的项目的。
通常四旋翼,自平衡车的参数都是由自己一个调节出来的,这是一个繁琐的过程。
增量式PID通俗解说
增量式PID通俗解说一开始见到PID计算公式时总是疑问为什么是那样子?为了理解那几道公式,当时将其未简化前的公式“活生生”地算了一遍,现在想来,这样的演算过程固然有助于理解,但假如一开始就带着对疑问的答案已有一定看法后再进行演算则会理解的更快!首先推荐白志刚的《由入门到精通—吃透PID2.0版》看完一、二章之后,建议你先通过实践练习然后再回来看接下来的所有章节,这样你对这本书的掌握会更加牢固、节省时间。
PID就是对输入偏差进行比例积分微分运算,运算的叠加结果去控制执行机构。
实践练习中,如何把这一原理转化为程序?为什么是用那几个error进行计算?以下是我摘录的一段PID程序,我曾用其对智能车的速度进行闭环控制:P:Proportional比例I:Integrating积分D:Differentiation微分Pwm_value:输出Pwm暂空比的值Current_error:当前偏差last_error:上次偏差prev_error:上上次偏差增量式PID计算公式:P=Kp*(current_error﹣last_error);D=Kd*(current_error﹣2*last_error﹢prev_error);I=Ki*current_error;PID_add=Pwm_value+P﹢I﹢D一、为什么是PID_add=Pwm_value+(P﹢I﹢D)而不是PID_add=P+I +D?如上图,有一个人前往目的地A,他用眼睛视觉传感器目测到距离目的地还有100m,即当前与目的地的偏差为100,他向双脚输出Δ=10 0J的能量,跑呀跑,10s之后,他又目测了一次,此时距离为40m,即current_error=40,他与10s前的偏差last_error=100对比,即current_error-last_error=-60,这是个负数,他意识到自己已经比较接近目的地,可以不用跑那么快,于是输出Δ=100+(-60)=40J的能量,40J的能量他刚好以4m/s的速度跑呀跑,10s之后,他发现已经到达目的点,此时current_error=0,大脑经过思考得出curre nt_error-last_error=0-40=-40,两脚获得的能量Δ=40+(-40)=0,即他已经达到目的地,无需再跑。
增量式PID的stm32实现,整定过程
【分享】增量式PID的stm32实现,整定过程1感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。
也下面我分享一下近期的这些工作吧。
欢迎大家批评指点~首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异。
资料上比较多的是:•还有一种是:感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧。
(比例、积分、微分三个环节的作用这里就详细展开,百度会有很多)硬件部分:控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形。
电机驱动模块是普通的L298N模块。
芯片型号,STM32F103ZET6软件部分:PWM输出:TIM3,可以直接输出4路不通占空比的PWM波PWM捕获:STM32除了TIM6 TIM7其余的都有捕获功能,使用TIM1 TIM2 TIM4 TIM5四个定时器捕获四个反馈信号PID的采样和处理:使用了基本定时器TIM6,溢出时间就是我的采样周期,理论上T越小效果会越好,这里我取20ms,依据控制对象吧,如果控制水温什么的采样周期会是几秒几分钟什么的。
上面的PWM输出和捕获关于定时器的设置都有例程,我这里是这样的:TIM3输出四路PWM,在引脚 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9输出四路捕获分别是TIM4 TIM1 TIM2 TIM5 ,对应引脚是:PB7 PE11 PB3 PA1高级定时器tim1的初始化略不同,它的中断”名称“和通用定时器不同,见代码:1./*功能名称IM3_PWM_Init(u16 arr,u16 psc)2.描述TIM3产生四路PWM3.*/4.void TIM3_PWM_Init(u16 arr,u16 psc)5.{6. GPIO_InitTypeDef GPIO_InitStructure;7. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;8. TIM_OCInitTypeDef TIM_OCInitStructure;9.10.11. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);12. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟使能13.14. GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);//Timer3全映射 GPIOC->6,7,8,9//用于TIM3的CH2输出的PWM通过该LED显示15.16. //设置该引脚为复用输出功能,输出TIM3 CH1 CH2 CH3 CH4 的PWM脉冲波形17. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 |GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //初始化GPIO18. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP; //复用推挽输出19. GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;20. GPIO_Init(GPIOC, &GPIO_InitStructure);21. GPIO_ResetBits(GPIOC,GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8 | GPIO_Pin_9);//默认电机使能端状态:不使能22.23. TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值24. TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值这里是72分频,那么时钟频率就是1M25. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim26. TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up; //TIM向上计数模式27. TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位28.29.30. TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1 31. TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable; //比较输出使能32. TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值33. TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High; //输出极性:TIM输出比较极性高34.35. TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx36. TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在CCR1上的预装载寄存器37.38.39. TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx40. TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器41.42. TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx43. TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在CCR3上的预装载寄存器44.45. TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx46. TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在CCR4上的预装载寄存器47.48. TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器49.50.51. TIM_Cmd(TIM3, ENABLE); //使能TIMx外设52.53.54.}55.56.57.58./*功能名称TIM4_PWMINPUT_INIT(u16 arr,u16 psc)59. 描述PWM输入初始化*/60.61.void TIM4_PWMINPUT_INIT(u16 arr,u16 psc)62.{63.64. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM的初始化结构体65. NVIC_InitTypeDefNVIC_InitStructure; //中断配置66. TIM_ICInitTypeDef TIM4_ICInitStructure;//TIM4 PWM配置结构体67. GPIO_InitTypeDefGPIO_InitStructure; / /IO口配置结构体68.69. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //Open TIM4 clock70. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //open gpioB clock71.72. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7; //GPIO 773. GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU; //上拉输入74. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;75. GPIO_Init(GPIOB, &GPIO_InitStructure);76.77. TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值78. TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值79. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim80. TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up; //TIM向上计数模式81. TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位82.83.84. /*配置中断优先级*/85. NVIC_InitStructure.NVIC_IRQChannel =TIM4_IRQn;86. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;87. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;88. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;89. NVIC_Init(&NVIC_InitStructure);90.91. TIM4_ICInitStructure.TIM_Channel =TIM_Channel_2;92. TIM4_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;93. TIM4_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI;94. TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;95. TIM4_ICInitStructure.TIM_ICFilter = 0x3; //Filter:过滤96.97. TIM_PWMIConfig(TIM4,&TIM4_ICInitStructure); //PWM输入配置98. TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2); //选择有效输入端99. TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset); //配置为主从复位模式100.TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发101.TIM_ITConfig(TIM4, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置102.TIM_ClearITPendingBit(TIM4,TIM_IT_CC2|TIM_IT_Update); //清除中断标志位103.TIM_Cmd(TIM4, ENABLE);104.}105.106.107.void TIM4_IRQHandler(void)108.{109.110. if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获1发生捕获事件111. {112. duty_TI M4 = TIM_GetCapture1(TIM4); //采集占空比113. if (TIM_GetCapture2(TIM4)>600 ) period_TIM4 = TIM_Get Capture2(TIM4);//简单的处理114. Collect Flag_TIM4 = 0;115. }116. TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位117.}118.119.120./*功能名称TIM1_PWMINPUT_INIT(u16 arr,u16 psc)121.描述PWM输入初始化*/122.123.void TIM1_PWMINPUT_INIT(u16 arr,u16 psc)124.{125.126. TIM_TimeBaseInitTypeDef TIM_TimeBaseStru cture; //TIM的初始化结构体127. NVIC_InitTypeDefNVIC_InitStructure; //中断配置128. TIM_ICInitTypeDef TIM1_ICInitStructure;//PWM配置结构体129. GPIO_InitTypeDefGPIO_InitStructure; / /IO口配置结构体130.131. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //Open TIM1 clock132.RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //open gpioE clock133.GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE);//Timer1完全重映射TIM1_CH2->PE11134. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11; //GPIO 11135.GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU; //上拉输入136.GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 137.GPIO_Init(GPIOE, &GPIO_InitStructure);138.139. TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值140. TIM_TimeBaseStructure.TIM_Prescaler =psc;//设置用来作为TIMx时钟频率除数的预分频值141. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim142. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式143. TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位144.145.146. /*配置中断优先级*/147.NVIC_InitStructure.NVIC_IRQChannel= TIM1_CC_IRQn; //TIM1捕获中断148.NVIC_InitStructure.NVIC_IRQChannelPreemptionPriorit y = 1;149.NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 150.NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 151.NVIC_Init(&NVIC_InitStructure);152.153.TIM1_ICInitStructure.TIM_Channel =TIM_Channel_2;154.TIM1_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;155.TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;156.TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;157.TIM1_ICInitStructure.TIM_ICFilter =0x03; //Filter:过滤158.159.TIM_PWMIConfig(TIM1,&TIM1_ICInitStructure); //PWM输入配置160.TIM_SelectInputTrigger(TIM1,TIM_TS_TI2FP2); //选择有效输入端161.TIM_SelectSlaveMode(TIM1,TIM_SlaveMode_Reset); //配置为主从复位模式162.TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发163.// TIM_ITConfig(TIM1, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置164.TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); //通道2 捕获中断打开165.//TIM_ClearITPendingBit(TIM1,TIM_IT_CC2|TIM_IT_Update); //清除中断标志位166.TIM_Cmd(TIM1, ENABLE);167.}168.169.170.void TIM1_CC_IRQHandler(void)171.{172.173. {174. if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)//捕获1发生捕获事件175. {176. duty_TI M1 = TIM_GetCapture1(TIM1); //采集占空比177. if (TIM_Get Capture2(TIM1)>600) period_TIM1 = TIM_GetCapture2(TIM1);178. Collect Flag_TIM1 = 0;179. }180. }181. TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位182.}183.184.185./*功能名称TIM2_PWMINPUT_INIT(u16 arr,u16 psc)186.描述PWM输入初始化*/187.188.void TIM2_PWMINPUT_INIT(u16 arr,u16 psc)189.{190.191. TIM_TimeBaseInitTypeDef TIM_TimeBaseStru cture; //TIM的初始化结构体192. NVIC_InitTypeDefNVIC_InitStructure; //中断配置193. TIM_ICInitTypeDef TIM2_ICInitStructure;//TIM2 PWM配置结构体194. GPIO_InitTypeDefGPIO_InitStructure; / /IO口配置结构体195.196. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Open TIM2 clock197.// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //open gpioB clock198.RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟199.GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JTAG200. GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //Timer2完全重映射TIM2_CH2->PB3201.202. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_3; //GPIO 3203. GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU; //浮空输入上拉输入204. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;205. GPIO_Init(GPIOB, &GPIO_InitStructure); 206.207. TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值208. TIM_TimeBaseStructure.TIM_Prescaler =psc;//设置用来作为TIMx时钟频率除数的预分频值209. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim210. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式211. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位212.213.214. /*配置中断优先级*/215. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;216.NVIC_InitStructure.NVIC_IRQChannelPreemptionPriorit y = 1;217.NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 218.NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 219.NVIC_Init(&NVIC_InitStructure);220.221.TIM2_ICInitStructure.TIM_Channel =TIM_Channel_2;222.TIM2_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;223.TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;224.TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;225.TIM2_ICInitStructure.TIM_ICFilter =0x3; //Filter:过滤226.227.TIM_PWMIConfig(TIM2,&TIM2_ICInitStructure); //PWM输入配置228.TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2); //选择有效输入端229.TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset); //配置为主从复位模式230.TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发231.TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置232.TIM_ClearITPendingBit(TIM2,TIM_IT_CC2|TIM_IT_Update); //清除中断标志位233.TIM_Cmd(TIM2, ENABLE);234.}235.236.237.void TIM2_IRQHandler(void)238.{239. {240. if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件241. {242. duty_TI M2 = TIM_GetCapture1(TIM2); //采集占空比243. if (TIM_Get Capture2(TIM2)>600) period_TIM2 =TIM_GetCapture2(TIM2);244. Collect Flag_TIM2 = 0;245. }246. }247. TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位248.}249.250./*功能名称TIM5_PWMINPUT_INIT(u16 arr,u16 psc)251.描述PWM输入初始化*/252.253.void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)254.{255.256. TIM_TimeBaseInitTypeDef TIM_TimeBaseStru cture; //TIM的初始化结构体257. NVIC_InitTypeDefNVIC_InitStructure; //中断配置258. TIM_ICInitTypeDef TIM5_ICInitStructure;//TIM4 PWM配置结构体259. GPIO_InitTypeDefGPIO_InitStructure; / /IO口配置结构体260.261. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //Open TIM4 clock262.RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //open gpioB clock263.264. GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1; //GPIO 1265.GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPU; //浮空输入上拉输入266.GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 267.GPIO_Init(GPIOA, &GPIO_InitStructure);268.269. TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值270. TIM_TimeBaseStructure.TIM_Prescaler =psc;//设置用来作为TIMx时钟频率除数的预分频值271. TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim272. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式273. TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位274.275.276. /*配置中断优先级*/277. NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;278.NVIC_InitStructure.NVIC_IRQChannelPreemptionPriorit y = 1;279.NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 280.NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 281.NVIC_Init(&NVIC_InitStructure);282.283.TIM5_ICInitStructure.TIM_Channel =TIM_Channel_2;284.TIM5_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;285.TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;286.TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;287.TIM5_ICInitStructure.TIM_ICFilter =0x3; //Filter:过滤288.289.TIM_PWMIConfig(TIM5,&TIM5_ICInitStructure); //PWM输入配置290.TIM_SelectInputTrigger(TIM5,TIM_TS_TI2FP2); //选择有效输入端291.TIM_SelectSlaveMode(TIM5,TIM_SlaveMode_Reset); //配置为主从复位模式292.TIM_SelectMasterSlaveMode(TIM5,TIM_MasterSlaveMode_Enable);//启动定时器的被动触发293.TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置294.TIM_ClearITPendingBit(TIM5,TIM_IT_CC2|TIM_IT_Update); //清除中断标志位295.TIM_Cmd(TIM5, ENABLE);296.}297.298.299.void TIM5_IRQHandler(void)300.{301. {302. if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件303. {304. duty_TI M5 = TIM_GetCapture1(TIM5); //采集占空比305. if (TIM_GetCaptu re2(TIM5)>600) period_TIM5 =TIM_GetCapture2(TIM5);306. Collect Flag_TIM5 = 0;307. }308. }309. TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位310.}311.复制代码PID部分:准备部分:先定义PID结构体:1.2.typedef struct3.{4.int setpoint;//设定目标5.int sum_error;//误差累计6.float proportion ;//比例常数7.float integral ;//积分常数8.float derivative;//微分常数9.int last_error;//e[-1]10.int prev_error;//e[-2]11.}PIDtypedef;复制代码这里注意一下成员的数据类型,依据实际需要来定的。
温度控制的增量式pid算法
温度控制的增量式pid算法温度控制是工业生产中非常重要的一项技术,它可以保证生产过程中的温度稳定,从而保证产品的质量。
而PID算法是一种常用的控制算法,它可以根据当前的误差来调整控制器的输出,从而实现对温度的精确控制。
在本文中,我们将介绍一种基于增量式PID算法的温度控制方法。
增量式PID算法是一种常用的控制算法,它可以根据当前的误差和误差变化率来计算控制器的输出。
具体来说,增量式PID算法可以分为三个部分:比例控制、积分控制和微分控制。
比例控制是根据当前误差来计算控制器的输出,积分控制是根据误差的积分来计算控制器的输出,微分控制是根据误差的变化率来计算控制器的输出。
这三个部分的输出可以相加得到最终的控制器输出。
在温度控制中,我们可以将温度传感器的输出作为反馈信号,将设定温度作为目标信号,然后使用增量式PID算法来计算控制器的输出。
具体来说,我们可以将当前温度与设定温度的差值作为误差,将当前温度与上一次温度的差值作为误差变化率,然后使用增量式PID算法来计算控制器的输出。
控制器的输出可以通过控制加热器或冷却器的功率来实现对温度的控制。
需要注意的是,增量式PID算法需要对控制器的输出进行积分和微分,这可能会导致控制器的输出出现过冲或震荡的情况。
为了避免这种情况的发生,我们可以使用一些技巧来优化控制器的输出。
例如,我们可以使用限幅器来限制控制器的输出范围,或者使用滤波器来平滑控制器的输出。
增量式PID算法是一种非常有效的温度控制方法,它可以根据当前的误差和误差变化率来计算控制器的输出,从而实现对温度的精确控制。
在实际应用中,我们需要根据具体的情况来选择合适的控制参数,并使用一些技巧来优化控制器的输出,从而实现更加稳定和精确的温度控制。
PID算法
PID算法一、首先介绍一下PID名字的由来:P:Proportion(比例),就是输入偏差乘以一个常数。
I :Integral(积分),就是对输入偏差进行积分运算。
D:Derivative(微分),对输入偏差进行微分运算。
注:输入偏差=读出的被控制对象的值-设定值。
比如说我要把温度控制在26度,但是现在我从温度传感器上读出温度为28度。
则这个26度就是”设定值“,28度就是“读出的被控制对象的值”。
然后来看一下,这三个元素对PID算法的作用,了解一下即可,不懂不用勉强。
P,打个比方,如果现在的输出是1,目标输出是100,那么P的作用是以最快的速度达到100,把P理解为一个系数即可;而I呢?大家学过高数的,0的积分才能是一个常数,I就是使误差为0而起调和作用;D呢?大家都知道微分是求导数,导数代表切线是吧,切线的方向就是最快到至高点的方向。
这样理解,最快获得最优解,那么微分就是加快调节过程的作用了。
二、然后要知道PID算法具体分两种:一种是位置式的,一种是增量式的。
在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明显没有必要。
而且小车的PID控制器的输出并不是绝对数值,而是一个△,代表增多少,减多少。
换句话说,通过增量PID 算法,每次输出是PWM要增加多少或者减小多少,而不是PWM的实际值。
所以明白增量式PID就行了。
三、接着讲PID参数的整定,也就是PID公式中,那几个常数系数Kp,Ti,Td等是怎么被确定下来然后带入PID算法中的。
如果要运用PID,则PID参数是必须由自己调出来适合自己的项目的。
通常四旋翼,自平衡车的参数都是由自己一个调节出来的,这是一个繁琐的过程。
本次我们可以不管,关于PID参数怎么确定的,网上有很多经验可以借鉴。
比如那个经典的经验试凑口诀:参数整定找最佳,从小到大顺序查。
先是比例后积分,最后再把微分加。
pid算法
在过程控制中,由偏差的比例(P),积分(I)和微分(D)控制的PID控制器(也称为PID调节器)是使用最广泛的自动控制器。
具有原理简单,易于实现,应用范围广,控制参数独立,参数选择简单等优点。
从理论上可以证明,对于过程控制的典型对象“一阶滞后+纯滞后”,对于“二阶滞后+纯滞后”的控制对象,PID控制器是一种最优控制。
控制点目前包含三种比较简单的PID控制算法,分别是:增量式算法,位置式算法,微分先行。
这三种PID算法虽然简单,但各有特点,基本上能满足一般控制的大多数要求。
算法种类:1) PID增量式算法离散化公式:注:各符号含义如下u(t);;;;; 控制器的输出值。
e(t);;;;; 控制器输入与设定值之间的误差。
Kp;;;;;;; 比例系数。
Ti;;;;;;; 积分时间常数。
Td;;;;;;; 微分时间常数。
T;;;;;;;; 调节周期。
对于增量式算法,可以选择的功能有:(1) 滤波的选择可以对输入加一个前置滤波器,使得进入控制算法的给定值不突变,而是有一定惯性延迟的缓变量。
(2) 系统的动态过程加速在增量式算法中,比例项与积分项的符号有以下关系:如果被控量继续偏离给定值,则这两项符号相同,而当被控量向给定值方向变化时,则这两项的符号相反。
由于这一性质,当被控量接近给定值的时候,反号的比例作用阻碍了积分作用,因而避免了积分超调以及随之带来的振荡,这显然是有利于控制的。
但如果被控量远未接近给定值,仅刚开始向给定值变化时,由于比例和积分反向,将会减慢控制过程。
为了加快开始的动态过程,我们可以设定一个偏差范围v,当偏差|e(t)|< β时,即被控量接近给定值时,就按正常规律调节,而当|e(t)|>= β时,则不管比例作用为正或为负,都使它向有利于接近给定值的方向调整,即取其值为|e(t)-e(t-1)|,其符号与积分项一致。
利用这样的算法,可以加快控制的动态过程。
(3) PID增量算法的饱和作用及其抑制在PID增量算法中,由于执行元件本身是机械或物理的积分储存单元,如果给定值发生突变时,由算法的比例部分和微分部分计算出的控制增量可能比较大,如果该值超过了执行元件所允许的最大限度,那么实际上执行的控制增量将时受到限制时的值,多余的部分将丢失,将使系统的动态过程变长,因此,需要采取一定的措施改善这种情况。
51单片机PID算法程序(三)增量式PID控制算法
51单片机PID算法程序(一)PID算法(原创文章,转载请注明出处/tengjingshu) 比例,积分,微分的线性组合,构成控制量u(t),称为:比例(Proportional)、积分(Integrating)、微分(Differentiation)控制,简称PID控制图1控制器公式在实际应用中,可以根据受控对象的特性和控制的性能要求,灵活地采用不同的控制组合,构成比例(P)控制器比例+积分(PI)控制器比例+积分+微分(PID)控制器式中或式中控制系统中的应用在单回路控制系统中,由于扰动作用使被控参数偏离给定值,从而产生偏差。
自动控制系统的调节单元将来自变送器的测量值与给定值相比较后产生的偏差进行比例、积分、微分(PID)运算,并输出统一标准信号,去控制执行机构的动作,以实现对温度、压力、流量、也为及其他工艺参数的自动控制。
比例作用P只与偏差成正比;积分作用I是偏差对时间的积累;微分作用D 是偏差的变化率;比例(P)控制比例控制能迅速反应误差,从而减少稳态误差。
除了系统控制输入为0和系统过程值等于期望值这两种情况,比例控制都能给出稳态误差。
当期望值有一个变化时,系统过程值将产生一个稳态误差。
但是,比例控制不能消除稳态误差。
比例放大系数的加大,会引起系统的不稳定。
图2比例(P)控制阶跃响应积分(I)控制在积分控制中,控制器的输出与输入误差信号的积分成正比关系。
为了减小稳态误差,在控制器中加入积分项,积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。
这样,即使误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减少,直到等于零。
积分(I)和比例(P)通常一起使用,称为比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
如果单独用积分(I)的话,由于积分输出随时间积累而逐渐增大,故调节动作缓慢,这样会造成调节不及时,使系统稳定裕度下降。
图3积分(I)控制和比例积分(PI)控制阶跃相应微分(D)控制在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。
增量式pid算法
增量式pid算法
增量式 PID 控制算法是一种改进的 PID 控制算法,它避免了
每次更新 PID 控制器输出时重新计算所有的控制参数。
该算
法将 PID 控制器的输出信号视为增量(差量)信号,即在前
一次控制信号基础上作出新的调整。
实现增量式 PID 算法的关键是保存前一次控制器的输出信号
以及相应的误差。
在每次控制周期内,首先根据当前的误差计算出 PID 控制器的增量部分,然后用前一次的控制信号加上
增量部分得到新的控制信号。
增量式 PID 算法的公式为:
Output(n) = Output(n-1) + Kp * (Error(n) - Error(n-1)) + Ki *
Error(n) + Kd * (Error(n) - 2 * Error(n-1) + Error(n-2))
其中,Output(n) 表示第 n 次控制的输出信号,Output(n-1) 表
示第n-1 次控制的输出信号,Error(n) 表示第n 次控制的误差,Error(n-1) 表示第 n-1 次控制的误差,Error(n-2) 表示第 n-2 次
控制的误差,Kp、Ki 和Kd 分别表示比例、积分和微分增益。
增量式 PID 算法的优点是可以减少计算量,提高控制器的响
应速度。
然而,由于增量式 PID 算法使用误差的差值计算增
量部分,因此对于系统初始状态的响应较慢。
此外,如果系统具有较大的噪声干扰或非线性特性,增量式 PID 算法可能出
现较大的误差累积。
因此,在实际应用中需要根据具体情况选择适当的 PID 控制算法。
PID算法举例
总所周知,PID算法是个很经典的东西。
而做自平衡小车,飞行器PID是一个必须翻过的坎。
因此本节我们来好好讲解一下PID,根据我在学习中的体会,力求通俗易懂。
并举出PID的形象例子来帮助理解PID。
一、首先介绍一下PID名字的由来:P:Proportion(比例),就是输入偏差乘以一个常数。
I :Integral(积分),就是对输入偏差进行积分运算。
D:Derivative(微分),对输入偏差进行微分运算。
注:输入偏差=读出的被控制对象的值-设定值。
比如说我要把温度控制在26度,但是现在我从温度传感器上读出温度为28度。
则这个26度就是”设定值“,28度就是“读出的被控制对象的值”。
然后来看一下,这三个元素对PID算法的作用,了解一下即可,不懂不用勉强。
P,打个比方,如果现在的输出是1,目标输出是100,那么P的作用是以最快的速度达到100,把P理解为一个系数即可;而I呢?大家学过高数的,0的积分才能是一个常数,I就是使误差为0而起调和作用;D呢?大家都知道微分是求导数,导数代表切线是吧,切线的方向就是最快到至高点的方向。
这样理解,最快获得最优解,那么微分就是加快调节过程的作用了。
二、然后要知道PID算法具体分两种:一种是位置式的,一种是增量式的。
在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明显没有必要。
而且小车的PID控制器的输出并不是绝对数值,而是一个△,代表增多少,减多少。
换句话说,通过增量PID算法,每次输出是PWM要增加多少或者减小多少,而不是PWM的实际值。
所以明白增量式PID 就行了。
三、接着讲PID参数的整定,也就是PID公式中,那几个常数系数Kp,Ti,Td等是怎么被确定下来然后带入PID算法中的。
如果要运用PID,则PID参数是必须由自己调出来适合自己的项目的。
通常四旋翼,自平衡车的参数都是由自己一个调节出来的,这是一个繁琐的过程。
51单片机PID算法程序(三)增量式PID控制算法解读
控制器公式
在实际应用中,可以根据受控对象的特性和控制的性能要求,灵活地采用不同的控制组合,构成
比例(P)控制器
比例+积分(PI)控制器
比例+积分+微分(PID)控制器
式中
或ቤተ መጻሕፍቲ ባይዱ
式中
控制系统中的应用
在单回路控制系统中,由于扰动作用使被控参数偏离给定值,从而产生偏差。自动控制系统的调节单元将来自变送器的测量值与给定值相比较后产生的偏差进行比例、积分、微分(PID)运算,并输出统一标准信号,去控制执行机构的动作,以实现对温度、压力、流量、也为及其他工艺参数的自动控制。
T ——采样周期。
如果采样周期足够小,则(2-4)的近似计算可以获得足够精确的结果,离散控制过程与连续过程十分接近。
51单片机PID算法程序(一)PID算法
(原创文章,转载请注明出处/tengjingshu)
比例,积分,微分的线性组合,构成控制量u(t),称为:比例(Proportional)、积分(Integrating)、微分(Differentiation)控制,简称PID控制
(图1,表1)
2)Atmel8-bit AVR Microcontrollers Application Note:AVR221: Discrete PID controller
(图2,图3,图4,图5,表2)
3)使用Ziegler-Nichols方法的自整定控制
/2007-03/200733042815.htm
最好的寻找PID参数的办法是从系统的数学模型出发,从想要的反应来计算参数。很多时候一个详细的数学描述是不存在的,这时候就需要实际地调节PID的参数.
Ziegler-Nichols方法
增量式PID公式的理解
一开始见到PID计算公式时总会问“为什么是这样子的一道公式”,为了理解那几道公式,当时将其未简化前的公式活生生地算了一遍,现在想来,这样的演算过程固然有助于理解,但假如一开始就带着对疑问的答案已有一定抽象了解后再进行演算则会理解的更快!PID就是对输入偏差进行比例积分微分运算,然后将运算的叠加结果去控制执行机构。
实践练习中,如何把这一原理转化为程序?为什么是用那几个error进行计算?以下是一段PID程序,我曾用其对智能车的速度进行闭环控制:P:Proportional 比例I:Integrating 积分D:Differentiation 微分Pwm_value:输出Pwm暂空比的值Current_error:当前偏差last_error:上次偏差prev_error:上上次偏差增量式PID计算公式:P=Kp*(current_error﹣last_error);D=Kd*(current_error﹣2*last_error﹢prev_error);I=Ki*current_error;PID_add=Pwm_value+P﹢I﹢D;一、为什么是PID_add=Pwm_value+(P﹢I﹢D)而不是PID_add=P+I+D?如上图,有一个人前往目的地A,他用眼睛视觉传感器目测到距离目的地还有100m,即当前与目的地的偏差为100,他向双脚输出Δ=100J的能量,跑呀跑,10s之后,他又目测了一次,此时距离为40m,即current_error=40,他与10s前的偏差last_error=10对比,即current_error - last_error=-60,这是个负数,他意识到自己已经比较接近目的地,可以不用跑那么快,于是输出Δ=100+(-60)=40J的能量,40J的能量他刚好以4m/s的速度跑呀跑,10s之后,他发现已经到达目的点,此时current_error=0,大脑经过思考得出current_error—last_error=0 -40=-40,两脚获得的能量Δ=40+(-40)=0,即他已经达到目的地,无需再跑。
PID算法通俗讲解
总所周知,PID算法就是个很经典得东西。
而做自平衡小车,飞行器PID 就是一个必须翻过得坎。
因此本节我们来好好讲解一下PID,根据我在学习中得体会,力求通俗易懂。
并举出PID得形象例子来帮助理解PID。
一、首先介绍一下PID名字得由来:P:Proportion(比例),就就是输入偏差乘以一个常数。
I :Integral(积分),就就是对输入偏差进行积分运算。
D:Derivative(微分),对输入偏差进行微分运算。
注:输入偏差=读出得被控制对象得值-设定值。
比如说我要把温度控制在26度,但就是现在我从温度传感器上读出温度为28度。
则这个26度就就是”设定值“,28度就就是“读出得被控制对象得值”。
然后来瞧一下,这三个元素对PID算法得作用,了解一下即可,不懂不用勉强。
P,打个比方,如果现在得输出就是1,目标输出就是100,那么P得作用就是以最快得速度达到100,把P理解为一个系数即可;而I呢?大家学过高数得,0得积分才能就是一个常数,I就就是使误差为0而起调与作用;D 呢?大家都知道微分就是求导数,导数代表切线就是吧,切线得方向就就是最快到至高点得方向。
这样理解,最快获得最优解,那么微分就就是加快调节过程得作用了。
二、然后要知道PID算法具体分两种:一种就是位置式得,一种就是增量式得。
在小车里一般用增量式,为什么呢?位置式PID得输出与过去得所有状态有关,计算时要对e(每一次得控制误差)进行累加,这个计算量非常大,而明显没有必要。
而且小车得PID控制器得输出并不就是绝对数值,而就是一个△,代表增多少,减多少。
换句话说,通过增量PID算法,每次输出就是PWM要增加多少或者减小多少,而不就是PWM得实际值。
所以明白增量式PID就行了。
三、接着讲PID参数得整定,也就就是PID公式中,那几个常数系数Kp,Ti,Td等就是怎么被确定下来然后带入PID算法中得。
如果要运用PID,则PID参数就是必须由自己调出来适合自己得项目得。
PID算法-增量(详细)
共三十六页
积分(jīfēn)调节器
e(t) t
0 y
t 0
图2积分作用(zuòyòng)响应曲线
共三十六页
比例(bǐlì)积分调节器
❖若将比例和积分两种作用结合起来(qǐ lái),就构成 PI调节器,调节规律为:
❖
(3)
❖ PI调节器的输出特性曲线如图3所示
共三十六页
比例(bǐlì)积分调节器
❖ e(t)作为PID 控制器的输入,u(t)作为PID 控制器的 输出和被控对象的输入。
共三十六页
❖所以模拟PID控制器的控制规律为:
u(t)
K
p
e(t)
1 TI
t
e(t)dt
0
TD
de(t)
dt
uo
❖其中 : (qízhōng) u(t)——调节器的输出信号;
❖ e(t)——调节器的偏差信号,它等于给定值与测量值之差
微分时间选择合适情况下,可以减少超调,减少调节时间。微分作用对噪声干扰有
放大作用,因此过强的加微分调节,对系统抗干扰不利。
共三十六页
❖ 三个参数要综合考虑,一般先将I,D设为0,调好 P,达到基本的响应速度和误差,再加上I,使误差 为0,这时再加入D,三个参数要反复调试,最终 达到较好的结果。不同(bù tónɡ)的控制对象,调试的 难度相差很大!
?uk第k次采样时刻的计算机输出值?ek第k次采样时刻输入的偏差值?ek?1第k1次采样时刻输入的偏差值?ki积分系数积分时间ti即为累积多少次个t?kd微分系数?u0开始进行pid控制时的原始初值应为前一次的给定值?如果采样周期取得足够小则以上近似计算可获得足够精确的结果离散控制过程与连续控制过程十分接近
增量式PID算法
增量式PID算法程序是自己编的,根据多方资料改写了一部分,为增量式PID算法。
程序采用浮点形式,如果MCU速度不够快,可根据需求转换定点运算。
关键变量:ref——设置的参数;feb——采样反馈;根据实际情况修改这两个变量即可。
相关参数:Kp、Ti、Td、T:根据各项目的控制对象不同而修改其定义值。
//定义变量double ref = 0;//设置参数double feb = 0;//采样反馈int pwm_var = 0; //PID调整量Uint16 PWM_out = 0; //PWM输出量double Uo = 0;double Ek = 0;double Ei = 0;double Ed = 0;#define Kp 8 //PID调节的比例常数#define Ti 0.05 //PID调节的积分常数#define Td 0.02 //PID调节的微分时间常数#define T 0.02 //采样周期#define Kpp Kp * ( 1 + (T / Ti) + (Td / T) )#define Ki (-Kp) * ( 1 + (2 * Td / T ) )#define Kd Kp * Td / T//#define Kpp 4//#define Ki 0.8//#define Kd 20//误差的阀值,小于这个数值的时候,不做PID调整,避免误差较小时频繁调节引起震荡#define Emin 3//调整值限幅,防止积分饱和#define Umax 100#define Umin -100//输出值限幅#define Pmax 15500#define Pmin 200/////////////////////////////////////////////////////////////////// ////// PID运算 ///////void pid_ctrl(void){Ek = ref - feb; //差值运算if( fabs(Ek) < Emin ) //误差的阀值(死区控制??){pwm_var = 0;}else{Uo = Kpp*Ek + Ki*Ei + Kd*Ed;//PID计算Ed = Ei;Ei = Ek;pwm_var = (int)Uo; //强制转化调整量,PWM为整数if(pwm_var >= Umax)pwm_var = Umax; //调整值限幅,防止积分饱和if(pwm_var <= Umin)pwm_var = Umin; //调整值限幅,防止积分饱和}PWM_out += pwm_var; //调整PWM输出if(PWM_out > Pmax)PWM_out = Pmax; //输出值限幅if(PWM_out < Pmin)PWM_out = Pmin; //输出值限幅TBCCR1 = PWM_out;//输出给寄存器,改变PWM占空比}/////////////////////////////////////////////////////////////////// 调用示例:void main(void){ref = 120.6;while(1){feb = adc_sample();pid_ctrl();}}另外附上:PID调节经验总结(搜索资源)PID控制器参数选择的方法很多,例如试凑法、临界比例度法、扩充临界比例度法等。
PID算法
PID一般有两种:位置式PID和增量式PID。
在小车里一般用增量式,为什么呢?位置式PID的输出与过去的所有状态有关,计算时要对e(每一次的控制误差)进行累加,这个计算量非常大,而明没有必要。
而且小车的PID控制器的输出并不是绝对数值,而是一个△,代表增多少,减多少。
换句话说,通过增量PID算法,每次输出是PWM要增加多少或者减小多少,而不是PWM的实际值。
下面均以增量式PID说明。
这里再说一下P、I、D三个参数的作用。
P=Proportion,比例的意思,I是Integral,积分,D是Differential 微分。
打个比方,如果现在的输出是1,目标输出是100,那么P的作用是以最快的速度达到100,把P理解为一个系数即可;而I呢?大家学过高数的,0的积分才能是一个常数,I就是使误差为0而起调和作用;D呢?大家都知道微分是求导数,导数代表切线是吧,切线的方向就是最快到至高点的方向。
这样理解,最快获得最优解,那么微分就是加快调节过程的作用了。
公式本来需要推导的,我就不来这一套了。
直接贴出来:看看最后的结果:△Uk=A*e(k)+B*e(k-1)+C*e(k-2)这里KP是P的值,TD是D的值,1/Ti是I的值,都是常数,哦,还有一个T,T是采样周期,也是已知。
而A B C是由P I D换算来的,按这个公式,就可以简化计算量了,因为P I D是常数,那么A B C可以用一个宏表示。
这样看来,只需要求e(k) e(k-1) e(k-2)就可以知道△Uk的值了,按照△Uk来调节PWM的大小就OK了。
PID三个参数的确定有很多方法,不在本文讨论范围内。
采样周期也是有据可依的,不能太大,也不能太小。
制模型:你控制一个人让他以PID控制的方式走110步后停下。
(1)P比例控制,就是让他走110步,他按照一定的步伐走到一百零几步(如108步)或100多步(如112步)就停了。
说明:P比例控制是一种最简单的控制方式。
pid整定算法
pid整定算法
PID控制器是一种广泛应用于工业控制系统中的控制器。
PID控制器实际上是将三个部分迭加在一起的算法。
这些部分分别是比例(P), 积分(I), 和微分(D)。
在PID控制器中,控制器输出值是由以下三个部分相加而成的:
P:比例部分用来控制系统的静态误差。
静态误差是指实际输出值与期望输出值之间的差距。
比例控制器将这个差值乘以一个比例系数,然后将结果放入控制器输出。
I:积分部分用来控制系统的动态误差。
动态误差是指实际输出值与期望输出值之间的偏差,并且还考虑到控制器响应的时间。
积分控制器将动态误差积分,然后将结果乘以一个比例系数,放入控制器输出。
D:微分部分用来控制系统的反向响应。
当一个系统发生急剧变化时,微分控制器可以立即响应以尽可能快地反应这个变化。
微分控制器将系统响应计算为输入信号的导数,然后将结果乘以一个比例系数,放入控制器输出。
PID控制器最重要的部分是在比例、积分和微分之间进行平衡。
当比例系数设置得太高,控制器可能会产生过度振荡或者不稳定的输出。
当积分系数过高,控制器可能会产生慢速振荡或者累计误差。
如果微分系数过高,则可能会导致控制器产生一个不稳定的输出,且不自然地去抵消输出值的变化。
PID控制器调整的目标是找到合适的比例、积分和微分参数,以便获得最佳控制效果。
调整PID控制器需要掌握一些技巧,通常需要经验和试验来完成。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
增量式PID的整型算法对于PID控制的程序算法,很多书上都讲了。
但是,最近真正要用PID算法的时候,发现书上的代码在我们51单片机上来实现还不是那么容易的事情。
简单的说来,就是不能直接调用。
仔细分析你可以发现,教材上的、网上现行的PID实现的C语言代码几乎都是用浮点型的数据来做的,可以想象,如果我们的计算使用浮点数据,那我们的51单片机来运行的话会有多痛苦。
所以,本人自己琢磨着弄了一个整型变量来实现了PID算法,由于是用整型数来做的,所以也不是很精确,但是对于很多的使用场合,这个精度也够了。
关于系数和采样电压全部是放大10倍处理的。
所以精度不是很高,但是也不是那么低,大部分的场合都够用了。
实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不超出整个数据类型的范围就可以了。
以下是具体的程序代码:typedef struct PIDValue{uint32 Ek_Uint32[3]; //差值保存,给定和反馈的差值uint8 EkFlag_Uint8[3]; //符号,1则对应的Ek[i]为负数,0为对应的Ek[i]为正数uint8 KP_Uint8;uint8 KI_Uint8;uint8 KD_Uint8;uint8 B_Uint8; //死区电压uint8 KP; //显示修改的时候用uint8 KI;uint8 KD;uint8 B;uint16 Uk_Uint16; //上一时刻的控制电压}PIDValueStr;PIDValueStr xdata PID;//PID = Uk + (KP*E(k) - KI*E(k-1) + KD*E(k-2));void PIDProcess(void){uint32 idata Temp[3]; //uint32 idata PostSum; //正数和uint32 idata NegSum; //负数和Temp[0] = 0;Temp[1] = 0;Temp[2] = 0;PostSum = 0;NegSum = 0;if( ADPool.Value_Uint16[UINADCH] > ADPool.Value_Uint16[UFADCH] )//给定大于反{Temp[0] = ADPool.Value_Uint16[UINADCH] - ADPool.Value_Uint16[UFADCH];//计算Ek[0]if( Temp[0] > PID.B_Uint8 ){//数值移位PID.Ek_Uint32[2] = PID.Ek_Uint32[1];PID.Ek_Uint32[1] = PID.Ek_Uint32[0];PID.Ek_Uint32[0] = Temp[0];//符号移位PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];PID.EkFlag_Uint8[0] = 0; //当前EK为正数Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0]; // KP*EK0Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1]; // KI*EK1Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2]; // KD*EK2}}else //反馈大于给定{Temp[0] = ADPool.Value_Uint16[UFADCH] - ADPool.Value_Uint16[UINADCH]; //计算Ek[0]if( Temp[0] > PID.B_Uint8 ){//数值移位PID.Ek_Uint32[2] = PID.Ek_Uint32[1];PID.Ek_Uint32[1] = PID.Ek_Uint32[0];PID.Ek_Uint32[0] = Temp[0];//符号移位PID.EkFlag_Uint8[2] = PID.EkFlag_Uint8[1];PID.EkFlag_Uint8[1] = PID.EkFlag_Uint8[0];PID.EkFlag_Uint8[0] = 1; //当前EK为负数Temp[0] = (uint32)PID.KP_Uint8 * PID.Ek_Uint32[0]; // KP*EK0Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[1]; // KI*EK1Temp[2] = (uint32)PID.KD_Uint8 * PID.Ek_Uint32[2]; // KD*EK2}}/*以下部分代码是讲所有的正数项叠加,负数项叠加*/if(PID.EkFlag_Uint8[0]==0){PostSum += Temp[0]; //正数和}else{NegSum += Temp[0]; //负数和} // KP*EK0if(PID.EkFlag_Uint8[1]!=0){PostSum += Temp[1]; //正数和}else{NegSum += Temp[1]; //负数和} // - kI * EK1if(PID.EkFlag_Uint8[2]==0){PostSum += Temp[2]; //正数和}else{NegSum += Temp[2]; //负数和} // KD * EK2PostSum += (uint32)_Uint16; //if( PostSum > NegSum ) // 是否控制量为正数{Temp[0] = PostSum - NegSum;if( Temp[0] < (uint32)ADPool.Value_Uint16[UMAXADCH] )//小于限幅值则为计算值输出 {_Uint16 = (uint16)Temp[0];}else{_Uint16 = ADPool.Value_Uint16[UMAXADCH]; //否则为限幅值输出}}else //控制量输出为负数,则输出0{_Uint16 = 0;}}=============================================================================== //总体调节=比例系数×压力误差+积分系数×积分误差+微分系数×(本次误差-前次误差)//P就是比例,就是输入偏差乘以一个系数;//I就是积分,就是对输入偏差进行积分运算;//D就是微分,对输入偏差进行微分运算;PIDValueStr xdata PID;void PIDCalc(unsigned int idata data1,unsigned int idata data2,unsigned int idata minfreq){unsigned int idata svdata;unsigned int idata pvdata;unsigned long idata dError,Error;unsigned long idata ResultP,ResultI,ResultD,PIDout,Result;svdata=data1;pvdata=data2;if(svdata>pvdata){Error=svdata-pvdata;// 压力偏差PID.SumError+=Error;// 积分dError=PID.LError-PID.PError;// 当前微分PID.PError=PID.LError;PID.LError=Error;ResultP=PID.KP*Error*100;// 比例项ResultI=PID.KI*(PID.SumError);// 积分项ResultD=PID.KD*dError;// 微分项PIDout=ResultP+ResultI+ResultD;Result+=PIDout;if(PIDout>=5000){PIDout=5000;PID.SumError-=Error;}else{ PIDout=ResultP+ResultI+ResultD;}}if(svdata<pvdata){Error=svdata-pvdata;// 压力偏差PID.SumError+=Error;// 积分dError=PID.LError-PID.PError;// 当前微分PID.PError=PID.LError;PID.LError=Error;ResultP=PID.KP*Error*100;//比例项ResultI=PID.KI*(PID.SumError);// 积分项ResultD=PID.KD*dError;// 微分项PIDout=ResultP+ResultI+ResultD;Result+=PIDout;if (PIDout>=5000){PIDout=0;PID.SumError-=Error;}else{ PIDout=ResultP+ResultI+ResultD;}}if (PIDout<minfreq){PIDout=0;}=PIDout; }。