算法 - FOC开环速度控制
目录
核心思想
一、三相电压矢量
二、电角度和机械角度
三、伪代码
3.1 预设部分
3.2 PWM
3.3 克拉克与帕克逆变换
3.4 Uq和电角度生成
核心思想
输入期望的速度 -> 生成Uq和旋转电角度 -> 根据电角度进行帕克变换生成
分量 -> 根据
分量进行克拉克变换,生成三相分量 -> 利用三相分量来控制PWM输出该为多少
一、三相电压矢量
电机算法 - 克拉克变换-CSDN博客
电机算法 - 帕克变换-CSDN博客
在这两个基础中,把电流矢量乘上一个相电阻R;
二、电角度和机械角度
电角度 = 机械角度 x 极对数
* 极对数:电机磁极对数,1个N极和1个S极为一对磁极;
比如机械角度旋转一圈,但是里面N对磁极,切割了N次,发了N个周期的电;
三、伪代码
3.1 预设部分
/* pwm输出引脚假设 30Khz int pwmA = 32; int pwmB = 33; int pwmC = 25; *///限制幅值 #define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))float voltage_limit = 10; float voltage_power_supply = 12.6; //供电电压 float shaft_angle=0, open_loop_timestamp=0; float zero_electric_angle=0, Ualpha, Ubeta=0, Ub=0, Uc=0, dc_a=0, dc_b=0, dc_c=0;// 电角度求解 // 机械角度*极对数 float _electricalAngle(float shaft_angle, int pole_pairs) {return (shaft_angle * pole_pairs); }// 归一化角度到 [0,2PI] // 前面取余,后面映射到[0,2PI] float _normalizeAngle(float angle){float a = fmod(angle, 2*PI); //取余运算可以用于归一化,列出特殊值例子算便知return a >= 0 ? a : (a + 2*PI);
3.2 PWM
// 设置PWM到控制器输出 void setPwm(float Ua, float Ub, float Uc) {//限制上限Ua = _constrain(Ua, 0.0f, voltage_limit);Ub = _constrain(Ua, 0.0f, voltage_limit);Uc = _constrain(Ua, 0.0f, voltage_limit);// 计算占空比// 限制占空比从0到1dc_a = _constrain(Ua / voltage_power_supply, 0.0f , 1.0f );dc_b = _constrain(Ub / voltage_power_supply, 0.0f , 1.0f );dc_c = _constrain(Uc / voltage_power_supply, 0.0f , 1.0f );//写入PWM到PWM 0 1 2 通道ledcWrite(0, dc_a*255);ledcWrite(1, dc_b*255);ledcWrite(2, dc_c*255); }
3.3 克拉克与帕克逆变换
void setPhaseVoltage(float Uq,float Ud, float angle_el) {angle_el = _normalizeAngle(angle_el + zero_electric_angle);// 帕克逆变换Ualpha = -Uq*sin(angle_el); Ubeta = Uq*cos(angle_el); // 克拉克逆变换Ua = Ualpha + voltage_power_supply/2;Ub = (sqrt(3)*Ubeta-Ualpha)/2 + voltage_power_supply/2;Uc = (-Ualpha-sqrt(3)*Ubeta)/2 + voltage_power_supply/2;setPwm(Ua,Ub,Uc); }
3.4 Uq和电角度生成
// 输入速度为rad/s float velocityOpenloop(float target_velocity){ //计算循环间隔 unsigned long now_us = micros(); float Ts = (now_us - open_loop_timestamp) * 1e-6f;// micros() 溢出时,修正Ts if(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;//根据给定的速度,每次循环计算一下新的轴角度(机械角度) shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts);float Uq = voltage_power_supply/3; setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, 7)); open_loop_timestamp = now_us; //用于计算下一个时间间隔return Uq; }