本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
1 t# l* U6 G, h! c7 }" K# S C( F# T1 q2 |. ?
经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 " h, h) R) J* s% f
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
6 ^6 [( V5 v8 n3 e - /** @addtogroup MCIAPI
7 {# o/ Q, l9 g" H) _8 L3 l - * @{1 b5 S6 K0 ~$ t ?/ d
- */
4 i) q L7 a3 ?* P; T - ' a9 V5 b) o. J' u
- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;1 K8 z6 ~' @8 E# E
- 8 h# [! ^: w4 h! k, F
- /* Starts Motor 1 */
( i* U; q6 m+ J - bool MC_StartMotor1(void);: ~6 w( `" `2 \! r
2 d u" \1 }1 D: y) _- i$ O- /* Stops Motor 1 */
, A7 c) B N2 w$ c _ - bool MC_StopMotor1(void);- s6 ]7 h2 X7 _$ E, @
- 0 d& F% i' P, C
- /* Programs a Speed ramp for Motor 1 */
0 f/ e4 |& r5 v0 M7 y% R; a, x - void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
1 K5 C* ^1 k8 Y# s- o - 7 i! [8 t$ R- g3 q
- /* Programs a Torque ramp for Motor 1 */
3 J4 x) r4 w+ K; S( g$ K - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );2 C& r" H4 W+ R. \% g1 D; R9 i
- m' v. j g0 Z5 s
- /* Programs a current reference for Motor 1 */0 Q, C6 }9 k( t+ j) w( R& |
- void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );
/ R5 R& W0 G2 Z# t& k R
! z% J$ Q1 n+ Y) k& i8 P4 I; X8 M- /* Returns the state of the last submited command for Motor 1 */
8 }% i5 x7 ?9 K% X8 T% x- t- K - MCI_CommandState_t MC_GetCommandStateMotor1( void);6 w9 |6 s H* k% u' E, N
- - ~. n! I) o& w- _8 s' }
- /* Stops the execution of the current speed ramp for Motor 1 if any */ y; t0 s9 |) A. V; F. M- l( O9 n2 q
- bool MC_StopSpeedRampMotor1(void); o7 `- _0 u4 c6 ?4 m% U/ }/ [6 E
- ( E, ]: S* C: I4 [3 i$ L7 O6 @
- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */
# _! o( o- n$ n U3 U, I - bool MC_HasRampCompletedMotor1(void);
1 }% G% I# n: w5 L
O8 e4 D$ K$ K) ]' B- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */
$ j, n8 P' G5 }* x - int16_t MC_GetMecSpeedReferenceMotor1(void);. J& P1 k5 h$ S/ K+ }4 e. `: E
* I9 W& a0 `8 D. I- K9 ]- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */
0 _% T/ y7 }0 q/ u; n7 z0 ~ - int16_t MC_GetMecSpeedAverageMotor1(void);2 f i# u5 ^4 `% C0 y4 `1 y
- $ c' @$ p/ C5 z
- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */+ {" s* [) j( @) O( v x& f
- int16_t MC_GetLastRampFinalSpeedMotor1(void);2 b/ k+ ?# t. B5 q( g# j% I" s, g& N
- 8 X& Z8 H$ ]5 g7 i6 N1 p. f2 T
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */' U: t2 J8 O. X( F
- STC_Modality_t MC_GetControlModeMotor1(void);$ Z( ^( B' T# C! O J+ Q
9 }: U* j4 @( f8 C" m- /* Returns the direction imposed by the last command on Motor 1 */$ F/ V# l% e2 ^( B" N
- int16_t MC_GetImposedDirectionMotor1(void);9 J5 B# n) A( ~) [3 J7 Y
& P0 t* O+ r. c, y$ m* I# r- /* Returns the current reliability of the speed sensor used for Motor 1 */4 D8 X0 e, b: V" H5 @
- bool MC_GetSpeedSensorReliabilityMotor1(void);' ~ }. r* i! u8 y- C! F9 {
- & k0 X F" O5 h3 i# ~8 B
- /* returns the amplitude of the phase current injected in Motor 1 */) F8 [7 c4 _5 }$ F2 T; D$ p
- int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);7 h" u' H' I2 A; ^7 C
- - T0 M1 k1 D' k* f- b2 E8 a* T% E) C% @5 P
- /* returns the amplitude of the phase voltage applied to Motor 1 */$ @* P$ t4 y5 P. @1 o* F
- int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);# A& ~0 k& Z7 R7 ?) G8 F9 a# R
- " v0 g3 o, r$ U. O5 `
- /* returns current Ia and Ib values for Motor 1 */
6 Y8 M% f% q3 V) F( O/ y$ U' u - Curr_Components MC_GetIabMotor1(void);
3 V# ^3 h& g/ F+ Y
4 v N' z# T5 H" o; v8 N- /* returns current Ialpha and Ibeta values for Motor 1 */& r( f" {" @- e9 L, v
- Curr_Components MC_GetIalphabetaMotor1(void);0 g& u% V' A l/ V0 u% {
- - T1 j8 l3 C$ w1 d7 j
- /* returns current Iq and Id values for Motor 1 */
# J; i; y1 V( q/ B/ }7 b* L - Curr_Components MC_GetIqdMotor1(void);+ H" ]* s, ~+ T+ b8 s$ s
& t6 e h* d% j3 F1 T) l1 v- /* returns Iq and Id reference values for Motor 1 */
6 J* s" ]3 o0 _ - Curr_Components MC_GetIqdrefMotor1(void);+ G9 n7 R' u, G
+ C9 T* b3 O* R$ k/ x6 d- /* returns current Vq and Vd values for Motor 1 */
; }* x! s! a" m6 w9 Y - Volt_Components MC_GetVqdMotor1(void);
0 s. s+ ~; ^6 G) w2 o/ g* B( B - x/ ^9 ]* ]" C& s$ e& }$ `
- /* returns current Valpha and Vbeta values for Motor 1 */7 c0 o) ^" p/ A4 R
- Volt_Components MC_GetValphabetaMotor1(void);6 K+ _" `, |( R& F x7 g
/ V+ o6 @/ G! _: J ]: r- /* returns the electrical angle of the rotor of Motor 1, in DDP format */
8 H, y+ k! K _9 m o - int16_t MC_GetElAngledppMotor1(void);4 J* n; x" H% \2 ^7 ]. p
- ! @7 G8 }7 d/ Z4 v; N+ v1 b
- /* returns the current electrical torque reference for Motor 1 */
+ ^# P5 j5 q, M$ z t! s9 ? E - int16_t MC_GetTerefMotor1(void);: Q! s( b! E0 @
- ( n d# V. o8 B, F
- /* Sets the reference value for Id */
' ]$ }' a0 d% u1 V% p. | - void MC_SetIdrefMotor1( int16_t hNewIdref );
% T: `: N$ X7 m: |$ |7 s0 c& Y) X
w, K* J; G3 q+ r3 Y* x- /* re-initializes Iq and Id references to their default values */
6 o' F. U% w- [% W - void MC_Clear_IqdrefMotor1(void);( y) O; {9 } `: t/ _ l4 L
- . [! b: k& G( y$ k6 x
- /* Acknowledge a Motor Control fault on Motor 1 */
" o) U5 h3 Q* q9 V1 M6 i( E* [ - bool MC_AcknowledgeFaultMotor1( void );
1 M. `; o6 |, W
; |/ w1 T1 p; Y( F- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */
8 `% Y3 G3 Y9 g - uint16_t MC_GetOccurredFaultsMotor1(void);
3 C, _7 Z. N* H/ b" A6 Q0 m D Q7 G - 3 w2 c9 k3 h, Q( i% O
- /* Returns a bitfield showing all current faults on Motor 1 */# o7 q' f0 }( v, W5 S2 S
- uint16_t MC_GetCurrentFaultsMotor1(void);2 A- `+ c' ?2 g, T' b
/ b* g9 V; M' t+ g6 C+ u1 m4 R7 n- /* returns the current state of Motor 1 state machine */9 s$ A1 p0 e/ J1 B
- State_t MC_GetSTMStateMotor1(void);5 K. @! ^8 `% c0 J* j5 E
- ( b6 S. y. k. I# \
- /* programs a user defined ADC regular conversion */
; g- G; o' x3 o1 q% z' W5 Q" k - void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);$ j+ e5 G& O7 Q/ W
' W) C: [ \7 A3 P- /* Returns the value of the last executed user defined ADC regular conversion */2 m2 b# o( Z1 V) |# z. X4 C
- uint16_t MC_GetRegularConversionValue(void);# P! H5 a+ X4 ?/ r
- ' Q* e& F; _- @3 e9 C8 V C
- /* Returns the status of the last requested user defined ADC regular conversion */6 ` @' A: P% Z$ u
- UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)/ U- P! r" T5 \. l: P
- {
. W; J- V9 x* D: Q0 t - MC_ProgramSpeedRampMotor1(3000/6,1000);
# n7 e2 G5 }, S& F0 F# I$ T- g6 I - MC_StartMotor1();% v s5 c; }$ v2 c- C
- HAL_Delay(10000);
( F9 M8 Y% j9 C: C; l: s - MC_StopMotor1();0 V. _2 s) y( X. `% X) W
- HAL_Delay(10000);
7 h8 ~* x% t- Q' A% v9 b/ e$ G$ k - }
复制代码主函数添加的代码: - /* Infinite loop */! u7 k' ]2 A5 G K, C
- /* USER CODE BEGIN WHILE */
2 ~( t& d" u9 ?- V; F# g4 V; S - while (1)' v+ d3 `: f2 y0 J* v: @$ w4 |
- {
: e3 `+ ]% D1 i$ n7 T8 G - , L/ U) B+ T9 X: X% w
- if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))6 B7 m" T/ g$ @& X4 i' ]- {' O; l
- {
: t8 z3 }. K: q9 z8 r0 I5 [ - task_1();
4 S1 S7 e% p- w v% | - }% F S) ^9 y$ F+ W* o
- else( q4 B* W$ N- p: J9 F: N5 B v* B
- {+ m" {3 q' }" V5 Y9 p
- MC_StopMotor1();
( L* b8 v! i3 Z n6 n3 J- t- A# C - }+ }3 K g% d I# E1 x$ m1 j2 k
- realspeed = MC_GetMecSpeedAverageMotor1()*6;
, r8 H$ r* |( u+ y5 ^" z - /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
; J; r7 a, s( `0 N' q' O - {, Z2 A/ Y7 y& [( Z) e
- /* USER CODE BEGIN START_STOP_BTN */: C* F `" l+ ]7 o) P
- HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);* Z1 U- N e1 a- ^
- /* USER CODE END START_STOP_BTN */0 h8 F8 U% e N! A3 O# s
- }
% Y" ^7 t6 u* W- t, R8 ]% m
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------
) h2 o e5 C( {4 ? 任务二代码: - void task_2(void)* q& J' `3 M9 O$ r1 k
- {& g% J2 C @. q: j- G
- int16_t Speed_Kp,Speed_Ki;
! S' h4 u6 n6 f5 P- W - MCT_Handle_t * pMctHdl;* I9 n6 I7 S2 p% E( ^
- MC_ProgramSpeedRampMotor1(3000/6,1000);1 P9 Z3 c& g. V2 ^1 \; ~8 }
- MC_StartMotor1();; [" e! _) ?: ^" v# g
- HAL_Delay(3000);* B3 U0 u' Z7 e% T. o
- MC_StopMotor1();
2 K2 Y6 U6 v- r - HAL_Delay(1000);
3 H' e8 O( d' }! p - pMctHdl = GetMCT(M1);8 n7 d% c @5 L+ Y. |: L7 G
- Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
% |( F; T+ H. ~- J( S$ d - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);0 ^, z0 L4 d$ C: D# K7 }1 m8 |
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);2 |, k" v! ~+ |8 t p
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);
/ z' O; g+ X) U9 p8 ?3 x6 i - MC_ProgramSpeedRampMotor1(3000/6,1000);/ b9 U& ]8 S5 B7 k
- MC_StartMotor1();
7 L( j( C' P+ C/ Q - HAL_Delay(3000);0 N4 T5 ?7 Q# }& ~. c% H
- MC_StopMotor1();0 h; ?$ o. z- h4 P6 c! C
- HAL_Delay(1000);
% |: p5 J( Q( H& v - PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);
0 i! A4 w4 b$ R5 ^4 P* W - PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);
/ j% C/ s+ p4 `( Z - MC_ProgramSpeedRampMotor1(3000/6,1000);
& b5 i* q, T+ D' m. j - MC_StartMotor1();1 a G3 t2 D1 j3 @* n
- HAL_Delay(3000);
7 i0 L+ \! T: M" m' M - MC_StopMotor1(); 8 C8 `1 a& Y* r: w; i
- HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);! m1 T0 h+ n( d" W, [3 Z
- }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。
9 O" H6 R" s. s6 K) o# ?5 x
" C( a# V" x" W6 E/ S7 e通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。
0 N( b% O1 g% S; V/ M/ k 我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 * ?' Q U% L# u) ~' S9 U+ o( W
' [5 K) m0 f: C, i/ Y+ P: P任务一和任务二已完成,欢迎大家留言讨论。
, C) B; {/ Z$ f/ K: S! x# H
2 I5 ?9 h' q$ w2 r+ }+ J, r, X1 K3 H! _
/ P3 M( O' ]# I r4 s K; M) b) E, H+ a% ]
|
/* Programs a Speed ramp for Motor 1 */
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快8 c) v7 d- G7 } \; I1 {
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题
回复20#和21#:4 G) _; p5 u3 `2 M9 ?, b* {: o
User_label那个自己想写什么名字无所谓,根据自己喜好就OK
回复22#和23#:
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做2 l. B. e7 J4 ^6 U! g* c6 G
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题