前言
电机的定位控速都离不开对于转子位置的检测。采用霍尔传感器的是电机控制的常用方法。
本文就笔者学习霍尔传感器的使用尝试自己写这部分算法的一些心得与各位大神交流。
1 电机霍尔状态
我们知道,一个周期有6个霍尔状态,而霍尔状态的数值顺序与霍尔安装角度和霍尔传感器的型号、安装方式都有关系。
以120°相位差安装为例,霍尔状态依次5(101)、4(100)、6(110)、2(010)、3(011)、1(001)。
关于霍尔传感器状态的顺序测量可以参见以下两篇文章:
链接: 【电机控制】霍尔传感器和反电动势的关系分析
链接: 【电机控制】无刷电机基础算法
以下通过伪代码简要说明实现方式。
/* 锁定HU HV HW与GPIO的对应关系 */
hall_u_status = Get_PinLevel(real_hall_u_port&pin);
hall_v_status = Get_PinLevel(real_hall_v_port&pin);
hall_w_status = Get_PinLevel(real_hall_w_port&pin);
/* 根据对应关系获取霍尔状态 */
hall_status = hall_u_status<<2 | hall_v_status<<1 | hall_w_status<<0;
如果MCU具备PWDT模块,且有HALL检测封装函数,可以直接调用。如AC780X系列:
g_hall.pData->hall_status_buff = PWDT_GetHallStatus(PWDT) & 0x07;
当然,其实现算法与伪代码类似,更为简洁的方式是直接按模块IO读取霍尔组合状态。
2 霍尔检测的基本目标
2.1 位置(电角度)初始化
对于一个确定的电极,霍尔状态分为6种,即每次霍尔状态更新我们可以校正一次电角度,显然,根据霍尔状态测量得到的电角度精度为60°。
以下代码摘自ST的开源算法库中的估算方式,依据霍尔状态对应的电角度中值进行设定。该方法的优点是不管正转反转,其误差都是±30°。需要注意的是,初始电角度只是给整个运行提供一个初始状态,并不需要一个特别精确的值。后面的电角度会根据前面的运行信息得到更精确的估算。
/**
* @brief Read the logic level of the three Hall sensors and individuates in this
* way the position of the rotor (+/- 30°). Electrical angle is then
* initialized.
* @param pHandle: handler of the current instance of the hall_speed_pos_fdbk component
* @retval none
*/
static void HALL_Init_Electrical_Angle(HALL_Handle_t *pHandle)
{
if (pHandle->SensorPlacement == DEGREES_120)
{
pHandle->HallState = LL_GPIO_IsInputPinSet(pHandle->H3Port, pHandle->H3Pin)<<2
| LL_GPIO_IsInputPinSet(pHandle->H2Port, pHandle->H2Pin)<<1
| LL_GPIO_IsInputPinSet(pHandle->H1Port, pHandle->H1Pin);
}
else {
pHandle->HallState = (LL_GPIO_IsInputPinSet(pHandle->H2Port, pHandle->H2Pin)^1)<<2
| LL_GPIO_IsInputPinSet(pHandle->H3Port, pHandle->H3Pin)<<1
| LL_GPIO_IsInputPinSet(pHandle->H1Port, pHandle->H1Pin);
}
switch(pHandle->HallState)
{
case STATE_5:
pHandle->_Super.hElAngle = (int16_t)(pHandle->PhaseShift+S16_60_PHASE_SHIFT/2);
break;
case STATE_1:
pHandle->_Super.hElAngle =(int16_t)(pHandle->PhaseShift+S16_60_PHASE_SHIFT+
S16_60_PHASE_SHIFT/2);
break;
case STATE_3:
pHandle->_Super.hElAngle =(int16_t)(pHandle->PhaseShift+S16_120_PHASE_SHIFT+
S16_60_PHASE_SHIFT/2);
break;
case STATE_2:
pHandle->_Super.hElAngle =(int16_t)(pHandle->PhaseShift-S16_120_PHASE_SHIFT-
S16_60_PHASE_SHIFT/2);
break;
case STATE_6:
pHandle->_Super.hElAngle =(int16_t)(pHandle->PhaseShift-S16_60_PHASE_SHIFT-
S16_60_PHASE_SHIFT/2);
break;
case STATE_4:
pHandle->_Super.hElAngle =(int16_t)(pHandle->PhaseShift-S16_60_PHASE_SHIFT/2);
break;
default:
/* Bad hall sensor configuration so update the speed reliability */
pHandle->SensorIsReliable = false;
break;
}
/* Initialize the measured angle */
pHandle->MeasuredElAngle = pHandle->_Super.hElAngle;
}
2.2 估算当前转速
基本思路:通过FIFO数组来记录通过六区的时间。
(1)启动时,电机速度尚未稳定,FIFO数组尚未被填满,当前转速用最近一次更新的数组数据来进行估算;
(2)FIFO数组填满后,电机处于变动过程中,可以使用最近一次的分区的时间进行估算;当电机转速相对稳定时,FIFO数组的值会在目标转速附近,其极差取决于转速稳定区间。
(3)每当霍尔状态更新时,校正当前霍尔角度。注意,不同转向的校正计算是不一样的。
2.3 霍尔相序的自学习
注:以下是笔者的思路,未参考成熟库的代码,不确保逻辑中没有漏洞。
(1) 通过VF定向方式,将转子按照10°间隔将转子锁定依次锁定在0°,10°,20°。。。350°,360°。。。(根据角度分解到Uq、Ud再分解到Ua,Ub,Uc)。
(2)获取不同角度下的霍尔状态,对于霍尔状态变化的角度区间,进一步缩小角度定向间隔为2°,获取更精确的霍尔状态切换角度,用于角度对齐。
2.4 代码实现
笔者的思路是创建6个霍尔分区节点并按照切换顺序构建循环列表。
核心的操作是每当霍尔状态切换时更新当前节点指针。
对于已知霍尔节点状态的中点角度估算的代码实现就非常方便,用当前节点对齐角度和下一个节点对齐角度求中值即可。
速度估算根据进入当前节点的方向前推或后推各节点的持续时间,对于入口方向和出口方向不同的节点,是转子的换向区(正反转切换)。
当节点切换后,电角度估算 = 对齐角度(依据转向设置) + 计数时间 * 估计角速度。
以下是具体代码,仅做原理说明,没有详细优化IQMATH计算和单位对齐。
#ifndef __HALL_SENSOR_H__
#define __HALL_SENSOR_H__
/*!
* @file hall_sensor.h
*
* @brief This file provides hall electric theta and hall self-learn functions interfaces.
*
*/
/* =========================================== Includes ==========