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

STM32电机PID速度控制

[复制链接]
STMCU-管管 发布时间:2020-9-16 10:22
2.3.1 解决的问题
* Y; x+ ]0 ?% {/ e
# ]& w8 _7 e) a+ e/ M& i5 S# J: \
# T8 w, i5 u$ K

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

. K/ |# x  S2 m8 T5 ~% F  ~

2.3.2 PID理论
6 h- s" P. _+ D' v* i7 H% s0 c/ l2 @2 q% a# [: h

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

# |' D( P7 w. N( e' f  [( y. m. h" f


3 s3 [+ z) J0 t

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


) j, x# L# J9 Y5 ?6 I2 ~) Y

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


/ E% L* u) I  d


* Y5 q: q; L' d- s% g0 g

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

1 i* q' f/ E$ N


  }/ q, u& x; }6 s! c

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


6 H: T$ W/ C3 ~; z

1 f  p9 N8 d: k8 U

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


1 [% Q1 ]0 j" ?! k' U7 H  F% G% `

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


3 Y4 N  t  v1 ]2 x


# x( X8 w& v7 L

: M& l0 s- u9 r7 c% U

0 n" v9 c8 D% x* N$ D9 p% a' s
2.3.3 代码分享6 X4 z0 z: s' `- p+ c% P9 h; Q

1 r) c& X. d: ^( u

(1)pid.h

  1. #include "pid.h"$ g5 \7 J- Q  G3 `8 D* B4 H# q
  2. 6 F  {* ?. j4 W* w" P* `

  3. ' A  i3 T7 [# W. s, a1 R
  4. struct pid_uint pid_Task_Letf;* h2 f" W3 I4 r3 q  ]& R
  5. struct pid_uint pid_Task_Right;
    ! `8 x; x# w- _7 J* j; u
  6. 0 s8 X, ~* Z9 Z5 C# P* r3 @
  7. /***************************************************************************** J/ O: b" y& S' R7 F/ H
  8. *函数名称:PID_Init(void)7 ]1 J' M6 u; N/ h$ z+ ~# n0 s' n# t
  9. *函数功能:初始化PID结构体参数7 J3 ]0 q7 ?& ]3 ^$ b" W
  10. ****************************************************************************/% L& u% w7 [3 j! h/ e$ h8 I- h% V
  11. 6 V  j" K+ ]% a; J( Y0 O  Q
  12. void PID_Init(void). L3 g5 l$ F: r6 L0 O4 [+ v
  13. {
    6 A9 O: z3 Y& I, h+ P, p
  14. //乘以1024原因避免出现浮点数运算,全部是整数运算,这样PID控制器运算速度会更快; I% t( Q. h. M* [. |  N5 Q; k/ _
  15. /***********************左轮速度pid****************************/5 a7 C+ R) |' {* N, J) @
  16.         pid_Task_Letf.Kp = 1024 * 0.5;//0.4
    ; {  V4 k% `: w( a2 W' ^9 w1 n1 x0 _
  17.          pid_Task_Letf.Ki = 1024 * 0;        
    , L/ B. D6 b0 P* \" W9 ?  e+ I
  18.         pid_Task_Letf.Kd = 1024 * 0.08; . p) l1 C( g$ Y  O! k, X
  19.         pid_Task_Letf.Ur = 1024 * 4000;
      a" k8 D  U% Y1 X6 N! S' s; v
  20.         pid_Task_Letf.Adjust   = 0;
    ; m; s2 O4 w# H; X& d
  21.         pid_Task_Letf.En       = 1;; b+ q  |! n) h8 N# i! ^
  22.         pid_Task_Letf.speedSet = 0;( V1 N- k1 \0 [5 A0 X( i
  23.         pid_Task_Letf.speedNow = 0;# o' N( i( N6 e) A( |5 E
  24.         reset_Uk(&pid_Task_Letf);               
    $ R) n0 s' [9 ^
  25. /***********************右轮速度pid****************************/
    : n3 G3 v* k% p$ P
  26.         pid_Task_Right.Kp = 1024 * 0.35;//0.25 V% i6 O& N6 L) P
  27.          pid_Task_Right.Ki = 1024 * 0;        //不使用积分
    " J* ?$ L0 w  N# u1 ^1 G  V( {  c
  28.         pid_Task_Right.Kd = 1024 * 0.06; 6 P6 t6 p; G# F9 x4 t1 R6 T
  29.         pid_Task_Right.Ur = 1024 * 4000;( p2 |' f5 s' y0 Y. ]' |
  30.         pid_Task_Right.Adjust   = 0;
    % [- L" U9 ^. Z1 B9 W0 P& \
  31.         pid_Task_Right.En       = 1;
    ) s% S( v4 s, u( }. D1 V) \; k. m
  32.         pid_Task_Right.speedSet = 0;
    " C) ~; R  w5 T( ~. l8 L
  33.         pid_Task_Right.speedNow = 0;
    & k0 Y& H8 i  U" y( R) b' w
  34.         reset_Uk(&pid_Task_Right);4 I1 |: B% s7 Z* {
  35. }
    + A% c6 n, ^, Q  a$ t

  36. 6 {: y8 `5 C7 H) H
  37. /***********************************************************************************************' l5 ?+ }6 D9 K9 `; C
  38. 函 数 名:void reset_Uk(PID_Uint *p)# r3 \4 g" I; B: G2 K
  39. 功    能:初始化U_kk,ekk,ekkk/ e) D5 @$ [* K! \
  40. 说    明:在初始化时调用,改变PID参数时有可能需要调用
    * M% m) K4 V" L# C% `7 w0 l
  41. 入口参数:PID单元的参数结构体 地址# A2 P; m1 u( N: g
  42. ************************************************************************************************/
    * ^4 x6 w2 v4 v. ^9 \

  43. % M' y/ w# I& x! q* M! u/ v1 t; i
  44. void reset_Uk(struct pid_uint *p), A" Y3 x" H- i( i1 p; o/ U
  45. {' m9 A8 I0 s. D% T- o& |4 Z
  46.         p->U_kk=0;
    / X# G% s0 i; K8 N! l5 o
  47.         p->ekk=0;
    1 W- O6 e( y# {% f& V& |1 U3 ^0 F
  48.         p->ekkk=0;
      ^$ \. p% e1 V' U5 B9 ~
  49. }
    8 C; F5 y" e" b( [4 r4 n. W  X

  50. & j$ Z# J  G% v2 \! z" `
  51. /***********************************************************************************************3 H8 |$ D& u( q8 w5 ], [
  52. 函 数 名:s32 PID_commen(int set,int jiance,PID_Uint *p)) r1 D) i% _" @" z  f
  53. 功    能:PID计算函数1 c  j7 t' R# e' H: C( J) V
  54. 说    明:求任意单个PID的控制量2 p5 ^/ W1 E6 c  S' W* p3 U- [
  55. 入口参数:期望值,实测值,PID单元结构体* W" \5 C- y8 a3 G
  56. 返 回 值:PID控制量! _+ M) U$ {5 h" d7 ?* i
  57. ************************************************************************************************// q. L1 B# _- A6 ]+ M4 t

  58. ! m7 E/ g! |- p9 e. g2 j* _: n9 |
  59. s32 PID_common(int set,int jiance,struct pid_uint *p)
    9 G& m/ G5 U) F/ G
  60. {
    0 b2 m4 Q2 @+ w+ u' w7 |
  61.         int ek=0,U_k=0;7 l$ P  B2 M: R% W" ~5 p# u0 C
  62. # `% P  V  \' P
  63.         ek=jiance - set;                                                               
    - M( R3 m9 w7 K6 s' w$ v
  64.         ' X3 S! a' L" [( k8 z% a
  65.         U_k=p->U_kk + p->Kp*(ek - p->ekk) + p->Ki*ek + p->Kd*(ek - 2*p->ekk + p->ekkk);" V  T& K! n# Q! [
  66.         
    0 i! u* Z: N8 C* }
  67.         p->U_kk=U_k;
    * }8 V7 J9 h8 G, z8 ~* z9 r9 P+ k* r$ j8 {
  68.     p->ekkk=p->ekk;
    ) S2 _5 }6 R" i. ]6 L2 u
  69.         p->ekk=ek;
    2 m  `( Q. L5 R& n
  70.         & W0 F/ b& }% I' A
  71.         if(U_k>(p->Ur))                                                   
    7 G  D! X8 j2 w; [! p3 i0 K5 Q# O
  72.                 U_k=p->Ur;# Q+ h$ G7 D' }) p* ?
  73.         if(U_k<-(p->Ur))9 K' |+ D) Y" ^9 w: p1 V, Z: y
  74.                 U_k=-(p->Ur);
    1 {* u4 q9 ~) I* h1 d
  75.         $ {3 C" J" {% Z/ ~4 x1 k
  76.         return U_k>>10; * a0 j0 u. A3 Q/ m( T% V
  77. }" Y5 O/ ~2 k$ c' z" J$ u

  78. 5 T& o6 x. n) {  ?" e! g
  79. /***********************************************************************************6 m9 \3 I& N7 S* g& _
  80. ** 函数名称 :void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)( b, [3 Q4 \! R8 @+ C3 M( S# w4 m1 u, R
  81. ** 函数功能 :pid选择函数              
    5 i# m4 w" V* L" ^# x+ M
  82. ***********************************************************************************/
    . O- u  F, M  P! ~% p
  83. ' e! ]: L: t3 T( O8 L& ]' z! Y4 E
  84. void Pid_Which(struct pid_uint *pl, struct pid_uint *pr)) X" Q  x* S* e
  85. {
    % ?0 x$ y: v# i. w$ e( b
  86.         /**********************左轮速度pid*************************/
    $ o( @, k, R- {+ P  H
  87.         if(pl->En == 1)
    1 a. U2 Q( x. Q# P3 c5 d
  88.         {                                                                        . f3 @( ~+ b( ]; e* x
  89.                 pl->Adjust = -PID_common(pl->speedSet, pl->speedNow, pl);               
    7 m/ V4 G6 |+ C' w$ b% h$ L* ~! Y
  90.         }        
    , ^+ \5 ?' {4 Y7 N
  91.         else' `6 r# \; a( ]6 i( ^
  92.         {
    9 |2 T, p% c9 }$ T; I
  93.                 pl->Adjust = 0;
    1 @  v+ P4 C1 \1 J; D& j
  94.                 reset_Uk(pl);
    + A! \  e2 q2 C$ y
  95.                 pl->En = 2;
    3 e( Z4 ^! F+ q5 U+ n. v, U
  96.         }1 n$ {( a8 `8 Z3 @; @
  97.         /***********************右轮速度pid*************************// o+ d. k2 J- j) t
  98.         if(pr->En == 1)) d1 c0 x; W4 M; _) B2 Y0 U
  99.         {
    ' N, b% M* S$ J1 L6 V/ w
  100.                 pr->Adjust = -PID_common(pr->speedSet, pr->speedNow, pr);               
    % b: f3 y6 o. S+ T2 G6 I! h& N
  101.         }        8 C* Z) ]" t. @5 l
  102.         else
    ; d- g. x/ P. ^& ?  p
  103.         {' P5 a3 F4 o' \  t- S* P" z
  104.                 pr->Adjust = 0;
    # M. ^' O/ c7 l* [, V$ E* h
  105.                 reset_Uk(pr);
    % S, K2 m3 g; `$ q
  106.                 pr->En = 2;
    * l( T& {) @% b! n7 v$ L/ [
  107.         }
    1 F  I; q+ Q  h7 M+ d: u, \
  108. }
    ; f# i1 ]2 d. ]7 a% [3 r- v  A
  109. . p2 Z/ T$ n1 z4 A( I7 [' p. e
  110. /*******************************************************************************) Z% D7 M2 B! Z/ |% _& a
  111. * 函数名:Pid_Ctrl(int *leftMotor,int  *rightMotor)* \$ t/ g; U( e8 x+ }5 ~. f* }. n
  112. * 描述  :Pid控制
    0 C4 \, o' O) F7 X
  113. *******************************************************************************/8 @6 g2 E8 i! P5 q. f' ?

  114. 5 f: D5 s, e8 z0 g" S
  115. void Pid_Ctrl(int *leftMotor,int  *rightMotor)
    ! C( P/ g6 I+ b7 S
  116. {
    7 V! K& _0 j* N2 `
  117.         Pid_Which(&pid_Task_Letf, &pid_Task_Right); $ W1 k% n3 Q) l& c
  118.         *leftMotor  += pid_Task_Letf.Adjust;- a2 ^7 D( c6 K+ {8 A: g* ~
  119.         *rightMotor += pid_Task_Right.Adjust;+ a1 U; e! D( Q% y! n, m
  120. }
    ( `  N  l5 e2 `
复制代码
5 O8 [; Z) \0 H  k7 l) a: L/ @

0 |  J$ m, I! z: {

(2)main.c

2 C1 x1 R/ h! m" [

, g7 ?) V0 ?7 b# V. g$ i

  1. #include "sys.h"
    . ~! @% d- X( U9 x

  2. 0 @! E  L; ~$ f8 `  m; N
  3. //====================自己加入的头文件===============================
    : O+ F% }9 M/ l( I/ r
  4. #include "delay.h"3 {( q% X' w3 b: p
  5. #include "led.h"6 z' v/ l) ^( Z
  6. #include "encoder.h"
    ; }8 u9 b; J3 G" Y' L3 {
  7. #include "usart3.h"
    ! o1 Q) r6 ?' ^
  8. #include "timer.h"
    & j! H7 I. ~. Z( J$ I
  9. #include "pwm.h"0 h( S7 _) R! x, S8 I; N0 s
  10. #include "pid.h"# u" x5 t( a3 Y/ s; j) W  P
  11. #include "motor.h"
    ( z# k# W) T5 t2 ?1 @( m+ w( J" u: O
  12. #include <stdio.h>
    ) V: q0 M' ~* D
  13. /*===================================================================
    + {- i7 e+ p7 U6 O- \. y# i6 G
  14. 程序功能:直流减速电机的速度闭环控制测试
    3 ~& J7 i) q! q1 c7 I) `( `
  15. 程序编写:公众号:小白学移动机器人2 c, A6 `2 v; L9 `" b
  16. 其他    :如果对代码有任何疑问,可以私信小编,一定会回复的。, a5 M# c! D' ?' h, a& w
  17. =====================================================================
    8 q: z+ R% D  Q
  18. ------------------关注公众号,获得更多有趣的分享---------------------
    ! N4 {5 Y( `& e( a3 q2 q- N
  19. ===================================================================*/# f5 y# x" l* T' T# u
  20. int leftSpeedNow  =0;
    ! W4 v' s% V2 _7 |. u" L
  21. int rightSpeedNow =0;0 D* G2 E# w2 A, e6 P$ U

  22. - ]; w% {1 U$ V1 x  v
  23. int leftSpeeSet   = -300;//mm/s
    8 {8 u1 |" b( m& d
  24. int rightSpeedSet = -300;//mm/s6 r, X, c, ?! L& [( ?$ k  L, N- Q
  25. / Y; I1 Q* f8 p! v$ F4 Y: o( e
  26. int main(void)1 k* k0 @% A8 K% \# q, L$ P
  27. {
    " S: ~9 c2 _+ \8 D7 l

  28. - J) z5 ~5 q5 [1 Y  D5 T
  29.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
    $ J! q7 I9 _1 E, H4 v
  30.         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁用JTAG 启用 SWD" u7 f$ J* S" @1 f1 W5 k
  31.         
    2 A6 {+ X: ?" W- h  R  f
  32.         MY_NVIC_PriorityGroupConfig(2);        //=====设置中断分组
    4 \9 l" [, y6 t* P- I
  33.         
    & H; t7 P2 {* P& a$ W0 I
  34.         delay_init();                            //=====延时函数初始化
    * a4 u. F- Q) w2 d
  35.         LED_Init();                     //=====LED初始化    程序灯        
    ; R; B8 Y3 h  I1 k' K6 z8 \
  36.         7 a( m3 B" K% n' i7 L( k8 l# B
  37.         usart3_init(9600);              //=====串口3初始化  蓝牙 发送调试信息
    : J1 T/ E6 W. Y% B% w- i: ~* w

  38. , g6 L6 c3 v& j0 R, h
  39.         Encoder_Init_TIM2();            //=====初始化编码器1接口! x( j6 Q  ~/ E4 n- u$ R1 E0 a
  40.         Encoder_Init_TIM4();            //=====初始化编码器2接口" }) Y2 L3 B! M% I+ v  C
  41.         * m/ q" f: z( }$ o$ G( a
  42.         Motor_Init(7199,0);             //=====初始化PWM 10KHZ,用于驱动电机 如需初始化驱动器接口
    2 M! |9 h/ h* D0 }) K2 a: V1 i
  43.         
    6 V7 C4 y" M/ H6 q7 H7 O/ S
  44.         TIM3_Int_Init(50-1,7200-1);     //=====定时器初始化 5ms一次中断
    ! K5 t6 a& q4 l- g- H) B% X

  45. 3 }/ g& W, ?9 w7 F
  46.         PID_Init();                                                //=====PID参数初始化
    ! Y" ]  S+ ]7 A. |
  47.         % w# z$ J2 m7 o: \+ w2 j( C: [
  48.         while(1)
    # E. C8 U& A+ ?* A# W+ U0 [2 [( ^  N
  49.         {
    : Q. i5 Q' i2 ^# k0 b5 Y" b
  50.                 //给速度设定值和实时值赋值5 {" O- j3 ~7 K, a2 L
  51.                 pid_Task_Letf.speedSet  = leftSpeeSet;
    * P% u5 N, C% R
  52.                 pid_Task_Right.speedSet = rightSpeedSet;6 ]+ V" p5 L, o1 @. {; m  s; S" X
  53.                 pid_Task_Letf.speedNow  = leftSpeedNow;) Y4 o5 x2 S3 {& {3 E+ R' E
  54.                 pid_Task_Right.speedNow = rightSpeedNow;
    2 M. y! O/ ?, o8 o! B( f2 C
  55.                 . `4 x, c% ^; n  D! r
  56.                 //执行PID控制函数9 R  c7 D' M2 i- E6 m
  57.                 Pid_Ctrl(&motorLeft,&motorRight);
      w- ]; J, z  L* E1 n0 K
  58.                 ! o- O$ \9 v  [3 B5 i2 ~' g
  59.                 //根据PID计算的PWM数据进行设置PWM/ x4 _, D3 N: b" G7 Z. P
  60.                 Set_Pwm(motorLeft,motorRight);
    - e7 K# T! w% k
  61.                 ! M1 x( H6 U5 u( f
  62.                 //打印速度2 ^0 ~+ L& P; @  Y- u( r) X' T7 g
  63.                 printf("%d,%d\r\n",leftSpeedNow,rightSpeedNow);
    * y8 P2 E2 _" Z# i$ E; a6 I
  64.         }
    * @( N$ y5 G, N& |( z
  65. }
    + I5 O& y" F3 `  Q( M, z$ s

  66. 7 y7 R: v# Z  k) p1 P# e
  67. //5ms 定时器中断服务函数
    " W8 \( ]% M: v% S7 \
  68. ; P9 B# s" o, Q0 Y! R! g7 n
  69. void TIM3_IRQHandler(void)                            //TIM3中断6 a  @/ l& C' o# [' s
  70. {  |! P0 @# I/ ]  h! b
  71.         if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否  x5 F' }! `6 r  ^  b; [; f
  72.         {
    8 l6 I; q! Q4 B9 W( V6 ]+ y
  73.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);   //清除TIMx的中断待处理位, c/ C# ~: X: B4 w6 m
  74.                
    - R& [/ C$ d' _0 @3 i1 j
  75.                 Get_Motor_Speed(&leftSpeedNow,&rightSpeedNow);//计算电机速度6 H6 E2 n/ S1 T6 o& ?0 z
  76.                 : J2 x% e, S4 d% B8 o0 l/ C
  77.                 Led_Flash(100);                               //程序闪烁灯
    , S3 j( D7 M" L) u/ o5 m
  78.         }2 G, C9 V: B. B: K& o* ~  B' n# T
  79. }
复制代码
/ I0 Q3 F' j% F( A

1 ^3 F! L+ s  N$ p; v7 {* |" m& s1 D2.3.4 总结
: R+ i! Y, e, M+ s- n2 j0 B

: R; c" U- A8 O1 d6 a6 \

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

) Y3 [  Z# d: s6 _  G7 ~% [
& y( {, u5 P9 ^3 K' m- u# H
; I# b7 a2 g. d* K3 l, I, Z

# J1 k, _- Q5 |
收藏 评论0 发布时间:2020-9-16 10:22

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版