
基于EG2133的有感/无感无刷电机驱动器设计
简介
关键词:STM32F401RCT6,EG2133三相半桥驱动芯片,AS5600磁编码器,MT6701磁编码器,有感FOC,无感FOC,SVPWM,可以使用SimpleFOC程序进行驱动。
简介:关键词:STM32F401RCT6,EG2133三相半桥驱动芯片,AS5600磁编码器,MT6701磁编码器,有感FOC,无感FOC,SVPWM,可以使用SimpleFOC程序进行驱动。开源协议
:CC BY-SA 3.0
(未经作者授权,禁止转载)描述
项目简介
设计该项目的原因:主要用于FOC控制算法的学习,从电路设计到控制算法设计,从基础做起,一步步地进行分析。
设计过程视频合集:无刷电机FOC控制算法学习记录
项目源码:github
PCB设计步骤:PCB设计参考基于AT32F413 的FOC驱动器
- EG2133单路无刷电机驱动板设计(带电流检测)
- AS5600传感器底板设计、MT6701传感器底板设计
有感FOC控制程序设计步骤:
- FOC开环速度测试代码编写
- MT6701编码器SPI驱动程序编写
- FOC闭环位置代码编写
- FOC闭环速度代码编写
- FOC电流闭环代码编写
无感FOC控制算法学习步骤:
- 无感FOC单路无刷电机驱动板设计(EG2133)
驱动板主要参数简介
- 主控:STM32F401RCT6,Arm Cortex-M4 core with DSP and FPU, 84 MHz CPU, 256 Kbytes of Flash memory, 64 Kbytes of SRAM
- 三相半桥驱动芯片:EG2133
- 位置传感器:AS5600(IIC协议,前期测试时使用过)、MT6701(SPI协议,后期主要使用该芯片)
- N-MOS:NCE4060K,阈值电压(Vgs(th)@Id):2.5V@250uA;漏源电压(Vdss):40V;连续漏极电流(Id):60A;功率(Pd):65W;导通电阻(RDS(on)@Vgs,Id):13mΩ@10V,20A
- 电流检测芯片:TP181A1
STM32F401算力测试
测试环境:开启硬件FPU加速,优化等级-O3,CPU频率84MHz。
1.运算类型float
运算类型float | 1亿次运算耗时 | 1次运算耗时 |
---|---|---|
+ | 16677ms | 166.77ns |
- | 16677ms | 166.77ns |
* | 16677ms | 166.77ns |
/ | 32154ms | 321.54ns |
2.运算类型:int | ||
运算类型 | 1亿次运算耗时 | 1次运算平均耗时 |
-------- | ------------- | --------------- |
+ | 14297ms | 142.97ns |
- | 14296ms | 142.96ns |
* | 14296ms | 142.96ns |
/ | 16679ms | 166.79ns |
3.标准库计算速度测试:运行1亿次速度太慢,测不出结果 | ||
运算类型 | 参数类型 | 1百万次运算耗时 |
-------- | ------------ | --------------- |
sinf | sinf (float) | 1204ns |
sin | sin (double) | 68848ns |
cosf | cosf (float) | 1108ns |
cos | cos (double) | 69902ns |
4.使用DSP库进行正弦计算测试:计算1亿次 | ||
运算类型 | 形参类型 | 1亿次运算耗时 |
----------- | -------- | ------------- |
arm_sin_f32 | float | 64313ms |
arm_cos_f32 | float | 63121ms |
5.使用fast_sin进行测试:执行1亿次 | ||
该算法参考设计:快速正弦算法 | ||
运算类型 | 形参类型 | 1亿次运算耗时 |
-------- | -------- | ------------- |
fast_sin | float | 66694ms |
fast_cos | float | 65503ms |
6.使用Cordic迭代算法计算正弦函数: | ||
运算类型 | 形参类型 | 1百万次运算耗时 |
---------------- | -------- | --------------- |
Cordic_sin(55.5f) | float | 46599ms |
Cordic_cos(55.5f) | float | 46456ms |
**总结:Cordic旋转迭代算法比较适用于FPGA计算正弦函数,对于使用软件进行编写计算没有优势。 | ||
如果没有DSP库,可以使用“快速正弦算法”进行正弦函数的计算,其计算速度与DSP库相当。** |
无刷电机选型
1.360度无刷云台:TB参考价格6.8元/个,工作电压12V,极对数7。
2.2804无刷电机:TB参考价格14.8元/个,工作电压12V,极对数7
径向磁铁和固定铜柱选型
1.径向磁铁:尺寸8 X 2镀锌N35,TB参考价格7.25元/5个。
2.六角单头尼龙柱塑料隔离柱支撑柱:尺寸M2.5 X 5 + 6,TB参考价格4.86元/50只。
3.径向磁铁安装:
AS5600和MT6701磁编码器底板
AS5600原理图:
MT6701原理图:
实物图:
BUCK降压模块
SY8205FCC同步降压芯片主要参数:
1.输入电压范围4.5-30V,最大输出电流5A,500KHz
2.过流保护功能、输出短路保护功能
EG2133三相半桥驱动电路
EG2133芯片主要特性:
1.集成三路独立半桥驱动,适应3.3V、5V输入电压(高电平输入信号)。
2.最高频率500KHz
3.VCC输入范围4.5-20V
4.内建死区控制电路,50-300ns,典型100ns
5.自带闭锁功能,彻底杜绝上、下输出同时导通。
三相逆变电路:
电流检测
电流检测芯片TP181A1主要特性:
1.测量电压偏差:±100uV(MAX)
2.共模电压范围:0-36V
3.电压增益50V/V,增益误差±1%,
20231129更新:GND和PGND应该使用一个零欧姆的电阻进行连接,从而避免在采集小信号时的干扰问题。
20231129更新关于波特率设置的问题
本项目使用的为WCH-Link仿真下载器,进行串口输出调试时,波特率最大只能设置为576000,再大可能会乱码。选择其他更好的仿真器,波特率可以自己尝试设置更高的值。
STM32CubeMX配置UART:使用DMA发送数据
以UART1为例进行配置:不涉及printf()函数的重定向问题,可以实现所有UART外设都可以打印信息到串口。
20231128补充:波特率设为576000Bits/s,再大可能会乱码。先前设置的波特率太低了,使用vofa+查看波形时,输出比较卡顿!
DMA配置:
20231128补充:RX不需要配置为DMA模式,只配置TX即可,因为不需要一直接收数据。
使能串口中断,并配置中断优先级:在NVIC里配置中断优先级。
UART串口发送数据业务代码:本项目使用的为DMA方式,其他方式可进行参考。
1.添加需要的头文件
#include
#include "usart.h"
#include
#include
2.传统方式:使用printf()发送数据,需要对printf函数进行重定向,且只能使用USART1。
// 重定向fputc函数,使用printf()发送数据
int fputc(int ch, FILE *f)
{
// 参数1:串口句柄,参数2:要发送的数据;参数3:要发生数据的长度;参数4:超时等待时间
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
return ch;
}
3.使用sprintf()函数,阻塞式发送:
// 堵塞模式
void log(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
HAL_UART_Transmit(&huart1, (uint8_t *)strBuf, strlen(strBuf), HAL_MAX_DELAY);
}
4.中断式发送:
// 中断模式
void log_IT(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
{
// Wait for transfer to complete
}
HAL_UART_Transmit_IT(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}
5.DMA发送:本项目中使用的方法
// DMA模式
void log_DMA(const char *format, ...)
{
va_list args; // 定义参数列表变量
va_start(args, format); // 从format位置开始接收参数表,放在arg里面
char strBuf[256]; // 定义输出的字符串
vsprintf(strBuf, format, args); // 使用vsprintf将格式化的数据写入缓冲区
va_end(args); // 结束可变参数的使用
// 等待上次的数据发送完成,避免新的数据覆盖正在传输的数据,导致混乱
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
{
// Wait for DMA transfer to complete
}
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)strBuf, strlen(strBuf));
}
STM32CubeMX定时器配置:输出3路PWM
PWM频率:15K,相关参数计算参考:
SVPWM核心代码
本项目的核心代码!
// FOC核心函数:输入Uq、Ud和电角度,输出三路PWM
void setPhaseVoltage(float Uq, float Ud, float angle_el)
{
Uq = _constraint(Uq, -5.0f, 5.0f);
// angle_el = _normalizeAngle(angle_el); // 使用MT6701计算电角度时,已限制角度范围
static float Ts = 1.0f;
float Ta, Tb, Tc;
float t1, t2, t3, t4, t5, t6, t7;
float sum, k_svpwm;
// 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);
// 扇区判断
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;
}
// FOC_log("[Ta,Tb,Tc]:%f,%f,%f\r\n", Ta, Tb, Tc);
Set_PWM(Ta, Tb, Tc); // 输出三路PWM,驱动无刷电机转动
}
SPWM开环速度测试输出三相波形
注:开环速度控制测试,电机抖动发热为正常现象,因为力矩和估计的角度增量不匹配时就会抖,没有角度反馈。Uq的值不能太大,时间久了会烧电机。
SVPWM开环速度测试输出三相波形
使用SPI协议读取MT6701磁编码器数据
程序参考:繁花云/f413_foc(gitee)
1.STM32CubeMX参数配置:
使用SPI1,注意MT6701最大通信速率15MHz,如果按照数据手册中写的CPOL = 1,则只能读取pi-2pi间的角度,把CPOL设为0,即可正常读取2pi周期的角度数据。
SPI1配置为全双工主模式:
使用SPI协议一次读出16bits数据,然后将16位数据右移2位取最高的14位角度数据:
注意:圈数值rotationCount长时间运运行可能溢出,不过在“灯哥FOC”的课程中,他说连续运行1年才有可能溢出,这点我保持怀疑态度。参考AS5600编码器的程序,重写了MT6701编码器数据的读取。
// 获取MT6701原始数据
uint16_t MT6701_GetRawData(void)
{
uint16_t rawData;
uint16_t txData = 0xFFFF;
uint16_t timeOut = 200;
while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY)
{
if (timeOut-- == 0)
{
FOC_log("SPI state error!\r\n");
return 0; // 在超时时直接返回,避免继续执行后续代码
}
}
MT6701_CS_Enable();
HAL_StatusTypeDef spiStatus = HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)&txData, (uint8_t *)&rawData, 1, HAL_MAX_DELAY);
if (spiStatus != HAL_OK)
{
MT6701_CS_Disable();
FOC_log("MT6701 read data error!\r\n");
return 0; // 在SPI传输错误时直接返回,避免继续执行后续代码
}
MT6701_CS_Disable();
return rawData >> 2; // 取高14位的角度数据
}
// 将传感器原始数据转化为弧度
float MT6701_GetRawAngle(void)
{
uint16_t rawData = MT6701_GetRawData();
return (float)rawData / 16384.0f * _2PI;
}
// 获得转过的总角度,有圈数累加
float MT6701_GetFullAngle(void)
{
static float angle_Last = 0.0f; // 上次的轴角度,范围0~6.28
float angle = MT6701_GetRawAngle(); // 当前角度,范围0~6.28
float deltaAngle = angle - angle_Last;
// 计算旋转的总圈数
// 通过判断角度变化是否大于80%的一圈(0.8f*6.28318530718f)来判断是否发生了溢出,如果发生了,则将full_rotations增加1(如果d_angle小于0)或减少1(如果d_angle大于0)。
if (fabsf(deltaAngle) > (0.8f * 6.28318530718f))
{
rotationCount += (deltaAngle > 0) ? -1 : 1; // 圈数计算
rotationCount_Last = rotationCount;
}
angle_Last = angle;
return rotationCount * 6.28318530718f + angle_Last; // 转过的圈数 * 2pi + 未转满一圈的角度值
}
// 计算转速
float MT6701_GetVelocity(void)
{
static float full_Angle_Last = 0.0f; // 记录上次转过的总角度
float full_Angle = MT6701_GetFullAngle();
float delta_Angle = (rotationCount - rotationCount_Last) * _2PI + (full_Angle - full_Angle_Last);
float vel = delta_Angle * 1000.0f; // Ts = 1ms
// 更新变量值
full_Angle_Last = full_Angle;
return vel;
}
可以看到读取到的角度值非常稳定,在静止状态下没有数据跳变。
电角度计算和零位校准问题
标定电角度的原因:为了确定D轴的位置。
电角度零位标定方式1:参考“SimpleFOC”的校准方法,这个方法我没有看懂其原理。
setPhaseVoltage(3.0f, 0.0f, _3PI_2);
HAL_Delay(1000);
zeroElectricAngleOffset = MT6701_GetElectricalAngle(); // 测量电角度零位偏差
setPhaseVoltage(0, 0, _3PI_2);
float zero_elAngle = MT6701_GetElectricalAngle(); // 观察电角度是否为0
测试结果:可以校准到零位。
电角度零位标定方式2:参考B站“热心市民翔先生”的FOC教程,这个原理更具有说服力,本人使用的这种方法进行校准。
setPhaseVoltage(0.0f, 1.0f, 0.0f);
HAL_Delay(100);
zeroElectricAngleOffset = MT6701_GetElectricalAngle(); // 测量电角度零位偏差
float zero_elAngle = MT6701_GetElectricalAngle(); // 观察电角度是否为0
两种开环速度运行测试程序
方法1:不使用编码器测量的电角度
// 开环运行测试1,模拟电角度
void OpenVelocity1(float target)
{
const float voltageLimit = 0.5f; // 开环电压限制
static float _estimateAngle = 0.0f; // 开环虚拟机械角度
const float deltaT = 0.00625f; // 开环运行时间间隔
_estimateAngle = _normalizeAngle(_estimateAngle + target * deltaT);
setPhaseVoltage(voltageLimit, 0.0f, _estimateAngle * 7);
}
方法2:使用MT6701编码器计算电角度,注此时还没有引入PID控制,使用vofa+进行速度观察,会发现速度波动范围比较大。
// 开环速度控制测试,使用MT6701反馈的电角度
void OpenVelocity2(float Uq)
{
float el_Angle = MT6701_GetElectricalAngle();
setPhaseVoltage(Uq, 0.0f, el_Angle);
}
位置式PID算法
typedef struct
{
float Kp;
float Ki;
float Kd;
float Umax; // 输出限幅
float I; // 积分项计算结果
float last_Error; // 上次误差
uint8_t saturation_flag; // 积分饱和标志位
float Ts; // PID调节周期
} PID_Typedef;
// PID参数设置
void PID_Init(PID_Typedef *pidHandle, float Kp, float Ki, float Kd, float Umax, float Ts)
{
// PID调节周期1ms,Ts = 0.001f
pidHandle->Kp = Kp;
pidHandle->Ki = Ki;
pidHandle->Kd = Kd;
pidHandle->Umax = Umax;
pidHandle->Ts = Ts;
}
// PID控制计算
float PIDCalculate(PID_Typedef *pidHandle, float SetValue, float ActualValue)
{
float Error = SetValue - ActualValue;
// 限制积分项的增长
// 因为当输出永远跟不上输入时,积分项会无限增长,可能会超出浮点数的范围
if (pidHandle->saturation_flag == 0)
{
pidHandle->I += pidHandle->Ki * Error * pidHandle->Ts; // I += Ki * Error * Ts
}
float P = pidHandle->Kp * Error; // P = Kp * Error;
float D = pidHandle->Kd * (Error - pidHandle->last_Error) / pidHandle->Ts; // D = Kd * (Error - last_Error) / Ts
float Uo = P + pidHandle->I + D; // 输出Uout = P + I + D
// 存储当前误差
pidHandle->last_Error = Error;
// 限幅处理
if (Uo > pidHandle->Umax)
{
pidHandle->saturation_flag = 1;
Uo = pidHandle->Umax;
}
else if (Uo < -pidHandle->Umax)
{
pidHandle->saturation_flag = 1;
Uo = -pidHandle->Umax;
}
else
pidHandle->saturation_flag = 0;
return Uo;
}
闭环速度控制
float Set_Velocity = 30.0f; // 目标转速
float actual_Velocity; // 实际转速
PID_Typedef velocity_PID; // 速度环PID参数配置
// 闭环速度PID控制参数设置
void velocity_PID_Config(void)
{
velocity_PID.Kp = 0.1f;
velocity_PID.Ki = 1.0f;
velocity_PID.Kd = 0.0f;
velocity_PID.Ts = 0.001f;
velocity_PID.Umax = 3.0f;
PID_Init(&velocity_PID, velocity_PID.Kp, velocity_PID.Ki, velocity_PID.Kd, velocity_PID.Umax, velocity_PID.Ts);
}
// 速度环PID控制
void close_Velocity_Control(void)
{
actual_Velocity = MT6701_GetVelocity(); // 实际转速
LowPassFilter(&actual_Velocity); // 对转速进行低通滤波
float Uq = PIDCalculate(&velocity_PID, Set_Velocity, actual_Velocity); // 速度环PID控制
float el_Angle = MT6701_GetElectricalAngle();
setPhaseVoltage(Uq, 0.0f, el_Angle);
}
闭环位置控制
// 位置环PID控制
void close_Angle_Control(void)
{
actual_Angle = MT6701_GetRawAngle(); // 实际机械角度
float set_Velocity = PIDCalculate(&angle_PID, Set_Angle, actual_Angle); // 角度环PID控制,输出转速
float actual_Velocity = MT6701_GetVelocity(); // 实际转速
LowPassFilter(&actual_Velocity);
float Uq = PIDCalculate(&velocity_PID, set_Velocity, actual_Velocity);
float el_Angle = MT6701_GetElectricalAngle();
setPhaseVoltage(Uq, 0.0f, el_Angle);
}
电流环控制
使用定时器触发ADC转换,ADC配置为注入组+多通道,在ADC注入组转换完成后的中断回调函数中,获取ADC转换值。
STM32CubeMX配置:
ADC1参数配置:
// 注入组ADC配置初始化
void adc_uesr_Init(void)
{
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // 开启TIM1_CH4,用于触发ADC转换
HAL_ADCEx_InjectedStart(&hadc1); // 启动注入模式的ADC转换
current_gain = 1.0f / shunt_Resistor / TP181_Gain;
adc_calibrate_offset(); // 计算ADC的偏置电压
}
// ADC采样偏置计算
void adc_calibrate_offset(void)
{
uint16_t cnt = 1000;
for (uint16_t i = 0; i < cnt; i++)
{
uint16_t adc1_value_Rank1 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
uint16_t adc1_value_Rank2 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
zero_offsetA += (float)adc1_value_Rank1 / 4095.0f * vref_voltage;
zero_offsetB += (float)adc1_value_Rank2 / 4095.0f * vref_voltage;
}
zero_offsetA = zero_offsetA / cnt;
zero_offsetB = zero_offsetB / cnt;
FOC_log("[zero_offset]:%f,%f\r\n", zero_offsetA, zero_offsetB);
HAL_ADCEx_InjectedStart_IT(&hadc1); // 开启ADC注入组中断
}
/* 注入组完成转换后的中断回调函数
* 1.计算电流采样值
* 2.获取转速
* 3.获取电角度
*/
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if (hadc == &hadc1)
{
// 获取注入组ADC1的转换值
uint16_t adc1_value_Rank1 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_1);
uint16_t adc1_value_Rank2 = HAL_ADCEx_InjectedGetValue(&hadc1, ADC_INJECTED_RANK_2);
// 计算相电流
phase_Current.Ia = ((float)adc1_value_Rank1 / 4095.0f * vref_voltage - zero_offsetA) * current_gain;
phase_Current.Ib = ((float)adc1_value_Rank2 / 4095.0f * vref_voltage - zero_offsetB) * current_gain;
// 获取MT6701编码器的相关数据
shaft_Angle = MT6701_GetRawAngle();
el_Angle = MT6701_GetElectricalAngle();
velocity = MT6701_GetVelocity();
// FOC_log("%f,%f\r\n", phase_Current.Ia, phase_Current.Ib);
// user_log("%f,%f\r\n", phase_Current.Ia, phase_Current.Ib);
// user_log("%f,%f,%f\r\n", shaft_Angle, el_Angle, velocity);
}
}
闭环电流控制程序
// 闭环电流控制
void close_Current_Control(void)
{
float el_Angle = MT6701_GetElectricalAngle(); // 电角度
Id_Iq_calculate(¤t, el_Angle); // 计算Iq、Id的电流
LowPassFilter(&(current.q));
LowPassFilter(&(current.d));
float Uq = PIDCalculate(&pid_Iq, Iq_set, current.q);
float Ud = PIDCalculate(&pid_Id, Id_set, current.d);
setPhaseVoltage(Uq, Ud, el_Angle);
}
设计图

BOM


评论