本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
' e, a- |4 S& A' w0 H' u- ~( q& E- i
$ o) B5 M: W9 [经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。 2 A1 ?9 m1 f2 D: L; z. D' Z
拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
& Y/ s3 [, H- o4 h) X - /** @addtogroup MCIAPI5 h& i" \ o1 }& j; R, J1 X
- * @{
/ i: v k& s( v - */
" b7 U' {! g8 x! L* i# |( z0 O - ; S$ }3 Z! A1 R0 k
- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;
9 V6 U3 M( V' e8 f - * Z+ ^! Z. L+ k% i1 f
- /* Starts Motor 1 */* W$ Y) H/ B0 @
- bool MC_StartMotor1(void);
# P9 c6 }$ B% h" [$ j4 `7 W( G - + Q- n1 g8 {4 p3 s# m* s
- /* Stops Motor 1 */
3 `$ B: j2 o( T, C - bool MC_StopMotor1(void);
& e2 M5 E9 d( E
9 E2 }0 i2 \% Q4 q- /* Programs a Speed ramp for Motor 1 */
% ?! ^& H- q+ H+ g* }4 t - void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
5 _1 Q9 Q! J, F$ B6 R5 j$ c. V6 g- s
+ T, f( o3 e" A! I$ j- /* Programs a Torque ramp for Motor 1 */
# }/ n: l+ n. J b1 ~1 v - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );
* ~; h: h3 k2 ` d3 D2 |1 {$ o
' Q6 T7 C8 \3 T5 W- /* Programs a current reference for Motor 1 */& e0 b0 e s& G& X ^* `
- void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );
4 U6 l& ]! d$ B' u: M" C# O
2 \1 p( D8 C8 P6 Z L- /* Returns the state of the last submited command for Motor 1 */$ |0 ~* `2 z2 c) Z( _
- MCI_CommandState_t MC_GetCommandStateMotor1( void);
: G, ^" \4 J$ c+ h1 q3 q" j - 0 W8 M r, b: ~( U% s. l
- /* Stops the execution of the current speed ramp for Motor 1 if any */2 ?* r( _0 H. _: \
- bool MC_StopSpeedRampMotor1(void);5 W0 t+ K; k( P% F2 v# ^
3 w, S' f2 p7 m r' G4 B8 k- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */6 i, l0 f. d+ ^9 Y
- bool MC_HasRampCompletedMotor1(void);
& J; H n, N% o* R - & o2 W" t3 J& S! ~! b! l
- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */
/ N6 e# W f& h- | - int16_t MC_GetMecSpeedReferenceMotor1(void);' z$ B+ G, k4 j' @
- ; P! T* S; X5 n6 `
- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */; L+ W$ `# y/ |+ ]
- int16_t MC_GetMecSpeedAverageMotor1(void);
4 z! @6 n6 `: R
" f4 o% `% s8 G" x) J) H; @' S- @- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */
! i# t7 X8 g. x9 f' J8 l# T - int16_t MC_GetLastRampFinalSpeedMotor1(void);
3 w3 r2 Q) l1 J2 m+ P+ x - % U g2 m( C: g! Z e; t/ R
- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */
- W# w$ Q) H% ^; ^! L6 w) |9 K: l. G - STC_Modality_t MC_GetControlModeMotor1(void);
: a* L* o1 z4 b+ A3 y
: h8 x0 j' j4 _5 @8 X3 o- /* Returns the direction imposed by the last command on Motor 1 */
T& p" `) U6 P% l1 K - int16_t MC_GetImposedDirectionMotor1(void);
9 d1 j% Y: L1 D: Z Y' b- G8 V0 \ - Z) u3 u$ }8 ?% U
- /* Returns the current reliability of the speed sensor used for Motor 1 */' }* \$ }; ~- o- q
- bool MC_GetSpeedSensorReliabilityMotor1(void);8 W" u+ `2 { {$ Y
- " p9 v5 N' x1 v- c. L: P+ \
- /* returns the amplitude of the phase current injected in Motor 1 */
( s; Z. _$ Y0 } - int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);9 z' P1 l2 `6 O1 s, i
( G9 d8 r+ X( A5 H# g( b- /* returns the amplitude of the phase voltage applied to Motor 1 */
0 j: G: g3 L& Y4 H6 f1 V - int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);
# g' ?+ b3 e6 [9 [) X
* v' v, g+ R! } u- /* returns current Ia and Ib values for Motor 1 */
, B' j/ D; a+ }; ?: _ - Curr_Components MC_GetIabMotor1(void);
2 F& O* x6 A8 T9 |1 k# Y - + \2 F7 v6 v* D) C# D' i
- /* returns current Ialpha and Ibeta values for Motor 1 */' v s# `! P! q# y# j
- Curr_Components MC_GetIalphabetaMotor1(void);) z+ c2 O& m# H4 m" k( V
- 2 q6 s. ^/ M7 m3 t* d
- /* returns current Iq and Id values for Motor 1 */
8 Q& T0 U" N9 N) g3 E - Curr_Components MC_GetIqdMotor1(void);; h& ^$ l. b* r: ?
- ; Q7 Y9 P5 ?! Z% m5 Z
- /* returns Iq and Id reference values for Motor 1 */5 J9 _( W L$ }' d5 M6 n. U
- Curr_Components MC_GetIqdrefMotor1(void); n3 d T9 ^; m7 Y3 x p7 [* g
- / q# d r& B5 M/ @
- /* returns current Vq and Vd values for Motor 1 */( P: G# A, f3 c% D( O' y
- Volt_Components MC_GetVqdMotor1(void);5 b/ J$ F% v( l
- 5 ~* m% A* E& s- f6 P: `, K- ? R0 i! `
- /* returns current Valpha and Vbeta values for Motor 1 */: W L+ U# [! e. ~4 Z/ A
- Volt_Components MC_GetValphabetaMotor1(void);1 E% D% j6 I* N$ j1 m
- - X; b' Y& |* K0 c U
- /* returns the electrical angle of the rotor of Motor 1, in DDP format */( p5 V. U' D: I* m; G
- int16_t MC_GetElAngledppMotor1(void);0 f4 X! t) H @# @* ?- Q! f5 {
! }. F M ?* B$ |0 J- /* returns the current electrical torque reference for Motor 1 */
! C" X3 B$ _- W& d1 Q% Q; p - int16_t MC_GetTerefMotor1(void);
: |% x, u* l' L( K# C
/ p! v% d! p9 f7 Z+ @( T- /* Sets the reference value for Id */9 p4 S3 m! }6 q9 b
- void MC_SetIdrefMotor1( int16_t hNewIdref );
; B3 f2 F L9 S5 p2 \ - ( n/ S& s% ^( E) l. _. a" S9 {
- /* re-initializes Iq and Id references to their default values */
: f) B+ Y( W9 n3 ^# X - void MC_Clear_IqdrefMotor1(void);7 D- F* q, x, M7 N+ z8 _
9 Z8 s. r! O! ~' W& ^' s! I- /* Acknowledge a Motor Control fault on Motor 1 */
, H( p: m+ }; A4 s a P; S - bool MC_AcknowledgeFaultMotor1( void );
+ M( h0 p/ x% Y3 s! X' y' |- h
0 i4 J7 D3 c! O# a9 v; s* E- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */
: k+ ?- y+ G% |6 i2 L - uint16_t MC_GetOccurredFaultsMotor1(void);0 t" O- t1 u8 _. H3 U1 P
- $ V3 _+ x9 i3 C. \
- /* Returns a bitfield showing all current faults on Motor 1 */
( P/ q3 F; S% v6 {6 ]1 p; o- V - uint16_t MC_GetCurrentFaultsMotor1(void);0 r. c/ `$ b& Z) n1 ?. V8 B( n
1 X. U1 m8 ?6 s( V5 d5 Q( L- /* returns the current state of Motor 1 state machine */
- _) ~5 |" ~0 h4 T1 p - State_t MC_GetSTMStateMotor1(void);
# R f7 _* u/ l/ ^) P) w" R. \
C" F* T' ?9 W. M) \) w7 f9 J! k- /* programs a user defined ADC regular conversion */
2 D# M6 ~& H* U/ { - void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);
7 S4 l5 ^& R0 u9 e - @" D( C% T: o
- /* Returns the value of the last executed user defined ADC regular conversion */ s0 X% F" j, p& N
- uint16_t MC_GetRegularConversionValue(void);
" {5 k0 @. L, G/ p0 Z2 y3 |$ m - 5 Z7 O) b) h2 U( I- ?* D* d% P5 F
- /* Returns the status of the last requested user defined ADC regular conversion */1 P E/ X/ c1 ?
- UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)# r( n. Z" c9 X0 `3 t+ v" B9 f
- {
6 n# U! W& k7 k* H' [5 a - MC_ProgramSpeedRampMotor1(3000/6,1000);
% r m& r! C% E- q; y4 s - MC_StartMotor1();
- @5 L$ t4 M' a5 d- C - HAL_Delay(10000);
[ V7 I( }& @. k* _8 ]* m4 L$ X0 T - MC_StopMotor1();
- }' E# ]9 F6 `! U. y9 k } - HAL_Delay(10000);
; w; d" C% r) n - }
复制代码主函数添加的代码: - /* Infinite loop */
4 ` G7 o8 x" j+ B+ E- a0 E - /* USER CODE BEGIN WHILE */3 p' c4 _! j6 X$ y
- while (1). J* j' w, u" g$ q
- {
% o5 X& v' W% I -
/ S- x! @ S% o Q* k - if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))
# M4 Y+ V1 s; M; P+ _: w - {
, y. K& L4 ]- U, i7 J! H - task_1();
6 v. A3 i" h, r - }
! S" |5 W! G9 ? - else+ G) a+ e2 E* B
- {
9 c! W% }+ M# G9 k. D' u# R2 Z - MC_StopMotor1();# H) U7 M; u: |3 e) k4 f( o
- }
: o( r8 N7 H; z# K* B) a0 F- k - realspeed = MC_GetMecSpeedAverageMotor1()*6;
0 k. q0 t) T5 K [3 g. t$ y: n - /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
3 A8 _6 V; H5 S - {9 g! T {5 b9 a8 a" y6 b
- /* USER CODE BEGIN START_STOP_BTN */$ q4 b3 \" b* `; A* r+ ~
- HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);
8 S0 r. A; I. G/ S - /* USER CODE END START_STOP_BTN */
- g! _# `* ]; a7 ~$ u - }; y# d! q! A9 H) Z: _! J8 y
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------' O D( }$ j$ o4 G2 o8 T
任务二代码: - void task_2(void), k) I1 p) a s
- {! w! l8 R2 ^% T% C f7 `
- int16_t Speed_Kp,Speed_Ki;2 `/ e, c* T, O8 ~1 r2 P; f
- MCT_Handle_t * pMctHdl;
+ y+ F8 W* g0 ]* a8 J& @: [ - MC_ProgramSpeedRampMotor1(3000/6,1000);9 Y- o5 L" x! C5 T, h
- MC_StartMotor1();- i" m V3 [3 G! s% i" ^6 r4 y
- HAL_Delay(3000);
# ]! [$ j# a2 M. c, A8 k& Y - MC_StopMotor1();
: \4 H" R1 |9 \! f - HAL_Delay(1000); & Q3 r1 A, `/ v$ b2 s: P8 L
- pMctHdl = GetMCT(M1);
; `- T) Z: @ |9 e6 r7 \ - Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
0 U* ]" i" U; U* G- {1 }, \( N) o9 n - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);8 @+ W9 O: p) G, V- h9 W, y
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);
! i# q; ?5 o, G8 k - PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);
$ f6 u* m4 h/ x; J2 k - MC_ProgramSpeedRampMotor1(3000/6,1000);
) @/ q* {+ L7 ~6 d, Q' d3 F - MC_StartMotor1();8 ]0 `2 C8 B K. d3 X0 ]
- HAL_Delay(3000);* A. ] I- h- l
- MC_StopMotor1();
/ Y$ ?- {; m3 n - HAL_Delay(1000);
p2 `9 e6 U/ Y' @9 l& g7 J! p* s w - PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);/ g9 [" y+ ~( L9 P
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);
9 s+ q+ Y% O/ a5 d" O9 T8 o0 y - MC_ProgramSpeedRampMotor1(3000/6,1000);
- m4 Q# L* G7 E7 f, p - MC_StartMotor1();
& d2 @% _" z" C+ P - HAL_Delay(3000);
# }3 p! U. q; B; I! N5 m. t% `3 L2 f - MC_StopMotor1(); ) [2 i$ n$ h/ s! [+ a' n. G. ` u
- HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);
4 l" Q$ X" R* [. u+ p' g1 I) c - }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。
9 Q# q) ~9 R/ m
1 K* T# ^1 m1 A+ K5 s. \通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。 + V: q5 C* _# l+ n, E5 \ {- D
我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 3 t& m" a" B" \1 t( f9 C
9 G# v7 Y( [$ l: {6 _+ I2 Y任务一和任务二已完成,欢迎大家留言讨论。5 a/ d, C7 [' {7 p% h6 Z
1 |5 B3 ~/ B. j I7 {
: n9 J+ V9 @' ~; v8 r
) e% p& [5 ]: T/ G7 j
" a# L% } b. J! W- c; c
|
/* Programs a Speed ramp for Motor 1 *// p: |, \4 c1 K% h, ^ U$ a6 w
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );( E" @& _7 Q5 @) n/ M
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快; P' }; q4 Y0 W/ b0 Y: u4 z
7 x0 c8 Q; a7 g! `
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。" }( ^+ J! d. I0 M- o: l: m& l
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题,还没完全看过来
回复20#和21#:
User_label那个自己想写什么名字无所谓,根据自己喜好就OK6 k+ V3 w5 n7 J5 X+ U
回复22#和23#:
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题