最近要做一个项目,对于市面上常用的电机类型,总感觉还是无刷电机比较可靠,伺服效果更好,那么来简单探讨一下FOC的原理和代码实现的过程。
此篇文章就是想让大家快速的应用FOC,不想理解太多的数学公式,让电机转起来。
首先要理解一件事,无刷电机的组成一般是由永磁同步电机所构成,包括定子,转子,永磁铁,在电机的选型上永磁体会在转子上也可定子上,其原理就根据磁铁的同性相吸,异性相斥的原理,同时在结构上是没有电刷的,不能够进行机械换向,是通过电子换向来驱动转子不断地转动,电机的接线方法分为星形解法和三角形解法,普遍的接法是星形解法。如下片的文章。
https://zhuanlan.zhihu.com/p/428964390https://zhuanlan.zhihu.com/p/428964390
同时在无刷电机的购买上,一般标有KV值,而电机的电压和KV值决定了电机的转速,而电机的转速也就决定了换向的频率。
还需要理解一点,相电压、相电流和线电压、线电流。
相电压:是每一相的电压,如图Ua,Ub,Uc
线电压:是指3根导线任意2根之间的电压,Uab,Ubc,Uac
同时对于星形解法来说,线电压的幅值是相电压的根号3倍。矢量相加的结果。
反电动势电压:手动匀速转动它的转子,然后用示波器观察它的三相输出电压,是3个正玄波信号
电角度:它描述了转子磁场相对于定子绕组的空间位置关系,
-
电角度 \theta_eθe 的范围是 0° 到 360°,超过 360° 后会重新从 0° 开始。
好了,知道了前提得一些知识,接下来就是电机FOC的东西了。主要参考,下面几篇文章。
https://zhuanlan.zhihu.com/p/147659820https://zhuanlan.zhihu.com/p/147659820
https://zhuanlan.zhihu.com/p/152144886https://zhuanlan.zhihu.com/p/152144886深入浅出FOC控制-CSDN博客文章浏览阅读10w+次,点赞640次,收藏3.5k次。深入浅出FOC(Field Oriented Control)前言:为什么要学习FOC?1.电机控制是自动化控制领域重要一环。2.目前直流无刷电机应用越来越广泛,如无人机、机械臂、云台、仿生机器人等等。3.电机控制工程师薪水较高。需要什么基础?1.C语言,指针,结构体,编程规范。2.STM32外设使用。3.原理图阅读。4.芯片手册阅读。5.数序坐标系知识为什么要出本教程?1.直流无刷电机应用越来越广泛,网上资料比较散落,因此想要出一篇系统性的教程,从头到尾,深入浅出,帮助初学者快速_foc
https://blog.csdn.net/qq_35947329/article/details/115483413
基于EG2133的有感/无感无刷电机驱动器设计 - 立创开源硬件平台关键词:STM32F401RCT6,EG2133三相半桥驱动芯片,AS5600磁编码器,MT6701磁编码器,有感FOC,无感FOC,SVPWM,可以使用SimpleFOC程序进行驱动。https://oshwhub.com/shadow27/tai-yang-neng-wu-ren-chuan
1,电机FOC算法概述
根据文章我们知道,想让一个无刷电机转起来,要就需要3路相差120度的正玄波信号,给入到uvw,三相电压。而此时FOC就是把单片机产生的3路pwm通过一些计算变成3路正玄波信号,使无刷电机进行转动。
这篇文章不深入探究FOC,仅仅是让其快速入门,让电机旋转起来。
先看一张图
可能第一次看这个有点懵,但是不要拍,如果仅仅让电机转起来的,并不需要全部的流程。
网上很对资料,都是由Clark变换和Park变换讲起,其实说白了一点。
Clark变换是把Ia,Ib,Ic的三项正玄波信号,通过数学的方法变换成Ialph,Itheta两项正玄波
Park变换是把Ialph,Itheta两项正玄波,通过数学的方法变成Iq和Id高低电平来显示
(其实这个2个变换,一般在电流环的时候出现,仅仅让电机转动则不需要)
那么让电机旋转需要什么呢?Park的逆变换和SVPWM
Park的逆变换是静态的Uq和Ud变换成两项正玄波的Ualph,Utheta
SVPWM是将两项正玄波的Ualph,Utheta变换成UVW电机的三项正玄波
由此可见,仅仅需要Park变换和SVPWM就可以实现电机的转动。
其中的符号在所有讲FOC的过程中都会解释的,这边就不赘述了。
2,硬件控制电机转动
好了还有一个问题,到底如何让无刷电机实现转向,持续运行呢?
其实各个大神在讲解FOC都会提到的,这简单说一下,硬件电路一般有三相逆变电路来实现,逆变电路具体的实现则一般是采用半桥MOS电路来制作的。半桥电路的原型如下,其实很简单,就是两个MOS管组成的上桥臂和下桥臂。
如图,当a项的上桥臂和bc项的下桥臂打开,此时电流会从a流向b和c,依次类推共8种,但是全打开和全关闭会导致短路,并不使用。也就是说当我按照一定的规律进行打开和关闭这些mos管,和控制打开和关闭的时间,就能控制无刷电机的转动了。
注:mos相当于开关,如果人为的控制也能实现电机转动,而更好的方法把这些工作交给单片机来处理呢?
3,软硬件控制电机转动
明白了基础的转动的思路,那么如何和单片机联系起来呢(不建议使用stm32F103系列的,没有单精度运算,可以使用stm32F4系列或者stm32G4系列)
使用一下大神的原理图。上面的连接。
芯片采用EG2133芯片,简单来说3个输入IN1、IN2、IN3,输入形式为pwm的形式。
也就是说如果改变pwm的占空比,就能实现上下桥臂的打开还是关闭的状态,并保证不能同时打开(有死区时间限制),换一句话说,只要不断的改变pwm的占空比,就能控制6个mos管的开与关和开关的时间。
从而生成3路正玄波信号的。
4、SVPWM与FOC的关系
那么最后什么是SVPWM,:使用这6个空间电压矢量作为基向量来合成任意矢量。在每一个扇区,选择相邻两个电压矢量以及零矢量,按照伏秒平衡原则来合成每个扇区内的任意电压矢量。
额。。有点难以明白是吧,不理解也没有事,知道一点,SVPWM是用来选择扇区的,并通过3路pwm的占空比来,确定mos的打开和关闭的时间来生成驱动无刷电机的信号的。
这2张图出现的频率特别的高,也就是说电机旋转角度0-360都给分布在扇区中,也就是根据输入的角度,推算出所在的区域,之后根据角度信息来确定3路pwm的占空比,每一个mos打开关闭的时间。
有的人会问了,你这是3路正常的pwm怎么变成了正玄波呢?其实是这样的每一个pwm的占空比对应着一个值,把一个周期所经历的占空比的数据用图像的方式显示出来,就是一周期的正玄波了。
注意哈,这个pwm占空比在写代码的时候要设置成中心对称的方式,即。
// 定时器时钟配置
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0; // 预分频器
htim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; // 中心对齐模式1
htim3.Init.Period = 999; // ARR值,决定PWM周期
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_PWM_Init(&htim3);
5、代码的编写
回顾上文,让电机开环运行,转起来,需要Park逆变换和SVPWM和单片机配置3路中心对其的pwm即可。
输入是uq和ud和电角度信息。
输出是3路pwm的占空比。
(1)Park逆变换
// Park逆变换
float U_alpha = -Uq * arm_sin_f32(angle_el) + Ud * arm_cos_f32(angle_el);
float U_beta = Uq * arm_cos_f32(angle_el) + Ud * arm_sin_f32(angle_el);
(2)SVPWM生成
// 扇区判断
float K = sqrt3 * Ts / Udc; // SVPWM调制比
float u1 = U_beta * K;
float u2 = (0.8660254f * U_alpha - 0.5f * U_beta) * K; // sqrt(3)/2 = 0.8660254
float u3 = (-0.8660254f * U_alpha - 0.5f * U_beta) * K;
uint8_t sector = (u1 > 0.0f) + ((u2 > 0.0f) << 1) + ((u3 > 0.0f) << 2); // sector = A + 2B + 4C
// 非零矢量和零矢量作用时间的计算
switch (sector)
{
case 3: // 扇区1
t4 = u2;
t6 = u1;
sum = t4 + t6;
if (sum > Ts) // 过调制处理
{
k_svpwm = Ts / sum;
t4 *= k_svpwm;
t6 *= k_svpwm;
}
t7 = (Ts - t4 - t6) / 2.0f;
Ta = t4 + t6 + t7;
Tb = t6 + t7;
Tc = t7;
break;
case 1: // 扇区2
t2 = -u2;
t6 = -u3;
sum = t2 + t6;
if (sum > Ts)
{
k_svpwm = Ts / sum;
t2 *= k_svpwm;
t6 *= k_svpwm;
}
t7 = (Ts - t2 - t6) / 2.0f;
Ta = t6 + t7;
Tb = t2 + t6 + t7;
Tc = t7;
break;
case 5: // 扇区3
t2 = u1;
t3 = u3;
sum = t2 + t3;
if (sum > Ts)
{
k_svpwm = Ts / sum;
t2 *= k_svpwm;
t3 *= k_svpwm;
}
t7 = (Ts - t2 - t3) / 2.0f;
Ta = t7;
Tb = t2 + t3 + t7;
Tc = t3 + t7;
break;
case 4: // 扇区4
t1 = -u1;
t3 = -u2;
sum = t1 + t3;
if (sum > Ts)
{
k_svpwm = Ts / sum;
t1 *= k_svpwm;
t3 *= k_svpwm;
}
t7 = (Ts - t1 - t3) / 2.0f;
Ta = t7;
Tb = t3 + t7;
Tc = t1 + t3 + t7;
break;
case 6: // 扇区5
t1 = u3;
t5 = u2;
sum = t1 + t5;
if (sum > Ts)
{
k_svpwm = Ts / sum;
t1 *= k_svpwm;
t5 *= k_svpwm;
}
t7 = (Ts - t1 - t5) / 2.0f;
Ta = t5 + t7;
Tb = t7;
Tc = t1 + t5 + t7;
break;
case 2: // 扇区6
t4 = -u3;
t5 = -u1;
sum = t4 + t5;
if (sum > Ts)
{
k_svpwm = Ts / sum;
t4 *= k_svpwm;
t5 *= k_svpwm;
}
t7 = (Ts - t4 - t5) / 2.0f;
Ta = t4 + t5 + t7;
Tb = t7;
Tc = t5 + t7;
break;
default:
break;
(3)定时器使能
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;
htim3.Init.Period = 2800-1;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
// 使能TIMx的通道y
void PWM_Init(void)
{
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
}
// 输入参数0.0f ~ 1.0f,输出3路PWM
void Set_PWM(float _CCR1, float _CCR2, float _CCR3)
{
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, _CCR1 * PWM_ARR);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, _CCR2 * PWM_ARR);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, _CCR3 * PWM_ARR);
}
(4)模拟电角度
const float _2PI = 6.28318530717958f;
// normalizing radian angle to [0, 2pi]
float _normalizeAngle(float angle)
{
float a = fmod(angle, _2PI); // fmod()函数用于浮点数的取余运算
return a >= 0.0f ? a : (a + _2PI);
}
// 开环运行测试
void OpenVelocity(float target)
{
static float _estimateAngle = 0.1f; // 开环虚拟机械角度
static float deltaT = 0.00625f; // 开环运行时间间隔
_estimateAngle = _normalizeAngle(_estimateAngle + target * deltaT);
setPhaseVoltage(voltageLimit, 0.0f, _estimateAngle * polePairs);
}
angle_el = _normalizeAngle(angle_el);
注意范围是0-360哈。
代码链接:通过网盘分享的文件:1.SVPWM开环速度测试
链接: https://pan.baidu.com/s/1Q-cyH1m3cdUdpeEOQbqghw?pwd=zyie 提取码: zyie
连线方法:定时器3通道123,PA6,PA7,PB0 ,注意需要工地哈(驱动器和单片机)
同时这个仅仅是让电机旋转起来,并没有完成3环的闭环操作,剩下的就可以进行闭环操作了。同时,这个仅仅是最简单的运行,里面的学问有点多,后续有需要可以深入理解一下。