你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32电机PID速度控制

[复制链接]
STMCU-管管 发布时间:2020-9-16 10:22
2.3.1 解决的问题
2 a) ]5 r; M' E9 _4 `
! P- g* L& U4 W0 R& \0 ?' V; ?% P, z# \

解决带编码器直流电机的速度闭环问题。


5 J" b# m7 m/ Y1 o& ?5 k

2.3.2 PID理论
, A3 J  G, `0 W+ n0 T6 Z( g. \( R# j' Y2 V4 B

将偏差的比例、积分、微分,通过线性组合构成控制量,用控制量对被控对象进行控制,这样的控制器称为PID控制器。在连续空间中,我们通常探讨模拟PID的控制原理,如图所示:

0 h; ^- K+ ^) x9 V7 r0 M8 I

$ I" {. F& A4 [% o7 h

我们这里用电机速度控制为例,讲解PID控制系统。r(t)为设定电机速度、y(t)为实际电机速度、e(t)=y(t)-r(t)为速度差值作为PID控制器的输入、u(t)为PID控制器的输出,作用到被控对象电机上。根据模拟PID控制器,科学家们也得出了模拟PID控制的公式,如图所示:


7 H9 Q. T# C0 G6 v2 S

其中Kp、Ti、Td,分别为控制器的比例系数、积分系数、微分系数。该理论用在控制的例子比比皆是。但是模拟PID控制系统是在连续空间的上描述的,无法在计算机上用代码实现。于是就有数字PID控制理论,将连续空间的PID控制系统在离散空间上描述。积分变成了求和、微分变成了求斜率,于是就出现数字PID控制系统的理论公式,如图所示:


8 V0 G1 B- X) d! k4 i


* q+ c0 u$ G( G6 v9 m8 f: E( \

其中Kp、Ti、Td和上面描述的一样,T为采用周期,ek是本次差值,ek-1上一次的差值,直接通过模拟PID转化的数字PID又叫做位置式PID,该方式的PID的输出直接是控制量,非常不适合经常出现异常的系统,另外一种方式是增量式PID,每次只输出一个正向或者反向的调节量,就算出现异常,也不会产生巨大的影响。具体数学公式如下所示:该方法较多的应用于生产生活中,本论文中电机的速度PID控制当然也不例外。


/ g. u6 ^2 I- L) }3 b0 u; ~% U5 E' k

( e2 F5 p+ `+ a2 j+ o$ l* f% @

有了上面的理论基础,开始代码实现的介绍。首先就是明确增量式PID系统的输入、输出、控制对象。将速度的设定值和速度的测得值作为PID控制器的输入参数,PID的输出参数为对PWM的调节偏差,控制对象PWM进而驱动电机达到设定速度。以上内容确定之后,就是PID控制器的代码部分了。其实仔细看看增量式PID就只有一个公式,所以使用代码实现并不困难。如下所示核心代码就这一句。

  d; M5 n9 ^: J- N( }& J+ G  C9 Q


$ q6 e" W4 i8 q4 y) ~* z4 z; k$ }3 |

完成上面的代码,只是完成速度PID的一部分,剩下的是尤为重要的PID参数整定。该整定方法丰富多样,最为准确的是模型计算,但是对于我们做机器人多使用试凑法。虽然需要调节一段时间,但是不需要对机器人进行建模。试凑法一般按照P、I、D的顺序进行调节。


  h! W7 q! b* j

初始时刻将Ki和Kd都设置成0,按照经验设置Kp的初始值,就这样将系统投入运行,由小到大调节Kp。求得满意的曲线之后,若要引入积分作用,将Kp设置成之前的5/6,然后Ki由小到大开始调节。达到满意效果之后,若要引入微分作用,将Kd按照经验调节即可。经过有规律的试凑,最终达到一个我们满意的就行。

6 c9 N' m, g3 S# v! X6 S2 `

% ^- c& U: ~, L  U# g" Q


+ [& r5 G$ u. ~* R* d! f

8 }9 W( o3 @) P
2.3.3 代码分享$ W: o, R/ _$ ~) t/ E* L. e
& N2 ~& l) [8 a, V+ g

(1)pid.h

  1. #include "pid.h", e: z+ ~5 T8 _& T8 @& y: z. O8 R

  2. $ x: a( Z1 B2 t& j) A! v7 q
  3. 1 Y1 B  A' J! L) d1 n3 x0 o
  4. struct pid_uint pid_Task_Letf;
    5 W( M% E7 B8 u! h3 G( a
  5. struct pid_uint pid_Task_Right;! o7 w# q" }8 a

  6. : W" X; I3 O' O+ ?# F
  7. /****************************************************************************
    & f% q. B7 u1 d, F; p
  8. *函数名称:PID_Init(void)' f2 s' u1 G: `  i$ g3 j; k/ e
  9. *函数功能:初始化PID结构体参数
    7 U/ z. u$ c7 O1 i# I
  10. ****************************************************************************/+ b/ _3 Z1 w. B2 h* C' M

  11.   u: j4 `7 c. F! J; ?
  12. void PID_Init(void)
    * ?$ [) e+ l& u2 l' q, b
  13. {
    8 a. n, \6 ]. A5 Y* |
  14. //乘以1024原因避免出现浮点数运算,全部是整数运算,这样PID控制器运算速度会更快
    $ H& [, j$ y& Z1 D7 \
  15. /***********************左轮速度pid****************************/
    4 e9 M/ B& i  ~( u+ V
  16.         pid_Task_Letf.Kp = 1024 * 0.5;//0.4
    # N5 _, D( g; e! `# U3 _
  17.          pid_Task_Letf.Ki = 1024 * 0;        5 g8 A- u5 t. n" k: a* b* l/ r# B2 g1 \
  18.         pid_Task_Letf.Kd = 1024 * 0.08;
    : H( V+ v9 |. f* x( k0 v0 s
  19.         pid_Task_Letf.Ur = 1024 * 4000;0 c4 G# g. O, p  L* D, N  u; ~
  20.         pid_Task_Letf.Adjust   = 0;
    - `" W! H6 ]1 [4 u, D
  21.         pid_Task_Letf.En       = 1;3 \3 @. C0 F+ a1 y
  22.         pid_Task_Letf.speedSet = 0;' J  o  j6 I7 A% r
  23.         pid_Task_Letf.speedNow = 0;# @' J8 z8 H: k0 M
  24.         reset_Uk(&pid_Task_Letf);               
    4 R4 y/ Z! q) e
  25. /***********************右轮速度pid****************************// x' t8 n6 M2 ^0 u1 }" m% m5 G$ U
  26.         pid_Task_Right.Kp = 1024 * 0.35;//0.24 r) C: H3 K+ O; H& K- ~
  27.          pid_Task_Right.Ki = 1024 * 0;        //不使用积分3 `( b, g9 W2 ~6 t! A7 x
  28.         pid_Task_Right.Kd = 1024 * 0.06;
    0 V2 M  d% D8 e
  29.         pid_Task_Right.Ur = 1024 * 4000;( b& G+ W* w9 @. G
  30.         pid_Task_Right.Adjust   = 0;5 v. ?* B- O7 X+ D% k; z; V
  31.         pid_Task_Right.En       = 1;# Z% T' N7 Z1 |1 L$ c. [
  32.         pid_Task_Right.speedSet = 0;
    . b4 V7 K% l* g3 O; O7 y! M2 _
  33.         pid_Task_Right.speedNow = 0;  j3 L% L8 C4 i7 i4 n
  34.         reset_Uk(&pid_Task_Right);4 S( x8 G1 ~/ h- H' Y3 L& f$ U
  35. }
    - p- \& E: y, z0 c0 N

  36. 2 q. m# i8 I; A- l
  37. /***********************************************************************************************' F8 w9 A5 p  J% M+ G
  38. 函 数 名:void reset_Uk(PID_Uint *p)
    * ~; o. [! d: b" c( r) ?
  39. 功    能:初始化U_kk,ekk,ekkk) Q, O( g0 o7 f! H- d2 r7 K
  40. 说    明:在初始化时调用,改变PID参数时有可能需要调用1 I1 w4 J6 u1 x0 c
  41. 入口参数:PID单元的参数结构体 地址
    % U8 Y2 U( w5 b" u- S
  42. ************************************************************************************************/( m1 A3 a  F" f4 w) [* ~( o

  43. 8 W$ ^/ R/ k# H) }# M$ M- V* p
  44. void reset_Uk(struct pid_uint *p). \* s$ \  ]0 T6 Z( c! ^3 H
  45. {
    - `5 \, N* |! `$ |# Z4 Y+ h
  46.         p->U_kk=0;+ c0 y8 Y$ H- z) e
  47.         p->ekk=0;$ K8 k& O/ z$ w9 {
  48.         p->ekkk=0;
    7 M8 j5 ^2 v0 W5 n$ d$ U
  49. }& X$ V2 F1 g) F6 z6 O
  50. " U: P7 E" I, E( A- _
  51. /***********************************************************************************************" N- @# E- r/ w" R
  52. 函 数 名:s32 PID_commen(int set,int jiance,PID_Uint *p)8 Z+ K7 N& H- e$ P" u4 M6 x& i
  53. 功    能:PID计算函数" S3 B) J6 O3 s3 l, f) G5 |$ o: l0 H
  54. 说    明:求任意单个PID的控制量5 Q8 H0 X. L. y; K  Z
  55. 入口参数:期望值,实测值,PID单元结构体7 \4 ~7 T1 J, Y$ {5 B' }
  56. 返 回 值:PID控制量# g2 Y$ g$ G; _% \
  57. ************************************************************************************************/) i5 C4 n/ ?7 F  _, d8 N' ?" }8 D

  58. 8 X. Y# D% x. k) N/ `
  59. s32 PID_common(int set,int jiance,struct pid_uint *p)* o7 u1 N, A$ x
  60. {
    0 Z- M4 K& s. ?1 @1 g
  61.         int ek=0,U_k=0;
    + M0 s) ]. {/ ~. D5 q

  62. / W% b: F% U+ o( ?$ I
  63.         ek=jiance - set;                                                               4 d/ a  c' x7 V& t- e8 U0 j' r+ d1 I2 i
  64.         , `5 x) P( ^: `
  65.         U_k=p->U_kk + p->Kp*(ek - p->ekk) + p->Ki*ek + p->Kd*(ek - 2*p->ekk + p->ekkk);
    " J, x0 @0 x, ^  _; H. }& e  y, Z
  66.         
    2 a% W: e7 x8 \6 G9 F5 p) p
  67.         p->U_kk=U_k;7 K- b  [. Y! v7 y6 f9 B
  68.     p->ekkk=p->ekk;4 ~1 Z9 J$ Z9 [* I5 c
  69.         p->ekk=ek;
    - [3 M9 O, ]% d/ O& s! V
  70.         / }0 [0 `" \2 @9 A8 o
  71.         if(U_k>(p->Ur))                                                   
    9 D4 a8 u/ Q( v8 g0 B' r: j$ `/ D
  72.                 U_k=p->Ur;) m2 W$ O, l6 F7 A0 F7 Z1 c6 E0 |9 ^5 T
  73.         if(U_k<-(p->Ur))
    4 x# [& H$ }* _4 `/ M
  74.                 U_k=-(p->Ur);
    $ }% Y" Z: N: ]6 w
  75.         0 @; |: Z7 t; f/ a7 {6 w% g# J; [, [; U
  76.         return U_k>>10;
    * }& A3 o/ W4 g; l# ^( d
  77. }
    8 {+ l8 z" m7 _% H2 d; R
  78. 8 h. j$ h! G, D  E( r" v
  79. /***********************************************************************************
    % P- a, |3 b& N, I& I+ _3 }
  80. ** 函数名称 :void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)
    ( l& e0 o9 g1 o$ p, ^2 n6 ~: {2 u! u
  81. ** 函数功能 :pid选择函数              
      o' I) i9 r* e7 h( G; q( n
  82. ***********************************************************************************/8 V7 W# w( ]. ~# {1 C
  83. : U$ }: c: Q( U+ C" W
  84. void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)
    / s* W6 p0 C, y4 ?+ g5 x
  85. {
    * S5 k4 \- ^  B% ~, R' ]8 V
  86.         /**********************左轮速度pid*************************/
    3 o7 L! a# U; f! O; |
  87.         if(pl->En == 1)
    ; A. r- [8 P1 g+ ^5 n" u
  88.         {                                                                        
    . @7 k, G3 m4 V8 r! J
  89.                 pl->Adjust = -PID_common(pl->speedSet, pl->speedNow, pl);                8 }3 o/ ^" ^  G# t( A
  90.         }        6 P8 F1 d- ?1 M' O! `
  91.         else
      w" l+ U) W& u* }, M
  92.         {* ]& i# q+ j- h  g- h
  93.                 pl->Adjust = 0;
    / R. ?; E5 P4 l$ w' F
  94.                 reset_Uk(pl);2 x$ |. h9 `% n  d
  95.                 pl->En = 2;
    0 [& d6 S8 s6 R2 a3 `
  96.         }: `% ^1 c2 W6 D. S2 e
  97.         /***********************右轮速度pid*************************/* d- j" Z  Q8 x1 o% Y
  98.         if(pr->En == 1)* ]5 y* m0 _3 }6 V( j. F
  99.         {! q& \3 s$ \. e( \! R
  100.                 pr->Adjust = -PID_common(pr->speedSet, pr->speedNow, pr);                ' k2 P8 v) I0 S5 Z0 v" g
  101.         }        
    $ B5 Y' O  e9 b* o: `
  102.         else# f5 ?! ]! A$ E  f( g6 }3 ~
  103.         {% a3 q) y# ^% S1 m% Z
  104.                 pr->Adjust = 0;: J# r: V( f; ], H; D& z7 c
  105.                 reset_Uk(pr);
    . Q% v/ r% a, @
  106.                 pr->En = 2;
    9 _# q$ W% q9 X
  107.         }4 P! d- i4 c" u6 m  c+ @
  108. }
    , d3 l. D% s6 K% {
  109. * H' D/ B  E+ f' s5 D+ @/ |7 ~; D
  110. /*******************************************************************************
    % v* J5 i3 z2 R- [
  111. * 函数名:Pid_Ctrl(int *leftMotor,int  *rightMotor)  ^( k$ D0 u* J
  112. * 描述  :Pid控制
    . Y1 w7 b6 `: K2 A$ o3 A# o% i8 E
  113. *******************************************************************************/
    " n6 l5 \9 T+ q& a% Y) {* a  E! `8 @
  114. & }( f$ g& t% ^2 K' @' D
  115. void Pid_Ctrl(int *leftMotor,int  *rightMotor)$ s3 ~- y" {: W. P
  116. {. W$ P! z' q9 a3 u8 Z
  117.         Pid_Which(&pid_Task_Letf, &pid_Task_Right);
    0 x  Q5 e' S" g" |- z! q+ r
  118.         *leftMotor  += pid_Task_Letf.Adjust;% |) p' m9 r3 y, ~" j5 q
  119.         *rightMotor += pid_Task_Right.Adjust;
    : v6 ~4 a: u1 b; v& `! w7 Y! m
  120. }! V, i  l% c1 t/ r  C/ t+ ~8 u
复制代码
2 T6 H. L1 x% F4 O, z
, ]0 A0 b7 J; ?, V# |. j

(2)main.c


3 _* u- M5 O' i  j


5 y9 x6 c, \& m" }# M" X

  1. #include "sys.h"0 l/ ~" p9 ~3 g
  2. . R' D, D! l. ^- {8 ^; ^
  3. //====================自己加入的头文件===============================
    - R8 M# Q8 P/ X/ O# H4 R" F
  4. #include "delay.h"
    / K0 M# {8 S5 S5 @4 l1 O- f, Y
  5. #include "led.h"2 o2 S% m& T' P2 D. F
  6. #include "encoder.h". E$ j& d0 D2 u
  7. #include "usart3.h"( `3 R  T2 j$ J# }5 w
  8. #include "timer.h"
    * ]; b3 I* [, Q& K0 }' H6 j1 k1 M: b( S
  9. #include "pwm.h"
    3 g9 _$ @5 Y9 r( X  P# W1 j; W
  10. #include "pid.h"
    ; q6 ?% B3 ?3 c; H- g3 c' V3 |
  11. #include "motor.h"- w2 x. q/ \+ G/ I3 I* F" ?
  12. #include <stdio.h>
    ( {( A, \" Q% ^% a# @4 J5 z- F
  13. /*===================================================================; S* V- m$ _' e4 F
  14. 程序功能:直流减速电机的速度闭环控制测试
    & q4 I7 K- J) N+ O2 G
  15. 程序编写:公众号:小白学移动机器人
    $ j5 O4 _+ `. s& q6 S4 S
  16. 其他    :如果对代码有任何疑问,可以私信小编,一定会回复的。
    ( r) C. d. M2 p& B. y+ m! P
  17. =====================================================================  a7 W% S: W/ \8 y
  18. ------------------关注公众号,获得更多有趣的分享---------------------
    5 d4 b' Y; l: W2 o( B4 z* F
  19. ===================================================================*/
    ( p1 {$ p" a" l3 Z
  20. int leftSpeedNow  =0;. c9 N7 O- p: M- z' p1 I
  21. int rightSpeedNow =0;4 }5 ~3 T' ], w/ G- d' z  o, X) c
  22. ; r( S+ Q5 `' x; L) ^- i0 Z# z7 T
  23. int leftSpeeSet   = -300;//mm/s; T% N1 S+ K3 |0 y
  24. int rightSpeedSet = -300;//mm/s. s; s3 J+ F( k8 H+ s

  25. " @9 b' {/ R7 p9 f* @4 u
  26. int main(void)
      S0 L7 ?" i0 P, N7 o
  27. {
    & w8 H9 U$ \+ j

  28. 1 S+ R) \. c4 H3 {$ V0 D
  29.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
    8 g- c+ j2 E# v) A' a8 t4 A* P
  30.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁用JTAG 启用 SWD
    8 b% F, Q7 i+ C4 {
  31.         
    4 ~1 A; [+ p. f
  32.         MY_NVIC_PriorityGroupConfig(2);        //=====设置中断分组0 U0 p5 b% f% ?/ ~9 R- O$ x( Z
  33.         + @9 C" w9 z+ L  ]
  34.         delay_init();                            //=====延时函数初始化9 x+ ^2 b1 L7 M# @6 j7 i4 w
  35.         LED_Init();                     //=====LED初始化    程序灯        / h! f2 h7 j0 W2 q1 X% |! _
  36.         * m( Y0 I0 |6 E" I9 A: x5 ~  |
  37.         usart3_init(9600);              //=====串口3初始化  蓝牙 发送调试信息  p6 K- D- R5 e6 T+ A

  38. ' w& |  {- T: b. ^8 Y' m
  39.         Encoder_Init_TIM2();            //=====初始化编码器1接口0 F) K1 ~# U: K; ?/ m# ?9 R
  40.         Encoder_Init_TIM4();            //=====初始化编码器2接口
    : k  Y4 ]2 m3 b, V
  41.         
    2 v* Q( o3 [5 _( e4 \
  42.         Motor_Init(7199,0);             //=====初始化PWM 10KHZ,用于驱动电机 如需初始化驱动器接口9 E2 D' t  B0 c& q9 S9 j$ n
  43.         * c: T3 b. R+ s" S5 o& S
  44.         TIM3_Int_Init(50-1,7200-1);     //=====定时器初始化 5ms一次中断
    . H$ E1 e* t. l

  45. + I+ R4 \5 B/ i, u) t* x  D# i
  46.         PID_Init();                                                //=====PID参数初始化, ]4 B8 b/ _2 r  W# d$ C% ^
  47.         
    - }% \% |9 S1 V9 S5 m) c
  48.         while(1)
    , n  t) w0 [5 ?* S$ t  M6 [
  49.         {
    5 Z/ G4 w1 v+ q0 s
  50.                 //给速度设定值和实时值赋值
    ; M2 G- x  e( F' W7 I& H" ~( y4 o  z
  51.                 pid_Task_Letf.speedSet  = leftSpeeSet;
    , D. t0 d6 W( t2 G
  52.                 pid_Task_Right.speedSet = rightSpeedSet;! k$ U- ~6 E; S: w' u* L: [7 K4 l
  53.                 pid_Task_Letf.speedNow  = leftSpeedNow;
      \. S2 [. Z( ]. {+ d" t4 U
  54.                 pid_Task_Right.speedNow = rightSpeedNow;
    ! S: `/ S* i) \
  55.                
    0 f# H2 |1 `- d7 n
  56.                 //执行PID控制函数, O+ k! r! G7 Q, J' n; w; C
  57.                 Pid_Ctrl(&motorLeft,&motorRight);
    " P, ~4 D6 ^" J: c+ H7 T
  58.                
    . e9 [1 j& ]% m$ u: j
  59.                 //根据PID计算的PWM数据进行设置PWM
      P- M. @' g) T& J# H
  60.                 Set_Pwm(motorLeft,motorRight);. L* y  I! {) ]: g
  61.                 ' u, ]! ~' y0 t
  62.                 //打印速度: X! ?4 M5 t8 A3 n8 W
  63.                 printf("%d,%d\r\n",leftSpeedNow,rightSpeedNow);
    . k! x# L& r) g- g
  64.         }
    - q9 Y  y, Y- C
  65. }9 {( J# b4 d  l6 a- j( i$ Z. \0 Z/ X+ n

  66. # M5 |* c0 h6 a3 J2 V/ f
  67. //5ms 定时器中断服务函数8 f. b0 n) Q/ O6 t% J4 e9 d
  68. + }3 U; r4 B3 X$ f
  69. void TIM3_IRQHandler(void)                            //TIM3中断" R) f  Z- O) b' T
  70. {( w; z5 @" W( j
  71.         if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否
    7 S0 H/ p" Y+ k* `3 V$ a
  72.         {
    9 S( x+ X( ?) K: g9 v* g
  73.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);   //清除TIMx的中断待处理位
    2 y8 n; v  e0 O! D
  74.                 3 |( e* J8 u7 n) R- D6 W
  75.                 Get_Motor_Speed(&leftSpeedNow,&rightSpeedNow);//计算电机速度7 b: s2 Q7 X6 X
  76.                 & J" |0 e' [/ Y: z& N8 Z2 @/ t2 f
  77.                 Led_Flash(100);                               //程序闪烁灯
    1 Z  t- o9 B3 t6 e- G1 G
  78.         }) ~, H* t- C) H( p  L, n2 L
  79. }
复制代码

; {  R; f  V) {0 j' [& X3 q: [) f/ K0 z- \+ f  Z, s. c; i# N3 h' K6 \
2.3.4 总结
: Z& u5 V$ O; d/ g" h$ j2 R

8 O% H5 @: r1 n

以上三篇内容,是关于直流减速电机的PWM控制、速度测量以及最后电机速度的闭环控制。现在对于电机的简单控制基本告一段落,对于做一个ROS小车的电机控制,这里基本是足够的。下面我们会介绍使用IIC+DMP获取MPU6050数据。


: b- k: |6 Y% i' h: ^( s% ~
  r& Y1 m8 k, N5 p1 r5 s6 ?' r# j% w& v, @1 P- H

$ \8 A1 n, @( P3 f& Q
赞 收藏 评论0 发布时间:2020-9-16 10:22

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版