发作品签到
专业版

基于EG2133的有感/无感无刷电机驱动器设计

工程标签

1.6w
0
0
24

简介

关键词:STM32F401RCT6,EG2133三相半桥驱动芯片,AS5600磁编码器,MT6701磁编码器,有感FOC,无感FOC,SVPWM,可以使用SimpleFOC程序进行驱动。

简介:关键词:STM32F401RCT6,EG2133三相半桥驱动芯片,AS5600磁编码器,MT6701磁编码器,有感FOC,无感FOC,SVPWM,可以使用SimpleFOC程序进行驱动。
星火计划2023

开源协议

CC BY-SA 3.0

(未经作者授权,禁止转载)
创建时间:2023-01-09 08:35:22更新时间:2023-12-04 02:45:56

描述

项目简介

设计该项目的原因:主要用于FOC控制算法的学习,从电路设计到控制算法设计,从基础做起,一步步地进行分析。
设计过程视频合集:无刷电机FOC控制算法学习记录
项目源码:github


PCB设计步骤:PCB设计参考基于AT32F413 的FOC驱动器

  1. EG2133单路无刷电机驱动板设计(带电流检测)
  2. AS5600传感器底板设计、MT6701传感器底板设计

有感FOC控制程序设计步骤:

  1. FOC开环速度测试代码编写
  2. MT6701编码器SPI驱动程序编写
  3. FOC闭环位置代码编写
  4. FOC闭环速度代码编写
  5. FOC电流闭环代码编写

无感FOC控制算法学习步骤:

  1. 无感FOC单路无刷电机驱动板设计(EG2133)

驱动板主要参数简介

  1. 主控:STM32F401RCT6,Arm Cortex-M4 core with DSP and FPU, 84 MHz CPU, 256 Kbytes of Flash memory, 64 Kbytes of SRAM
  2. 三相半桥驱动芯片:EG2133
  3. 位置传感器:AS5600(IIC协议,前期测试时使用过)、MT6701(SPI协议,后期主要使用该芯片)
  4. N-MOS:NCE4060K,阈值电压(Vgs(th)@Id):2.5V@250uA;漏源电压(Vdss):40V;连续漏极电流(Id):60A;功率(Pd):65W;导通电阻(RDS(on)@Vgs,Id):13mΩ@10V,20A
  5. 电流检测芯片:TP181A1
    1.实物图.png

STM32F401算力测试

测试环境:开启硬件FPU加速,优化等级-O3,CPU频率84MHz。
1.运算类型float

运算类型float1亿次运算耗时1次运算耗时
+16677ms166.77ns
-16677ms166.77ns
*16677ms166.77ns
/32154ms321.54ns
2.运算类型:int
运算类型1亿次运算耗时1次运算平均耗时
------------------------------------
+14297ms142.97ns
-14296ms142.96ns
*14296ms142.96ns
/16679ms166.79ns
3.标准库计算速度测试:运行1亿次速度太慢,测不出结果
运算类型参数类型1百万次运算耗时
-----------------------------------
sinfsinf (float)1204ns
sinsin (double)68848ns
cosfcosf (float)1108ns
coscos (double)69902ns
4.使用DSP库进行正弦计算测试:计算1亿次
运算类型形参类型1亿次运算耗时
--------------------------------
arm_sin_f32float64313ms
arm_cos_f32float63121ms
5.使用fast_sin进行测试:执行1亿次
该算法参考设计:快速正弦算法
运算类型形参类型1亿次运算耗时
-----------------------------
fast_sinfloat66694ms
fast_cosfloat65503ms
6.使用Cordic迭代算法计算正弦函数:
运算类型形参类型1百万次运算耗时
---------------------------------------
Cordic_sin(55.5f)float46599ms
Cordic_cos(55.5f)float46456ms
**总结:Cordic旋转迭代算法比较适用于FPGA计算正弦函数,对于使用软件进行编写计算没有优势。
如果没有DSP库,可以使用“快速正弦算法”进行正弦函数的计算,其计算速度与DSP库相当。**

无刷电机选型

1.360度无刷云台:TB参考价格6.8元/个,工作电压12V,极对数7。
image.png
2.2804无刷电机:TB参考价格14.8元/个,工作电压12V,极对数7
image.png


径向磁铁和固定铜柱选型

1.径向磁铁:尺寸8 X 2镀锌N35,TB参考价格7.25元/5个。
image.png
2.六角单头尼龙柱塑料隔离柱支撑柱:尺寸M2.5 X 5 + 6,TB参考价格4.86元/50只。
image.png
3.径向磁铁安装:
径向磁铁1.png 径向磁铁2.jpg


AS5600和MT6701磁编码器底板

AS5600原理图:
AS5600原理图.png
MT6701原理图:
image.png
实物图:
MT6701编码器.jpg 安装示意图3.jpg
安装示意图1.jpg 安装示意图2.jpg


BUCK降压模块

SY8205FCC同步降压芯片主要参数:
1.输入电压范围4.5-30V,最大输出电流5A,500KHz
2.过流保护功能、输出短路保护功能
image.png


EG2133三相半桥驱动电路

EG2133芯片主要特性:
1.集成三路独立半桥驱动,适应3.3V、5V输入电压(高电平输入信号)。
2.最高频率500KHz
3.VCC输入范围4.5-20V
4.内建死区控制电路,50-300ns,典型100ns
5.自带闭锁功能,彻底杜绝上、下输出同时导通。
image.png


三相逆变电路:
image.png


电流检测

电流检测芯片TP181A1主要特性:
1.测量电压偏差:±100uV(MAX)
2.共模电压范围:0-36V
3.电压增益50V/V,增益误差±1%,
image.png
image.png
20231129更新:GND和PGND应该使用一个零欧姆的电阻进行连接,从而避免在采集小信号时的干扰问题。


20231129更新关于波特率设置的问题

image.png
本项目使用的为WCH-Link仿真下载器,进行串口输出调试时,波特率最大只能设置为576000,再大可能会乱码。选择其他更好的仿真器,波特率可以自己尝试设置更高的值。


STM32CubeMX配置UART:使用DMA发送数据

以UART1为例进行配置:不涉及printf()函数的重定向问题,可以实现所有UART外设都可以打印信息到串口。
20231128补充:波特率设为576000Bits/s,再大可能会乱码。先前设置的波特率太低了,使用vofa+查看波形时,输出比较卡顿!
image.png
image.png
DMA配置:
image.png
20231128补充:RX不需要配置为DMA模式,只配置TX即可,因为不需要一直接收数据。

使能串口中断,并配置中断优先级:在NVIC里配置中断优先级。
image.png


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,相关参数计算参考:
image.png
image.png
image.png


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的值不能太大,时间久了会烧电机。
image.png


SVPWM开环速度测试输出三相波形

image.png


使用SPI协议读取MT6701磁编码器数据

程序参考:繁花云/f413_foc(gitee)
1.STM32CubeMX参数配置:
使用SPI1,注意MT6701最大通信速率15MHz,如果按照数据手册中写的CPOL = 1,则只能读取pi-2pi间的角度,把CPOL设为0,即可正常读取2pi周期的角度数据。
SPI1配置为全双工主模式:
image.png
image.png
使用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;
}

MT6701角度值读取.png
可以看到读取到的角度值非常稳定,在静止状态下没有数据跳变。


电角度计算和零位校准问题

标定电角度的原因:为了确定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

测试结果:可以校准到零位。
image.png

电角度零位标定方式2:参考B站“热心市民翔先生”的FOC教程,这个原理更具有说服力,本人使用的这种方法进行校准。

    setPhaseVoltage(0.0f, 1.0f, 0.0f);
    HAL_Delay(100);
    zeroElectricAngleOffset = MT6701_GetElectricalAngle(); // 测量电角度零位偏差
    float zero_elAngle = MT6701_GetElectricalAngle();      // 观察电角度是否为0

image.png


两种开环速度运行测试程序

方法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);
}

image.png


位置式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);
}

image.png


闭环位置控制

// 位置环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配置:
image.png
image.png
image.png


ADC1参数配置:
image.png
image.png
image.png
image.png


// 注入组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

暂无BOM

附件

序号文件名称下载次数
1
1.EG2133数据手册.PDF
95
2
2.MT6701_Rev.1.6_中文版.pdf
87
3
3.电流感应放大器_TP181A1.PDF
85
4
4.SY8205同步降压芯片.pdf
64
5
1.SVPWM开环速度测试.mp4
131
6
2.SVPWM闭环速度控制.mp4
102
7
3.SVPWM闭环位置控制.mp4
132
克隆工程
添加到专辑
0
0
分享
侵权投诉

工程成员

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航