说明
本文为无刷电机或PMSM电机驱动的简易代码,旨在分享一些个人调试过程的小心得,提供一个demo文件,程序仍有许多不完善的地方,建立起个人的FOC底层驱动,可以帮助快速熟悉FOC算法原理与使用方法,可以帮助验证新的电机控制算法。原理部分不再阐述。
整个部分共有PWM模块、ADC电流采集、定时器编码器配置、SVPWM模块、FOC核心、PID模块、电压限幅模块,其实有了PWM与SVPWM以及一些必要的数学变换,我们就可以开环使电机转起来了,加入电角度与电流采集作为反馈后,我们就能做到电流闭环,再加入速度PID就可以做到速度闭环,其他的模块只是这些目的的辅助手段罢了。
注意:
调试一定要注意安全!!!
使用带有保护的电源,调试时一定要限制电流在安全等级,开关放手边,随时断电!
程序里做了标幺,比如编码器S16格式,最终都是-32768—32768表示-PI — PI!!!
硬件相关:
(1)MCU为STM32F405RGT6
(2)引脚分配
PWM:TIM1–PA8、PA9、PA10、PB13、PB14、PB15
电流采样:IA–PA6、IB–PA7、IC–PC4
编码器: EA–PA0、EB–PA1
串口: PB6、PB7
(3)编码器为1250线,电机为PMSM、4対极
软件相关:
STM32CubeMX、Keil
如果自制硬件可参考:迷你FOC驱动器
参考资料:
(1)ST电机库
(2)PMSM的FOC 矢量控制算法调试流程,新手上手流程
(3)PMSM矢量控制算法调试流程
(4)FOC和SVPWM的C语言代码实现
(5)上官致远–深入理解无刷直流电机矢量控制技术–科学出版社
0、系统配置
将下列值加入到Cube的User Constants下,然后按照下面的图配置好基本外设。
#define CKTIM 168000000//定时器时钟频率
#define PWM_PRSC 0
#define PWM_FREQ 15000//PWM频率
#define PWM_PERIOD CKTIM/(2*PWM_FREQ*(PWM_PRSC+1))
#define REP_RATE 1 //电流环刷新频率为(REP_RATE+1)/(2*PWM_FREQ)
#define DEADTIME_NS 1000//死区时间ns
#define DEADTIME CKTIM/1000000/2*DEADTIME_NS/1000
#define POLE_PAIR_NUM 4//极对数
#define ENCODER_PPR 1250//编码器线数
#define ALIGNMENT_ANGLE 300
#define COUNTER_RESET (ALIGNMENT_ANGLE*4*ENCODER_PPR/360-1)/POLE_PAIR_NUM
#define ICx_FILTER 8
1、电机有力了!(PWM模块)
高级定时器主要用于产生6路互补的PWM来驱动MOS管,加入死区防止电源导通,本文未使用刹车引脚。高级定时器1通道1、2、3用于产生PWM,通道4用于触发ADC电流采样,根据扇区的位置,灵活设置PWM占空比,进而选择合理的触发点,避免在噪声点采样。引脚配置与PWM极性请根据自己的硬件合理配置,如IR2101是高电平有效,而IR2103则是低端低有效,高端高有效。
PWM测试
生成工程后,应首先对PWM模块进行测试,如果有示波器,先测试PWM是否正常(安全起见一路路测试),死区时间是否正确,然后主函数中加入下列代码,导通U相,注意:占空比一定不能设置的过大,防止电流过大,烧毁电机与驱动板。同理可测试其它相。测试完成后进入下一项。
当然,也可以通过这种方法知道你电机的极对数,导通一相后,用手转动电机一圈,感到有几次阻力,就是几对极。或者,不使用驱控板,先用万用表测试电机任意两相间的电阻,然后通合适的电压,如电阻为2欧,则可以通1V电压,然后用手转动电机一圈,感到有几次阻力,就是几对极。
/* USER CODE BEGIN 2 */
//此时电机应该是有阻力的
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,400);//不能设置的过大
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,5600);//5600为最大占空比
/* USER CODE END 2 */
不加驱动板时50%占空比波形与1000ns死区
2、让电机转起来吧!(SVPWM)
在主函数头文件main.h中加入下面定义,这在后面都会用到。
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef __IO uint32_t vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t vu8;
#define U8_MAX ((u8)255)
#define S8_MAX ((s8)127)
#define S8_MIN ((s8)-128)
#define U16_MAX ((u16)65535u)
#define S16_MAX ((s16)32767)
#define S16_MIN ((s16)-32768)
#define U32_MAX ((u32)4294967295uL)
#define S32_MAX ((s32)2147483647)
#define S32_MIN ((s32)-2147483648)
加入下面代码,主要是数学变换中的Clark变换、Park变换、反Park变换,以及SVPWM模块。
//结构体定义
typedef struct
{
s16 qI_Component1;
s16 qI_Component2;
} Curr_Components;
typedef struct
{
s16 qV_Component1;
s16 qV_Component2;
} Volt_Components;
typedef struct //电压值结构体
{
s16 hCos;
s16 hSin;
} Trig_Components; //存放角度sin和cos函数值的结构体
typedef struct
{
s16 hKp_Gain; //比例系数
u16 hKp_Divisor; //比例系数因子
s16 hKi_Gain; //积分系数
u16 hKi_Divisor; //积分系数因子
s16 hLower_Limit_Output; //总输出下限
s16 hUpper_Limit_Output; //总输出上限
s32 wLower_Limit_Integral; //积分项下限
s32 wUpper_Limit_Integral; //积分项上限
s32 wIntegral; //积分累积和
s16 hKd_Gain; //微分系数
u16 hKd_Divisor; //微分系数因子
s32 wPreviousError; //上次误差
} PID_Struct_t;
//数学变换部分
#define S16_MAX ((s16)32767)
#define S16_MIN ((s16)-32768)
#define divSQRT_3 (s16)0x49E6 //1/sqrt(3)的Q15格式,1/sqrt(3)*2^15=18918=0x49E6
#define SIN_MASK 0x0300
#define U0_90 0x0200
#define U90_180 0x0300
#define U180_270 0x0000
#define U270_360 0x0100
#define SQRT_3 1.732051
#define T (PWM_PERIOD * 4)
#define T_SQRT3 (u16)(T * SQRT_3)
//SVPWM部分
#define SECTOR_1 (u32)1
#define SECTOR_2 (u32)2
#define SECTOR_3 (u32)3
#define SECTOR_4 (u32)4
#define SECTOR_5 (u32)5
#define SECTOR_6 (u32)6
#define PWM2_MODE 0
#define PWM1_MODE 1
#define TW_AFTER ((u16)(((DEADTIME_NS+MAX_TNTR_NS)*168uL)/1000ul))
#define TW_BEFORE (((u16)(((((u16)(SAMPLING_TIME_NS)))*168uL)/1000ul))+1)
#define TNOISE_NS 1550 //2.55usec
#define TRISE_NS 1550 //2.55usec
#define SAMPLING_TIME_NS 700 //700ns
#define SAMPLING_TIME (u16)(((u16)(SAMPLING_TIME_NS) * 168uL)/1000uL)
#define TNOISE (u16)((((u16)(TNOISE_NS)) * 168uL)/1000uL)
#define TRISE (u16)((((u16)(TRISE_NS)) * 168uL)/1000uL)
#define TDEAD (u16)((DEADTIME_NS * 168uL)/1000uL)
#if (TNOISE_NS > TRISE_NS)
#define MAX_TNTR_NS TNOISE_NS
#else
#define MAX_TNTR_NS TRISE_NS
#endif
//函数声明
//数学变换
Curr_Components Clarke(Curr_Components Curr_Input);
Trig_Components Trig_Functions(s16 hAngle);
Curr_Components Park(Curr_Components Curr_Input, s16 Theta);
Volt_Components Rev_Park(Volt_Components Volt_Input);
//SVPWM
void SVPWM_3ShuntCalcDutyCycles (Volt_Components Stat_Volt_Input);
//FOC核心
void FOC_Model(void);
//系统初始化
void motor_init(void);
//变量定义部分
Trig_Components Vector_Components;
u8 bSector;
u8 PWM4Direction=PWM2_MODE;
s16 cnt = S16_MIN;//开环调试变量
//FOC相关
Trig_Components Vector_Components;
Curr_Components Stat_Curr_a_b;
Curr_Components Stat_Curr_alfa_beta;
Curr_Components Stat_Curr_q_d;
Curr_Components Stat_Curr_q_d_ref_ref; //电流环的给定值,用于电流环Id,Iq和前馈电流控制的给定值
Volt_Components Stat_Volt_q_d;
Volt_Components Stat_Volt_alfa_beta;
PID_Struct_t PID_Torque_InitStructure;
PID_Struct_t PID_Flux_InitStructure