本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
" ^1 R% K5 {# Z* @5 x+ R. P! H/ i) S- H
经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 0 b) F2 ^. p4 M6 y6 o
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
& }* X' n s5 ^6 K - /** @addtogroup MCIAPI3 @& L; R* a$ J3 B( p B9 {
- * @{8 @) d4 l+ ]1 b% x1 v @
- */
8 ^" ?2 ?: c# h7 E" ]6 |
6 G! f) i7 e8 [9 ?8 L, s6 A- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;
2 ` M, Q$ `3 Q - 6 F0 d6 \: `% ` h
- /* Starts Motor 1 */
% y% v! R1 p% w3 Z - bool MC_StartMotor1(void);- X0 U# `6 l- z' [* d# G
, T+ E# M& c. M& d- /* Stops Motor 1 */
$ o7 Y8 p: O( W - bool MC_StopMotor1(void);
: }3 Z( v3 T- ] - 2 }# L1 u% _* ~& I t' o4 g
- /* Programs a Speed ramp for Motor 1 */
9 W+ C' d9 V5 M - void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
, k- t% n7 G3 W/ ?* C
6 }$ Q: M& [% k- /* Programs a Torque ramp for Motor 1 */
8 V! ]9 K4 x& h2 d. K7 x( B; j+ w - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );
5 n% c9 l, ?& `8 o5 F4 v - 4 W8 Z0 r8 r6 i# w
- /* Programs a current reference for Motor 1 */
8 h2 k) L5 m) e: L! G1 k; K, U - void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );" ~; n. L( V9 ?2 @; @
- ! Y6 S: B0 Z. c% e0 H
- /* Returns the state of the last submited command for Motor 1 */
; y2 G! e$ {" |5 ~ - MCI_CommandState_t MC_GetCommandStateMotor1( void);- N9 P1 I, r- F3 W3 _$ u" f* o0 ^
- ! z5 M9 d% v2 z5 o" f+ U
- /* Stops the execution of the current speed ramp for Motor 1 if any */' `0 n. P" C6 F* f7 x
- bool MC_StopSpeedRampMotor1(void);) \# t* w8 @8 r# a% ^$ O
6 T9 ]7 v( a& U5 E) ^0 Y/ n, \& U- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */& g/ V5 _# n( N# n7 U% | C2 U
- bool MC_HasRampCompletedMotor1(void);, y4 s" Q) [3 F
- 8 m+ ~. f. U: W7 A6 R# f0 w3 R' {* `
- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */
& y4 l% X7 m. V6 p3 C - int16_t MC_GetMecSpeedReferenceMotor1(void);" P8 o# U* _, d" d" _+ d
; b [1 k) l( u: T. V" C( x5 v- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */
]3 t- J3 M! y3 f N& C - int16_t MC_GetMecSpeedAverageMotor1(void);
9 ^5 F+ o8 c6 ~2 ^1 q
4 S. n G2 y/ T' h- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */
' Q' u; G$ U2 v1 i - int16_t MC_GetLastRampFinalSpeedMotor1(void);2 ^( I1 h# v5 I; d" Z! ~- o
- 9 B$ W! [7 m+ ?! F! x0 v( V
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */
& k$ W* y) v5 T0 C9 E5 G - STC_Modality_t MC_GetControlModeMotor1(void);
3 j* H1 T. s4 y& j5 w
7 @, Z3 j4 E' Z1 L1 |& H1 Z' X( n- /* Returns the direction imposed by the last command on Motor 1 */
% U; @; { y' {$ k! P - int16_t MC_GetImposedDirectionMotor1(void);0 \2 Q% u8 T. b5 q$ v
) ~* T% }# g9 H* d- /* Returns the current reliability of the speed sensor used for Motor 1 */3 u0 ^/ Z# H) |% W B
- bool MC_GetSpeedSensorReliabilityMotor1(void);; s7 a* y% ]3 x, k
8 e" z* K# I/ ~/ {) R5 H- /* returns the amplitude of the phase current injected in Motor 1 */
1 I$ g& t. Z: N0 T; C- n - int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);0 e7 M$ Z" g# z5 x+ k* ~
- f! c Z, g: c% w- /* returns the amplitude of the phase voltage applied to Motor 1 */5 u& n, F s- k1 p6 Y5 r
- int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);6 t) Y7 m; i# D% f8 l
- 8 {# T7 F2 v/ t, u7 t5 t; Z$ z
- /* returns current Ia and Ib values for Motor 1 */
6 ^0 |. _1 J; K0 a" `8 L0 [ - Curr_Components MC_GetIabMotor1(void);
! `# W( i* d, R) v. {0 m" v - 1 K; L+ B8 [& Y
- /* returns current Ialpha and Ibeta values for Motor 1 */7 X# c" x8 {2 v5 X3 G9 s
- Curr_Components MC_GetIalphabetaMotor1(void);
, Q& }: s7 i% o! Z9 K - 7 B) P. I& Z1 m
- /* returns current Iq and Id values for Motor 1 */
1 ]. ^9 H" m) w - Curr_Components MC_GetIqdMotor1(void);
* \7 H1 [% J* G8 @$ R$ t
- v" o+ K) }" {8 s$ u4 K B9 u- /* returns Iq and Id reference values for Motor 1 */7 s- W/ x7 ]& g0 {0 N& U
- Curr_Components MC_GetIqdrefMotor1(void);( `. w% `" V9 l
- 3 j. w2 M# p' H8 I% H( `
- /* returns current Vq and Vd values for Motor 1 */8 c( G/ L: Z5 e* C
- Volt_Components MC_GetVqdMotor1(void);4 a' c" G [. E
- ( w) v2 f+ j3 ^0 F! ~; @
- /* returns current Valpha and Vbeta values for Motor 1 */2 g; ~+ B' ]( ?2 v& W; c& T. b
- Volt_Components MC_GetValphabetaMotor1(void);8 ^8 f v) u3 H3 v& @. C0 e
- + W( ?$ H7 U/ [; S: ]% I% d! C
- /* returns the electrical angle of the rotor of Motor 1, in DDP format */. ?( K. y( |/ y, C6 _3 L
- int16_t MC_GetElAngledppMotor1(void);
& h8 `$ K7 x9 J9 i
$ {" e* l' K# R- /* returns the current electrical torque reference for Motor 1 */6 x8 h) f1 f( v& S
- int16_t MC_GetTerefMotor1(void);
$ K8 f8 {1 T& b% a% @
: M% O1 |1 C3 N# D K& l1 p3 S- /* Sets the reference value for Id */
/ n: V8 N9 `+ \; F' | - void MC_SetIdrefMotor1( int16_t hNewIdref );7 r K z4 u h+ m3 z/ x) E6 ?2 S
- 9 `' T* T3 }2 h; f+ z* C5 P
- /* re-initializes Iq and Id references to their default values */
9 @ }$ W/ c& q/ N v - void MC_Clear_IqdrefMotor1(void);6 x I3 ^; S7 U3 C$ @ D
- 5 m6 H9 t& I7 a. |9 a8 x: ^
- /* Acknowledge a Motor Control fault on Motor 1 */
2 m; K4 H9 f) Q) _" V. r9 s. c, p - bool MC_AcknowledgeFaultMotor1( void );
6 u- I* o7 ]2 U* {' e' e, E' Q/ ]
& c8 x0 @& M0 ^" k# O+ E- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */. |) h' x5 ~. S" C! K* B3 P
- uint16_t MC_GetOccurredFaultsMotor1(void);. e7 R: y- ~$ {- Z) }4 y
: _' `0 N3 @, A7 x- /* Returns a bitfield showing all current faults on Motor 1 */9 F# r' L" _) _* Y+ Z+ t4 }2 t1 k2 s; f% E
- uint16_t MC_GetCurrentFaultsMotor1(void);7 `4 M0 E7 v, N5 W0 T
% X* c) n2 a6 v7 y0 T$ R5 O- /* returns the current state of Motor 1 state machine */0 O2 k- K5 S' d" i2 H
- State_t MC_GetSTMStateMotor1(void);
; `' C) y( X- A' \
$ Q" Z9 I9 V9 v3 ?/ p+ X0 y- /* programs a user defined ADC regular conversion */
% Z& W- e! H7 s# N( R7 I; U" P, S( D - void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);
8 s) J' J- g y) O; E+ ^ - 3 D/ a8 D2 ~$ G) k' |6 p& G
- /* Returns the value of the last executed user defined ADC regular conversion */' Y8 \! A* C2 a0 Y# v
- uint16_t MC_GetRegularConversionValue(void);
9 ]0 G( M8 C, a$ h3 Q2 ` - 4 E9 Y/ n: R* O/ ^! T" o: q
- /* Returns the status of the last requested user defined ADC regular conversion */
: R3 Y9 q, d c! J- [ - UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)
$ Q) J$ |: K& T - {
* k1 t7 j/ Y9 l' w0 c1 N! ? - MC_ProgramSpeedRampMotor1(3000/6,1000);
. g! p9 w1 c, W8 z/ i - MC_StartMotor1();
7 P# H' S( {8 H - HAL_Delay(10000);4 m5 g- @6 Z/ H5 w* O! ~
- MC_StopMotor1();
v5 g3 ~2 [: S6 k. ?: q" X - HAL_Delay(10000);) E7 E* w4 k. g7 I
- }
复制代码主函数添加的代码: - /* Infinite loop */5 q! I: _( E3 t! H8 w+ p' d
- /* USER CODE BEGIN WHILE */
$ R9 T$ N/ r3 J! C/ w0 \. r - while (1)
J4 P1 \/ O% d3 u - {
) M1 Z2 l& s# S! J' }3 A' {# S - # y2 k9 h: l k0 ?* p
- if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))
1 [ f: T r0 O; ?3 S( O - {: q% Z& P8 I# j! M u6 e0 p
- task_1();
# ]$ v8 s7 O- _7 S; ~( S - }: s, K+ a% M$ C% @4 ?0 b) ]* ^
- else
: q; Q5 m+ i( r) z3 e2 A( n( R+ N - {7 @! M0 \! m, G1 L+ P6 N
- MC_StopMotor1();
+ p% \' \; \, L. H3 I" H/ @& C - }
8 {) t/ q2 Z X% d' y& F - realspeed = MC_GetMecSpeedAverageMotor1()*6;
5 Q: C1 p& n0 N1 O* _: A7 J - /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
' h( A8 [% G/ V; P - {9 X* Q6 z0 D5 k/ l% Y2 Q f
- /* USER CODE BEGIN START_STOP_BTN */
3 ^% E0 ~) ^' e7 ~1 q. j - HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);5 w7 s# Q! o. u" ?* U J
- /* USER CODE END START_STOP_BTN */
$ G+ |0 e7 C7 d6 A/ c9 W/ T7 F - }
* {: `) v) Q/ M( B( @: c
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------. c5 ?* Q$ P5 s/ }* B3 Z
任务二代码: - void task_2(void)7 C" m" o1 f0 Z6 B2 w" k
- {% j! [# u6 J9 ^" J
- int16_t Speed_Kp,Speed_Ki;7 q$ z" O# y1 K1 D3 M
- MCT_Handle_t * pMctHdl;$ f9 @4 v5 i/ H3 l
- MC_ProgramSpeedRampMotor1(3000/6,1000);$ {1 j5 Y' J# E5 t1 q# O X: \
- MC_StartMotor1();
; d3 }; m0 O" D$ b - HAL_Delay(3000);0 E% C( O- J; b/ B) v
- MC_StopMotor1();
, S! z; s( v6 d, N0 k! j+ k - HAL_Delay(1000); % i/ }5 W7 o3 t3 U+ ]1 N
- pMctHdl = GetMCT(M1);
+ \: I( o7 c* a' k2 C% S - Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
! | \" g7 h _( a8 W - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);& w/ c/ V+ G$ W: ]- f; N) R
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);1 M# ?+ B4 ~2 N8 u6 w4 Q- B: B
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);+ G! g( I* V& N! u2 C( c* \5 [
- MC_ProgramSpeedRampMotor1(3000/6,1000); ?( u/ q" F6 u9 i
- MC_StartMotor1();
, N$ `* N& J L+ d' K. H - HAL_Delay(3000);
+ F. z9 i3 z6 i- g& _ - MC_StopMotor1();! ]& |9 u7 W' L+ ^ o; x
- HAL_Delay(1000);' g, r& U* Q& x3 T6 ]9 e6 {/ Z9 L5 i
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);
3 J' Q9 p; ~9 j/ J. D - PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);
. y# k! j, A1 G0 [5 \; X - MC_ProgramSpeedRampMotor1(3000/6,1000);9 Y( n2 c/ `. }2 I/ y; u8 d! @( x# t
- MC_StartMotor1();
8 ~( ?0 o' j I - HAL_Delay(3000);4 y" W# b; n0 ]& k: ]* @ i9 N4 o
- MC_StopMotor1(); 7 m1 s$ t$ N; g8 a1 T0 ?! [& o( t
- HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET); L6 `# i/ M7 k- a8 T [, L
- }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。
8 E3 T( n5 y! x7 G6 K6 }% X
. L" [* I; m- l0 [* J5 G通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。 ' h5 s# j4 u. u
我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 J9 D$ J" X- h
- o0 @# p- V2 k; P任务一和任务二已完成,欢迎大家留言讨论。( ?& N0 u9 z% i- U8 H- C
" J: L, D' H) n2 X2 a
, J. u" J6 g; P E' g
7 D, G5 Q Q, X' C7 ]9 t1 m' ]1 m8 {
1 ~0 y# C: L( d7 i
|
/* Programs a Speed ramp for Motor 1 */
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );) g# N$ I! v; G; h1 A2 R* f/ t
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快
* L( T6 C5 t" X6 T, X5 y6 E
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题,还没完全看过来/ B* }: p) f3 m) Q3 k/ |1 l* J
回复20#和21#:
User_label那个自己想写什么名字无所谓,根据自己喜好就OK
回复22#和23#: O V! ^+ C, |5 _# c2 } K
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题