臭猫FOC驱动器设计日志
主控芯片:WCH-CH32V307VCT6
预驱芯片:EG2133
MOS:NEC6050
下载芯片:CH549G
电流检测:INA240A2
2024-9-15 期待已久的FOC驱动器终于开工设计!设计完成PCB以及原理图。第一次设计双路的FOC驱动器,也是第一次是设计功率地与普通的GND隔离。
另外就是电流检测芯片选择的是TI的INA240A2,有点难以购买qaq0.0每个芯片的价格在3元左右,属实有点成本爆炸。下次准备学习更换更为便宜的INA199或者其他国产方案。
2024-9-17 计划物料到货开始焊接
这板子有一些bug,就是CH549G下载电路的供电有些问题。在使用DC-12v供电测试的时候,CH549G下载电路的供电不稳定。
另外在开环测试的时候供电也不稳定。不知道是不是程序问题。
接下来抽时间对驱动器进行软件开发
方波驱动测试
在每个换相周期内,定子绕组中的电流被切换为高或低两个状态,形成矩形波。通常采用六步换向法,即每60度电角度换相一次,从而产生转矩。
开环FOC驱动测试
开环运行即根据系统时间为索引,根据时间固定生成三相的正弦波。需要涉及Clark变换以及Park变换。
simpleFOC的开环速度代码如下
参考了:https://github.com/haotianh9/DengFOC_on_STM32
电压控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
static inline uint32_t LL_SYSTICK_IsActiveCounterFlag(void)
{
return ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == (SysTick_CTRL_COUNTFLAG_Msk));
}
uint32_t getCurrentMicros(void)
{
/* Ensure COUNTFLAG is reset by reading SysTick control and status register */
LL_SYSTICK_IsActiveCounterFlag();
uint32_t m = HAL_GetTick();
const uint32_t tms = SysTick->LOAD + 1;
__IO uint32_t u = tms - SysTick->VAL;
if (LL_SYSTICK_IsActiveCounterFlag()) {
m = HAL_GetTick();
u = tms - SysTick->VAL;
}
return (m * 1000 + (u * 1000) / tms);
} //【应该是获取运行时间的代码段。】
float _electricalAngle(float shaft_angle, int pole_pairs) {
return (shaft_angle * pole_pairs);
}
float _normalizeAngle(float angle){
float a = fmod(angle, 2*M_PI); //取余运算可以用于归一化,列出特殊值例子算便知
return a >= 0 ? a : (a + 2*M_PI);
//三目运算符。格式:condition ? expr1 : expr2
//其中,condition 是要求值的条件表达式,如果条件成立,则返回 expr1 的值,否则返回 expr2 的值。
//可以将三目运算符视为 if-else 语句的简化形式。
//fmod 函数的余数的符号与除数相同。因此,当 angle 的值为负数时,余数的符号将与 _2M_PI 的符号相反。
//也就是说,如果 angle 的值小于 0 且 _2M_PI 的值为正数,则 fmod(angle, _2M_PI) 的余数将为负数。
//例如,当 angle 的值为 -M_PI/2,_2M_PI 的值为 2M_PI 时,fmod(angle, _2M_PI) 将返回一个负数。
//在这种情况下,可以通过将负数的余数加上 _2M_PI 来将角度归一化到 [0, 2M_PI] 的范围内,以确保角度的值始终为正数。
}
void setPwm(float Ua, float Ub, float Uc) {
// // 限制上限
Ua = _constrain(Ua, 0.0f, voltage_limit);
Ub = _constrain(Ub, 0.0f, voltage_limit);
Uc = _constrain(Uc, 0.0f, voltage_limit);
// 计算占空比
// 限制占空比从0到1
dc_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 通道
TIM1->CCR1 = (uint32_t) roundf(dc_a*period);
TIM1->CCR2 = (uint32_t) roundf(dc_b*period);
TIM1->CCR3 = (uint32_t) roundf(dc_c*period);
}
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);
}
//开环速度函数
float velocityOpenloop(float target_velocity){
// uint32_t now_us = getCurrentMicros();
// uint32_t now_us = HAL_GetTick();
// Provides a tick value in microseconds.
//计算当前每个Loop的运行时间间隔
// float Ts = (now_us - open_loop_timestamp) * 1e-3f;
float Ts=5E-3f;
// 通过乘以时间间隔和目标速度来计算需要转动的机械角度,存储在 shaft_angle 变量中。
//在此之前,还需要对轴角度进行归一化,以确保其值在 0 到 2π 之间。
shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts);
//以目标速度为 10 rad/s 为例,如果时间间隔是 1 秒,则在每个循环中需要增加 10 * 1 = 10 弧度的角度变化量,才能使电机转动到目标速度。
//如果时间间隔是 0.1 秒,那么在每个循环中需要增加的角度变化量就是 10 * 0.1 = 1 弧度,才能实现相同的目标速度。
//因此,电机轴的转动角度取决于目标速度和时间间隔的乘积。
// Uq is not related to voltage limit
float Uq = 5.5;
setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs));
// open_loop_timestamp = now_us; //用于计算下一个时间间隔
return Uq;
}
|
波形图根据上述代码来生成的话有些错误。这导致电机不能正确转动。而发出固定的啸叫。
时间改为us后,波形图更加混乱。
将时间的获取改为定时器中断+全局变量后。首先设置1us生成波形图如下:
调整为200us时波形图如下:
按理说这样运行开环已经可以完美运行,但是接入电脑5v-usb供电的时候电机依然跳动+啸叫。
接入正常12v电源供电时,板子直接没了反应。。可能是设计的电源出现了问题。将电压降低到5v后板子可以正常上电启动,但是无法正常运行,整体是一种上电运行后,电机转动力巨大,然后系统死机重启陷入了死循环。
电源设计还是不太过关。。。而且设计的有些混乱。。计划下一板改进,但是这种工程耗费时间太大了,下次进行工程实现之前应该提前做好功课。
AS5600磁编码器电机底板
2024-9-18 PCB刚刚到货,准备抽时间进行焊接。再一次把CM_FOC的串口通信部分焊接完成,方便查看波形等。
SH1.25的接口画错了,属实是大意了。飞线暂时解决了问题。
AS5600磁编码器数据读取
AS5600是12位的霍尔磁编码器,它的地址是0x36,只需要读取0x0C、0x0D这两个寄存器就可以读出角度的原始数据,再将其乘以360,再除以4096,就可以获得角度值。
鸽了一段时间,等忙完就马上开始测试。在此之前还需要把电源修好、、、、悲