本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
" M2 l( _7 Y- |9 D7 h
7 d( Q/ X' ?9 ~4 E经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 & E5 @( C7 G1 Q- [
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。; F3 O$ {; F2 o2 J7 G
- /** @addtogroup MCIAPI
7 U9 u# J8 z5 r+ D7 X2 S! L/ K - * @{$ D2 g% x5 H1 D. _4 f+ c& Q
- */8 j+ z6 k5 `5 v G% ^ s- O' }
- 8 l8 C7 d: Y2 ]
- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;, }: l, z% g! Q$ B: a7 f& ~
- 6 x: B* Z$ A& d% U- M
- /* Starts Motor 1 */
1 G8 e. g% N( k7 ^, a" Y - bool MC_StartMotor1(void);
2 N8 V0 p# U4 \- b - ' Q3 o- m! B2 `1 p; t
- /* Stops Motor 1 */
. B' z4 `* y' M! d; k" A- d - bool MC_StopMotor1(void);, _1 E2 v# H5 Z, A2 q1 Q9 i
- ( L( C+ s+ U# S5 ^: m
- /* Programs a Speed ramp for Motor 1 */9 \0 u& Q' E+ P1 W
- void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
+ `% C! P% _$ S( p' t: j, O1 y - & v( O2 O, Q" p: T6 V, O5 A; \( C( p
- /* Programs a Torque ramp for Motor 1 */1 s7 Z, d- i1 ^, G) ]3 {! r- Y, L
- void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );
$ r/ V8 c3 x+ n+ `0 H
4 G# `5 E" h3 P4 H- /* Programs a current reference for Motor 1 */7 v5 S+ I5 k7 t9 M& ^
- void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );: [! G3 B) q h2 ~
) P; e1 r! j/ b/ B- I9 U( Q. B% B0 B+ A! x- /* Returns the state of the last submited command for Motor 1 */
( S" i9 |7 X( c4 S - MCI_CommandState_t MC_GetCommandStateMotor1( void);
4 d ]' v; r) i
8 o9 q8 q2 Q# G- /* Stops the execution of the current speed ramp for Motor 1 if any */4 {- ]: r ?4 P' o2 J3 `( `, A
- bool MC_StopSpeedRampMotor1(void);+ y4 R6 _( v- K1 c. ~
- : A5 q+ I; Z/ a; A- z4 D2 ?
- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */: |; p# h- b1 _& j y$ i W: M$ G, x
- bool MC_HasRampCompletedMotor1(void);
4 _6 S2 m& |" X - % ~( S6 E2 [1 w4 k
- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */
* U' r, a; @) M3 P$ Y8 j - int16_t MC_GetMecSpeedReferenceMotor1(void);; G+ R; h! u) n- X" R
6 o% Q5 A* O7 R( f0 Q4 F- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */8 ?$ R6 l( k5 j$ Q8 Z5 D$ F
- int16_t MC_GetMecSpeedAverageMotor1(void);
5 d- \: z+ k4 @/ T - 7 {! F# v7 a4 B, F
- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */
) r, t9 @, O n J3 N4 h% V - int16_t MC_GetLastRampFinalSpeedMotor1(void);
8 P0 g1 k) u- h1 A - 8 [& Z2 y$ t0 i) F! ]- i
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */6 N) y A8 ]3 s. D, ^
- STC_Modality_t MC_GetControlModeMotor1(void);; p- O; T$ h5 C' v4 G! C
/ u0 x0 C }4 [% M0 W- /* Returns the direction imposed by the last command on Motor 1 */
! z( T, @4 a4 O) m2 e. x3 T8 Y - int16_t MC_GetImposedDirectionMotor1(void);
. c: {$ \6 w' B& p! t1 V' t" n$ x7 k' L- f - 1 m% J X; F1 F* b; }4 ]
- /* Returns the current reliability of the speed sensor used for Motor 1 */
/ ?5 L1 a) j+ X" ?" H! v% j - bool MC_GetSpeedSensorReliabilityMotor1(void);( o# z8 Y& C( k7 N7 [5 Y$ S+ ^2 a
- . P8 s/ G. G% Z- d6 b
- /* returns the amplitude of the phase current injected in Motor 1 *// Y3 b$ Z: ^' I$ J
- int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);; [) i1 _9 d6 v/ U. q2 o5 z
- / |1 x+ J( @8 i5 ]; `* {7 C; U
- /* returns the amplitude of the phase voltage applied to Motor 1 */. Y* n$ }2 z' h3 p* M' w+ q
- int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);8 }" z# u. T M
- . p' g8 d) o J q2 |% Z
- /* returns current Ia and Ib values for Motor 1 */! t; m7 [/ j2 v5 M0 D. R
- Curr_Components MC_GetIabMotor1(void);
" _6 ?2 n$ t$ ?) {8 d5 d1 P - ( ]4 b' {. u! s$ [
- /* returns current Ialpha and Ibeta values for Motor 1 */' k# F, I+ h8 L+ a' X' v+ L
- Curr_Components MC_GetIalphabetaMotor1(void);
! i; u: K- w ^' I- s7 g/ R( @
$ k9 n' T# x* Z3 S1 f- K- /* returns current Iq and Id values for Motor 1 */
4 i' w$ m3 H% `* t - Curr_Components MC_GetIqdMotor1(void);
+ E, X: A W8 H3 ` Y9 l- S - 7 g* J& B. Q! ^
- /* returns Iq and Id reference values for Motor 1 */
/ V0 L: M4 E" r! o: A - Curr_Components MC_GetIqdrefMotor1(void);
; S# A# E( b' g8 Q$ M
0 `' b& X: R0 ?: A' _# V- /* returns current Vq and Vd values for Motor 1 */- z: P% k$ w6 O# V _
- Volt_Components MC_GetVqdMotor1(void);
1 J7 a5 @) `& X7 s5 r
# m% ~2 x- A8 f, i* c# N( m" ^& G- /* returns current Valpha and Vbeta values for Motor 1 */
: `! Q% V9 Y5 D0 K/ j- M5 q - Volt_Components MC_GetValphabetaMotor1(void);: w+ c4 Q5 W1 }# B2 Z
- 0 h/ c- B! l7 Y
- /* returns the electrical angle of the rotor of Motor 1, in DDP format */( m% ]5 A2 V9 A1 {
- int16_t MC_GetElAngledppMotor1(void);' o- K: V& k5 C; _0 x0 k, h
- 6 L0 z5 \! i) z. B- S/ y8 _
- /* returns the current electrical torque reference for Motor 1 */2 \- i" U& G+ y3 M2 O
- int16_t MC_GetTerefMotor1(void);- l" [6 |! j% M
9 _' B; ?$ L8 U+ x2 h# J- /* Sets the reference value for Id */
; A0 y. X0 B$ W6 z - void MC_SetIdrefMotor1( int16_t hNewIdref );
" K4 I% G8 s9 w - ' P1 k C8 V, M% S% |9 h5 f
- /* re-initializes Iq and Id references to their default values */# M9 v( U c, ~7 V1 B" z0 D
- void MC_Clear_IqdrefMotor1(void);4 m( g* c/ Y; j# L
/ V6 E) c. |0 \$ P5 V y2 r- /* Acknowledge a Motor Control fault on Motor 1 */9 @% n' w7 [7 f! c. ~
- bool MC_AcknowledgeFaultMotor1( void );1 P* X% j8 F1 s# ]* _! [
5 `" \" y& e- H: d3 e- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */
+ q4 f8 ~3 o$ j- O - uint16_t MC_GetOccurredFaultsMotor1(void);; K- `+ P( l- v" r8 Q
& f5 @* _. F. c- /* Returns a bitfield showing all current faults on Motor 1 */
, Y) x+ S& |2 p4 O! \; e0 ` - uint16_t MC_GetCurrentFaultsMotor1(void);
a: j! _: D) N - $ J5 `1 c- n& ~' K4 c( {
- /* returns the current state of Motor 1 state machine */" N/ q; m6 @; v: D. s1 ]- `
- State_t MC_GetSTMStateMotor1(void);& u: z2 L8 {8 n) q) w" _! s
- : K. F4 k8 \8 B4 \+ k4 Z
- /* programs a user defined ADC regular conversion */+ ]1 [' z" {7 o! f
- void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);
* U, B; i6 ?# _ - % d0 ]( t& j" i
- /* Returns the value of the last executed user defined ADC regular conversion */
+ |% }) e$ d- b& R4 c' M - uint16_t MC_GetRegularConversionValue(void);& |! E" s8 {+ B0 p
- E& f& f! r; a! ]4 `- C
- /* Returns the status of the last requested user defined ADC regular conversion */
, D; t. @7 ^1 A' u. I3 E, I - UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)
8 S& r$ U# e. i% P* P& V. v - {
, L! I! |1 m! s8 Z - MC_ProgramSpeedRampMotor1(3000/6,1000);
1 V4 F4 [$ {. Q# H - MC_StartMotor1();; p1 a/ H( g3 {' A2 s8 P$ n& z" c
- HAL_Delay(10000);
5 ] C Y- c% x3 @5 t - MC_StopMotor1();
' H/ M/ E" O. z) U5 { - HAL_Delay(10000);
+ z8 }1 b4 S* i/ Y7 y+ g - }
复制代码主函数添加的代码: - /* Infinite loop */9 |. B A, r7 T2 G# M( E/ P
- /* USER CODE BEGIN WHILE */
2 s$ o) j# k/ [# ^7 ~ - while (1)
! A& q' }7 ]$ u$ D - {9 [7 x$ u. q) r; D7 ~/ L
-
; z: g: J1 I B8 H. e - if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))
: S7 x0 o8 _/ v$ X - {
, c2 M1 W; R# ]3 n - task_1();
" W( g# ^/ m, L O) S1 b# X - }
$ Z) i3 D& `% S5 d8 u - else% n( d; m# \, n9 w5 ?% M1 i
- {
4 J) c( j% k' t9 v - MC_StopMotor1();
- O1 _% h6 a0 }2 D. c g - }
u, p' }8 w, q- x$ l1 n; v - realspeed = MC_GetMecSpeedAverageMotor1()*6;3 S" T: @6 ~7 L+ y2 ~- u1 a( v% I
- /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
5 L% R; x" _% w! @ M - {
+ K4 o% Q. s p - /* USER CODE BEGIN START_STOP_BTN */
5 ~3 m9 U+ N( d; ~; d P - HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);: \# I. i1 o! `0 W6 u( Y+ N
- /* USER CODE END START_STOP_BTN */
2 q) C/ r$ T4 @3 l4 Z! i - }! }# Q0 b* x% H2 g2 ]4 I
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------
+ f/ G& {+ ?7 y9 q- b 任务二代码: - void task_2(void)% l* u0 z; r4 u0 ~
- {
/ b4 z* f! n& C, m( K# \ - int16_t Speed_Kp,Speed_Ki;/ q) j }6 \8 v& G2 ~1 ^" w0 B/ y
- MCT_Handle_t * pMctHdl;1 q( o0 G' D5 B4 u% f7 F8 }# Y
- MC_ProgramSpeedRampMotor1(3000/6,1000);: O5 r! H6 O" K7 g
- MC_StartMotor1();; E Z9 c, i$ c! E& N
- HAL_Delay(3000);6 }/ {$ B1 q2 R
- MC_StopMotor1(); T: y( v: b; w0 X' \% M
- HAL_Delay(1000); , p0 c, `) v2 d1 ]: `# P5 k
- pMctHdl = GetMCT(M1);
3 c# d9 ^+ w' ` - Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);4 U( n/ C& r% q9 p5 B B. ~% |3 D
- Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);4 D% b" s0 _; [! v
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);
# g4 G4 v3 p3 b- s - PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);9 |; Y5 l1 J+ Y$ D$ B3 i
- MC_ProgramSpeedRampMotor1(3000/6,1000);
) c) [- {* S" \5 c7 ^ - MC_StartMotor1();" Y2 S- h8 R9 f+ L: m
- HAL_Delay(3000);& H; r, \( Y$ y. {, P2 Y- K
- MC_StopMotor1();' ?$ O# b$ ]" W9 S
- HAL_Delay(1000);
2 t/ y8 q) O- [) o! \0 O3 ?9 Y- d - PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);9 V2 I& v/ \+ F" e
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);: ^+ W, y* s7 t4 w. j( o
- MC_ProgramSpeedRampMotor1(3000/6,1000);
0 I+ Q/ }& Z7 i! q5 }6 J - MC_StartMotor1();
. t7 d- B q9 Q - HAL_Delay(3000);
2 S% L/ r# {' ? U - MC_StopMotor1(); ! v% L( C( S; I# U$ C
- HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);) @5 C, g U+ ~, ?; j2 B+ Z$ t
- }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。
& T( r% A, m v- w: i& X) s
9 R6 ^; y+ W' A6 [通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。 * W3 K, b% C. ]1 K3 I- g
我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 4 o/ r, u$ Z. J' J+ S! W* p$ b
; G7 h4 f( ~5 l h: z' x5 H
任务一和任务二已完成,欢迎大家留言讨论。$ W8 | @* O' P( I0 g% G
( R- L3 L) _7 c! t* x8 M) M+ r* S" t- @4 ], i9 g1 E
' [# E/ X8 Q# u3 m6 X; L
9 u- R; g g8 j |
/* Programs a Speed ramp for Motor 1 */
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快
4 ]8 m, S y( ~" i. J- v
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题,还没完全看过来
回复20#和21#:
User_label那个自己想写什么名字无所谓,根据自己喜好就OK
回复22#和23#:7 _8 F2 y/ m0 l- p; ]% ~, L
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做# z0 a1 b8 m0 f0 ^; [
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题