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

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

[复制链接]
STMCU小助手 发布时间:2022-3-15 22:00
开始之前我们需要了解的是完成闭环控制输出任务前提是必须要有printf输出功能和PWM输出功能。
. y( R. t) }4 A
2 r' j" t2 O- n/ r- K1)其中printf功能是为了在最后阶段,监测实时的PWM值,检测是否实现闭环控制。0 q  \; u9 o- g2 O+ p& v
9 Q! M( P4 v! R  U" J3 A
关于printf功能的实现可参考教程4的内容:
9 g( H; t, I( Z" R( t- e
: D6 A; k# O& v, m) Q, ?! aSTM32CubeIDE自平衡小车教程4.配置串口并实现字符的输出/ c2 x( V. y: d5 D' ?1 O
9 E* b: F! {: V; n, a3 b
2)PWM输出功能是为了实现最后车轮能按照设定的转速转动。
2 ?+ e4 F; g! Z
8 ]. M6 ~( z2 \* u9 K6 o7 m关于PWM输出功能的实现可参考教程5的内容:
5 ]' h5 Z% U  p9 D4 n' x' y- a
: Y6 i& n& N4 e' Z2 a0 i6 mSTM32CubeIDE自平衡小车教程5.直流电机转速开环控制6 H( x. {% \% m

2 a5 f& V( c  s& |, o8 S以下是实现电机转速闭环控制的步骤:
+ {2 l' q; `/ E4 ^3 R7 Y, G6 o1.打开上节的工程文件,在工程文件中新加一个User文件夹,在文件夹目录下新建Src和Inc文件夹,并分别添加.c文件和.h文件并命名为motor_control.c和motor_control.h
5 ^$ u; o1 B; E  c3 l% T8 t( L8 C, ^0 T& x: `, t
KVT(36B]M16PXRR)C6XZ5XL.png
1 ~' I/ o9 w: g8 v1 S
4 c( F' F3 [2 l' T( b2.在motor_control.c文件中加入以下代码:
* i; h1 M9 r+ w# p' z# z7 K! o
  1. #include "main.h"
    ) V' a+ U5 M1 f* N

  2. # K6 U6 C2 Z& A) W" z# D1 e; f6 r, F
  3. float SpeedKp = 10.0, SpeedKi = 1, SpeedKd = 0;
    6 l& n7 B% Q0 N5 G4 E

  4. 5 M' t3 z; G* Z. H7 s
  5. int Motor1SpeedClosedControl(int Encoder,int Target)
    " U8 M# K  I& e
  6. {& \1 m* L, R+ f
  7.         static float Error,ErrorPrev,ErrorLast,PWM;
    9 C' @' v9 D8 A9 ~2 \* R

  8. 5 m' k  t4 ^$ c, Y0 Q
  9.         Error = Target - Encoder;
    6 `7 v. X- N* Y7 G* p0 Q$ x, f
  10. 8 [5 z# B- w+ c# O! n8 E
  11.         PWM += SpeedKp*(Error - ErrorPrev) + SpeedKi*Error + SpeedKd*(Error - 2*ErrorPrev + ErrorLast);
    / ?3 r1 ^" n8 h7 _* H7 M! H

  12. ' M. @0 O8 I! i2 b: c: Y6 |
  13.         ErrorLast = ErrorPrev;
    9 m+ P& B( G) d, B( l
  14.         ErrorPrev = Error;
    : P! g3 a7 w# E: V& G8 u8 r
  15. % D+ t, e  u9 u% }
  16.         if(PWM >= 100) PWM = 100;$ ?7 g4 \* r$ c6 j
  17.         if(PWM <= -100) PWM = -100;
    # |# U- }. z2 C& O

  18. 4 ~- `5 @& n/ ~- y0 M/ ^, K, `
  19.         return PWM;
    ! O( _3 k9 k$ {/ d
  20. }1 y5 I' f% S. E: N* W" ?
  21. . t# A9 E9 q0 p# s# J7 h5 G
  22. void SetMotor1Direction(int Pwm)//设置电机方向* R9 w/ P3 `4 b% b/ r$ N7 Z
  23. {) z6 a) u4 O8 U; y3 F
  24. if(Pwm < 0)//反转6 ?$ Z! i0 J' t
  25. {  @& H7 p0 D- Q8 G! l% e6 S& ]
  26. HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_RESET);1 U9 F4 |6 D1 }2 h
  27. HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_SET);
    7 D# [2 F% E$ o# f( ~* }
  28. Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值
    * m/ d. r* @! q* ~3 R: |( y
  29. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, Pwm);
    # e& w6 P- ?' D$ f2 G
  30. }else8 p3 i7 T$ k! k! R* A4 a
  31. {
    2 Q0 z1 ^) z$ j9 W) N" ?' d
  32. HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_SET);
    ! x. H9 c# f+ E
  33. HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_RESET);
    " H  _$ ]4 e/ {; {
  34. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, Pwm);1 F: @& Q/ F, |. E1 e' P
  35. }
    # p8 C& x  q0 ^
  36. }& W+ o3 m# @4 c
  37. 1 h, T' v! f5 I7 G. N% z
  38. int Motor2SpeedClosedControl(int Encoder,int Target)
    . h' X, a# s6 s- Y  C  C: Q$ @" y
  39. {& u& M: h+ z, s6 ?
  40.         static float Error,ErrorPrev,ErrorLast,PWM;
    8 @  }2 V% c3 Q' P- @/ A4 o  v5 B* e

  41. # d( a  Z5 Z- R7 z
  42.         Error = Target - Encoder;# R* G/ t8 @. h2 `

  43. ! L, Q/ c/ V1 q1 A' A# [' Y" a
  44.         PWM += SpeedKp*(Error - ErrorPrev) + SpeedKi*Error + SpeedKd*(Error - 2*ErrorPrev + ErrorLast);
    ( S# c# ]* l- Q# x( p0 O# Q
  45. - Q9 `3 G) O2 X, p# o) T, U
  46.         ErrorLast = ErrorPrev;3 a- g0 Y) H" C+ D* T
  47.         ErrorPrev = Error;4 b4 _0 t! ~- z% c+ l  j$ @

  48. 1 ]. M2 R: z. n' I9 V
  49.         if(PWM >= 100) PWM = 100;9 F7 d+ I8 t- w1 t  h
  50.         if(PWM <= -100) PWM = -100;& ~0 m7 ?' Z9 E% m

  51. 8 F' D" h2 ^4 Z' t+ O. X
  52.         return PWM;
    ' R: l/ M# m) k9 Z; o
  53. }
    . m5 ^( ?9 T' a$ P8 b" @

  54. , [% q( P% t3 p( g" b
  55. void SetMotor2Direction(int Pwm)//设置电机方向9 r0 t/ o5 \% V2 |+ \5 j5 a
  56. {
    5 Q* }5 S& i, i& K7 K' Q
  57.         if(Pwm < 0)//反转. f; ~3 C7 }, M( s
  58.         {
    8 d  a8 J$ k4 Z( a  h) {: o
  59.         HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_SET);) r2 f5 l* V0 M: v) M
  60.         HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_RESET);
    ' b9 {$ `- [& D, m1 O
  61.         Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值0 t/ t8 r( l; x" v( o2 L6 p5 L2 e
  62.         __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, Pwm);
    # r( Q) q) v8 ~& }2 s( k" J
  63.         }
    ! W* O. n  k/ d# i
  64.         else3 @& V5 h4 X; v2 \! b/ `* {' I
  65.         {; R1 R! ^4 k1 N$ I: ?! I6 c0 R
  66.         HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_RESET);
    0 l. y& u: D9 e/ E- ~; I
  67.         HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_SET);5 R9 H( ?' k, @0 {, v
  68.         __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, Pwm);, X2 ?9 z" {5 y0 F% Z% j9 c
  69.         }9 o. f( _6 l! \+ i) ?. q1 M
  70. }
复制代码

, w3 Q7 q9 C, F: d7 @3 q7 B3.在motor_control.h文件中加入以下代码:& {! ]4 ?- m- m$ p
  1. int Motor1SpeedClosedControl;
    5 T  S8 \& L! I, \7 J7 D
  2. int Motor2SpeedClosedControl;$ R" K: K5 {+ p& p
  3. void SetMotor1Direction(int Pwm);
    4 v# _6 a7 V9 J: X) {4 ^
  4. void SetMotor2Direction(int Pwm);
复制代码
6 r1 A! ?' e+ Y& R( o8 j1 B4 f' a# A1 d4 m
4.在main.c文件中在上节代码的基础中添加如下代码:  W+ w. S6 x6 R* o# L" r. x
  1.         HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);
    - R/ e$ i. E$ [4 I# n+ C
  2.         HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);
复制代码
5 N: U6 [: a. i( P; K% G/ R1 ~* k
R{CTSRAY1347YBOGK]E_S$O.png
% p$ Q; ~/ @' T  O, p" p' g
, p3 D) W: ?( u/ ~4 _ 5.打开在Core文件夹下Src文件夹中的stm32f1xx_it.c文件,下拉找到void SysTick_Handler(void),并加入以下代码(要加在CODE BEGIN和CODE END中间):
4 j; B% D$ U# c$ i9 p( ^
  1. static unsigned char Timer5msCounter;
    4 R8 [/ s6 {9 D- z7 G; t. ?# k* |. h* d
  2.         static int Motor1Speed;
    $ ?' {9 s$ d( M' I& @; Y
  3.         static int Motor1PWM;2 h4 s/ O- H) M% J
  4.         static int Motor2Speed;& V& N* J, z, B& ?: p7 Z
  5.         static int Motor2PWM;) D) o& W5 x. A3 e8 p9 B8 [& Y
  6. 8 P% R( r) U7 I  i) Q* {
  7.         Timer5msCounter++;) k" M% m3 L$ O" N2 ~8 Z
  8.           if(Timer5msCounter >=5)//每5s一个周期
    + ^( \! {* [- J* h
  9.           {
    9 R3 C+ T$ W7 J" u6 W) R
  10.                   Timer5msCounter = 0;* U& C* U* O) {" k' }5 F
  11.                   Motor2Speed = GetTim4Encoder();- E  i5 t- H" W; k/ m4 M
  12.                   Motor1Speed = GetTim3Encoder();9 F( R6 z1 D8 m4 ?2 D1 @# h

  13. ' {: T: t. x' y  y4 g; ^* @
  14.                   printf("M1Speed = %d \n", Motor1Speed);
    - m3 e, r5 k; U; v: F; Z
  15.                   printf("M2Speed = %d \n", Motor2Speed);! D/ _/ e& k8 |! |# S0 [: q
  16. 8 Y8 e, B+ B/ a
  17.                   Motor1PWM = Motor1SpeedClosedControl(Motor1Speed,-20);
    $ B4 L. a  M( v
  18.                   Motor2PWM = Motor2SpeedClosedControl(Motor2Speed,30);6 i3 `) ]/ c: q. t& U$ c

  19. 6 G$ z0 W7 r, j: w: x
  20.                   SetMotor1Direction(Motor1PWM);" C* U6 o9 C+ f% |8 H% b* S
  21.                   SetMotor2Direction(Motor2PWM);
    5 i& a) W* Y) a+ X! n9 Z
  22.       }
    % [' B! ^+ ^0 ~0 \
复制代码

: n' U5 s  d# c$ q) ?7 E4 q ZJ0A]YBZRXQOV1{BGO%N~WA.png ; O: ^! p# V8 a+ H9 h
+ X# L; S8 p1 d5 b+ J
6.在工程文件目录下的Core文件夹下添加Inc和Src文件夹,并添加encoder.c文件和encoder.h文件。
, g6 R7 o' y" z% N在encoder.c文件下添加以下代码:
3 J! X0 G" X$ r6 Z6 [6 V
  1. #include "tim.h"//包含tim头文件
    " E" T% X  c1 O. y
  2. #include "encoder.h"
    & A! L, }* S+ w, T
  3. 0 S$ h$ K; R/ w" M  ]8 b) g  [
  4. int iTim4Encoder;//存放从TIM4定时器读出来的编码器脉冲) \, O) l: o. L/ v' ^) L3 W/ ?
  5. int iTim3Encoder;$ Q. ~$ t7 e5 n. ]
  6. ! Q' ]; B* S! Y& A! _7 ^
  7. int GetTim4Encoder(void)//获取TIM4定时器读出来的编码器脉冲
    $ ?, X& @) v! C3 y: E6 T& G2 @% ]; X
  8. {
    ( k% x$ v0 O% `
  9. iTim4Encoder = (short)(__HAL_TIM_GET_COUNTER(&htim4));//先读取脉冲数
    : T" x* ^/ i- v6 y: b6 o: h
  10. __HAL_TIM_SET_COUNTER(&htim4,0);//再计数器清零
    $ O3 B7 S  `# U; C4 r
  11. return iTim4Encoder;//返回脉冲数) W% H- s' p# U. G% ^- _
  12. }- l" F" I* k- I2 m: p* o
  13. / F' ]# s# J5 \
  14. int GetTim3Encoder(void)//获取TIM4定时器读出来的编码器脉冲
    . p5 r2 s8 v) ?  u" W. \2 J
  15. {
    5 k) ?9 |; w( M# w
  16. iTim3Encoder = (short)(__HAL_TIM_GET_COUNTER(&htim3));//先读取脉冲数( t5 X6 T: P7 B  _, {# ?( r& r
  17. __HAL_TIM_SET_COUNTER(&htim3,0);//再计数器清零/ l2 v3 w) K  I& n4 K2 w7 d
  18. return iTim3Encoder;//返回脉冲数; Z6 g! j3 I$ o2 c% w2 k* {1 @8 u
  19. }
复制代码
/ H( n0 i: F  z9 Q
在encoder.h文件下添加以下代码:
% w- }1 B: F. |' K8 ]! s$ D
  1. int GetTim4Encoder(void);//声明函数% m  B) e  I- u$ x
  2. int GetTim3Encoder(void);
复制代码

  L3 i' n# |' G; Z: j5 K7.点击编译并进行烧录,完成PID速度闭环控制任务。可在在stm32f1xx_it.c中更改小车M1和M2电机的脉冲速度,正数转向为正向,负数转向为反向,并在调试器中接收小车的脉冲速度。(需要打开小车电源开关)
$ s* y- c4 K3 _例如此时设置M1电机脉冲速度为-20,M2电机脉冲速度为40。. ]7 T, L1 _; i) I1 t' e5 R
7BSW6FV]GYDF@NA[)BQ4(6C.png ; x/ Q9 q5 B% T& q/ F5 {

3 c5 J1 h: ~. P8 l打开串口数据调试工具,可查看小车实时输出的PWM值:9 j4 T8 C1 W9 J8 Q/ q% p

. N* E2 I6 n7 e OL4ES%3}4BT@M2VO{J{HBT0.png / C# O& l: B5 x9 H1 a( s& A+ s  [* Y
0 ~9 p0 @* w4 j1 ~
" V5 ~; j# c4 V. `$ C2 g
收藏 评论0 发布时间:2022-3-15 22:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版