1 引言
本博客是为了记录自己在无人机公司中,所涉及的技术栈,博客既是记录自己的成长轨迹,亦是总结所学,便于后续持续学习进步。
实验使用到了STM32F407 + EG2133三相独立半桥驱动芯片 + MT6701磁性角度编码器芯片 + 无刷电机(10对极)无刷电机,本博客记录的是Foc开环驱动无刷电机转动实验过程,记录可能理解浅薄,请多包涵。
2 实验记录
在进行开环foc驱动无刷电机过程中,遇到的记录点如下。
(1)foc驱动无刷电机转动,无需校准转子位置,转子在任何位置都可以。
原因是foc开始驱动转子转动时,首先通过软电角度生成器不断累计角度,磁场矢量随之旋转,在未来的某一刻总能抓住转子,驱动转子转动。
时间轴: t=0: 磁场在0°,转子在30° → 夹角30°,有微弱力矩 t=1ms: 磁场转到10°,转子还在30° → 夹角20°,力矩增大 t=2ms: 磁场转到20°,转子开始跟随 → 夹角变小,进入同步
(2)foc驱动无刷电机,需要增加软角度生成器,使得转子先转动起来。
原因是转子初始时是静止的,此时即使角度传感器,但因为转子未转动,此时得到的角速度就是0 rad/s。如果将0 rad/s输入clark和park变换,那么得到的输出是一个定值,磁场矢量不会旋转变化,就无法驱动转动转动。因此需要实现一个软件角度生成器,逐步累加角度,然磁场缓慢变化,用以驱动转子转动。
(3)软角度生成器注意点
| 1 | 角度生成速度不宜过快,此会导致转子跟不上变化的旋转磁场 |
| 2 | 公式:θ = current_rad_s + ∫ accel*dt |
| 3 | 注意单位,rad_s那么积分的时间也必须是s,如果获取的是ms或us,那么也要转换成s才行 |
| 4 | 开环foc驱动时,目标角速度不要太大,否则会失速 |
(4)代码说明
// 本实验中pwm周期是10KHz ,故每次进入motorTsk_foc_open_update函数都是0.1ms
void motorTsk_foc_open_update(void)
{
......
// ===== 1. 计算实际时间步长 =====
curr_tick_us = fc_timer_get_us();
if (last_tick_us == 0)
{
last_tick_us = curr_tick_us;
return;
}// 单位需是s
dt = (float)(curr_tick_us - last_tick_us) / 1000000.0f;
if (dt > 0.001f) dt = 0.001f; // 防跳变
last_tick_us = curr_tick_us;
// ===== 2. 角速度缓慢加速(软启动) =====
if (current_speed_rad_s < target_speed_rad_s)
{
current_speed_rad_s += accel * dt; // 积分
if (current_speed_rad_s > target_speed_rad_s)
{
current_speed_rad_s = target_speed_rad_s;
}
}// ===== 3. 角度累加(平滑) =====
s_elc_angle_rad += current_speed_rad_s * dt; // 角速度对时间积分得到角度
if (s_elc_angle_rad > 6.2832f) s_elc_angle_rad -= 6.2832f; // 弧度归一化
// 进行clark变换和park变换
......
}
3 实验代码
完整的代码在:git clone https://gitee.com/a1410898565/foc_pro.git
代码片段如下:
void motorTsk_foc_open_update
(
void
)
{
static float angle_rad = 0.0f;
static float motor_voltage = 0.8f; // 电压幅值 (0.0~1.0)
static uint32_t last_tick_us = 0;
uint32_t curr_tick_us = 0;
float dt = 0.0f;
static float current_speed_rad_s = 0.0f;
float target_speed_rad_s = 1000.0f; // 目标速度 2000 rad/s (≈191 RPM)
float accel = 200.0f; // 软启动加速度 200 rad/s²
// ===== 1. 计算实际时间步长 =====
curr_tick_us = fc_timer_get_us();
if (last_tick_us == 0)
{
last_tick_us = curr_tick_us;
return;
}
// 此中断是10kHz中断时间是0.1ms
// 15438802us - 15436320us = 2482us
// 2.482ms = 2482us /1000
// 0.002482s = 2482us /1000000
dt = (float)(curr_tick_us - last_tick_us) / 1000000.0f;
if (dt > 0.001f)
{
dt = 0.001f; // 防跳变
}
last_tick_us = curr_tick_us;
// ===== 2. 缓慢加速(软启动) =====
if (current_speed_rad_s < target_speed_rad_s)
{
current_speed_rad_s += accel * dt;
if (current_speed_rad_s > target_speed_rad_s)
{
current_speed_rad_s = target_speed_rad_s;
}
}
// ===== 3. 角度累加(平滑) =====
s_elc_angle_rad += current_speed_rad_s * dt;
if (s_elc_angle_rad > 6.2832f)
{
// 弧度归一化
s_elc_angle_rad -= 6.2832f;
}
// ===== 4. clark 和 park变换 =====
foc_clark_and_park_transf(PWM_HALF*0.2, 0.0f, s_elc_angle_rad, &s_duty_a, &s_duty_b, &s_duty_c);
s_duty_a += PWM_HALF;
s_duty_b += PWM_HALF;
s_duty_c += PWM_HALF;
// ===== 5. 限制占空比 =====
s_duty_a = CONSTRAIN_VALUE(s_duty_a, PWM_MIN, motor_voltage*PWM_FULL);
s_duty_b = CONSTRAIN_VALUE(s_duty_b, PWM_MIN, motor_voltage*PWM_FULL);
s_duty_c = CONSTRAIN_VALUE(s_duty_c, PWM_MIN, motor_voltage*PWM_FULL);
// ===== 6. 更新PWM =====
TIM1->CCR1 = (uint32_t)s_duty_a;
TIM1->CCR2 = (uint32_t)s_duty_b;
TIM1->CCR3 = (uint32_t)s_duty_c;
}
4 实验记录
下图所示为本实验驱动转动效果。




被折叠的 条评论
为什么被折叠?



