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

STM32电机PID速度控制

[复制链接]
STMCU-管管 发布时间:2020-9-16 10:22
2.3.1 解决的问题. U' x6 n4 l) v2 F- R

( C/ u% C0 f5 y
+ ^# O8 K( n5 G

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

5 q. y% {# A; [1 Q& P3 e* F8 j

2.3.2 PID理论
" G  l: T+ V. j8 }
, Y. R: b2 ~7 K. z7 m

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


6 Z( U. F" ]& ?& @# b$ n

& Z( x* Q' |7 r9 E# V; Z1 `

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

+ Q, G/ C( k  h/ E2 j, |0 ^$ l

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

" q7 ]- T* ~% @9 }5 d) I1 M, S

# [8 {& l3 `# {, f

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


- k' L0 D- Y% M" H

2 |% R4 c: B+ m3 R1 r3 G- b+ q

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

3 h, Y4 F5 ^& C; c1 G; Y


# h, m1 l% M- y4 q6 }7 e& J: L$ b

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


  u* r+ r* I* ~- r# f4 r5 Z. l( V7 x. M

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

/ R4 D6 _7 b) D* h


; `- H! @; I& U8 @: ~5 |& X  D2 b

! V: ^% ^+ e2 a( h, r; W% m( L

, c8 V) a5 b( s9 `; P
2.3.3 代码分享( a% s: k) H, T5 |

6 A# v! t4 ^* _* R3 f+ T

(1)pid.h

  1. #include "pid.h"
    , k. i& e/ M  Q1 E3 i" T8 i
  2. & Q6 P0 E4 W0 i
  3. " C2 k, j" y7 U" N) x- ~
  4. struct pid_uint pid_Task_Letf;
    % w/ O* H) |2 u$ _
  5. struct pid_uint pid_Task_Right;
    & ^/ n1 ^5 ?! {
  6. $ \; {  T, ~8 G1 u1 U5 G! W
  7. /****************************************************************************
    ) P; U  R. |% Q5 e7 y) \4 W: g
  8. *函数名称:PID_Init(void)% S4 X: v# I4 [' O5 `
  9. *函数功能:初始化PID结构体参数
    2 d' T! v, P, F
  10. ****************************************************************************/
    1 L6 L' ~& [3 A1 T

  11. ! b$ W) D9 e4 z7 K! B, X+ O4 ]
  12. void PID_Init(void)
    9 r6 X* L1 }4 d' x6 j; W
  13. {
    # L% p, i- h" A) [  ]) Y! Z: A  q' S
  14. //乘以1024原因避免出现浮点数运算,全部是整数运算,这样PID控制器运算速度会更快# S6 Q8 N2 m( C0 E
  15. /***********************左轮速度pid****************************/
    3 E! U4 _0 z! y1 g
  16.         pid_Task_Letf.Kp = 1024 * 0.5;//0.4
    * \! c' ?& O2 W  |% D" I
  17.          pid_Task_Letf.Ki = 1024 * 0;        
    , f) Y" U$ I8 {; X: C
  18.         pid_Task_Letf.Kd = 1024 * 0.08; 2 |% ~0 M( v5 G! S5 b9 T! {# k
  19.         pid_Task_Letf.Ur = 1024 * 4000;9 C+ O$ j9 e* T" p; h* I1 H
  20.         pid_Task_Letf.Adjust   = 0;4 X! R5 w9 ^0 R. K
  21.         pid_Task_Letf.En       = 1;
    2 N) X, a1 n* h9 n' Y2 v3 G8 F2 j. C
  22.         pid_Task_Letf.speedSet = 0;) r' A; Q5 y2 D" p( R
  23.         pid_Task_Letf.speedNow = 0;. s8 U; A  k# }3 J' Y
  24.         reset_Uk(&pid_Task_Letf);                , ?/ S% }/ J  `# k. L7 g, }
  25. /***********************右轮速度pid****************************/6 Z# w" h: m" q6 Q% u2 i& c7 \7 N
  26.         pid_Task_Right.Kp = 1024 * 0.35;//0.2
    % Z* H  ]. b9 T: C% P
  27.          pid_Task_Right.Ki = 1024 * 0;        //不使用积分
    ! }0 t4 v% @3 i& _. ?& ?) L
  28.         pid_Task_Right.Kd = 1024 * 0.06;
      Q3 ^1 K: C) T, a# }
  29.         pid_Task_Right.Ur = 1024 * 4000;8 ^$ w1 d2 v% d: Y
  30.         pid_Task_Right.Adjust   = 0;
    " `& K0 q* b3 M% Q* {/ A$ [+ T7 E
  31.         pid_Task_Right.En       = 1;
    3 |5 R# P# Q9 ?, v0 X/ o! o
  32.         pid_Task_Right.speedSet = 0;
    7 d6 e7 w5 R, x& W
  33.         pid_Task_Right.speedNow = 0;. R& a9 |4 {; i1 F$ E- u( V
  34.         reset_Uk(&pid_Task_Right);
    6 `, L% C; H: u* O/ r
  35. }
    ) Z+ h1 V8 a; Q+ P$ h/ r

  36. ( U$ L# [, o3 X' {9 }
  37. /***********************************************************************************************7 B1 Z. P# J7 D% r0 M: P
  38. 函 数 名:void reset_Uk(PID_Uint *p)
    ( [7 B. v/ ^: q" U
  39. 功    能:初始化U_kk,ekk,ekkk$ ^+ I8 t! q6 N: T5 Q5 R5 I
  40. 说    明:在初始化时调用,改变PID参数时有可能需要调用
    4 [: s0 B* j# C% D9 A" c4 d
  41. 入口参数:PID单元的参数结构体 地址
    5 B2 V3 R0 l( |$ A2 q1 U
  42. ************************************************************************************************/6 s( `3 r  e5 X1 z$ l& B% F
  43. ' D$ [2 l2 G% _# d- M8 A  u, V. i
  44. void reset_Uk(struct pid_uint *p)/ x4 @" R3 ~2 S9 n: ]' q
  45. {2 E4 S$ Y' L0 s6 ], q
  46.         p->U_kk=0;
    ) y. q* E+ M0 r2 u
  47.         p->ekk=0;$ E. \- j$ I) A1 @; n+ ^
  48.         p->ekkk=0;
    & I6 j* ~& @7 |
  49. }
    ) y0 L. Y$ E0 a5 p$ o8 G' J- g1 C
  50. * g4 [0 U: r% u# h' L
  51. /***********************************************************************************************  ~6 {" L* h" d- |) V! y& p& Z* r
  52. 函 数 名:s32 PID_commen(int set,int jiance,PID_Uint *p)$ i0 p0 w. b9 S
  53. 功    能:PID计算函数" w6 J1 f1 D2 v( ^( B
  54. 说    明:求任意单个PID的控制量
      [# r! Q. z- G' j" c% N1 |' o" p- q
  55. 入口参数:期望值,实测值,PID单元结构体
    " u2 J. _, D1 Z1 W. ]/ j" Q( r
  56. 返 回 值:PID控制量% e2 j2 _6 {# n9 R* V6 E
  57. ************************************************************************************************/
    ! ?# \% Q& }" U2 g( y/ E
  58.   h. u' e1 a/ H/ ?  ?
  59. s32 PID_common(int set,int jiance,struct pid_uint *p)
    $ r  U4 I3 u+ j1 Z
  60. {
    ) X, o9 g& z+ y7 l# j& [
  61.         int ek=0,U_k=0;: I0 t3 l" N+ K7 s/ T" B
  62. - B& U$ V0 |4 L. T. w7 z( o
  63.         ek=jiance - set;                                                               
    7 x" a5 c" y# {5 p8 m
  64.         
    ( `4 f7 t9 S, D: \: C
  65.         U_k=p->U_kk + p->Kp*(ek - p->ekk) + p->Ki*ek + p->Kd*(ek - 2*p->ekk + p->ekkk);+ d2 z- P" \9 r3 x9 V, @% @  c* I5 q
  66.         
    + R( K7 c2 v- m7 e. ^
  67.         p->U_kk=U_k;1 ~( e+ D% B& e3 R/ A
  68.     p->ekkk=p->ekk;
    2 \' Y4 ^5 j% i- D2 l) t# u
  69.         p->ekk=ek;- Y: l5 O& `" b
  70.         ! d, ?: g# J* m, S" L! C- P6 L  y
  71.         if(U_k>(p->Ur))                                                   
      Z# q+ R. H7 L6 W
  72.                 U_k=p->Ur;
    # z. j1 z* Q9 \7 t8 o& n& _' `
  73.         if(U_k<-(p->Ur))
    ! t3 K1 u- r6 e9 m) }
  74.                 U_k=-(p->Ur);3 K1 u$ T4 R1 F* n$ ^
  75.         1 L* R/ e; |/ F) A3 ~6 i
  76.         return U_k>>10;
      x' h! E+ I" i) x
  77. }# |9 s; p% m" S  n( O
  78. % o& X' t  d( K& r# b, t, ~$ C
  79. /***********************************************************************************
    9 K* H1 H+ R! O( Y4 R/ W
  80. ** 函数名称 :void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)
    - }/ @; m6 d' W0 z1 W) ?# |& o
  81. ** 函数功能 :pid选择函数              
    & E! [( W  \3 T4 ?# p9 Y. M1 [' e- T
  82. ***********************************************************************************/
    % j2 O$ [+ g2 a; U; ?
  83. / h! R% C* E/ K; o7 n
  84. void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)# P0 i6 N6 D. _7 o
  85. {6 b; E1 ?4 y# Y' z3 g8 I
  86.         /**********************左轮速度pid*************************/; e: J8 ~9 `: _) f8 T4 o
  87.         if(pl->En == 1)
    6 u) N% k1 H8 x5 x
  88.         {                                                                        : w/ e/ X! f0 G" A6 B$ V
  89.                 pl->Adjust = -PID_common(pl->speedSet, pl->speedNow, pl);               
    3 o  s6 a- a$ q" x' ]9 Q3 p% {
  90.         }        
    ! \6 J0 l5 T% T1 m; z0 Z1 Z
  91.         else
    8 j! l7 b1 g, L; l. s+ U
  92.         {. R, _1 O; j. p7 J+ E6 A9 ~  ?# S
  93.                 pl->Adjust = 0;
    4 h( s6 H6 ~, ^1 f8 [( y
  94.                 reset_Uk(pl);& l! y# h3 v1 Q# A
  95.                 pl->En = 2;
      y( D3 k% j0 K1 ?" Y
  96.         }
    ( K, ^, K8 m8 e
  97.         /***********************右轮速度pid*************************/
    8 Y' Q+ N4 O# W% N# H. _
  98.         if(pr->En == 1)
    5 u6 R; e  D- Q
  99.         {
    8 W; c# x* o( [4 I
  100.                 pr->Adjust = -PID_common(pr->speedSet, pr->speedNow, pr);               
    % Y' G/ _% o* I7 p9 z$ i' t
  101.         }        6 u! p  E* A% G& m! z
  102.         else
    6 v! j  o" `- S/ P
  103.         {# a+ K7 Y! d) T) |3 t4 b1 p
  104.                 pr->Adjust = 0;
    * G5 M. T8 L/ D5 z' h' p5 a1 ?
  105.                 reset_Uk(pr);
      K& j- u& W3 f$ d% Q
  106.                 pr->En = 2;
    / o* |: Q3 X1 \- b2 d
  107.         }, k( [* S2 D8 N0 I, J
  108. }% s* Y6 J& U0 w5 V& w
  109. . s1 f! f$ G5 V" i% j
  110. /*******************************************************************************, v* S$ a- v! W# {( u
  111. * 函数名:Pid_Ctrl(int *leftMotor,int  *rightMotor)2 ]* H0 M) R! Y2 m* [2 s
  112. * 描述  :Pid控制
    ( a0 v1 r4 w8 i6 s/ J$ N( Z9 X
  113. *******************************************************************************/1 n1 r! z: t7 Z! O- @
  114. ' P9 D$ ^" b4 H2 Y# \! H* q, t! w& s
  115. void Pid_Ctrl(int *leftMotor,int  *rightMotor)' i8 u7 e1 ~7 ?5 Q% h: V/ X1 {2 U
  116. {# V5 h+ M3 S. J8 b: U
  117.         Pid_Which(&pid_Task_Letf, &pid_Task_Right); / p6 A/ ]' V8 l. X3 d$ S0 Q
  118.         *leftMotor  += pid_Task_Letf.Adjust;
    1 y5 x: t( O) d* j
  119.         *rightMotor += pid_Task_Right.Adjust;: N, ?6 [- a+ }7 z
  120. }
    + ?+ |3 d$ t* B
复制代码
0 ?, E7 F, w+ c3 {1 R0 f: J
$ b' h9 k% R3 M% y: E# q

(2)main.c


0 d  q6 j  y& O3 w- d6 p( N

9 {- x. a) q0 e: f

  1. #include "sys.h"8 E1 Y5 c. _, c) r9 [3 V
  2. 6 I! f. U' z. K% l
  3. //====================自己加入的头文件===============================
    ) @" m4 V1 @, z. l: t& k* T8 [
  4. #include "delay.h"
    5 b. `1 c5 ~5 O5 y+ L. Z. ?) ?
  5. #include "led.h"
    ' C/ i$ S% A- d; E4 q1 |. Z
  6. #include "encoder.h"
    3 Z8 F) m' G3 r4 P0 w9 i9 X; x+ h
  7. #include "usart3.h"; H% @& c9 S: p0 f( y
  8. #include "timer.h"
    & Q3 e6 ?4 w$ u# v6 H3 K: W0 ^
  9. #include "pwm.h"7 Y, i! G0 [# C" e
  10. #include "pid.h"
    6 d% J6 L, I  ~) p/ ?
  11. #include "motor.h"0 o( ?; ~" f4 c
  12. #include <stdio.h>
    + N1 {- p5 D; t7 C+ l( J
  13. /*===================================================================
    % ~8 ~$ s/ B+ L& N1 @8 |
  14. 程序功能:直流减速电机的速度闭环控制测试' C+ m: u, T8 f! L( W; P2 N
  15. 程序编写:公众号:小白学移动机器人
    8 ~& t/ M6 S6 L2 L
  16. 其他    :如果对代码有任何疑问,可以私信小编,一定会回复的。+ U' x( P' n) v! S: `0 P  ]
  17. =====================================================================
    7 d; `- l% r! W* [4 P7 ~
  18. ------------------关注公众号,获得更多有趣的分享---------------------
    4 K' Q1 u( \9 A% g0 J% W& P
  19. ===================================================================*/
    4 V3 n; v8 n) d* C. z! L9 W6 Y
  20. int leftSpeedNow  =0;9 X8 d  Y) W' A+ b
  21. int rightSpeedNow =0;: i3 P- |5 G) Z5 C8 g& E

  22. 7 \5 g2 B5 |0 H) j
  23. int leftSpeeSet   = -300;//mm/s
    " V  C) u  A: J3 }
  24. int rightSpeedSet = -300;//mm/s
    & V* ~& a$ c) w! F8 Y
  25. & U/ R/ i( ?+ ^" }" i5 y& {
  26. int main(void)
    + ^- X) q) A7 E1 L
  27. { # {( v  L# \% V/ M

  28. 2 c% ?& Z, A' G& K1 k1 |
  29.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);' L4 f2 R) O, x4 x+ S9 G& q6 H
  30.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁用JTAG 启用 SWD8 {. x) F! w4 o# N. o8 Q) [
  31.           Z( E7 D; ^* b" w
  32.         MY_NVIC_PriorityGroupConfig(2);        //=====设置中断分组8 O+ V' B' x# e# ?% d- z1 O8 }
  33.         & C0 K' G2 _1 R7 Z# Y
  34.         delay_init();                            //=====延时函数初始化
    - w, }# x3 c4 y# f; j$ ]" l
  35.         LED_Init();                     //=====LED初始化    程序灯        
    5 N  p# B8 H3 U$ I: m2 D& A
  36.         % l$ S8 y" i; L9 g
  37.         usart3_init(9600);              //=====串口3初始化  蓝牙 发送调试信息
    & x( }7 h# N- r4 t9 w

  38. : r8 q4 k1 S! C! F1 x) O
  39.         Encoder_Init_TIM2();            //=====初始化编码器1接口, m) C( y1 `4 I8 Q& c4 h7 g- _
  40.         Encoder_Init_TIM4();            //=====初始化编码器2接口/ b6 k+ |1 W' a' l2 r: f
  41.         # }3 O) C* t5 k& x+ W  J  d2 a
  42.         Motor_Init(7199,0);             //=====初始化PWM 10KHZ,用于驱动电机 如需初始化驱动器接口
    - d$ j% S' x" \& K
  43.         
    / T6 n/ G7 l; @5 V0 v; K4 s; Z
  44.         TIM3_Int_Init(50-1,7200-1);     //=====定时器初始化 5ms一次中断4 T! X1 q: }- A; H5 E/ V/ z

  45. ; b6 w7 c' Z8 ]9 K. S6 z$ ]* t
  46.         PID_Init();                                                //=====PID参数初始化7 D# o! A( N8 E7 a( w, ?  m% M
  47.         
    5 a! P0 c' w) ?
  48.         while(1)7 o% D. ?4 D* c- z
  49.         {
    ! p& P0 p! B* x
  50.                 //给速度设定值和实时值赋值
    * d) h3 R: F, u9 {) |
  51.                 pid_Task_Letf.speedSet  = leftSpeeSet;
    : v  t- n9 X- R1 f, K  M9 G
  52.                 pid_Task_Right.speedSet = rightSpeedSet;! Y' E' B! c  S0 Q1 A
  53.                 pid_Task_Letf.speedNow  = leftSpeedNow;
    1 |: Y0 I% k5 V5 y8 |( W. f; x
  54.                 pid_Task_Right.speedNow = rightSpeedNow;
    # U8 D+ L6 R/ m) C- i9 T" W
  55.                 : D* Y/ f0 B0 Y) t: A7 b: i
  56.                 //执行PID控制函数. s% d6 q% V2 k  p
  57.                 Pid_Ctrl(&motorLeft,&motorRight);
    + S6 B/ l6 s4 r7 q1 O# s
  58.                
    4 K. {" @3 U( F) c
  59.                 //根据PID计算的PWM数据进行设置PWM8 S8 u' H3 ?6 m0 i$ G
  60.                 Set_Pwm(motorLeft,motorRight);! x! o7 \: v6 h3 }* N9 C
  61.                
    ' m+ m, d4 p  r( i. e& F! s7 K
  62.                 //打印速度- F* ~- ^4 l* o5 ], n3 x
  63.                 printf("%d,%d\r\n",leftSpeedNow,rightSpeedNow);4 i0 I, k! O1 f7 ]4 Z! q' r/ c
  64.         }
    % Z. H5 f4 J' A+ h4 M. p
  65. }/ g/ ~8 F$ S# ~
  66. ( j6 b) F0 X! g/ C
  67. //5ms 定时器中断服务函数4 T( T( r  h: C1 y: n

  68. . O# F7 ]& o# S0 o1 h
  69. void TIM3_IRQHandler(void)                            //TIM3中断6 @/ s) E/ ~! p: z
  70. {
    2 {  d% o6 v" G+ @' b# D5 V
  71.         if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否
    ' O5 ]4 ^9 [6 ~0 }- b; ?/ E5 e
  72.         {! u$ Z$ F5 F- r8 s% K: h3 Y
  73.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);   //清除TIMx的中断待处理位. H, `, h$ F- L# D0 a9 d# N& |  |1 R
  74.                
    : w3 k* h5 X0 N/ {2 [
  75.                 Get_Motor_Speed(&leftSpeedNow,&rightSpeedNow);//计算电机速度
    % v* ~. p; K) A, n6 n: E
  76.                
    " m9 w& J2 R/ {6 \- Q; d6 O8 Z& t9 `
  77.                 Led_Flash(100);                               //程序闪烁灯
    " K) Q. Z( K: P: C0 ~* Q9 p% [
  78.         }; l2 t) X) K$ Z9 B3 ]4 f5 v6 ]
  79. }
复制代码
7 j/ f& m9 ^/ E5 N
: X7 g6 J2 K) S3 V1 S1 o5 x2 t
2.3.4 总结
+ Z+ r) w6 C$ N) B, k
1 X. Z  C! w7 j: ^) W, g% S  V+ I

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


$ M$ O" b! H4 \" {/ ?: n/ K9 P7 j4 y6 ~! z9 O: W2 v8 d, H& d  }

3 D7 @! B8 k& l! ~" F& G* Q" [: V$ d. B4 i# G$ k* h+ X, R
收藏 评论0 发布时间:2020-9-16 10:22

举报

0个回答

所属标签

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