旋转编码器绝对位置测量方法

一般的旋转编码器本身只能提供相对位置信息,不过配合零点信号(即Z相信号)即可确定绝对位置,下面结合TI C2000系列单片机来讨论具体实现方法。

基本原理

在C2000系列单片机中,使用QEQP模块对旋转编码器输入信号进行处理,先根据输入的A、B、Z三相信号生成QCLK内部时钟信号、QDIR方向信号及QI同步信号,这部分工作是由QDU(Quadrature Decoder Unit)子模块完成的。输入信号的极性,输出的来源等均可配置,具体详见数据手册。

生成的QCLK信号来源于A、B两相信号跳变沿,此信号与QDIR方向信号一起确定QPOSCNT寄存器的计数增减,具体时序图如下:

从理论上说,只要确定了一点的绝对位置,就可以通过读取QPOSCNT寄存器获取任意时刻的绝对位置,以两对极电机为例,示例性代码如下:

1
theta = _IQmpyI32(_IQ(PI / QEP_LINE), EQep1Regs.QPOSCNT);

此处的theta是电角度而不是机械角度,QEP_LINE为编码器线数。对于两对极电机来说,假设QPOSCNT的初值是0,电机完整的顺时针转过一圈后QPOSCNT中的值应该是4 * QEP_LINE,使用上式计算得到的对应电角度就是4PI rad

再考虑到电机的对称性及角度的周期性,theta的范围在[0, 2PI)内即可,对应的QPOSCNT的范围就是[0, 2 * QEP_LINE)。在C2000单片机中,可以通过QPOSMAX寄存器来设置这个最大值,示例代码如下:

1
2
3
EQep1Regs.QEPCTL.bit.PCRM = 1;         // 0 : QPOSCNT reset on an index event
// 1 : QPOSCNT reset on the maximum position
EQep1Regs.QPOSMAX = 2 * QEP_LINE - 1; // Set the maximum position

然而,这有两个问题,首先是初始时刻的绝对位置如何确定;其次是如何消除累积误差。解决方法是:初始时刻的绝对位置通过霍尔信号进行估测,累积误差通过Z相同步信号来消除。下面分别来讨论这两个问题。

初始时刻定位

初始时刻的位置确定比较简单,只要预先测定出Ha、Hb、Hc三个霍尔信号输出与绝对角度间的关系,在启动时通过查表的方法即可大致估算出初始角度。因为这一估算过程本来就不要求也不可能精确,故也无需测定霍尔信号跳变沿的准确位置,粗略的使用示波器观察信号估计一下即可。
示例性代码如下:

1
EQep1Regs.QPOSCNT = GetHall();

这句代码在初始化EQEP模块的时候调用一次,GetHall()函数可返回根据Hall信号猜测出的QPOSCNT寄存器的初值:

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
// Hall signal delt
#define HALL_DELT (QEP_LINE / 3)
// Hall signal offset
#define HALLOFFSET (HALL_DELT / 2)

Uint32 GetHall(void)
{
Uint16 Ha, Hb, Hc;
Uint16 HallSignal;

// 输入斯密特触发器处进行了取反
// 此处再次取反获取原信号
Ha = ~GpioDataRegs.GPADAT.bit.GPIO9 & 0x01;
Hb = ~GpioDataRegs.GPADAT.bit.GPIO23 & 0x01;
Hc = ~GpioDataRegs.GPADAT.bit.GPIO10 & 0x01;

HallSignal = (Ha << 2) + (Hb << 1) + Hc;

switch (HallSignal)
{
case 0x00: // 000
return HALLOFFSET + 0;

case 0x01: // 001
return HALLOFFSET + HALL_DELT;

case 0x03: // 011
return HALLOFFSET + 2 * HALL_DELT;

case 0x07: // 111
return HALLOFFSET + 3 * HALL_DELT;

case 0x06: // 110
return HALLOFFSET + 4 * HALL_DELT;

case 0x04: // 100
return HALLOFFSET + 5 * HALL_DELT;

default:
__asm (" ESTOP0");
}

return 0;
}

Z相同步信号

Z相信号用于对QPOSCNT寄存器进行同步定位,这个信号需要仔细考虑下,否则会造成之后得到的绝对位置存在误差。首先需要考虑的是,Z相信号本身是一个存在一定宽度的脉冲信号,从旋转编码器的原理上来看,正转和反转时Z相信号的上升沿和下降沿对应的绝对位置是不同的,正转时的上升沿对应反转时的下降沿,反之亦然。这就需要在正转和反转时使用不同的边沿触发同步事件,C2000单片机中可以很方便的实现这一功能,只需要设置IEI寄存器即可:

1
2
3
EQep1Regs.QEPCTL.bit.IEI = 3;  // 0 : Does nothing
// 2 : Initializes QPOSCNT on rising edge of QEPI
// 3 : Initializes QPOSCNT on rising or falling edge of QEPI depends on direction

同步事件发生时写入QPOSCNT中的值由QPOSINIT寄存器确定:

1
EQep1Regs.QPOSINIT = INDEX_OFFSET;    // eQEP Position Counter Initialization Value

这里就涉及到INDEX_OFFSET这个值怎么确定的问题,因为Z相脉冲并不是严格的出现于绝对零点位置处,故需要进行角度校正。

角度校正

角度校正的基本思想是,记录下Z相信号对应的绝对角度值,将其写入QPOSINIT寄存器即可,即上述代码中的INDEX_OFFSET宏定义的值。要确定绝对角度,必须要有一个基准,在进行角度校正时,使用预定位的方式确定绝对角度的零点。

具体做法是, 使能三相逆变器,使用SVPWM算法生成一个Ualpha > 0;Ubeta = 0的矢量,Ualpha不宜设置得过大,以免电流过大,此时电机会旋转至绝对零点处。之后使能EQEP模块,将QPOSCNT的值设为0,SEI设为0,以禁用QI信号信号的自动同步复位功能;与此同时,使能IEL,以便在QI信号发生时自动锁存QPOSCNT寄存器的值。以上初始化过程用代码表示如下:

1
2
3
EQep1Regs.QPOSCNT = 0;
EQep1Regs.QEPCTL.bit.IEI = 0; // Does nothing on rising or falling edge of QEPI
EQep1Regs.QEPCTL.bit.IEL = 3; // Latch QPOSCNT on rising or falling edge of QEPS depends on direction

按照以上步骤初始化EQEP模块后,禁用三相逆变器,此时电机可以自由旋转。用手旋转电机以产生QI信号,此时QPOSCNT寄存器中的值会被自动锁存在QPOSILAT寄存器中,可以正反多旋转几次电机,记录下若干次QPOSILAT寄存器中的值取平均值即可。读取寄存器的值可以通过使用仿真器进入调试模式实现。

计算得到的平均值即QI信号对应的绝对角度值,将此值定义为INDEX_OFFSET宏写入QPOSINIT寄存器中即可。

注:上述叙述假设编码器Z相信号连接至了QEPI输入端上,若连接至了QEPS输入端处,只需将QI相关部分改为QS即可,二者的功能基本相同。

文章目录
  1. 1. 基本原理
  2. 2. 初始时刻定位
  3. 3. Z相同步信号
  4. 4. 角度校正