84【无人机】003 六步换相 驱动无刷电机

直流无刷电机ABC轴线怎么划分?电角度、机械角度与坐标变换解析 三相交流电机运行时,定子绕组轴线与转子位置的概念常让初学者混淆。直流无刷电机的三相绕组轴线并非按三维直角坐标的x/y/z垂直分布,而是位于垂直于转轴的径向平面内,彼此相差120°电角度。理解电角度与机械角度的换算关系(θe=p×θm),是正确安装霍尔传感器、设计换相逻辑和绕组排布的关键。在现代FOC控制中,还需进一步通过Clarke变换和Park变换将abc轴系转换到αβ轴系及dq轴系,使交流量变为直流量,从而实现高性能转矩控制。掌握这些基础概念,有助于快速排查电机抖动、堵转和霍尔相位错误等工程问题,并为深 阅读详情

1 引言

        本博客是为了记录自己在无人机行业中,所涉及的技术成长路线。既是记录自己的成长轨迹,亦是总结所学,便于后续持续学习进步。

        本blog记录了使用STM32F407 + EG2133三相独立半桥驱动芯片 + MT6701磁性角度编码器芯片 + 无刷电机(10对极)无刷电机,使用六步换向驱动电机转动实验过程。记录可能理解浅薄,请多包涵。

2 实验过程

2.1 机械角度和电角度

        机械角度:

转子实际旋转的角度。

如:转子正方向旋转一圈,那么机械角度是360°;正方向旋转两圈,则机械角度是720°。     

若:转子反方向旋转一圈,那么机械角度是-360°;反方向旋转两圈,则机械角度是-720°。

        电角度:

电角度是描述转子与磁场相关的角度。

(1)转子在磁场中旋转会产生正弦交变电流,一个完整的正弦波周期对应 360° 电角度。

(2)电角度本质上衡量的是“时间”和“相位”,而不是“空间位置”。

        电角度和机械角度关系:

电角度 = 机械角度 x 电机磁极对数。

若电机有N对磁极,转子旋转一圈,机械角度=360°,电角度=360° x 磁极对数N。

2.2 死区产生

        来自deepseek回答:只要无刷电机(BLDC/PMSM)使用“三相全桥逆变器”驱动,且采用“PWM脉宽调制”方式,那么在每一个PWM周期中,都必然存在死区时间。

物理原因:MOSFET功率管的开通速度永远比关断速度快

        如果没有死区时间,那么当程序命令“上桥开通”的同时命令“下桥关断”,由于下桥关断有延迟,而上桥瞬间就通了,这会导致上下桥臂瞬间直通(贯穿),相当于把电源正负极直接短路。结果就是:巨大的尖峰电流烧毁MOS管。

      死区时间是为了规避功率开关管固有的‘开通延迟小于关断延迟’特性,通过插入一段两管均截至的空白区间,以防止上下桥臂发生贯穿性短路。

        死区时间中,下桥臂的驱动信号全部被硬件强制拉低,保证上桥完全关闭后,再开通下桥。属于偷走共有的电压输出时间。

        死区时间是插入在PWM周期内部的,如下图示。

2.3 死区时间计算

        说是不同的芯片,死区的计算公式不一样。这里用了STM32F407单片机,故就一起看看STM32F407 的死区时间计算。

公式:死区时间 = DTG值 × t_DTS

           t_DTS = 1 / f_TIM = 1 / 168MHz ≈ 5.95ns

          STM32F4 参考手册完整公式(DTG 分段编码):

DTG[7:5]死区时间公式DTG 范围死区范围 @168MHz
0xxDT = DTG[7:0] × t_DTS0~1270~756ns
10xDT = (64 + DTG[5:0]) × 2 × t_DTS128~191760ns~1.5µs
110DT = (32 + DTG[4:0]) × 8 × t_DTS192~2231.5µs~3.0µs
111DT = (32 + DTG[4:0]) × 16 × t_DTS224~2553.0µs~4.5µs

        定时器设置的DeadTime会直接设置到OTG寄存器,如下示例。

DeadTimeDTG 二进制死区时间公式
170b00010001~101ns17 × 5.95ns
420b00101010~250ns42 × 5.95ns
840b01010100~500ns84 × 5.95ns

2.4 实验记录

记录1:换相表。

        换相表默认按电角度从 0° 到 360° 递增设计,当转子旋转电角度持续增加时,必须顺着步骤 0→1→2… 的换相表顺序切换通电状态,才能产生正向的旋转力矩,持续驱动电子转动的力矩。否则可能会出现转子原地震动等现象。

记录2:无刷电机无法转动且高频震动。

        按照换相表,电角度从0到360°方向增长驱动电机旋转时,若磁性编码器读出的电角度是递减的,此时与换相表递增设计是相反的。即故转子在物理上正转,可编码器测量电角度却在减小(反转),按代码实际照换向逻辑,此时会产生来回变化的反向力矩,让电机剧烈“原地”抖动。

记录3:机械角度0°其实等于电角度0°

        机械角度0°可通过 磁性传感器z相 输出信号定位。当转子旋转到z相0°时,此时z相输出高电平,单片机通过上升沿捕获,标记此时机械角度0度。

        电角度0°是描述电磁起始点。如果无刷电机有多对磁极,那么机械角度0°实际上是对应“其中某一对极”的电角度0°,而对于其它的对极电角度不是0度。

重要!!!

(1)当转子转到机械0度时,如果电机是2极(1对极),此时电角度直接就是0度;

(2)对于多对极电机,一般会将机械角度为0时,将此时的电角度直接定义为0度;

记录4:实际电角度计算时,要“手动” 减去 机械角度偏移,否则电角度计算有误差。

        简单测量机械角度的设备一般是霍尔传感器,如项目中使用了MT6701传感器测量转子位置。当转子转到z相输出高电平时,此时机械角度为“0”时(转子稳定位置),但霍尔传感器实测机械角度输出并不是0度,而由于转子稳定时,电角度是可定义成0度的。

        根据电角度和机械角度关系式:

理想状态:电角度 = 机械角度 x 电极对数

实际状态:电角度= (实测机械角度 - 偏移角度)x 电极对数

        此时,在软件算法中对于电角度的计算,是必须要减去当电角度为0时的机械角度,这样才能使用:电角度 = 机械角度 x 电极对数 这个公式。

电角度0度 = 0 x 电极对数              // 0 = (实测机械角度 - 偏移角度)

3 六步换相代码

        如下是六步换相电机控制代码。

/******************************************************************************/
/* file         : motorTsk.c                                                  */
/* description  : motor task                                                  */
/*                                                                            */
/* author       : justin                                                      */
/* version      : 1.0                                                         */
/* date         : 2024-01-15                                                  */
/******************************************************************************/

/****************************************************************************/
/* Head files                                                               */
/****************************************************************************/
#include <math.h>
#include "gpio.h"
#include "fc_main.h"
#include "fc_public.h"
#include "fc_mt6701.h"
#include "fc_EG2133.h"

#include "sysMngr.h"
#include "keyTsk.h"

#include "motorTsk.h"

/****************************************************************************/
/* Marco Define                                                             */
/****************************************************************************/
#define PWM_PERIOD                  8399    // TIM1 ARR值
#define PWM_HALF                    4199    // 50%占空比
#define PI                          3.14159265f
#define PIX2                        (2.0f * PI)

/****************************************************************************/
/* Type Definitions                                                         */
/****************************************************************************/

/****************************************************************************/
/* Global Variable Declarations                                             */
/****************************************************************************/
uint8_t                                         g_motor_run     = 0;        // 电机运行标志
float                                           g_motor_speed   = 5.0f;     // 目标电角度速度 (Hz)
float                                           g_motor_voltage = 0.5f;     // 电压幅值 (0.0~1.0)

/****************************************************************************/
/* static Variable Declarations                                             */
/****************************************************************************/
static fc_core_task_id_t                        s_motorTsk_id       = -1;
static uint8_t                                  s_last_step         = 0;       // 上一次换相步骤

static uint8_t                                  s_motor_pwr_enable      = 0;       // 0-off 1-enable
static uint8_t                                  s_has_calib             = 0;       // 0-编码器未校准 1-电角度已标定
static float                                    s_elec_zero_offset_deg  = 0.0f;    // A相对齐时编码器的机械角度(°),电角度零点偏置
static float                                    s_comm_adv_deg          = 0.0f;   // 换相提前角(°),需根据实际电机标定
static int8_t                                   s_comm_direction        = -1;       // +1正向 -1反向,若电机抖动可尝试改为-1

/****************************************************************************/
/* extern Variable Declarations                                             */
/****************************************************************************/

/****************************************************************************/
/* extern functions Declarations                                            */
/****************************************************************************/

/****************************************************************************/
/* Function Declarations                                                    */
/****************************************************************************/

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_pwrCtl                                    */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_pwrCtl
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{

    s_motor_pwr_enable = (s_motor_pwr_enable==0)?(1):(0);

    if(s_motor_pwr_enable == 0)
    {
        // pwr off
        HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);
    }
    else
    {
        // pwr on
        HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_SET);
    }

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_callbZero                                 */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_callbZero
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_fixAngle();
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_moterRun                                  */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_moterRun
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_run();
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : _motorTsk_keyCB_moterStop                                 */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
static void _motorTsk_keyCB_moterStop
(
    KEY_NO_X_VALUE                  keyValue,
    uint32_t                        occurTick
)
{
    motorTsk_stop();
    return;
}

/****************************************************************************/
/* 辅助函数:设置单相的工作状态(使能/浮空)并更新比较值                    */
/* phase : 0=A相, 1=B相, 2=C相                                             */
/* enable: 1=使能输出, 0=浮空(上下管均关断)                               */
/* ccr   : 比较值(当 enable=1 时有效)                                     */
/****************************************************************************/
static void Motor_SetPhaseState(uint8_t phase, uint8_t enable, uint32_t ccr)
{
    uint32_t ccer_mask;

    switch (phase)
    {
        case 0: /* A相 : CH1 & CH1N */
            ccer_mask = TIM_CCER_CC1E | TIM_CCER_CC1NE;
            if (enable)
            {
                TIM1->CCR1 = ccr;                 // 先更新比较值
                TIM1->CCER |= ccer_mask;          // 再使能输出
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;         // 同时关闭 CH1 和 CH1N
            }
            break;

        case 1: /* B相 : CH2 & CH2N */
            ccer_mask = TIM_CCER_CC2E | TIM_CCER_CC2NE;
            if (enable)
            {
                TIM1->CCR2 = ccr;
                TIM1->CCER |= ccer_mask;
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;
            }
            break;

        case 2: /* C相 : CH3 & CH3N */
            ccer_mask = TIM_CCER_CC3E | TIM_CCER_CC3NE;
            if (enable)
            {
                TIM1->CCR3 = ccr;
                TIM1->CCER |= ccer_mask;
            }
            else
            {
                TIM1->CCER &= ~ccer_mask;
            }
            break;

        default:
            break;
    }
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_tim1_update                                      */
/* description  : TIM1更新中断回调 - 基于编码器电角度的六步换相              */
/*                使用fcMT6701_GetElcAngle()获取电角度进行闭环换相          */
/*                浮空相通过关闭PWM输出实现                                  */
/*                                                                          */
/****************************************************************************/
void motorTsk_tim1_update(void)
{
    float elc_angle_deg;                     // 当前电角度(度),0~360
    uint8_t current_step;                    // 当前换相步骤 (0~5)
    static uint8_t s_last_step = 0xFF;       // 上一次的步骤,0xFF强制首次更新

    if(fcMT6701_GetCalib() == false || s_has_calib == 0)
    {
        return;
    }
    // 六步换相表 (index 0~5 对应电角度 0°~60°, 60°~120°, ... 300°~360°)
    // 2: 高侧PWM(上管PWM调制,下管互补导通)
    // 1: 低侧导通(下管常通,上管关断)
    // 0: 浮空(上下管均关断)
    const uint8_t commutation_table[6][3] = {
        {2, 1, 0},  // 步骤0: A→B (  0°~ 60°)
        {2, 0, 1},  // 步骤1: A→C ( 60°~120°)
        {0, 2, 1},  // 步骤2: B→C (120°~180°)
        {1, 2, 0},  // 步骤3: B→A (180°~240°)
        {1, 0, 2},  // 步骤4: C→A (240°~300°)
        {0, 1, 2},  // 步骤5: C→B (300°~360°)
    };

    // 1. 计算修正后的电角度(°): 机械角度 - 偏置 → 转换为电角度
    float mech_deg = fcMT6701_GetAngle() - s_elec_zero_offset_deg;
    if (mech_deg < 0.0f) mech_deg += 360.0f;
    elc_angle_deg = mech_deg * 10.0f;   // MOTOR_POLE_PAIRS = 10
    while (elc_angle_deg >= 360.0f) elc_angle_deg -= 360.0f;

    // 2. 根据电角度+提前角确定换相步骤, 换相方向可调
    current_step = ((uint32_t)((elc_angle_deg + s_comm_adv_deg) / 60.0f)) % 6;
    if(s_comm_direction < 0) current_step = 5 - current_step;

    // 3. 计算当前电压指令对应的占空比
    uint32_t duty_on  = (uint32_t)(g_motor_voltage * PWM_HALF);
    uint32_t duty_low = 0;   // 低侧常通:CCR=0 → 下管常通(上管关断)

    // 4. 根据步骤是否发生变化,执行不同的更新策略
    if (current_step != s_last_step)
    {
        /* ---- 发生了换相:重新配置三相的使能状态与占空比 ---- */
        s_last_step = current_step;

        for (uint8_t phase = 0; phase < 3; phase++)
        {
            uint8_t mode = commutation_table[current_step][phase];

            if (mode == 2)          // 高侧PWM
            {
                Motor_SetPhaseState(phase, 1, duty_on);
            }
            else if (mode == 1)     // 低侧导通
            {
                Motor_SetPhaseState(phase, 1, duty_low);
            }
            else                    // mode == 0 → 浮空
            {
                Motor_SetPhaseState(phase, 0, 0);  // enable=0, ccr值无所谓
            }
        }
    }
    else
    {
        /* ---- 步骤未变:仅更新高侧PWM相的占空比,跟踪电压指令变化 ---- */
        for (uint8_t phase = 0; phase < 3; phase++)
        {
            if (commutation_table[current_step][phase] == 2)
            {
                // 直接更新该高侧相的CCR,低侧和浮空相保持不变
                switch (phase)
                {
                    case 0: TIM1->CCR1 = duty_on; break;
                    case 1: TIM1->CCR2 = duty_on; break;
                    case 2: TIM1->CCR3 = duty_on; break;
                }
                break;  // 每步只有一个高侧相
            }
        }
    }
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_ReTOZero                                         */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_ReTOZero
(
    void
)
{
    static uint8_t      step        = 0;
    const float         voltage     = 0.04f;   // 固定小电压

    // 使用你原换相表
    const uint8_t       table[6][3] =
    {
        {2, 1, 0},
        {2, 0, 1},
        {0, 2, 1},
        {1, 2, 0},
        {1, 0, 2},
        {0, 1, 2}
    };


    HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_SET);
    fc_delay_ms(20);
    fcEG2133_enablePWM();

    do
    {
        // 先全部浮空
        TIM1->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1NE |
                        TIM_CCER_CC2E | TIM_CCER_CC2NE |
                        TIM_CCER_CC3E | TIM_CCER_CC3NE);

        uint32_t duty_on  = (uint32_t)(PWM_HALF*voltage);
        uint32_t duty_low = 0;

        // 设置比较值
        uint32_t ccr_a = (table[step][0] == 2) ? duty_on : ((table[step][0] == 1) ? duty_low : 0);
        uint32_t ccr_b = (table[step][1] == 2) ? duty_on : ((table[step][1] == 1) ? duty_low : 0);
        uint32_t ccr_c = (table[step][2] == 2) ? duty_on : ((table[step][2] == 1) ? duty_low : 0);
        TIM1->CCR1 = ccr_a;
        TIM1->CCR2 = ccr_b;
        TIM1->CCR3 = ccr_c;

        // 只使能非浮空相
        uint32_t ccer = 0;
        if (table[step][0] != 0) ccer |= (TIM_CCER_CC1E | TIM_CCER_CC1NE);
        if (table[step][1] != 0) ccer |= (TIM_CCER_CC2E | TIM_CCER_CC2NE);
        if (table[step][2] != 0) ccer |= (TIM_CCER_CC3E | TIM_CCER_CC3NE);
        TIM1->CCER |= ccer;

        step = (step + 1) % 6;

        fc_delay_ms(100);
    }
    while(fcMT6701_GetCalib()== false);

    // Z相校准完成,关闭PWM,编码器归零
    fcEG2133_disablePWM();
    HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);

    fcMT6701_SetZero();

    printf("step =  %d\r\n", step);
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_fixAnglee                                        */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_fixAngle
(
    void
)
{
    // Step1: 找Z相并归零编码器
    s_has_calib = 0;
    fcMT6701_ResetCalibFlag();
    motorTsk_ReTOZero();

    // Step2: 给A相通电,转子自动对齐到A相磁极的电角度0°位置
    fcEG2133_setPWM(400, 0, 0);
    fcEG2133_enablePWM();
    fc_delay_ms(1000);
    fcEG2133_disablePWM();

    // 此时编码器的读数就是电角度零点的机械角度偏置
    s_elec_zero_offset_deg = fcMT6701_GetAngle();

    // 标记电角度标定完成,ISR可以开始换相
    s_has_calib = 1;

    printf("ElecOffset = %.1f\r\n", s_elec_zero_offset_deg);
    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_run                                              */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_run
(
    void
)
{
    if(fcMT6701_GetCalib() == true && s_has_calib == 1)
    {
        fcEG2133_enablePWM();
    }

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_stop                                             */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_stop
(
    void
)
{
    fcEG2133_disablePWM();

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_task                                             */
/* description  : none                                                      */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_task
(
    void                            *user_params
)
{
    static uint8_t  has_init    = 0;

    // attention:
    // task can not be blocked!!!!!
    // this is 100ms task
    do
    {
        if(has_init == 0)
        {
            has_init = 1;
            motorTsk_ReTOZero();
        }

        // 电机控制任务:可以在这里添加速度调节、模式切换等逻辑

        // 打印编码器信息(电角度以°显示,便于调试)
         printf("pos:%d ang:%.1f eAng:%.1f off:%.1f adv:%.0f dir:%d cal:%d\r\n",
                fcMT6701_GetPosition(), fcMT6701_GetAngle(),
                fcMT6701_GetElcAngle() * 180.0f / PI,
                s_elec_zero_offset_deg, s_comm_adv_deg,
                s_comm_direction, s_has_calib);

    } while(0);

    return;
}

/****************************************************************************/
/*                                                                          */
/* Function     : motorTsk_Init                                             */
/* description  : module init                                               */
/*                                                                          */
/* Parameters   :                                                           */
/*   void - none                                                            */
/*                                                                          */
/* Returns      : none                                                      */
/*                                                                          */
/* Author       : justin                                                    */
/* Created      : 2025-10-25                                                */
/* Modified     : 2025-10-25                                                */
/* Version      : 1.0.0                                                     */
/*                                                                          */
/****************************************************************************/
void motorTsk_Init
(
    void
)
{
    keyTsk_register_callback(KEY_NO_1_SHORT_PRESSED, _motorTsk_keyCB_callbZero);
    keyTsk_register_callback(KEY_NO_2_SHORT_PRESSED, _motorTsk_keyCB_moterRun);
    keyTsk_register_callback(KEY_NO_3_SHORT_PRESSED, _motorTsk_keyCB_moterStop);
    keyTsk_register_callback(KEY_NO_4_SHORT_PRESSED, _motorTsk_keyCB_pwrCtl);

    // 注册电机任务(100ms周期)
    s_motorTsk_id = fc_core_task_register(motorTsk_task, 100, NULL);
    s_motorTsk_id = s_motorTsk_id;

    return;
}

实验设备图:

over!

知识普及篇——动手做foc无刷电机电子调速器 第一篇-电机常识无刷电机模型电机构造电机模型与运动原理电机模型电机运动原理   本系列博客将从零,详细的讲解FOC电机调速器的制作(包括电机理论知识、软件、硬件,以及具体的实现)。涉及的知识面有点大,希望读者是有一定计算机知识储备的受过高等教育的学生或者相关行业的公司职员。或者意志坚定要做好FOC的所有人。   最近手欠做起了无刷电机的控制器。查阅大量文献和博客发现,对于无刷电机的控制在国外已经非常的普及,在国内相应的创客却很少有开源的(网上找到的国内资料要不就是只讲理论,要不就是一帮码农贴代码)。为什么国 阅读详情

相关推荐

无刷电机学习笔记

无刷电机

u011221522的博客 1万+

电机的电角度和机械角的关系

系统上电后直线电机以一定的速度向零点运动,当系统检测到电机端部的Z轴脉冲时,计数器复位信号有效,计数器清零,此时电机所在的位置即为零点。常用的三相无刷直流电动机,一般有3个位置传感,输出波形有两种:一种是相位差60°电角度,另一种是相位差120°电角度。例如,1对磁极,相位差120°电角度,则3个位置传感器的空间间隔为120°机械角度;2对磁极,相位差为60°电角度,则3个位置传感器的空间间隔为30°机械角度。电机每对极在定子内圆上所占的角度360°/p指的是实际的空间几何角度,这个角度被称为机械角度。

weixin_66732375的博客 4737

直流无刷电机(BLDC)六步换相驱动原理

直流无刷电机相对直流有刷电机具备效率更高,所需维护更少,寿命更长等诸多特点被广泛应用。六步换相控制FOC矢量控制直接力矩控制多种控制方式中,六步换相控制相对其他控制较为简单,也适合作为直流无刷电机的控制的入门学习方案。关于六步换相控制,网上的资料很多,但基本上都是基于厂商提供了对应电机的换相表直接根据换向表内容进行换向控制,这样是实现起来简单,但是对于深层次的原理理解将不够,本文完整的阐述。以上便是针对直流无刷电机的六步换向控制啦,欢迎大家共同讨论。创作不易,转载请注明出处!

爱出名的狗腿子 2万+

电机知识总结

对一些电机的总结。

xiaoxuechong的博客 3045

【信息科学与工程学】【控制科学】第十二篇 微型计算机控制技术01

更精确的经典模型:I1在第5周期WB结束,I2最早可在第6周期进入EX,但I2在ID阶段就需要R1,因此I2的ID需在第6周期,而I1的WB在第5周期,所以I2的ID可以紧接在第6周期,但中间仍有一个stall(因为I1的EX结果要等到MEM之后才能转发给ID?有优先级继承后,Task_L被提升优先级,不会被Task_M抢占,阻塞时间缩短为Task_L剩余执行时间(9ms),仍可能超过10ms,但可通过调整任务周期或使用中断处理缓解。电感L=10μH,输出电容C=100μF,ESR=5mΩ。

weixin_49199313的博客 8634

【MATLAB代码,多无人机路径规划6】基于RRT与动态窗口法(RRT+DWA)的多无人机二维动态路径规划与避障。订阅专栏后可查看完整代码

本文基于MATLAB实现四架无人机在二维动态障碍环境中的协同路径规划,采用RRT+DWA算法,支持参数自定义。通过对比RRT+APF与RRT+DWA的避障效果,可视化轨迹、净间隙、速度加速度及航程等,输出任务完成率与碰撞统计。代码可直接运行,订阅专栏后获取完整源码,支持定制与讲解。

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 550

FOC无刷电机控制:关于极对数与电机物理原理的一些疑惑和推测

本文仅代表个人在学习过程中对一些知识的疑惑与猜测,如发现错误,敬请不吝赐教。 在学习FOC控制的过程中,有一个常被忽视、即使在知识浩如烟海的互联网上也难觅只言片语的知识点。当我们费尽千辛万苦,终于理解了一堆数学变换与电路控制知识后,正以为即将拨云见日之时,有的人也许会突然注意到它,然后便与前些日子的我一般,开始盯着抽象的示意图怀疑人生。 虽然从控制算法的角度来看,它实在是简单的出奇,但是只要我们细想,便会发现这件事情并没有许多教程中阐述的那么简单,这个隐藏问题就是电机的极对数、电角度与机械角度之间的神秘

qq_61895755的博客 1万+

【MATLAB代码】基于RRT与人工势场法(RRT+APF)的多无人机二维动态路径规划与避障。订阅专栏后可查看完整代码

本文基于RRT+APF算法实现多无人机动态路径规划与避障仿真,通过MATLAB完整代码可直接运行。对比传统APF方法,该方案在轨迹平滑性、安全净间隙及到达效率上表现更优。支持参数自定义,订阅专栏后可获取源码与定制服务,适用于科研与工程实践。

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 184

从基础描述无刷直流电机的工作原理

关注、星标公众号,不错过精彩内容作者:涅哀编辑整理:strongerHuang来源地址:https://www.zhihu.com/question/318357171/answer/7...

strongerHuang 7186

【MATLAB代码,无人机避障7】基于RRT*与人工势场法(RRT*+APF)的多无人机二维动态路径规划与避障。订阅专栏后可查看完整代码

本文基于RRT与人工势场法(APF)实现四架无人机在二维动态障碍环境中的协同路径规划与避障。通过RRT优化全局路径,结合APF进行局部避碰,支持参数自定义,提供完整MATLAB代码,可直接运行并生成轨迹、安全净间隙、速度加速度及航程等可视化结果,对比RRT+APF与RRT*+APF性能,适用于科研与教学。

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 223

DataWorks数据安全治理最佳实践

DataWorks基于数据安全治理的常见思路,针对资产梳理、技术体系建设和运营体系建设,提供了一系列数据安全产品能力,您可通过“基础防护建设、数据安全防护措施及策略增强建设、数据安全持续运营”三个阶段在DataWorks上落地数据安全治理项目。参考本文启动数据安全治理项目前,建议您先了解DataWorks数据安全产品相关能力了解DataWorks数据安全产品能力后,您可参考如下三个阶段在DataWorks上落地数据安全治理项目。

soso1968的博客 1438

直流无刷电机控制(一)六步换相(有感霍尔)附六步换相实现代码

直流无刷电机的转子为永磁铁,定子为换相线圈,有别于有刷电机通过电刷或者换向器换相,无刷电机通过控制器电子换相。

今届入室,众流剋上 1万+

C#安装OpenCv及打开笔记本默认摄像头方法

C#安装OpenCv及打开笔记本默认摄像头方法

cg1135217680的博客 2572

电机电角度和机械角度的终极解释(网络上没一个说清楚什么是电角度,我去墙上看到的解释,给力)

bldc FOC控制里面, park变换,用的就是电角度。说人话就是,机械角度就是转子相对于定子旋转的角度,就是人看到的角度。所以电角度=极对数(或者级数)*机械角度。的时候,代表电角度是180度(电角度: 一个点的磁极发生。

raominping的专栏 2万+

超过4.2万个AOI(地理围栏),深圳市2025年2月15日更新的全类别AOI,矢量图层(全国22个超大特大城市AOI更新系列)

超过4.2万个AOI(地理围栏),深圳市2025年2月15日更新的全类别AOI,矢量图层(全国22个超大特大城市AOI更新系列)

1071

JaCoCo报告聚合的5个常见坑点排查指南:从单模块到多模块的完整避坑手册

本文详细解析了JaCoCo在多模块Maven项目中生成聚合报告时的5个常见问题,包括多模块报告聚合失效、覆盖率数据不一致、增量构建导致的覆盖率丢失等,并提供了具体的配置示例和解决方案。帮助开发者高效排查和解决JaCoCo报告聚合中的各种疑难杂症,提升代码覆盖率分析的准确性和效率。

weixin_27918373的博客 250

简单理解:电角度 = 机械角度 × 极对数

文章摘要:FOC无刷电机控制的核心公式为电角度=机械角度×极对数。机械角度反映转子物理旋转(0-360°),电角度表示磁场交变周期(0-360°)。例如极对数p=4时,转子转1圈(机械360°)对应电角度1440°。FOC需用电角度进行矢量变换,因磁场周期由磁极对数决定,直接使用机械角度会导致控制异常。实际应用中需对电角度模360°处理,且电角速度=机械角速度×极对数。该原理是多极电机控制的基础。

DIY 638

嵌入式工程师必学(9):USB 3.0协议理解

USB3.0和USB2.0相比,在线缆上从4根线(Vbus、GND、D+、D-)变为了8根线(Vbus、GND、D+、D-、SSRX+\SSRX-\SSTX+\SSTX-),可见增加的4根线都是和超速相关的,新增加的超速有两类,分别为:超速Gen1(5.0Gbps),超速+Gen2(10Gbps),还兼容USB2.0的3类速率:low-speed(1.5Mbps),full-speed(12Mbps),andhigh-speed(480Mbps)。从设计可以看出,USB3....

码农17年的博客 1万+

区分电角度和机械角度

电角度的区别和联系 以下内容均来自于网络搜索,这里仅用作于自己记录笔记 解释1: 机械角度意为空间几何角度,相当于360° 电角度是指通过一个完整的周期内电流完成变化。从电磁分布的角度来看,永磁体(或励磁)产生的磁场空间分布呈现周期性变化,一个周期为电角度的360°显然从任意N极触发沿着某圆周方向经过S极再到下一个N极为一个周期的电角度。其周期可以在空间180°或者90°或者60°完成。 解释2: 磁场每转过一对磁极时,导体的基波电动势变化一个周期,在电路理论中,定义一个空间为360°的空间电角度。若电

ApexYuan 2万+

LVGL 蜂巢气泡菜单(Hex Menu)

h。

摸鱼专家 176

【ArcGIS风暴】Win10操作系统ArcGIS许可License无法启动的解决方法汇总(绝对成功!)

文章目录1. 关闭Windows Defender2. 关闭系统防火墙3. 删除迈克菲(McAfee)杀毒软件4. 在系统服务中启动 在安装ArcGIS软件时,最重要的一步是许可服务的正常启动,通常,由于各种各样的原因,ArcGIS许可管理器License Manager十有八九会无法启动,点N多次都没反应,如果许可服务不能如愿启动的话,即使Desktop安装成功,也是无法打开的。本文汇总了Win10操作系统之上ArcGIS安装过程中可能会导致服务无法启动的原因及解决办法。 ArcGIS安装参考教程:

智慧空间实验室 2万+

BLDC基础概念之机械角和电角度

BLDC基础概念之机械角和电角度 机械角:机械角就是空间几何角度,用圆规能够测量到的。因为电机是圆形的,所以它的范围是0-360度。 电角度:从定子来看,定子电流变化一个完整的周期定义为电角度的0-360度,称为一个电周期。一个电周期可以在空间360度完成也可以在空间180度或者90度或者60度完成,这和电动机(发电机也是这样)绕组布置成几对磁级有关。 从转子来看, 转子上分布有N对磁钢,电角度以一对磁钢为基准,形成电磁场的绕组经过一对磁钢的N极、S极、再回到另一对磁钢的N极时,完成从N、S、再到 N极一对

leekay123的博客 1万+

C# 零基础入门知识点汇总

本文属于C#零基础入门之百识百例系列目录文章。此系列文章已经完结,欢迎大家点击文中文章链接查看详情进行学习。

陈言必行 -- Unity游戏开发领域优质博主 5348

无人机航拍垃圾检测数据集深度学习 目标检测 无人机航拍 垃圾检测 环境卫生 YOLO格式 数据集发布9029期

无人机航拍垃圾检测数据集深度学习 目标检测 无人机航拍 垃圾检测 环境卫生 YOLO格式 数据集发布9029期

qq_2529413168的博客 186

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

基于 Hightopo 低空经济 WebGIS 无人机配送平台开发实践

低空物流配送的可视化开发,需要把城市空间、无人机飞行状态、航线和配送任务组织到同一套界面中。开发人员既要呈现无人机在三维城市中的位置与飞行姿态,也要让操作人员能够查看航线参数、气象预警和配送进程,完成从空间观察到业务操作的衔接。图扑(Hightopo)基于自研国产化可视化平台构建的低空经济无人机运维监控平台,覆盖空域管理、快递物流和外卖配送等场景。平台开发围绕场景组织、交互实现和数据展示展开。前端以二三维能力为基础,场景、图形和业务可视化均围绕 HT 实现,不接入或引用外部第三方组件。

Hightopo的博客 251

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: 83【无人机】002 mavlink协议
下一篇: 【84】004 开环Foc驱动无刷电机
Chasing_Chasing
博客等级 码龄10年 233粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值