记录驱动三相无刷电机的过程

·875·3 分钟阅读
嵌入式开发

原理

简单来说就是电生磁,磁场的方向可以根据 右手螺旋定则 又称 安培定则 来判断,然后根据磁铁的同斥异吸产生的力,就可以带动磁铁旋转起来,这篇文章不做详细解释,只记录自己写代码和思考的过程

三相无刷电机结构图

三相无刷电机结构图

硬件购买

https://item.taobao.com/item.htm?id=798692885752&mi_id=00004bCXyEbhWUxPilYAZcWq6_E4UiCvb_UTOWkkVvzVQw8&spm=tbpc.mytb_itemcollect.item.goods&upStreamPrice=4500

2804电机 + AS5600编码器 + FOC驱动板(MS8313芯片)

六步换相开环驱动

代码如下:

void test1(void)
{
    static uint8_t step;

    U_Enable;
    V_Enable;
    W_Enable;
    switch (step)
    {
    case 0:
        U_HIGH;
        W_LOW;
        V_Disable;
        break;
    case 1:
        U_HIGH;
        V_LOW;
        W_Disable;
        break;
    case 2:
        W_HIGH;
        V_LOW;
        U_Disable;
        break;
    case 3:
        W_HIGH;
        U_LOW;
        V_Disable;
        break;
    case 4:
        V_HIGH;
        U_LOW;
        W_Disable;
        break;
    case 5:
        V_HIGH;
        W_LOW;
        U_Disable;
        break;
    default:
        break;
    }
    if (++step >= 6)
        step = 0;
}

调用

while (1)
{
    if (sysCnt >= 10)
    {
        sysCnt = 0;
        if (++stepCnt >= 500) // 500ms调用一次
        {
            stepCnt = 0;
            test1();
        }
    }
}

很显然,电机是一步一步走的,非常卡顿,并且是开环控制,我并不知道转到哪里了,接下来是我一步一步的优化和思考过程

testMotorDriver函数的调用频率问题

现在电机是一步一步走的,是因为我是500ms调用的,这让我有了思考,如果我把调用频率加快,它是不是就可以快速转动起来了,于是我改成1ms调用:

while (1)
{
    if (sysCnt >= 10)
    {
        sysCnt = 0;
        if (++stepCnt >= 500) // 500ms调用一次
        {
            stepCnt = 0;
        }
        test1();
    }
}

发现电机速度并没有加快,并且抖动特别厉害 这个可能是由于换相过快,电机根本追不上来,盲目换相,导致的电机剧烈抖动

接下来一步一步实现闭环控制

了解机械角度和电角度的概念

机械角度: 转轴实际转过的物理角度。转一整圈就是 360°,和极数无关。

电角度: 以绕组感应电势的一个完整周期为 360° 来度量的角度。转子每扫过一对 N-S 磁极,定子绕组里的电势就经历一次完整的正弦周期,这就是一个"电角度 360°"。

核心公式:

电角度=机械角度.极对数电角度 = 机械角度 . 极对数

为什么需要两个角度?

机械角度用于描述转速、位置(如编码器读数、转子机械位置)。 电角度用于换相控制(六步换相、FOC 矢量控制)。驱动器需要知道当前电角度来决定哪一相该通电、电流矢量的方向等。

使用AS5600读取转子的位置

uint16_t AS5600_ReadRawAngle(void)
{
    uint8_t high, low;
    uint16_t raw_angle;

    IIC_Start();

    IIC_SendAddr(AS5600_ADDR << 1);

    IIC_SendByte(AS5600_RAW_ANGLE_HIGH);

    IIC_Start();

    IIC_SendAddr((AS5600_ADDR << 1) | 0x01);

    IIC_Ack();

    high = IIC_ReadByte();

    IIC_Nck();

    low = IIC_ReadByte();

    IIC_Stop();

    raw_angle = (((uint16_t)high << 8) | low) & 0x0FFF;

    return raw_angle;
}

uint16_t AS5600_ReadAngle(void)
{
    return (uint16_t)((uint32_t)AS5600_ReadRawAngle() * 3600 / 4096);
}

根据转子位置驱动无刷电机

void test2(void)
{
    uint16_t angle = AS5600_ReadAngle();
    uint16_t e_angle = (uint16_t)((angle * POLE_PAIRS) % 3600);
    uint8_t step = e_angle / 600;

    U_Enable;
    V_Enable;
    W_Enable;
    switch (step)
    {
    case 0:
        U_HIGH;
        W_LOW;
        V_Disable;
        break;
    case 1:
        U_HIGH;
        V_LOW;
        W_Disable;
        break;
    case 2:
        W_HIGH;
        V_LOW;
        U_Disable;
        break;
    case 3:
        W_HIGH;
        U_LOW;
        V_Disable;
        break;
    case 4:
        V_HIGH;
        U_LOW;
        W_Disable;
        break;
    case 5:
        V_HIGH;
        W_LOW;
        U_Disable;
        break;
    default:
        break;
    }
}

将test2函数1ms调用一次,发现速度已经可以提上来了,但是噪音很大,

于是我上网查找噪音大的原因:

  • 转矩脉动大:六步换相将360°电角度分为6个60°扇区,每步仅两相通电、第三相悬空,输出方波/梯形波电流。换相瞬间一相突断、一相突通,电感导致电流突变形成转矩冲击,每转产生6次脉冲,典型转矩脉动约13%。
  • 磁场方向跳跃:定子磁场非连续旋转,而是每60°“跳”一次。大部分时间磁场与转子磁场不垂直,产生无用径向分力拉扯定子铁心引发振动。
  • 谐波含量高:方波电流谐波丰富,直接转化为电磁噪声和机械振动。

正弦波驱动(SPWM)

原理解析

就是生成一个旋转的磁场带动转子转动,U、V、W三相物理位置上面可以等效为相差120°,我用动画演示一下:

制作正弦表

用到的数学公式:

sin(θ+d)=sinθ.cosd+cosθ.sindsin(θ+d) = sinθ . cosd + cosθ . sind

cos(θ+d)=cosθ.cosdsinθ.sindcos(θ+d) = cosθ . cosd - sinθ . sind

cosx=±1sin2x\cos x = \pm\sqrt{1 - \sin^2 x}