本帖最后由 子曰好人 于 2018-9-2 10:21 编辑
9 \3 R1 k2 C% B; B& X( o2 @& F1 ], h j( I" H3 O& ]" C
经过前期的准备,可以使用电机套件完成一些实验任务了。 首先是任务1和任务2的要求: 任务一和任务二基于workbench生成的代码来做并不难,因为代码里面提供了很多api函数并且做了很多软件上的保护,可以放心写代码,硬件不会那么容易损坏。
0 [! f& S/ g: Z6 s8 Z4 t3 ~( Z+ q拿到一份陌生的代码除了了解我前面几篇帖子所说的内容外,在开始写代码前还需要了解api函数。我们可以打开mc_api.h看一看workbench都给我们提供了什么函数。
! n# w( |% [2 C- ]; {5 Z - /** @addtogroup MCIAPI0 |. f: J" U# i& q$ O r Y1 Q
- * @{- P# n+ T( C& p* I
- */, d! [' [7 e8 P5 ]. F+ q3 R* `$ B
/ c5 g- r1 v, C4 k- E" A+ m- typedef enum {UDRC_STATE_IDLE, UDRC_STATE_REQUESTED, UDRC_STATE_EOC} UDRC_State_t;
! L5 q: t9 w2 ^- i
8 R& S4 f6 M* Q* D7 P- /* Starts Motor 1 */ N5 b- `, F+ K/ E
- bool MC_StartMotor1(void);
* R- \; f. b5 K: G9 |
( m6 D0 B! n5 c2 I) I' x- /* Stops Motor 1 */
& c& y% G# \5 e4 \2 z, l0 h - bool MC_StopMotor1(void);
1 r9 A* g6 X# K& I$ W! t5 V g
' ~' e$ L- q. [+ A6 N) M! f6 v2 s- /* Programs a Speed ramp for Motor 1 */. Q' b2 X! E) g6 n
- void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
% }/ }+ h O" G& h0 J' u. W
% D, P$ P4 q! _# g0 x5 A- /* Programs a Torque ramp for Motor 1 */
4 u. a y6 }- ^- i$ N$ v5 r - void MC_ProgramTorqueRampMotor1( int16_t hFinalTorque, uint16_t hDurationms );
9 S6 f' ], O$ x) T3 U& s9 D - : \2 ^3 e1 u6 t# E8 b3 \
- /* Programs a current reference for Motor 1 */
: J! T7 b( ?% M# h- r0 E+ n - void MC_SetCurrentReferenceMotor1( Curr_Components Iqdref );
/ @* N' \7 |9 [. A) i& K9 h, g - 4 D/ W( {6 T- I8 h' a" ~# |
- /* Returns the state of the last submited command for Motor 1 */
% _; w2 G7 f$ L$ W - MCI_CommandState_t MC_GetCommandStateMotor1( void);
; S) O, q* r) p5 ]4 c0 D# f' k
- }( o4 i9 G, ~- /* Stops the execution of the current speed ramp for Motor 1 if any */
. e7 Z; Z, g1 @ - bool MC_StopSpeedRampMotor1(void);
$ b H8 i! V! q$ o1 k' i9 T
* a$ T0 I. ~* Q: X3 ^8 {- /* Returns true if the last submited ramp for Motor 1 has completed, false otherwise */
1 B- Q' ?7 A3 q3 n, U- `9 _3 ^ - bool MC_HasRampCompletedMotor1(void);6 R- N& G' W* c, @
* V( h# Q! Q3 p& P1 L- /* Returns the current mechanical rotor speed reference set for Motor 1, expressed in dHz (tenth of Hertz) */
7 E" j% ^) V. F' O - int16_t MC_GetMecSpeedReferenceMotor1(void);
- w1 r# |; g. f' r- F9 ^6 G
) b4 P+ x! Z' t! |. U- /* Returns the last computed average mechanical rotor speed for Motor 1, expressed in dHz (tenth of Hertz) */
6 A; ]6 ^7 R$ v4 A! A - int16_t MC_GetMecSpeedAverageMotor1(void);
6 }% y) [5 G: d - " l% a! r+ s j+ Y" O' o
- /* Returns the final speed of the last ramp programmed for Motor 1, if this ramp was a speed ramp */* C# Q% j& e( Z" ^2 T: j, @
- int16_t MC_GetLastRampFinalSpeedMotor1(void);
+ g: ]( R5 d+ G% B7 i0 N- p
( q" t9 S+ v4 U2 F. S- /* Returns the current Control Mode for Motor 1 (either Speed or Torque) */
, i, ^# A! {1 Z+ r: ^" H" r - STC_Modality_t MC_GetControlModeMotor1(void);
4 c/ O8 U+ T. W2 ~4 z6 G: V! K+ D
% L0 o0 o, @/ {9 I& V, d' r- /* Returns the direction imposed by the last command on Motor 1 */
) s! p% Q% f& k7 y - int16_t MC_GetImposedDirectionMotor1(void);
' v1 e+ n) N; T% J/ m# ?8 P
7 u& i; n! k9 \( v4 ~" f2 f9 u- /* Returns the current reliability of the speed sensor used for Motor 1 */! d. d8 ?. i1 ^4 H. R% L7 J8 _# L
- bool MC_GetSpeedSensorReliabilityMotor1(void);
- B; y. @* N2 A) [ - * N/ A- d- x3 D. p% ?- Y1 Y9 e
- /* returns the amplitude of the phase current injected in Motor 1 */
% r: V1 W( p5 }& Y( v$ G( c - int16_t MC_GetPhaseCurrentAmplitudeMotor1(void);/ _: o/ q; }& G/ U y. I
; a. v* U0 L' G( \- /* returns the amplitude of the phase voltage applied to Motor 1 */8 [/ I4 V4 p- d( I
- int16_t MC_GetPhaseVoltageAmplitudeMotor1(void);. c1 z5 u: C! s$ L; i( p+ k4 D
- 1 X4 Z! N( d& k/ B# O7 L' [! s% M
- /* returns current Ia and Ib values for Motor 1 */7 I1 ]+ C% A4 z# k/ |
- Curr_Components MC_GetIabMotor1(void);/ l {1 c+ D! Q) ^/ u
2 k- H. o! W4 u# M( e C- /* returns current Ialpha and Ibeta values for Motor 1 */
* }4 O8 A$ v# c - Curr_Components MC_GetIalphabetaMotor1(void);
# `9 L' T% s3 U" k9 S+ b - - s, N6 K. v3 L( s, E
- /* returns current Iq and Id values for Motor 1 */
3 w0 {) N" i! w2 ^+ F! S - Curr_Components MC_GetIqdMotor1(void);
6 U0 e; L8 A: k# I9 G
/ [, A, A" F6 u; |: W J- /* returns Iq and Id reference values for Motor 1 */
& v/ g6 j! L) [+ X7 a H/ u - Curr_Components MC_GetIqdrefMotor1(void);. k, ~0 j" ^$ L
" i6 `) C7 g: S' C& |- /* returns current Vq and Vd values for Motor 1 */
1 R0 h* \! t* y7 O, d5 ^ R1 Q# f - Volt_Components MC_GetVqdMotor1(void);
! @; ^9 }" ^# e$ W7 i - ! k5 ?- u4 ~ f p. c( {
- /* returns current Valpha and Vbeta values for Motor 1 */
4 W3 L8 z* f5 [ - Volt_Components MC_GetValphabetaMotor1(void);5 a3 O# A P' A, A( y
! m5 j" m* J* d l: S( D9 ^8 l- /* returns the electrical angle of the rotor of Motor 1, in DDP format */- w; `( G# O j* @# F, p4 V7 K
- int16_t MC_GetElAngledppMotor1(void);3 J: `4 u/ L& f
- ( p# I' o) L* W) |5 l: M
- /* returns the current electrical torque reference for Motor 1 */9 W5 A- l% j) e3 o2 c2 G$ m
- int16_t MC_GetTerefMotor1(void);0 A5 g! {# g5 [+ ?3 C
- , V6 D4 [2 c5 }
- /* Sets the reference value for Id */
* [3 n: I+ D9 W; Z+ L! }4 z - void MC_SetIdrefMotor1( int16_t hNewIdref );- i' Q' J$ A h: E- @% ?" \" t
2 C, { i' f1 `8 e2 J+ Q3 c- /* re-initializes Iq and Id references to their default values */
. T" t/ J5 H$ o# M \7 o - void MC_Clear_IqdrefMotor1(void);" `1 x2 h0 r+ z# X" F/ `) v) A
- $ u+ t. d4 h* z! I) r3 D: _- ~, [/ A+ m
- /* Acknowledge a Motor Control fault on Motor 1 */. x% w5 l0 Y- ?( H
- bool MC_AcknowledgeFaultMotor1( void );% @% J. F1 a( x- ]8 o8 y0 ~
- * K/ A' F' |, X0 O9 o
- /* Returns a bitfiled showing faults that occured since the State Machine of Motor 1 was moved to FAULT_NOW state */: V0 I: b1 ~2 P" G
- uint16_t MC_GetOccurredFaultsMotor1(void);% @# d9 \5 U7 C8 W3 M6 u/ n- i+ p. e
: g, E2 F% W- z" a2 v6 p/ W- /* Returns a bitfield showing all current faults on Motor 1 */* [/ G- S; J' N# m) c8 y4 o
- uint16_t MC_GetCurrentFaultsMotor1(void);/ W. z9 r: l! G. t0 l, L
8 n% t1 @# a6 M' }- /* returns the current state of Motor 1 state machine *// A1 [) Z' b; P% L
- State_t MC_GetSTMStateMotor1(void);
& @; C$ {5 t2 D# F, c" x3 k
: A( b( w6 ^* d/ n( `" ~: p- /* programs a user defined ADC regular conversion */# h/ \. d% m: c- s+ ~7 M6 n/ D% N
- void MC_ProgramRegularConversion(uint8_t bChannel, uint8_t bSampleTime);. `" g5 P! ~% c* @7 U2 Y% e( b
& e9 c0 S8 `$ v. h0 g5 c; H4 F T- /* Returns the value of the last executed user defined ADC regular conversion */& z0 n, V# @' P: p2 ~* F# h9 h
- uint16_t MC_GetRegularConversionValue(void);' l6 m/ d5 ~& m* U
- : j: E4 _/ r& D) }: E: Y
- /* Returns the status of the last requested user defined ADC regular conversion */+ ?) {3 C y: Z* D; z2 f% r
- UDRC_State_t MC_GetRegularConversionState(void);
复制代码上面这些api函数是对单个电机的操作,包含了启动、调速、调转矩、以及电机各种状态的获取。 看了任务一的要求,个人认为电机控制还是需要与外部交互好一点,电机启停不可控对于大功率的电机控制来说比较危险。 任务一代码: - void task_1(void)/ j5 L7 U! x4 R W$ z: {( x+ F9 ]
- {
8 i0 I& G) h8 }' e. r. z6 ~4 i - MC_ProgramSpeedRampMotor1(3000/6,1000);! Z6 b8 |* ]$ @/ D" G! s
- MC_StartMotor1();. Y5 B$ v8 E4 a+ `& f$ Y
- HAL_Delay(10000);/ M% [ o$ R6 U" \* T; s* O; ~, [
- MC_StopMotor1();7 W4 j0 v( T5 M( y
- HAL_Delay(10000);0 l7 f8 r5 q9 I* ?2 d( T+ m
- }
复制代码主函数添加的代码: - /* Infinite loop */
1 G- U! A1 w* X$ k3 `4 f - /* USER CODE BEGIN WHILE */
' t9 ^4 F" |8 H2 N7 _4 _ - while (1)
5 ]- a2 Q0 n3 g1 _: R - {
6 _3 Q `1 Q# C2 L; Y( U - ! T; K4 h9 t% {4 }+ ^2 n
- if(GPIO_PIN_SET == HAL_GPIO_ReadPin(LED11_GPIO_Port,LED11_Pin))
7 Y' H3 d% }2 ^7 k: y, }# s - {
# l/ k8 h5 C& f( a# r- T, A - task_1();- F0 ?0 F8 x4 [# @
- }+ u, k$ h* {- \* j% \: d5 }% g& V
- else
& x3 k1 d ?" f - {
/ \/ Z, P, [; J! Y* G - MC_StopMotor1();# w) z7 |- X4 U8 {
- }
& F2 U* \$ G6 r# Y5 w: H# Q+ S - realspeed = MC_GetMecSpeedAverageMotor1()*6;
- G+ E* f$ x' S' ~5 H, }- O; i - /* USER CODE END WHILE */
复制代码按键中断处理函数代码在ui_task.c这个文件中: - void UI_HandleStartStopButton_cb (void)
7 w# c, ~* X6 [0 R4 f7 v; y - {, g8 A: K( g3 N! C
- /* USER CODE BEGIN START_STOP_BTN */' N8 E P) }% H+ D. ~2 |
- HAL_GPIO_TogglePin(LED11_GPIO_Port,LED11_Pin);2 o( {4 Y2 k) K
- /* USER CODE END START_STOP_BTN */9 ^% c0 ]% O3 P) q9 \
- }
% W0 M8 I8 v \ h+ z+ e. q
复制代码这样可以通过按键来控制任务的运行并且可以通过led的亮灭来观察系统所处的状态。LED11是驱动板上的一颗led,引脚号是PB2,可以通过cubemx来设置初始化代码。 通过monitor可以看到速度变化曲线图: ok,任务一完成。 -------------------------------------------------------------
( X; Q; ~+ S) R0 K; \8 [3 q" u 任务二代码: - void task_2(void)
5 |% x2 Z% D% [, P% c' C* Y3 D+ B o - {
) Z ~. N" v7 v% ]$ V3 @$ e - int16_t Speed_Kp,Speed_Ki;
+ G4 W3 O0 P# C) c - MCT_Handle_t * pMctHdl;
: ^( U" Y4 G7 N! { - MC_ProgramSpeedRampMotor1(3000/6,1000);8 k- x7 N0 |- g" H5 v- H, Q1 @) H( H
- MC_StartMotor1();9 i" o3 P- X+ ]! h1 O; P
- HAL_Delay(3000);
& G& i2 n% z4 T7 C% D& p6 Q - MC_StopMotor1();
3 _& f( f7 n& A# o/ V4 U - HAL_Delay(1000); : H0 N9 {1 w5 R' n: H: k! E5 c
- pMctHdl = GetMCT(M1);, J9 F6 z) Z$ K, I: K$ t( f! Q
- Speed_Kp = PID_GetKP(pMctHdl->pPIDSpeed);
9 Y3 Q/ c$ }( A" X* b$ Z! E" O0 s - Speed_Ki = PID_GetKI(pMctHdl->pPIDSpeed);
* D" i, f3 X( |/ v6 z - PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp*2);, F+ v! O7 R8 F3 V& ~
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki*2);
9 [4 ~! E' Y; w b* J* A; [ - MC_ProgramSpeedRampMotor1(3000/6,1000);
7 p" s* H, F- h; D+ ^ B' g3 p' |6 U- u - MC_StartMotor1();) O6 O) c) O, @9 W7 m- ?
- HAL_Delay(3000);
1 p' z' B+ p( s+ \, L - MC_StopMotor1();
3 v9 I% H' ~2 r( b+ t8 Y5 y9 @# D - HAL_Delay(1000);: u. V3 G$ Z4 ]+ e2 v
- PID_SetKP(pMctHdl->pPIDSpeed,Speed_Kp/2);1 y) ^$ {; `9 K' t! J/ g% s2 [
- PID_SetKI(pMctHdl->pPIDSpeed,Speed_Ki/2);6 R s" e/ g4 P5 d0 g
- MC_ProgramSpeedRampMotor1(3000/6,1000);
( I; u8 c2 j3 ^9 _: T! F - MC_StartMotor1();
4 F9 H( c1 l+ W3 _3 ~# m, d. \ - HAL_Delay(3000);
4 E, S. V% Q7 H/ S% }" i, O - MC_StopMotor1();
# U" l ]6 L% f - HAL_GPIO_WritePin(LED11_GPIO_Port,LED11_Pin,GPIO_PIN_RESET);
, g* w8 ^" @. m8 C" L7 z3 | - }
复制代码主函数代码和任务一相同,只是把task_1()改成task_2()就行了。最后一行把LED引脚拉低是为了让代码只运行一次,多次运行可以通过按键进行操作。 可以看到和预期结果是一致的,原始PI调节速度快,有超调现象;Kp、Ki同时增大一倍的时候,调节加快了,并且超调现象被抑制了;当Kp、Ki同时缩小一倍时可以看到虽然调节很快,但是有严重的超调现象。 ) O9 ]; ]$ f0 C/ F+ J/ r7 J0 T- \6 J
0 G5 K! ]& B, Q3 W3 U" l/ J& a
通过monitor的图形显示速度波形极大的方便调试PID的过程,ST考虑得真周到。
/ I3 c3 q Q, m: B% n) Q 我在这里有个疑问,这个plotter只能显示参考速度的波形吗,还能不能添加其他变量来查看系统某个变量的变化趋势呢。之前我一直是用的Jscope,但是Jscope需要连接Jlink来查看,对于这款套件来说需要额外连接Jlink调试器,有一点点麻烦。后面调试有必要我还是会使用Jscope来查看一些变量的波形,并且分享到论坛。 6 h. ~- c. e8 |+ T" N
7 [3 X! p& ]" b K任务一和任务二已完成,欢迎大家留言讨论。
! b+ f2 k% w" L( H3 P+ ~3 K. M1 e . D# f: [* g2 g7 `% M9 g' u, C/ V
& y1 c* o9 l1 q" y
0 d: h& f( X$ |" l3 e
- v7 n- v5 C+ Y/ B9 l% [* ] |
/* Programs a Speed ramp for Motor 1 */; T- x+ L2 n M5 W& T" n5 U0 ?
void MC_ProgramSpeedRampMotor1( int16_t hFinalSpeed, uint16_t hDurationms );
这个函数的第二个参数你改过吗,第二个参数就是达到目标值的时间,越小加速度越快 n5 T: G% O+ E/ W' y; m/ Z
考虑另外一个问题,电机惯性较大,电机驱动板的驱动能力有限,也许最多就只能10+s才能达到目标转速
1.在我的程序里按键的作用起的是传递信号的作用,按键中断中翻转LED11引脚,主函数通过读取LED11引脚电平值做是否启动任务的判断。7 O C. S2 c; I
2.在我的代码里启停是可控的,通过LED11引脚电平来判断是否执行task1。另外,task1的要求就是延时不断启停,我这样写是没有问题的
直接扔好几个问题
回复20#和21#:
User_label那个自己想写什么名字无所谓,根据自己喜好就OK
回复22#和23#:& @' W+ @- `7 c* u
不用跟我的代码完全一样,这个只是我用于控制实验进行与否的一种方式,你也可以通过其他方式来做
好的,有时间我去了解一下通讯协议的代码,尝试显示其他变量。另外一个就是觉得plotter采样率有点低,Jscope采样率1kHz在好些时候都显得不太够用。
我没试过其他电压,一直用的12V,你是不是正负极接反了
不是,我是从24V慢慢升上去的,
我后面尝试一下高电压再给你反馈吧,主要是现在我也没有高电压的电机,所以一直用的12V
好的,还是小心点吧
上电40V驱动板坏了,底板还是好的,这个可能需要告知一下ST了
板子和上位机通讯协议是啥
我还没看,你可以去串口中断函数中了解通信协议
正常呀,这属于C语言基本功,MCT_Handle_t这个结构体在mc_tuning.h中定义的,你要在其他文件中使用当然要包含定义这个结构体的头文件嘛
那就好,我还以为是我工程建立的有问题