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

【经验分享】STM32CubeIDE自平衡小车教程6.电机转速闭环控制

[复制链接]
STMCU小助手 发布时间:2022-3-15 22:00
开始之前我们需要了解的是完成闭环控制输出任务前提是必须要有printf输出功能和PWM输出功能。, o+ k& {4 S% C, w
4 R# `6 T/ E) w5 Y9 |: R- I
1)其中printf功能是为了在最后阶段,监测实时的PWM值,检测是否实现闭环控制。4 @6 a: _1 b5 R1 L
$ o* S* w# c# K
关于printf功能的实现可参考教程4的内容:. ~! I# m: ?' \' j+ g

! Y( e" V" h8 x- C. w  f: YSTM32CubeIDE自平衡小车教程4.配置串口并实现字符的输出
9 F! N5 f3 H! g# }
; d2 X! a0 W! w! q$ C5 @2 F  c2)PWM输出功能是为了实现最后车轮能按照设定的转速转动。! X# r' h9 H+ `: E, S0 v7 ?
% y$ ]- ?, f* X0 T1 L% E8 i6 K2 {
关于PWM输出功能的实现可参考教程5的内容:& O5 Z/ f! o) a  Y3 B- a: Q3 M+ o& |
- ]' M+ h# a9 b) q
STM32CubeIDE自平衡小车教程5.直流电机转速开环控制
; _. c# B7 O( l! ?% z' R$ e! K& o1 S9 S! z. D+ a5 _6 _* T( ?5 `
以下是实现电机转速闭环控制的步骤:, g& [) d  B& b: g5 G. X, E
1.打开上节的工程文件,在工程文件中新加一个User文件夹,在文件夹目录下新建Src和Inc文件夹,并分别添加.c文件和.h文件并命名为motor_control.c和motor_control.h
+ E3 V/ J: l, T3 x3 |. ^
0 Y& \& T. l' @4 b! z6 h$ Z KVT(36B]M16PXRR)C6XZ5XL.png
/ S" ^) N# W3 D! p9 |4 f) a. d# a3 P) [$ ]
2.在motor_control.c文件中加入以下代码:
$ T/ X0 ], S/ c% M' n8 a' e
  1. #include "main.h"
    / q2 L. j" c" u2 q: F6 L/ s  P& d

  2. / r% ~! N3 S/ \" ~& a
  3. float SpeedKp = 10.0, SpeedKi = 1, SpeedKd = 0;
    2 |/ r& `4 c: ^! j  _; d* ?0 t! j+ X

  4. 9 S$ I; p. E1 r, h+ `# _/ t) E
  5. int Motor1SpeedClosedControl(int Encoder,int Target)
    - m$ v5 X/ e. i$ j  @: E
  6. {
    % C" T# }) r6 m! w1 `6 t
  7.         static float Error,ErrorPrev,ErrorLast,PWM;
    " }9 F2 F+ X# A/ ?. |
  8. 0 o  ?5 Y6 V. E4 `; Q6 A$ l6 M
  9.         Error = Target - Encoder;  D4 T! s- D8 T9 \: \' t

  10. 1 H9 U) P+ l7 X6 P$ j
  11.         PWM += SpeedKp*(Error - ErrorPrev) + SpeedKi*Error + SpeedKd*(Error - 2*ErrorPrev + ErrorLast);! \6 f) d+ ^1 }. m
  12. $ t# ~$ @3 ^0 Q. n9 I
  13.         ErrorLast = ErrorPrev;. Q: u( b# @  @1 w2 y' l
  14.         ErrorPrev = Error;
    7 K0 G0 G7 U# l2 R7 e+ P
  15. 4 K4 F/ x2 k7 ], D0 U( V$ m
  16.         if(PWM >= 100) PWM = 100;8 U! K9 {! O  n8 @8 h4 ]/ I
  17.         if(PWM <= -100) PWM = -100;: m. W; h2 P: q# \! B9 {! g6 a
  18. 5 j* [: z- f" f) s$ W. u$ {6 ?
  19.         return PWM;
    % Y! E) d  F2 Q' o8 }. |
  20. }2 u8 [( p8 l9 E
  21. * m. u  `4 i( L& f
  22. void SetMotor1Direction(int Pwm)//设置电机方向/ T( R5 W+ `1 T  ~
  23. {7 M7 v9 `+ Y  {( V' Y+ ?' m
  24. if(Pwm < 0)//反转
    : u+ D+ d' A# u2 T, X. C
  25. {
    5 p6 y# f. w- I- K9 y
  26. HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_RESET);
    ; i2 G, r3 Z; Z4 h* ?
  27. HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_SET);
    ( b4 w# a% J6 j1 s& s
  28. Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值
    % Z2 x$ i; [# w  ^' o2 i
  29. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, Pwm);
    + T3 @( t; ?- Q) k
  30. }else5 W2 w1 Y: X9 D8 k/ k* Z
  31. {
    9 u" x9 n- V" [9 N1 q
  32. HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_SET);/ g* r! j! ]1 q" N# S. @# ^
  33. HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_RESET);
    1 m$ b7 u$ N& N  v5 a" r
  34. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, Pwm);7 C3 N7 ^, ?: m
  35. }
    4 k: m4 u# z; x% ^- Y- I. D
  36. }
    * [; G1 u; I( d/ H, x

  37. * U2 {+ ]* p: }2 v  b
  38. int Motor2SpeedClosedControl(int Encoder,int Target)
      g% _! b: O" S5 d$ s2 F% `  ^$ {
  39. {7 O6 C/ ?3 O5 }9 q
  40.         static float Error,ErrorPrev,ErrorLast,PWM;
    ' s' U- ~2 e" ?; q
  41. . g* K% a0 j9 s2 O; e2 h
  42.         Error = Target - Encoder;
    9 Z" \' e/ B9 @( N0 E

  43. 9 W& v& B1 ~5 t; n0 _
  44.         PWM += SpeedKp*(Error - ErrorPrev) + SpeedKi*Error + SpeedKd*(Error - 2*ErrorPrev + ErrorLast);6 {. ]) K: R# h) i0 O5 o

  45. - T- f3 F, T7 a6 m1 b
  46.         ErrorLast = ErrorPrev;
    & Q1 b2 C8 b4 ?5 H5 l
  47.         ErrorPrev = Error;
    * u# D/ \+ [; U8 ~$ A, X5 @% {
  48. 1 ~- D" `2 o1 d5 v" z. w7 ^
  49.         if(PWM >= 100) PWM = 100;
    # p7 f% s+ _' m' ]# u
  50.         if(PWM <= -100) PWM = -100;  l) h- s9 s+ ], ]1 O, N+ q

  51. $ m( Y& \5 h- y! G$ @! d
  52.         return PWM;
    " Z' y6 s# d7 s$ k  w6 {( z
  53. }/ V( i$ j' F# g7 q' z

  54. - L' A, o8 t; w* k7 k  N+ E
  55. void SetMotor2Direction(int Pwm)//设置电机方向
    - \9 ]0 ?4 d% B
  56. {/ X# r( b! [: c/ `+ `
  57.         if(Pwm < 0)//反转3 I: w; j  J7 |3 y* m
  58.         {
    ' d2 x$ }3 k0 H! Y( B  v9 H
  59.         HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_SET);
    ; J7 w9 q9 S5 P- S( ^
  60.         HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_RESET);
    " @5 Y6 ?  J- p  E  n
  61.         Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值4 R' Y  N% p, j9 o% O
  62.         __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, Pwm);
    , q- Y% _: l, i1 N
  63.         }
    ( P1 h' p- G6 f+ P& z4 H
  64.         else6 N/ R# D1 |/ B+ m9 `
  65.         {
    1 U' \5 J$ q8 z
  66.         HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_RESET);
    2 C1 q% l: W6 k& }/ n5 z/ p: }6 {
  67.         HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_SET);
    ; }- _9 m; Y" J' G8 u, N/ s  ~+ P
  68.         __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, Pwm);+ ]3 l8 Q! P1 q/ h- U
  69.         }
    / S7 F" L  X, K7 ^
  70. }
复制代码
) G9 a5 {9 s1 @" p/ v( I2 P1 \$ g
3.在motor_control.h文件中加入以下代码:
5 X2 @: Q, h8 V2 C1 |" Y- j
  1. int Motor1SpeedClosedControl;& q* c  c. P6 I
  2. int Motor2SpeedClosedControl;
    1 Y: y9 y7 ~- K5 O; p1 i$ b
  3. void SetMotor1Direction(int Pwm);9 ]1 W4 d6 f9 O
  4. void SetMotor2Direction(int Pwm);
复制代码
' W% Q( Y# Q- T* h2 E
4.在main.c文件中在上节代码的基础中添加如下代码:7 p% {' P0 H9 R6 |8 h) Y( Q; \
  1.         HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);
    4 ^) G$ ^2 ]( b' S2 ]
  2.         HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);
复制代码
  i& h, Z4 @  U2 Y
R{CTSRAY1347YBOGK]E_S$O.png - C  n! [3 o- Q0 p) X! K

5 L6 X! p$ E$ u+ R* y0 V 5.打开在Core文件夹下Src文件夹中的stm32f1xx_it.c文件,下拉找到void SysTick_Handler(void),并加入以下代码(要加在CODE BEGIN和CODE END中间):, g5 |" L7 R, q: V
  1. static unsigned char Timer5msCounter;( @4 B  T( g, p- R
  2.         static int Motor1Speed;& p1 K( @; T4 n, z+ Z( y. M
  3.         static int Motor1PWM;3 n& [6 {$ c* `2 V/ q# j
  4.         static int Motor2Speed;
    ; T7 Z' i1 W, f0 B
  5.         static int Motor2PWM;, A9 U3 [7 I+ L  e; f

  6.   ?8 g% a& e& L
  7.         Timer5msCounter++;! E# d3 ]( k+ ~
  8.           if(Timer5msCounter >=5)//每5s一个周期  J& G5 r0 T4 O% p0 ~4 m: _
  9.           {
    " o  }& ?/ L$ W; p$ A
  10.                   Timer5msCounter = 0;3 J! W5 @' L3 |  a& P
  11.                   Motor2Speed = GetTim4Encoder();
    8 n7 w3 T" z( M! W4 U4 X5 V; e. J
  12.                   Motor1Speed = GetTim3Encoder();
    & Q; p; X, _3 {

  13. 8 M' w8 ?# r1 U
  14.                   printf("M1Speed = %d \n", Motor1Speed);
      H* `# v: l0 R7 G5 m" \
  15.                   printf("M2Speed = %d \n", Motor2Speed);
    - ~/ B) p' x  V0 Z" t, P4 P" A

  16. + t$ L/ P, U& ?: R! N
  17.                   Motor1PWM = Motor1SpeedClosedControl(Motor1Speed,-20);* d& ]1 k) N( s7 K! l  p
  18.                   Motor2PWM = Motor2SpeedClosedControl(Motor2Speed,30);
    ! J  j2 b/ {. q& v1 t4 Z, E: c
  19. 0 r% i; Q; y/ c  ?
  20.                   SetMotor1Direction(Motor1PWM);+ ~7 C6 K9 p( s% E- l) y) [7 b
  21.                   SetMotor2Direction(Motor2PWM);# s6 d- s% ~4 H- h/ f. b
  22.       }( R6 r, ?  }/ t) o
复制代码

1 D+ V4 b! `* a& z. y7 Y* }& z ZJ0A]YBZRXQOV1{BGO%N~WA.png
5 v. s: B* ^+ U2 `$ A5 Y9 V; n
# x0 `' g$ Y1 o6.在工程文件目录下的Core文件夹下添加Inc和Src文件夹,并添加encoder.c文件和encoder.h文件。- x, b) z' B; r+ t0 q0 J! M
在encoder.c文件下添加以下代码:
! N8 _2 }  I; s2 ^$ }/ A, C
  1. #include "tim.h"//包含tim头文件, g$ c7 `- A" G8 c
  2. #include "encoder.h"
    + Q* c- h8 a' n' _, m5 j

  3. - \' M7 q. m) y
  4. int iTim4Encoder;//存放从TIM4定时器读出来的编码器脉冲' d  x8 o( ^6 [
  5. int iTim3Encoder;) C8 C1 m  |, |) P* w& C
  6. % ]; O. e7 X  q3 g( h/ S
  7. int GetTim4Encoder(void)//获取TIM4定时器读出来的编码器脉冲1 o4 `& h& ~! G, P& C8 I
  8. {  q" u' p# M  d- L9 C
  9. iTim4Encoder = (short)(__HAL_TIM_GET_COUNTER(&htim4));//先读取脉冲数9 c- ]. W  ^; j/ s" A) n7 s
  10. __HAL_TIM_SET_COUNTER(&htim4,0);//再计数器清零+ P$ T0 @6 H6 G) G, c, g0 e
  11. return iTim4Encoder;//返回脉冲数
    6 V% e: x' R  a3 W6 c
  12. }
    . g+ R% _, d: ^0 T

  13. % y" z& F4 Z& e& u2 R/ S$ `: j. v
  14. int GetTim3Encoder(void)//获取TIM4定时器读出来的编码器脉冲4 e2 D; Y- y) m* p5 e0 v- \
  15. {
    9 j  B4 y% e" S& j
  16. iTim3Encoder = (short)(__HAL_TIM_GET_COUNTER(&htim3));//先读取脉冲数7 V5 t4 h6 o, T) R! q
  17. __HAL_TIM_SET_COUNTER(&htim3,0);//再计数器清零
    + n3 V- P$ H3 F  Y
  18. return iTim3Encoder;//返回脉冲数7 ?5 L$ H" R3 L! F: l, r
  19. }
复制代码

0 k4 w- j) Q- `! h在encoder.h文件下添加以下代码:
8 O9 J2 O! j# e, K* V
  1. int GetTim4Encoder(void);//声明函数
    4 o& u6 B7 W9 E% @: w
  2. int GetTim3Encoder(void);
复制代码

  w( {$ |* a0 Z4 H7.点击编译并进行烧录,完成PID速度闭环控制任务。可在在stm32f1xx_it.c中更改小车M1和M2电机的脉冲速度,正数转向为正向,负数转向为反向,并在调试器中接收小车的脉冲速度。(需要打开小车电源开关)2 C) {  V' ?1 k$ G9 i$ e, s: z& f
例如此时设置M1电机脉冲速度为-20,M2电机脉冲速度为40。
) u: Q- o' E+ i* c) s 7BSW6FV]GYDF@NA[)BQ4(6C.png 8 A) C  x+ a# D. W* p4 a

& ?+ m2 t0 E5 A" T% q8 I打开串口数据调试工具,可查看小车实时输出的PWM值:
! H' h8 I* O9 m1 D1 `2 h* ]2 ~( D: |3 S) P5 b
OL4ES%3}4BT@M2VO{J{HBT0.png + f* B3 e& [& Q( x/ H

5 ^$ R4 b, W7 w" O. c; P% f6 {$ I! p6 R+ O" P- s# n) i
赞 收藏 评论0 发布时间:2022-3-15 22:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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