本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
, A. R" E P% Y- ^3 a$ b6 A( v' M5 q' U
经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 & [/ _( C! s, k! H
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
& `( \! k4 R1 e }* F6 U4 [ - /** @addtogroup MCIAPI; V! [' Y1 K* D, Q* f
- * @{! O; l7 P3 G7 C) b
- */
' B% t* n: q# \) d+ S; ` - 9 }2 b! M6 J* b$ _( `
- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;- [* n e, t) a, F% P5 |: ~
- # [3 H0 L4 B6 @5 D9 E
- /* Starts Motor 1 */
2 |8 ~8 J6 e4 d" D/ a - bool MC_StartMotor1(void);/ J: ?! o$ L) D) V$ f, u
# O2 C' N3 f& c- /* Stops Motor 1 */$ V+ Z+ d& b, y
- bool MC_StopMotor1(void);1 p. C( Q% E3 ?4 B8 v
9 `3 t- ]5 ^# T- c9 g- /* Programs a Speed ramp for Motor 1 */. j, p4 L1 @" f/ i K* P8 n& A
- void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
/ a; i( ~$ U- j
8 U) \ y2 K" s! B* n1 r- V6 D- /* Programs a Torque ramp for Motor 1 */
$ W( g* O9 P1 |( U+ Q) s3 I/ ] z3 x7 N - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );
( C$ w$ w1 ]) y( q; e: Y8 O/ [6 M
4 L+ G$ z, m! `5 |. b% ?- /* Programs a current reference for Motor 1 */
6 O$ |0 `+ ^' r' K t @ - void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );
& ~5 z; F3 z( U+ f* E, V& `3 {4 D
: A. {0 f2 w. r5 r. O- /* Returns the state of the last submited command for Motor 1 */" L7 e8 i6 B k% z! |6 A: z0 C( B
- MCI_CommandState_t MC_GetCommandStateMotor1( void);
- k7 f' L) D! r4 _
P( T* i9 Y) n, v+ V" _- /* Stops the execution of the current speed ramp for Motor 1 if any */
0 b" j/ `. W- Q4 ^) H - bool MC_StopSpeedRampMotor1(void);
) j* n5 ] v2 j- w% p
& n- `) w, f* ?) }- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */' ~1 _- d+ T4 C+ r, j
- bool MC_HasRampCompletedMotor1(void);& O: J- a2 b5 X; M$ f2 i
8 P: Z" d8 k* N- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */6 B. w: n- ]( e4 V
- int16_t MC_GetMecSpeedReferenceMotor1(void);
# J6 h, t$ \0 Y5 U
Q4 N8 w3 q$ n; o- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */
3 t- K/ C7 n# L7 q, G- p9 y - int16_t MC_GetMecSpeedAverageMotor1(void);
- e4 z6 R( x5 F) b. S1 M - - b- W; l/ T9 n% _3 w
- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */0 n/ R2 } C5 T
- int16_t MC_GetLastRampFinalSpeedMotor1(void);
# @8 X; c; \, g1 t4 r7 K - 6 ?4 v+ x% s+ K$ y; v# D
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */
0 m( r' _, L% P3 j. A' O - STC_Modality_t MC_GetControlModeMotor1(void);
* @: j8 U; W7 @' _4 g7 a X H( k) o
]. {+ m0 B. W% e- /* Returns the direction imposed by the last command on Motor 1 */
' v4 l$ U: ^- H+ p- {, c- r - int16_t MC_GetImposedDirectionMotor1(void);/ ~6 d# E8 }. L
$ M6 [! H+ i' v6 m, G' o- /* Returns the current reliability of the speed sensor used for Motor 1 */+ x' ]# S6 @# K- ~- }. I
- bool MC_GetSpeedSensorReliabilityMotor1(void);
( M- L% k; S4 g6 H% J - ! l {) ~0 U, c/ i/ P
- /* returns the amplitude of the phase current injected in Motor 1 */
( v7 S- ?; p. B: h+ h% z; Y% i - int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);7 A6 t" _+ I+ j4 O& Y# [6 q$ y. ^
; [9 @; w. u; u2 ]% [- /* returns the amplitude of the phase voltage applied to Motor 1 */
. n- n' l* e4 l1 ] ?* c" E - int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);) s' m, q: [. P4 z- l( ]. P
- 5 s5 u7 Y6 V; p" y
- /* returns current Ia and Ib values for Motor 1 */$ j, m3 K+ a8 y9 S! l+ \" j0 f
- Curr_Components MC_GetIabMotor1(void);
' @6 M" b, K8 ~0 ?% f - ) H. d( M3 N {0 d, s$ } j' s9 i- S
- /* returns current Ialpha and Ibeta values for Motor 1 */
) Q! \' o/ b8 a - Curr_Components MC_GetIalphabetaMotor1(void);
# ~- L0 `# T5 g8 D% @; k
+ [/ y/ i- H5 T) Y* y- /* returns current Iq and Id values for Motor 1 */
3 d7 l5 l4 d9 `- k - Curr_Components MC_GetIqdMotor1(void);
6 C4 W4 P2 B' q+ S# ]) j
$ ?$ N1 M0 n% X& Q! _* t: y- /* returns Iq and Id reference values for Motor 1 */
M3 I1 ?! k& V - Curr_Components MC_GetIqdrefMotor1(void);) _1 V+ f7 a; o W
- 9 M' C1 I" x$ ?+ |+ J
- /* returns current Vq and Vd values for Motor 1 */
T8 K1 V& A% a. A - Volt_Components MC_GetVqdMotor1(void);
" N1 V0 v) X# L8 B" \# o
2 n! D6 j' j# C) n$ x [- /* returns current Valpha and Vbeta values for Motor 1 */) s; ~* l+ i. [# f
- Volt_Components MC_GetValphabetaMotor1(void); M5 @# p6 ^. |3 g
9 ]6 |3 z( M# v/ p& x- /* returns the electrical angle of the rotor of Motor 1, in DDP format */4 g: J- A4 j8 I+ i/ X
- int16_t MC_GetElAngledppMotor1(void);* \7 P' ~, I, g0 H2 A
- * a( }7 U1 k- I
- /* returns the current electrical torque reference for Motor 1 */
1 E: ~1 i: G) m - int16_t MC_GetTerefMotor1(void); i2 O! n2 S. Q5 q5 V& H6 _
@" k- ]0 H# h- /* Sets the reference value for Id */) ]2 |0 J' k3 u. F. R4 p
- void MC_SetIdrefMotor1( int16_t hNewIdref );
+ |+ {# V, z2 }! a' H4 y+ L8 O, t - 6 _! H. W/ s9 @: t3 W6 N) [
- /* re-initializes Iq and Id references to their default values */4 q7 [1 i3 M4 c# E7 H
- void MC_Clear_IqdrefMotor1(void);
$ j2 R4 I! s+ F8 y( R1 I3 A
- k1 H, |9 ]( I* ?$ F- /* Acknowledge a Motor Control fault on Motor 1 */, B3 V3 h6 J. v# Z9 }5 n
- bool MC_AcknowledgeFaultMotor1( void );+ D. ]. o" [8 q. b
- [, }7 H, }# W7 ]4 x
- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */
( x4 M, @% Z5 R# u) | - uint16_t MC_GetOccurredFaultsMotor1(void);
3 t, j* `9 h* j5 U' K
, ?% n% U- D% z; x. X- /* Returns a bitfield showing all current faults on Motor 1 */
4 v' Q: |% v, C! G5 `& F9 n2 { - uint16_t MC_GetCurrentFaultsMotor1(void);3 E3 F5 j# F# F( [, M6 w
- # L1 C! T1 e% A% T! ^# `% C
- /* returns the current state of Motor 1 state machine */
' }) T1 E) Z4 H! q l" r |2 X - State_t MC_GetSTMStateMotor1(void);
2 g# y0 q- m$ \ - , ?. ~7 z# g4 t/ I. P1 S) [1 k
- /* programs a user defined ADC regular conversion */
: c0 w0 `$ u- @0 a" [; p - void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);
2 T0 q2 X& e# r - 9 A, A, T H$ L( D. F5 ~
- /* Returns the value of the last executed user defined ADC regular conversion */; ^3 q- h1 ?' @6 {- ^7 t
- uint16_t MC_GetRegularConversionValue(void);' \- d; o1 B. {$ x: V
' M: d0 O5 Q2 p+ [ P- /* Returns the status of the last requested user defined ADC regular conversion *// a9 l" w0 T+ r x. l! p3 m
- UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)
/ P- K( ?" p. \# C1 a - {
/ R0 V1 I4 L6 J6 f+ Y, y - MC_ProgramSpeedRampMotor1(3000/6,1000);, b& Y5 G) I& h+ p: W
- MC_StartMotor1();
% W) y0 s# v! ]0 T6 C8 H - HAL_Delay(10000);! d1 s9 T, L# j
- MC_StopMotor1();
; A; G$ S$ H1 E, d" F% b8 W9 l, j - HAL_Delay(10000);3 @( K8 C5 t3 R2 p5 h Z: t- K
- }
复制代码主函数添加的代码: - /* Infinite loop */! ?2 ? k* |1 b
- /* USER CODE BEGIN WHILE */3 ]/ x6 k! j" h# c9 ?5 T' S
- while (1)
( ]# X9 S' E" r* d6 `! p# p! H& | - {
* O7 E# [; [6 n6 J' T) r$ f9 I -
% l3 m' A1 J" R - if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))
* r8 v* Y; F' y( S( E - {
9 \+ E* R. U0 Y8 Z9 ? - task_1();
; t/ h. V& R" ^# A - }
5 x% D. l0 b2 y9 H - else# p' N" T6 P" N8 O! w: [7 G
- {' h; R' Z) Y9 f( h }( V0 i
- MC_StopMotor1();
" ~1 U! _+ R. h - }' ~7 {) c. }. J
- realspeed = MC_GetMecSpeedAverageMotor1()*6;2 w/ x2 X/ B3 V4 l9 C
- /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
" A# M5 J3 m; X" Q' N } - {
7 w0 U2 |- t7 ]" @ - /* USER CODE BEGIN START_STOP_BTN */2 ]: E2 ~( O( ~
- HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);! P5 ]$ {" k3 N, M' Q. h
- /* USER CODE END START_STOP_BTN */ G/ H) B! L0 e% U. Q7 p1 J
- }
: ~0 @$ ?3 r: x2 Q, l
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------) B' e" I) L' e1 W! ^
任务二代码: - void task_2(void)
) t! G& h4 ? m4 f5 O: b8 V8 ] - {
! l9 z- |; l- K* l; ~' r8 R - int16_t Speed_Kp,Speed_Ki;
& p* P0 E+ w8 N E - MCT_Handle_t * pMctHdl;
5 s, m. A. V5 W4 a. e - MC_ProgramSpeedRampMotor1(3000/6,1000);
* ?+ X. y2 h, @6 { - MC_StartMotor1();
3 P; q$ x! U8 f$ E. i1 U7 m% k - HAL_Delay(3000);
w/ B1 `3 P" z4 [; z3 O0 f - MC_StopMotor1();
5 E9 B% s$ B/ |6 f; W% h - HAL_Delay(1000);
$ ^+ A# u$ A) P1 O F5 I - pMctHdl = GetMCT(M1);0 ?1 Z6 y7 C# G! o$ A% X
- Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
2 B* F# S% e& Q- l$ w) F - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);) j+ {: l, f) X
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);
8 X- @% ^( ~0 r: d - PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);$ X5 _/ f( g6 i) v/ @
- MC_ProgramSpeedRampMotor1(3000/6,1000);
% Q7 `5 W" w$ p, z - MC_StartMotor1();6 g: v9 [3 |- R, o: [( U/ j1 v
- HAL_Delay(3000);
- \! @$ T1 T( n$ a - MC_StopMotor1();0 C( I; O+ j5 O; _. M
- HAL_Delay(1000);: }/ X- p+ e q' O0 @
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);8 _ @" |2 ` A
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);
& y: t1 E6 b% o6 M0 m+ |8 _8 Z - MC_ProgramSpeedRampMotor1(3000/6,1000);
1 M* h" I4 p' P - MC_StartMotor1();* e6 x& M0 h# ~; u! j
- HAL_Delay(3000);
. D- o: j. X: |+ D. z3 H - MC_StopMotor1(); . ~8 \/ a; ~& T A# z" I
- HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);
$ U+ \/ `0 ^% F6 W1 O+ n; | - }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。 : e% t! @+ n. T
n( Q" u- @' T通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。
7 A( m. n# ^( T$ `( c% C" [ 我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 2 Q/ ^* M4 S4 [. C8 s
, i4 ~/ R3 D+ Q' U4 F- _" C任务一和任务二已完成,欢迎大家留言讨论。9 h' S1 \! U' m8 ?3 n% c
T7 W4 Y, j5 |% }3 ^
$ w$ Y! k% P1 P6 T1 i, Y' N( Y6 \; _
: Q; G; q! F: h$ M" v
|
/* Programs a Speed ramp for Motor 1 */
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快
. Q9 L4 _% c9 [* r S% c
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题
回复20#和21#:
User_label那个自己想写什么名字无所谓,根据自己喜好就OK0 t( f! G3 d/ ^5 S
回复22#和23#:
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做3 `6 @5 [9 C5 x- N; ]$ d. F
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题