本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
7 u' ]/ i7 j U
* ]+ o& G9 f+ _& b9 @2 Z3 D经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 $ Z t, U4 s9 p1 L
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
4 b/ B; S# m) b9 a - /** @addtogroup MCIAPI
1 W) B, j1 q) O `/ N8 J" b- K - * @{
! i' l s2 J/ p7 u* ^7 Z7 D; N - */
, i! h1 s% x7 o J8 G. |7 S
1 G) Y" G% w+ r) o w% G* z- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;0 L1 z, z0 _6 d+ m9 r8 _7 ?
- * A2 l/ l. |9 c4 p4 \ {
- /* Starts Motor 1 */" |3 N6 l( `0 i& \( y) A0 s
- bool MC_StartMotor1(void);5 W2 T9 s1 s/ [( p
- ?- N0 Y( ?, X- /* Stops Motor 1 */( |/ n3 [& ^8 }, \* C, P6 h$ ~$ }
- bool MC_StopMotor1(void);& G/ L! t y. I6 q" k; h
7 |8 _" E( q4 x2 S- /* Programs a Speed ramp for Motor 1 */) k3 z" a- F$ S0 f+ E: n4 _
- void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
7 q r! \% G) D8 @ - 8 a( F' P" G! i( f) Q: z, f
- /* Programs a Torque ramp for Motor 1 */
+ m1 \4 ^6 y2 Z - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );; M+ t9 Z" @1 b; t
- ; M; R& ]* o$ n4 \; Q3 q
- /* Programs a current reference for Motor 1 */3 F4 u+ o1 v, A; m6 M; z7 t# ]
- void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );
, J8 E$ w8 E0 h! m' C* A% m
0 c, j3 l4 i" x- /* Returns the state of the last submited command for Motor 1 */
8 ]; j/ Y0 A# c" D - MCI_CommandState_t MC_GetCommandStateMotor1( void);
7 n# m3 j$ S# w1 q* b - 4 R/ f8 @8 s1 n, o
- /* Stops the execution of the current speed ramp for Motor 1 if any */; Z" p' ~# G4 b* U* `1 ~
- bool MC_StopSpeedRampMotor1(void);5 M; ?( I' `) W* Q* H* @+ U4 V' ]
- 3 J" ?+ j) d h
- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */* W2 }; s5 q6 B2 u' J6 R* W" E: G
- bool MC_HasRampCompletedMotor1(void);
2 h% F$ H! d' o/ U) \; r! x( n& u& m - ; z: @8 W* x4 V2 X
- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */* i- L1 o3 w; I8 ~; Q0 G
- int16_t MC_GetMecSpeedReferenceMotor1(void);% H; j( C2 W; o |' j$ ^" ^( [
- ; }! X# X1 I/ D* J9 p
- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */% L- P/ c, A; a% p- O/ O$ o
- int16_t MC_GetMecSpeedAverageMotor1(void);: }: z" E$ S' M6 Y
1 F" `8 ^6 y$ o. D- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */
: \% \1 d! T6 n8 p) [7 |4 c0 f5 a - int16_t MC_GetLastRampFinalSpeedMotor1(void);$ P3 d Q7 c) S6 ]- n, @
- & f# {/ c! Q( x+ S) k6 S
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */9 B: o5 z- n- X2 Y
- STC_Modality_t MC_GetControlModeMotor1(void);6 N ]; o- e: y0 \- c L
- + D9 T3 A* i$ `
- /* Returns the direction imposed by the last command on Motor 1 */6 ?- u0 o; v+ z/ }% m; ]" L2 y
- int16_t MC_GetImposedDirectionMotor1(void);1 {" l9 c# E/ | t$ g
: V5 m6 l" ^. p$ ` j* U- /* Returns the current reliability of the speed sensor used for Motor 1 */
; ]) v3 X3 l( d9 J' C, }& P% r+ v - bool MC_GetSpeedSensorReliabilityMotor1(void);& p1 K4 j# p% P/ j! w7 H* j
- I% o+ G$ a, K
- /* returns the amplitude of the phase current injected in Motor 1 */
% [5 o h( Z/ D6 h) S7 s, p - int16_t MC_GetPhaseCurrentAmplitudeMotor1(void); j- L% U# _+ c0 m
& F8 H+ p# l' B* @- y2 C: r- /* returns the amplitude of the phase voltage applied to Motor 1 */
~6 |2 F7 z' S - int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);/ j, P! ~ t m# [4 Y8 G
; l9 \% o1 u& x* i- /* returns current Ia and Ib values for Motor 1 */
7 J1 B3 b' E p" X7 l - Curr_Components MC_GetIabMotor1(void);( w2 V" M: B. E! Z! V r
; ], B7 b4 }% r; t+ z- /* returns current Ialpha and Ibeta values for Motor 1 */' h) W( C1 z/ M# K6 n
- Curr_Components MC_GetIalphabetaMotor1(void);8 p: f& z' u# [( I, x: t* g& k
- ' n$ p r# ~1 l: o& Y
- /* returns current Iq and Id values for Motor 1 */
m& M5 i8 R% V* D' N - Curr_Components MC_GetIqdMotor1(void);
X! T* s' T. y7 a' F8 Q - 6 @" \" c& y6 Y- n% Q! e# \
- /* returns Iq and Id reference values for Motor 1 *// S# o2 u6 h; c, h- P
- Curr_Components MC_GetIqdrefMotor1(void);
: y& _, f' i9 d5 r* ^) F( k, U- K
$ M+ s1 f- \, ~8 x- /* returns current Vq and Vd values for Motor 1 */
$ x, F2 o- m, @% F( q - Volt_Components MC_GetVqdMotor1(void);
& ^( z) X( u1 M. ? - 3 w" b7 s: A" t3 r) H( F7 i2 ]9 Q" k
- /* returns current Valpha and Vbeta values for Motor 1 */
+ H4 E1 b$ ]* S4 t9 R, ~ - Volt_Components MC_GetValphabetaMotor1(void);
2 P& ]# d; N& k
) |9 A. }. `* d9 O- /* returns the electrical angle of the rotor of Motor 1, in DDP format */
$ f: `0 m! A3 e - int16_t MC_GetElAngledppMotor1(void);
+ ?' e+ H6 b- R' L; G3 t* D3 w - # n2 R' a/ i# X8 d9 b
- /* returns the current electrical torque reference for Motor 1 */
3 y0 U% G& M3 g - int16_t MC_GetTerefMotor1(void);
* o+ Q4 }3 x+ R. h1 P. C9 x! k
9 |! Z( ]0 r/ b& ~" G/ G7 t+ r% Y- /* Sets the reference value for Id */0 ^' Q0 V1 {- k; t7 ^
- void MC_SetIdrefMotor1( int16_t hNewIdref );
5 W- |( F5 B6 E9 \1 U
4 t3 V* ~! m9 W0 o! [" E- /* re-initializes Iq and Id references to their default values */ J5 b$ }. T' d# w" Y. D
- void MC_Clear_IqdrefMotor1(void);& [* w+ I4 R% i
8 d8 l) c! j# r5 O/ q- /* Acknowledge a Motor Control fault on Motor 1 */4 f- K7 c6 I: R! x. ?9 f7 F; h
- bool MC_AcknowledgeFaultMotor1( void );
3 D! t& ?: Q7 ?+ z/ J
* @: ?& |& Y+ K2 w( S% G- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */. Z1 r4 ]/ d7 X/ ? _4 \/ ~1 ~
- uint16_t MC_GetOccurredFaultsMotor1(void);
" Z. \/ g; F8 k7 Q* V$ c( x7 e9 s
1 L3 S1 K0 q* x6 Z9 P4 H$ R2 C- /* Returns a bitfield showing all current faults on Motor 1 */, n: Z6 n( v) U: t0 q) C$ ^1 o# R% i
- uint16_t MC_GetCurrentFaultsMotor1(void);7 s8 e* H1 X! m% S, I1 W2 }
% ~" z; }1 G! n; J2 l( i U- /* returns the current state of Motor 1 state machine */' K. Q$ q" H2 K: h" T" F
- State_t MC_GetSTMStateMotor1(void);
/ B% ?- N" r) Y - + \8 I/ [* v+ b& V
- /* programs a user defined ADC regular conversion */
5 q) Z" K! Q$ D- X - void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);2 P% S- F" q) T7 N6 ~" q' ?
- ) G& \: o# W. {, ^2 `
- /* Returns the value of the last executed user defined ADC regular conversion */% O0 M% E* A& z6 k
- uint16_t MC_GetRegularConversionValue(void);1 ?9 e- }$ Z/ f" @/ c+ l' ^0 I" v; M
/ U/ [- p+ l& ]2 x& W; K3 F$ c5 y- /* Returns the status of the last requested user defined ADC regular conversion */
/ `/ C- c4 G# \1 d - UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)6 L# ^! E! j& K6 ]
- {* l* W H: |) ?0 z* I) y
- MC_ProgramSpeedRampMotor1(3000/6,1000);
% D ]/ V1 l5 r6 C. p- U- G! g! [4 y - MC_StartMotor1();! X/ M! W+ a: {" R
- HAL_Delay(10000);, ?" I6 Z8 x/ z& A# z
- MC_StopMotor1();" e+ N) \; K, p( o, N
- HAL_Delay(10000);) a0 ^, b/ ?' J p& C; Y* o6 N c6 c
- }
复制代码主函数添加的代码: - /* Infinite loop */
6 O$ O- _/ g$ W - /* USER CODE BEGIN WHILE */
; g! J) ]5 n# T - while (1) ?/ y$ l s4 B/ M
- {
1 [/ c$ R' T# ~8 a6 W - ; _5 @* C9 ~7 k
- if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin)) Z5 X3 \: p' b: `: |5 }) S( T
- {2 m+ f+ N) Q4 A3 W
- task_1();
) R' w: t4 l1 S* M1 @- ^. [: A - }4 h: d0 ?+ I$ P# N) z8 R
- else
) S4 V) h$ I- l- Z8 q - {
; Z8 j) O9 z, X. i3 I; I3 Y7 r - MC_StopMotor1();
1 o, N0 n# h9 k7 d - }, k. @0 t, |, }: {
- realspeed = MC_GetMecSpeedAverageMotor1()*6;
& }2 t9 O4 M' f. ^2 _* m$ x) C U - /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void). Z* }( c, n! {& J2 M5 [, k; Q
- {
$ |% N8 l" b5 I$ u) K5 r - /* USER CODE BEGIN START_STOP_BTN */
3 [1 t$ s- X9 q2 |. d# k! k0 J - HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);
6 v! E1 u. o/ f7 P$ z - /* USER CODE END START_STOP_BTN */; X$ k" A! j& Q. t- G: l; g3 `
- }
z' A' C$ c, D) l, e8 A, ?, t- A3 N
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------) I& L4 ~5 x/ L% k6 a. X: l! P
任务二代码: - void task_2(void)
( S$ z, |- c9 M, s% [' M1 f - {
$ R3 J5 o& [) Y0 F) z. u* [ - int16_t Speed_Kp,Speed_Ki;$ C. ]6 w/ C/ r% t
- MCT_Handle_t * pMctHdl;
6 t% J8 J% _, N" N; K3 e - MC_ProgramSpeedRampMotor1(3000/6,1000);' T- w/ G `. `$ ^2 R! c
- MC_StartMotor1();
, {0 W$ r. }% q - HAL_Delay(3000);/ o8 `& c5 X/ O/ j) F7 ?( \2 _2 A- L
- MC_StopMotor1();
5 h$ c; e2 \+ o* }& } - HAL_Delay(1000); 6 @. M S) D# Q; } ]
- pMctHdl = GetMCT(M1);
; x9 O. y" k1 [# } - Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
% ]2 |8 U$ v% L3 q$ e0 ]& N - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);/ m+ ~3 r& Q% t: m1 g% o9 \ D, i& s
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);! R/ V: O# r1 ~; w6 \$ u& o
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);- P$ d5 U3 e9 }3 M- r
- MC_ProgramSpeedRampMotor1(3000/6,1000);; K; d6 i8 X- t
- MC_StartMotor1();
s3 \3 E& K! @1 j: o - HAL_Delay(3000);
: F9 C5 e) z- h* w! X& s - MC_StopMotor1();. y# C+ B) Z! K! u$ o* h/ {1 n) r, Z
- HAL_Delay(1000);" {7 W8 P+ R r5 P1 v
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);/ k5 {6 ]+ }% m" W
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);6 I, a" b4 N) d8 i8 b x, ~
- MC_ProgramSpeedRampMotor1(3000/6,1000);
- p D1 ]8 P" D# F) S( S" D6 Q - MC_StartMotor1(); H' W; d. c& G
- HAL_Delay(3000);
- K* d$ Y, N$ V0 [9 y! q& n% O - MC_StopMotor1();
. l+ ~ [& z" X y3 j9 B; _1 @ - HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);
, K2 [7 A" S, Y- c) q) f8 N) Y - }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。
6 u0 z4 L$ l3 C& U+ V ' @0 W6 c; K% B2 j
通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。 ! y6 J5 q- m: w, e* J& T' r# j
我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。
- p: ], P) M0 B `7 w5 ] . M- d! e7 u% I! M: \
任务一和任务二已完成,欢迎大家留言讨论。
5 _9 k9 o, ~9 O( c* Y* | ; e. Z# m& W8 z/ O; w5 A& s8 `
$ _/ f0 S! z# N. C
* Z# V! D R) l/ O2 l+ J; V
9 K6 }% K# y( w: r' h; O$ }: [ |
/* Programs a Speed ramp for Motor 1 */6 t0 j2 S t8 p }. C* ?9 U
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快$ }) @8 S: `& I) w
& [6 r5 b1 v4 _6 p5 S
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题,还没完全看过来
回复20#和21#:8 w. l3 Z4 g) u* J' |4 D
User_label那个自己想写什么名字无所谓,根据自己喜好就OK
回复22#和23#: N* q$ @/ [" _/ C. L7 `
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做4 Q2 e+ p8 P3 {$ {% A5 O
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题