本帖最后由 nyszx 于 2017-12-26 19:31 编辑
" r* g3 l# ?" F' c% Q
' n6 j# o+ F: d/ u! L8 L原帖:【分享】增量式PID的stm32实现,整定过程
0 h0 ]! e u! G$ z, \原文网址:http://www.amobbs.com/thread-5575823-1-1.html
( r" }8 C h" H6 v+ m出处:阿莫电子论坛
( S& c6 _$ @: `作者:tim4146
, i& R3 K9 `4 t感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。
8 c" e# Y* u! Q' A也下面我分享一下近期的这些工作吧。欢迎大家批评指点~ : v( V. g8 p- N- R! E- l9 D, @7 e# V
5 a7 M; O+ y8 r$ E& f首先说说增量式PID的公式,这个关系到MCU算法公式的书写,实际上两个公式的写法是同一个公式变换来得,不同的是系数的差异。9 Z0 A# d" N7 i9 l
资料上比较多的是:/ O' |. F& x4 o: M# U0 c
1 l7 _$ P! I5 V. a% K还有一种是:
+ o6 T3 u; X, F
! w r3 s' e. [感觉第二种的Kp Ki Kd比较清楚,更好理解,下面介绍的就以第二种来吧。(比例、积分、微分三个环节的作用这里就详细展开,百度会有很多)4 i$ S& g1 v. ~) x3 a
. A; ?. X- W1 p5 @
硬件部分:7 m( o9 L& ?* H+ Y
控制系统的控制对象是4个空心杯直流电机,电机带光电编码器,可以反馈转速大小的波形。电机驱动模块是普通的L298N模块。
& O K, H. ^' l1 l芯片型号,STM32F103ZET6
z d6 r: w- Q4 n; U- w
; h: J1 C" `% s- Z* g软件部分:
0 N: W) w3 a! l8 G% E0 hPWM输出:TIM3,可以直接输出4路不通占空比的PWM波
6 ]' j& @. P% p7 R F& [. tPWM捕获:STM32除了TIM6 TIM7其余的都有捕获功能,使用TIM1 TIM2 TIM4 TIM5四个定时器捕获四个反馈信号4 y' i) D; H2 e2 r% I5 q/ _
PID的采样和处理:使用了基本定时器TIM6,溢出时间就是我的采样周期,理论上T越小效果会越好,这里我取20ms,依据控制对象吧,如果控制水温什么的采样周期会是几秒几分钟什么的。/ ]2 m" G) A: E/ R7 m. \% D- W
6 J7 y8 _( m/ I5 \上面的PWM输出和捕获关于定时器的设置都有例程,我这里是这样的:5 s N( G7 N9 H5 I2 R$ P% W# [# S
TIM3输出四路PWM,在引脚 C 的 GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9输出$ @& D$ S, `- G% {! K+ F A
四路捕获分别是TIM4 TIM1 TIM2 TIM5 ,对应引脚是: PB7 PE11 PB3 PA1
; {5 ` o: C; H7 T9 `高级定时器tim1的初始化略不同,它的中断”名称“和通用定时器不同,见代码:
6 [7 ]3 O- \) q- /*功能名称IM3_PWM_Init(u16 arr,u16 psc)
, @! c: I7 J/ ~9 z: T1 X' y - 描述 TIM3产生四路PWM/ ~* e* c0 ~8 H% m/ F1 z
- */6 ?& _: J, Y6 I& B, T* J
- void TIM3_PWM_Init(u16 arr,u16 psc)* B$ P+ ^ ~ D- ?/ a
- {
' `+ e% ?& |8 W( T - GPIO_InitTypeDef GPIO_InitStructure;1 j' {1 a/ O+ F! o+ a+ G( a
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;" Y" H" ^" f+ u% Y1 e* d# o
- TIM_OCInitTypeDef TIM_OCInitStructure;
/ b. Z2 s" s( ] - . K- U! _9 w$ F8 T& y2 y" P4 Y
- 1 k$ h' y7 _, H& j3 m
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);5 Z' S3 p u+ T6 r6 G9 p7 M
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟使能
* S( Y4 ^: S* k% P
# f3 n6 x4 i6 ~% D( x# z! Y- GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3全映射 GPIOC-> 6,7,8,9 //用于TIM3的CH2输出的PWM通过该LED显示
1 h2 ]6 B* C9 `8 o- V: P
2 Y. j0 q' j; L& q2 K- //设置该引脚为复用输出功能,输出TIM3 CH1 CH2 CH3 CH4 的PWM脉冲波形/ I, {; {3 f h5 r. [$ m
- GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; //初始化GPIO8 f1 Y# W% n/ S) T
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出# R5 {' N& r: A
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;: V/ v7 ?2 X; Q! d1 b3 ^5 p
- GPIO_Init(GPIOC, &GPIO_InitStructure);
1 g6 a( ^8 A+ N6 ^8 K2 S6 n C1 U; q" [ - GPIO_ResetBits(GPIOC,GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);//默认电机使能端状态:不使能
% @. G! P, S5 B2 h! g - / B/ f U+ F* r. C6 A0 u
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值4 h! K: t+ M9 h% h2 w- G2 X
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 这里是72分频,那么时钟频率就是1M
, V: [3 U/ T( a - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim$ R5 J) D) o/ v2 B" E
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
' f3 L7 g% |7 ?& q. ^/ i9 r - TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
# w: M9 v6 y! \4 d! r" H
) C. Y% K/ s) C% V3 _
9 F$ P- i! { B9 m2 V2 L% g: _& ]- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
8 v8 C, }5 q. k - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能- O* l6 x/ f$ R
- TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值6 X4 N) V% \3 N# y0 e
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高1 ^ j' b0 S3 g, s: M
- & H: O0 k1 R8 ^' j. l
- TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
& L4 N8 R2 e' }' r3 X - TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR1上的预装载寄存器
' m8 b s8 @0 H - 0 r7 N" Y" `* L* j& \ Y# _
- 0 n+ g( A2 U3 v. p( L f
- TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx- k5 s; }- \/ S: t/ ]- y, C0 {
- TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR2上的预装载寄存器, W( m* q" Z8 j1 j% u; W1 i
- 2 G& E/ o$ ?: U; z: r& b
- TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx/ D# N( S0 l9 d+ y
- TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR3上的预装载寄存器1 x# e+ g, f( `% @; Z$ ]- L
- $ H* ?3 e* N. f: |9 _- r
- TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
5 A: N+ Q/ a6 `3 B) X - TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIMx在CCR4上的预装载寄存器) y* C/ H7 I& g
* j y& F. C1 O- TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器
3 B6 _% [2 l7 }; K) Z/ O
# A( s; E4 O" u/ {2 i! z' i* @' G- . K5 c$ S) R+ O+ H
- TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
, O# S( S |" L" S* H
( v" I: m: G1 _ u
+ ^; [: P( x1 o8 [9 T- }$ [) b0 a/ }& f: W; Q, r0 I
* j: R6 q; a% `- f- & M3 k0 ?: B; n" [
- $ f6 s+ E( {4 r; q% n9 w
- /*功能名称TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
, z) Z6 O8 c, _, O - 描述 PWM输入初始化*/
( d1 X! ]# O. a% l
5 n, S4 R h+ [0 m: ?- void TIM4_PWMINPUT_INIT(u16 arr,u16 psc)
9 B( Q* H. m3 n s* n' m. s - {
4 E1 `! t" L- I- z9 v - 8 X5 m" Y/ c `( l: ~
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM的初始化结构体
# s' Z* I& d2 F: N* d* Z - NVIC_InitTypeDef NVIC_InitStructure; //中断配置
$ A% D' F* l" {- B - TIM_ICInitTypeDef TIM4_ICInitStructure; //TIM4 PWM配置结构体
" L$ @$ n# {* ~5 q - GPIO_InitTypeDef GPIO_InitStructure; //IO口配置结构体- a% a+ ^7 b2 [& S
& ]8 y: {8 @, m5 V% Y5 s$ U- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //Open TIM4 clock
3 ^4 d! y- s0 h8 s1 @* X% w8 L- ~ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //open gpioB clock
" o; g0 a8 ?% f - . O2 V; \6 J% E; U3 W2 y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //GPIO 7, v- E U0 K3 M2 ^- J
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
( k6 b0 O8 u8 C5 j - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;" e$ O6 w3 j7 @
- GPIO_Init(GPIOB, &GPIO_InitStructure);- _- z6 I, h) t) n/ K
- 5 s* i3 y3 s2 |1 K% S
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值7 \' \4 p2 Y7 l, [
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
) n4 W( C1 `# b" Y% h - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
; {5 v9 D: S3 d5 L$ n$ J1 d* \8 V - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
) D! x2 n, g% \# |, C! {' i - TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位+ t+ \# `% `2 @! T# ~
& l% A( Q, i) f# X5 B2 y+ c% j) V- : y& d" K: e( F3 Z, V; B |
- /*配置中断优先级*/. E" ?* r( h+ m, c$ j
- NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;7 ?) ^7 O) v/ N7 W0 M
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;# A( [% i( n" v5 c- @, G+ W+ p6 U j1 K
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
8 w( j! \* s$ e# f) Q) d. e - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;5 v9 b5 d( R' d; C( }
- NVIC_Init(&NVIC_InitStructure);; a, E J: A O3 y
- ( w9 s. d+ _6 O" m$ W+ E
- TIM4_ICInitStructure.TIM_Channel = TIM_Channel_2;5 z4 I. u& R1 Z- m3 H4 t
- TIM4_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;' Z/ n8 z2 Q/ ~% m, U! r
- TIM4_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
( C# s9 F- F+ s$ B! o - TIM4_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;# R9 v. L2 [. B. \' m6 K7 z
- TIM4_ICInitStructure.TIM_ICFilter = 0x3; //Filter:过滤
% I0 \0 U5 u$ O$ B - * M3 d) [4 O' P8 U- Z
- TIM_PWMIConfig(TIM4, &TIM4_ICInitStructure); //PWM输入配置
) P* h& k) `, `" ^% ^ - TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2); //选择有效输入端# l( [ y; k$ t2 @6 Y; C
- TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset); //配置为主从复位模式
9 G+ I# I* ?! S0 g `0 v% D - TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
: z# V/ |0 L9 N% G6 X - TIM_ITConfig(TIM4, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置
0 P, M# A4 K6 h7 B - TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
/ d. D$ v+ t" ^% e( x* a8 t - TIM_Cmd(TIM4, ENABLE);7 n4 R' m+ L/ O; B$ V! v
- }$ ~( y9 t- b; n! k* q+ Y! K
, g$ _0 v' ?/ J6 X- 0 G4 x4 R; o: l4 q# f* t
- void TIM4_IRQHandler(void)
+ r1 N& M4 f P3 ~' t$ f - {4 R6 c3 Q" r( y+ M, @: h
- t$ m7 s4 ~* [' q- if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获1发生捕获事件6 G1 V) F# B0 n
- {5 y. j o' p, z# X
- duty_TIM4 = TIM_GetCapture1(TIM4); //采集占空比
' y* b# |8 W4 S* K - if (TIM_GetCapture2(TIM4)>600) period_TIM4 = TIM_GetCapture2(TIM4);//简单的处理
* s: ]4 b( B7 d. A - CollectFlag_TIM4 = 0;
e, W0 ^) ~$ {( r1 L- b5 i8 b$ ? d/ @ - }, \' m) U Q( k8 P
- TIM_ClearITPendingBit(TIM4, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
, p! w# z$ f. o9 Q! N8 a2 }1 [$ ^5 V9 y - }+ e% H! j5 t- K. \1 E
# `( C1 L: `! [$ c4 |- ) ^5 F2 v* j0 Y2 N
- /*功能名称TIM1_PWMINPUT_INIT(u16 arr,u16 psc)) Q8 u3 z( @3 X2 s" `
- 描述 PWM输入初始化*/
1 G6 Y% w0 V: [& t - : ]0 @# D' V4 g1 D
- void TIM1_PWMINPUT_INIT(u16 arr,u16 psc)( q0 ]. P: Z& }* y" k) W- i" { D
- {# V, G6 J' K6 Q' E5 a
5 F& b7 U" f$ Q/ l4 F- g" t, _- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM的初始化结构体8 f) u- M. a& W4 q- ^4 ~$ d8 u
- NVIC_InitTypeDef NVIC_InitStructure; //中断配置 u3 b6 |' S8 E
- TIM_ICInitTypeDef TIM1_ICInitStructure; //PWM配置结构体+ n4 G7 P, i; `$ v$ `& `
- GPIO_InitTypeDef GPIO_InitStructure; //IO口配置结构体6 H- M9 p9 n' G; R: m
- 0 I1 s) Y/ ~; h' j' B
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //Open TIM1 clock
/ e& Y/ p% W! ^. j - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //open gpioE clock k N* F! e Q6 T" V" v+ A
- GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); //Timer1完全重映射 TIM1_CH2->PE11" j: G O4 |8 ?: |# e) @6 I# @
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //GPIO 11! @7 d8 f, ^3 h6 J% y
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入: \1 x) B, [( [3 U+ ?' r+ c
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) o* v- ]# y+ J4 B
- GPIO_Init(GPIOE, &GPIO_InitStructure);
7 v% o1 o, E9 f% ? - + T4 N) H/ j: P/ D+ v, x: r
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值0 M+ u% U" c* F) U& C% h
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
) g+ ^$ t$ K0 f: ^5 @7 W* Z& f - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
- E- J$ k" p D" ^) L; z& [ - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式" c% o6 O# P8 d$ g( e* L0 q
- TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位+ C" l+ h+ d) K$ ^" ^5 X
; v6 j* u! E5 \: Q- 5 D. j" @; a+ a4 I6 L
- /*配置中断优先级*/9 M7 e- }& L$ e+ W
- NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; //TIM1捕获中断2 c: {. k1 [, j) b+ i. L
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/ x4 p! z$ {5 Y
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;. A$ I* e2 O; }8 C, c) R
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
$ A$ J A3 N# F% _& ^ - NVIC_Init(&NVIC_InitStructure);
- x* i+ W) F+ X# O2 R - ) p5 {" o( Q( v" V2 V3 q
- TIM1_ICInitStructure.TIM_Channel = TIM_Channel_2;& m1 n3 [' @8 H v. N
- TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;5 \1 V5 [9 _$ a9 @3 P
- TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;- r* r# {) c+ j3 N7 d+ |7 N" q
- TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;; s7 w5 m# L% m1 H R
- TIM1_ICInitStructure.TIM_ICFilter = 0x03; //Filter:过滤
: X$ m5 n: `* M4 V. X
5 i# t+ [. e6 V, @- TIM_PWMIConfig(TIM1, &TIM1_ICInitStructure); //PWM输入配置0 O+ I, e* s" Y2 ?1 c' ]# Z, S/ F+ d
- TIM_SelectInputTrigger(TIM1, TIM_TS_TI2FP2); //选择有效输入端) y1 e1 e2 s9 z& J4 r5 [1 C
- TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset); //配置为主从复位模式
* x# G; C# |: Y7 _, s - TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发! }: e) ~1 b- \0 h. ~7 P- y8 C
- // TIM_ITConfig(TIM1, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置; |1 v; O) F9 k. I1 D. P7 j
- TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); //通道2 捕获中断打开
! s$ L; q9 P( y& [* a7 k' X3 j - //TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位4 |1 k! H: N& X% E; m# O
- TIM_Cmd(TIM1, ENABLE);
+ ^4 i2 @- S8 z% ^! ~+ c1 r2 u - }
, h% d8 i# X3 r( U/ m7 B - / Y0 p1 }2 V) g
0 m/ }7 Y4 e& q3 C, p0 ?- void TIM1_CC_IRQHandler(void)$ R6 {9 Z. ^0 p) z4 i# ]7 P l
- {4 x: s& D) O% H; q, Y, Q& ~! O
: o( d K- m3 x# _5 J" o: s% l8 L9 |- {" G; |, f& ~6 {2 m
- if (TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
* P" [; p5 D# e# x. B, g - {3 s5 o0 J1 X5 N3 I; |
- duty_TIM1 = TIM_GetCapture1(TIM1); //采集占空比
7 b; z% o7 `/ S/ k! |. {7 Y. k$ e l - if (TIM_GetCapture2(TIM1)>600) period_TIM1 = TIM_GetCapture2(TIM1);" y7 s' t% x: b Q! ?5 _$ y) C+ h& D
- CollectFlag_TIM1 = 0;
) h3 p) v* ?' h' O# N3 d - }7 \! x$ T% m' A- u7 ?: D& a
- }) ~* y- X: G2 e8 ?3 C
- TIM_ClearITPendingBit(TIM1, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位- M& M! {" Z) D4 c+ p. m' u( e
- }
1 }* ~; o4 s e4 y& x
@, X' Y5 Z2 k S4 @
0 ^8 b+ \4 |4 m0 G, @- /*功能名称TIM2_PWMINPUT_INIT(u16 arr,u16 psc)' k* T) e5 ~4 x
- 描述 PWM输入初始化*// `5 a) ]; C7 x2 |, [5 Z+ b8 U
- / H: z4 U; P1 X" W V3 b1 m
- void TIM2_PWMINPUT_INIT(u16 arr,u16 psc)
7 d6 \& @6 Y( G+ W - {% ]/ O7 z! W" a& \, J- t
6 R5 p/ ?* e; A# ?- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM的初始化结构体) x" H6 o8 u3 C* A( M
- NVIC_InitTypeDef NVIC_InitStructure; //中断配置9 q3 R5 h- V4 |- F) \
- TIM_ICInitTypeDef TIM2_ICInitStructure; //TIM2 PWM配置结构体8 I& R& h! \ r. i, e( H$ K
- GPIO_InitTypeDef GPIO_InitStructure; //IO口配置结构体
& k, Y% X& Q: }2 ? - ( D9 q. J0 S) B# c9 t8 d4 ^$ y
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Open TIM2 clock4 ?( r$ t/ z" r8 h
- // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //open gpioB clock8 h2 Z1 v4 X' `6 K$ w+ Z0 X
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟% F% @3 y( g. u4 {/ H1 `) V
- GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG
3 S( k! \ A2 c4 @$ g7 E - GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); //Timer2完全重映射 TIM2_CH2->PB3
* |* R8 v4 m3 f, z1 W - , }% c4 c/ [. e
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIO 3
6 `6 h; j- L6 ~. H% H$ Y4 Q N- I0 ` - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //浮空输入 上拉输入& R+ ?/ q) S; v8 |5 y
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;5 J+ ] M9 P7 h! P
- GPIO_Init(GPIOB, &GPIO_InitStructure);' F. }: B9 n3 b( s; w- v. l
- % u1 L9 _4 n- }& f2 `- Q
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
+ j2 }* ^& r, l2 f w9 P' P - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
: e. o' f( k; c7 u: b% ] - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
( \, t1 u" e" s p: D - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式; Y6 Y& Y ^5 ^
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位- w/ k- \% N4 S! h @( o/ c
- " b, z. F& N* ?/ G6 o$ E; u8 e( q
: l- X3 Y: A/ w$ \. x( G' f. M- [! P- /*配置中断优先级*/1 U0 V* p( b( u/ v7 `
- NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;: x B' a) m" i k* g
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
; d1 c m) O0 I) ~ - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
6 T1 Y, g% M; g9 ~9 z - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
% v" h0 ?/ s( k - NVIC_Init(&NVIC_InitStructure);2 v* I6 J7 t$ V% @/ h7 R3 i
% A! w& [4 P, A; P) n' l0 ?- TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2;
" y1 z8 O% o# e# ]) l% X - TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
! h; E9 h" @5 p9 Q2 d - TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;+ X* n# r6 T N3 I W6 E' n+ a
- TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
" U1 p% N( u9 M - TIM2_ICInitStructure.TIM_ICFilter = 0x3; //Filter:过滤! Z' P. h8 L. X! `1 p7 J* }
- 6 t7 Z- M" W, {0 C# N+ L4 B2 E3 x
- TIM_PWMIConfig(TIM2, &TIM2_ICInitStructure); //PWM输入配置3 {* ? ]: E; f% b% D
- TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //选择有效输入端4 T- b9 C" w# z( p
- TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset); //配置为主从复位模式, _+ `0 P6 C+ j) Y
- TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
1 p; v: d8 s& T% X p8 V - TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置
8 U4 T! \+ `) g' G. c1 V0 }( }2 k - TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位# w% o9 a5 I5 ^! W e: B
- TIM_Cmd(TIM2, ENABLE);& \0 ]$ `! t$ v7 Q3 o" t: V, N+ c& F3 C
- }
, g( B/ f' D4 p- G6 c5 P/ _0 P2 v( ?
. H. t3 c# G- u* N0 d* b$ B( ^! F
5 A. ?# P) r7 z0 X$ c" i- void TIM2_IRQHandler(void)
# B3 M8 \. [# Y - {, e# V* E+ E* o: l& D4 `! S
- {
5 y5 _* G- [; Y; [3 w9 T - if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
& t& s1 x. ?6 k - {, m7 }3 D" u5 S5 }; f
- duty_TIM2 = TIM_GetCapture1(TIM2); //采集占空比+ m6 f0 Y& K v& F8 s1 _- e
- if (TIM_GetCapture2(TIM2)>600) period_TIM2 = TIM_GetCapture2(TIM2);
) }9 w. r! \: y z' V* Y - CollectFlag_TIM2 = 0;/ I8 c3 X' P/ Z) l" _2 p6 q
- }
, j5 F( O3 W9 i; K1 J4 ] - }2 U; V0 G* W7 U6 ]
- TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
# G0 `+ l! Y% f6 M2 q3 V - }7 e7 g Z/ R. m
- " \$ U+ L i. R. F/ s3 B' ?
- /*功能名称TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
( P3 T: Z! P% q+ n - 描述 PWM输入初始化*/
, ?& a" U7 I# i9 Z1 C$ s+ N9 `
6 P- _9 {3 ^# `4 k+ t u- void TIM5_PWMINPUT_INIT(u16 arr,u16 psc)
0 x$ B7 F k0 E4 S6 Y2 R5 H - {+ q. k3 C* n7 J$ D# Z% {
- 0 _. `% f# ?$ y: I
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //TIM的初始化结构体; n- |/ y B3 D
- NVIC_InitTypeDef NVIC_InitStructure; //中断配置/ j# ~* b# r1 B% t* T- a6 J& {3 B" Z
- TIM_ICInitTypeDef TIM5_ICInitStructure; //TIM4 PWM配置结构体
" D+ x' D8 [6 e. K" q - GPIO_InitTypeDef GPIO_InitStructure; //IO口配置结构体" w5 H( W2 k5 s& W8 g' _
- . r. ~+ V9 k( \# t% d4 T
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //Open TIM4 clock) a8 G6 S I5 R9 \* ]
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //open gpioB clock* ^: O# U3 U1 f- f) v" A; c# @* X
* W4 `' N7 U' D) q+ B- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //GPIO 1
6 P: f+ a' N+ E( r# p - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //浮空输入 上拉输入' Y' c/ W0 C4 i# J. E y
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;& C9 @( x G' P6 ]6 v3 b
- GPIO_Init(GPIOA, &GPIO_InitStructure);6 o* s& \3 n$ n; [2 Z J+ w- a. r
- 0 ?0 O$ Q1 A4 F3 x. v8 T9 A
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
! ]* |% i/ E& j* G& B" | p - TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
# e/ R8 F, E- D" @& \7 g - TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
# Y/ V' M& t0 ^& D3 J1 ? - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
' }! d/ ^' ]: n5 M7 U - TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位/ s& Y R" i4 D d. p
F3 z+ r+ q$ [5 U& f
9 \, p% N) o8 R7 [) W' k- /*配置中断优先级*/* [# @/ O% e' D3 v+ [: ]1 h
- NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
& k$ i/ ~9 `3 G( g& x - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/ } I: O" S: f" F! g6 _) G - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;* Z4 C. I5 q- A' r) ^
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 \0 u. t/ U9 \
- NVIC_Init(&NVIC_InitStructure); v# m! D! d. O+ s, d1 B( w
/ q4 |! y: B/ s" U o C- TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
% W: Z6 L, ?# |3 u9 L - TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;4 F ~& b; E# ^( `3 g
- TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;9 M; z: z" ~* O
- TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
* o5 Q, _! Y+ K) z* |; Q; Z1 k - TIM5_ICInitStructure.TIM_ICFilter = 0x3; //Filter:过滤! e: m0 s0 ]5 }! J: O5 r0 n( B
- , W+ }) Y4 @4 B/ t
- TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure); //PWM输入配置
9 T P8 s! O+ N0 } - TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2); //选择有效输入端( o0 I4 ]$ J# n9 U% q0 j8 R$ E
- TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset); //配置为主从复位模式
5 q7 L! Z6 N+ o - TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发8 Y2 |5 \% E; C" y
- TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE); //中断配置
4 n& A3 q Y# s$ D - TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位: U3 r. U! k- _! F) i* D$ i, r
- TIM_Cmd(TIM5, ENABLE);& [7 E' b5 A8 @8 O
- }
# O' g/ |, ^! Z; _
+ J3 [- g2 X) S' q" ]- ]- ; v. x3 I) M8 T# s" ] R" v
- void TIM5_IRQHandler(void)% ^+ L2 h1 X7 n& v/ b G
- {/ f' t% C+ k# n
- {3 D& R5 ~; m2 ~
- if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件: l, |8 {7 s6 t
- {+ R" L4 K$ ~% [9 X# z1 U' Z
- duty_TIM5 = TIM_GetCapture1(TIM5); //采集占空比4 a4 i6 @$ A# N$ G0 Q: S. y
- if (TIM_GetCapture2(TIM5)>600) period_TIM5 = TIM_GetCapture2(TIM5);
3 v& k' S1 i7 X& |" D - CollectFlag_TIM5 = 0;
8 `. y; s' V c7 C" A- S- { - }% U& h/ T5 b& V
- }( @0 }# k7 I: |7 Q; R
- TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位, u" S+ m8 e' @' ~
- }
复制代码 : O% H0 {( Q7 u4 D* ~6 V
( C9 h: z/ ^, Z, f0 b! D
PID部分:3 |4 _5 H6 |* f" F5 \: P7 O2 w
准备部分:先定义PID结构体:* j& R% _/ w- J
0 s8 F! v( i- t7 Q5 d- typedef struct! w; c* f6 V5 h+ e+ o: x
- {$ ~1 P1 @& R6 T& i$ |5 Q- q
- int setpoint;//设定目标
! B/ I5 A! K3 `, }% R+ I - int sum_error;//误差累计
5 ~; K+ [" ? o - float proportion ;//比例常数
, P* f* U; u! I7 ~3 \' L - float integral ;//积分常数
; K; X$ j. E+ T3 T( t1 c: j - float derivative;//微分常数% j- M D/ p( e O8 S9 C
- int last_error;//e[-1]
2 ~3 f" |- b4 b7 T! \ - int prev_error;//e[-2]+ L* q( k0 u* d2 G
- }PIDtypedef;
复制代码 0 `0 J4 I# R& W4 w( k! p
# M0 Y3 Q- I; x) Y8 g6 }2 |! w) g- f% \# H- V) I( G0 l
这里注意一下成员的数据类型,依据实际需要来定的。
; N' z2 ?( ~4 n: i1 ~在文件中定义几个关键变量:
. p) M/ U: ?# b2 h/ J5 ~$ J- float Kp = 0.32 ; //比例常数
& Y5 a3 I& E7 e/ K2 ?. n* ^ - float Ti = 0.09 ; //积分时间常数
1 S3 }# v& |: E6 I - float Td = 0.0028 ; //微分时间常数$ c5 Y2 k A0 R& J* ^9 H) C3 ]
- #define T 0.02 //采样周期
, T& |# F/ D2 X; {" w' z - #define Ki Kp*(T/Ti) // Kp Ki Kd 三个主要参数1 x; b, C* F* [, h" U- R
- #define Kd Kp*(Td/T)
复制代码
! e! C9 B5 b* p- Y* b+ p& @: {( F8 ~- V, _1 P
C语言好像用#define 什么什么对程序不太好,各位帮忙写个优化办法看看呢? 用const?
' j& Q+ E# m9 O6 U4 U' q3 Z) N3 u F% u6 D8 Z
PID.H里面主要的几个函数:
% Q0 r; ?' `6 T( M4 u- void PIDperiodinit(u16 arr,u16 psc); //PID 采样定时器设定
+ a7 R9 J* r; V7 O! n. P/ K- J/ L - void incPIDinit(void); //初始化,参数清零清零
" q- m6 j0 H( _. t4 j - int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint); //PID计算3 Y8 @- W6 Q5 ]4 X+ P! g
- void PID_setpoint(PIDtypedef*PIDx,u16 setvalue); //设定 PID预期值0 b0 _* {7 ]( U, {* g- @2 G9 n
- void PID_set(float pp,float ii,float dd);//设定PID kp ki kd三个参数
. i6 L1 t# }* d% F! c$ ]1 R - void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码
0 W8 ~- n4 R; K. D7 u
! }/ X) l1 Z0 @0 R( ~PID处理过程:
! _ E0 u$ z- s/ X& ?岔开一下:这里我控制的是电机的转速w,实际上电机的反馈波形的频率f、电机转速w、控制信号PWM的占空比a三者是大致线性的正比的关系,这里强调这个的目的是
# ?4 r9 ^8 C# R" v* k+ D! W因为楼主在前期一直搞不懂我控制的转速怎么和TIM4输出的PWM的占空比联系起来,后来想清楚里面的联系之后通过公式把各个系数算出来了。
; a, M% \/ C& G7 k8 z( }* e( c
3 z4 ?7 x2 g' n8 Q正题:控制流程是这样的,首先我设定我需要的车速(对应四个轮子的转速),然后PID就是开始响应了,它先采样电机转速,得到偏差值E,带入PID计算公式,得到调整量也就是最终更改了PWM的占空比,不断调节,直到转速在稳态的一个小范围上下浮动。
: w4 T2 \8 j, b9 k上面讲到的“得到调整量”就是增量PID的公式:$ D# G9 x# N. S5 g# `
- int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
6 e& h1 V r7 [( X9 @4 g% P - {
/ M A6 @: @1 e" ] - int iError,iincpid;7 } r8 d7 `6 H
- iError=PIDx->setpoint-nextpoint; //当前误差
% p. @/ T1 H' n& q - /*iincpid= //增量计算' H; ?7 s% o0 s/ j$ K1 C
- PIDx->proportion*iError //e[k]项
4 P# Q7 s6 N0 z7 k. n9 K+ m; i- s - -PIDx->integral*PIDx->last_error //e[k-1]4 q* W; l4 Z/ q( M% a( S" p
- +PIDx->derivative*PIDx->prev_error;//e[k-2]
w! ]( \1 u+ G% h; _% K* @7 c - */
) }% B7 r0 P! X6 k7 d8 u - iincpid= //增量计算
9 z9 |! Y7 d# J0 E r% w. { - PIDx->proportion*(iError-PIDx->last_error)
! Q% D6 e4 Q6 L) N - +PIDx->integral*iError
2 W8 B e+ P# c- I7 I" O - +PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
! m- _( J( g& C7 {! d+ i - / @3 U5 e4 _- e
- PIDx->prev_error=PIDx->last_error; //存储误差,便于下次计算
! x$ P, s+ `% o# {' t - PIDx->last_error=iError;
2 ?( B/ X( ?4 v- U0 N - return(iincpid) ;7 }3 S f, y* J( _" s3 |( Q
- }
7 f: F* i+ ~* L1 A
M. T# q( c- M' v' M
3 y# Y, \4 b* S! z$ [3 K- 复制代码
* i1 J& b( W( [ - # e8 l6 @ _; z; C
- 注释掉的是第一种写法,没注释的是第二种以Kp KI kd为系数的写法,实际结果是一样的。
; V5 x0 g- s3 V! E1 M, z6 w6 A - 处理过程放在了TIM6,溢出周期时间就是是PID里面采样周期(区分于反馈信号的采样,反馈信号采样是1M的频率)7 |9 v+ `" V5 Y- k! \" E8 J
- 相关代码:
- G9 X& I: b$ P% d# w# i# m
/ V, w) V+ H$ J5 ]$ r
# G7 c/ r& [, k* ~; q& d- void TIM6_IRQHandler(void) // 采样时间到,中断处理函数
1 l. T, g t2 H( u$ m' ^& s - {( `. P8 Z- p. C1 X
6 q% R* h( w# H- if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中断
; [ a* j$ F# S- T4 m$ J# e$ H9 ]4 W - {
2 h/ @4 J3 c: Z - frequency1=1000000/period_TIM4 ; //通过捕获的波形的周期算出频率 R a% t1 W" B: V" A+ u, u
- frequency2=1000000/period_TIM1 ;
# ~5 t2 W4 [6 g, b! o# G7 S - frequency3=1000000/period_TIM2 ;
9 U- U, B9 E8 W5 C - frequency4=1000000/period_TIM5 ;, x; t+ C+ L* i9 |: g
- /********PID1处理**********/
8 f; m' b2 A8 f3 O - PID1.sum_error+=(incPIDcalc(&PID1,frequency1)); //计算增量并累加. N7 V/ u0 r, [7 h
- pwm1=PID1.sum_error*4.6875 ; //pwm1 代表将要输出PWM的占空比1 {2 F. A3 V- }) _) `4 |
- frequency1=0; //清零0 R4 X8 `, s2 {. M" V6 P
- period_TIM4=0;
- o0 p( `& S. j5 l - /********PID2处理**********/; z0 [% g/ m$ r: x
- PID2.sum_error+=(incPIDcalc(&PID2,frequency2)); //计算增量并累加 Y=Y+Y'0 ^9 q2 ]! N' N# m4 u4 V' z0 i) N
- pwm2=PID2.sum_error*4.6875 ; //将要输出PWM的占空比* a* E( {+ I7 s& c6 V' ^/ ~
- frequency2=0;
C. Y+ Q3 q4 v9 H8 g - period_TIM1=0;
$ A: l( o2 P& L2 {$ C h, K - /********PID3处理**********/2 r1 c2 {9 B! q" S/ t: h6 {
- PID3.sum_error+=(incPIDcalc(&PID3,frequency3)); //常规PID控制
+ f( S k3 ^; |" O! J - pwm3=PID3.sum_error*4.6875 ; //将要输出PWM的占空比
5 D+ s% o6 ~ o8 K4 h - frequency3=0;) M3 i: s9 V8 K6 K) l
- period_TIM2=0;5 v5 X( H1 a' B
- /********PID4处理**********/3 U4 W, z8 B; H7 T- o' _: x
- PID4.sum_error+=(incPIDcalc(&PID4,frequency4)); //计算增量并累加; |, n4 C, |% O( ~
- pwm4=PID4.sum_error*4.6875 ; //将要输出PWM的占空比1 F' y' ~+ P, \
- frequency4=0;
. L2 S+ A$ b/ z, i" J0 K# \3 ^9 B - period_TIM5=0;
! ^) ]5 p8 Q3 d& X( w# {7 k& L - }
5 E, t4 r" A* O0 @9 H3 g. G - TIM_SetCompare(pwm1,pwm2,pwm3,pwm4); //重新设定PWM值
1 h; h% H, D% P' h - TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
/ S; g; N' c$ p/ H/ _ - }
复制代码
1 d8 R( r" _& j# _+ G# s+ {9 \0 i6 B7 k! [+ Y
上面几个代码是PID实现的关键部分
7 U7 i; ]% x- B, Q# m6 r
- t6 E/ u1 [: @+ |整定过程:" x9 L6 h7 h% ]) ?7 g
办法有不少,这里用的是先KP,再TI,再TD,在微调。其他的办法特别是有个尼古拉斯法我发现不适合我这个控制对象。6 w5 B. K5 H0 r+ n$ U7 T
先Kp,就是消除积分和微分部分的影响,这里我纠结过到底是让Ti 等于一个很大的值让Ki=Kp*(T/Ti)里面的KI接近零,还是直接定义KI=0,TI=0.
f. C# q! \8 x) D6 a& g然后发现前者没法找到KP使系统震荡的临界值,第二个办法可以得到预期的效果:即KP大了会产生震荡,小了会让系统稳定下来,当然这个时候是有稳态误差的。
; r, O) A% o6 b随后把积分部分加进去,KI=Kp*(T/Ti)这个公式用起来,并且不断调节TI 。TI太大系统稳定时间比较长。# g& ~/ X& Y Y1 |' R9 _
然后加上Kd =Kp*(Td/T),对于系统响应比较滞后的情况效果好像好一些,我这里的电机反映挺快的,所以Td值很小。' I8 h7 x; r* D( ~
最后就是几个参数调节一下,让波形好看一点。这里的波形实际反映的是采集回来的转速值,用STM32的DAC功能输出和转速对应的电压,用示波器采集的。
( p1 F: T* p u( N% e最后的波形是这样的:: Z/ [2 J0 r5 }' g
/ n/ T g: g7 u; T最后欢迎大家拍砖,有批评才会让我更加进步!8 t7 t7 p7 x, p& v6 I' k
最后把PID文件放上来
pid.zip
(2.88 KB, 下载次数: 134)
|
$ K' u" E4 i, p' U- \4 T
这是个好东西
书到用时方恨少
果断收藏