龙空技术网

旋转编码器控制的另一种算法

armarm 165

前言:

当前咱们对“旋转屏幕算法”可能比较关切,我们都想要知道一些“旋转屏幕算法”的相关知识。那么小编同时在网摘上网罗了一些关于“旋转屏幕算法””的相关文章,希望同学们能喜欢,咱们快快来了解一下吧!

旋转编码器控制的另一种算法操作原理

旋转编码器是通常将轴的角运动转换为数字输出信号的设备。有许多 Web 资源解释了这些设备的机制以及如何将它们连接到微型计算机,但本页并非完整的概述。这个想法是提出另一种算法来正确读取机械旋转编码器的输出。

原则上,常见的旋转编码器通过交替闭合两个开关来产生信号,如上图所示。根据连接,中性状态可以是高 (1) 或低 (0)。我们在这里假设中性状态为高的最常见连接。对于顺时针运动,第一个开关的动作先于第二个开关的动作,而逆时针运动则相反。如果我们将每个状态表示为二进制数,两位数字表示两个开关的状态,则中性状态表示为11, 顺时针旋转由状态链表示11→01→00→10→11逆时针旋转由状态链表示11→10→00→01→11.

开关弹跳

问题是机械电气开关不完善,所以会出现开关弹跳的现象。当切换开关时,触点必须从一个位置物理移动到另一个位置。当开关的组件进入新位置时,它们会机械弹跳,导致底层电路多次打开和关闭。得到的信号如上图所示。

这个问题可以通过硬件或软件来解决。在软件的情况下,这涉及到某个主观确定的保持时间,在此期间开关的活动被忽略。然而,在旋转开关的情况下,我们可以完全避免保持时间。由于这对开关经过四个连续的状态,我们原则上可以准确地定义操作何时完成。

算法

微处理器一共可以读出四种不同的状态,连续两次读出总共给出了十六种可能的转换,如上图所示。四个过渡代表没有移动,四个过渡代表向右四分之一移动,四个过渡代表向左四分之一移动,四个过渡代表理论上不可能的过渡。

让我们将一个完整的周期定义为一个以中性状态开始和结束的过程。通过指定 0 表示没有移动,+1 表示向右移动四分之一,-1 表示向左移动四分之一,我们得到 +4 的总和表示向右的一个完整周期,-4 的总和表示一个完整的周期循环向左,总和为 0 表示没有移动。特别是,每个单独的开关弹跳,无论是向左还是向右,总和为 0,对结果没有影响。此外,聚合和 4 的模数为我们提供了确切的状态。例如,如果模数为零,则当前状态为中性状态。

必须特别注意“不可能”的转换。由于技术上的不足,它们确实是可能的。如果我们将值 0 分配给不可能的转换,则具有恰好一个不可能转换的完整循环的总和是 -6、-2、+2 或 +6。要认识到整个循环包含一个(或多个)不可能的转换,我们必须为不可能的转换分配一个大于 10 的数字,以便整个循环的总和大于 4。但是,如果我们分配数字 14 ,我们不仅认识到不可能转换的存在,而且当且仅当达到中性状态时,聚合的模数和 4 再次为零。

执行

所有这些考虑因素都可以在以下 Python 脚本中观察到,该脚本旨在用于 Raspberry Pi。rotary函数首先更新,lrmem一个四位二进制变量,其中前两位表示前一个状态,后两位表示当前状态,本质上是最后一次转换。该列表TRANS包含每个转换的值,如下表所示。

lrmem

转型

TRANS

评论

0b0000

00→00

0

没有动静

0b0001

00→01

-1

向左移动

0b0010

00→10

+1

向右移动

0b0011

00→11

+14

不可能的运动

0b0100

01→00

+1

向右移动

0b0101

01→01

0

没有动静

0b0110

01→10

+14

不可能的运动

0b0111

01→11

-1

向左移动

0b1000

10→00

-1

向左移动

0b1001

10→01

+14

不可能的运动

0b1010

10→10

0

没有动静

0b1011

10→11

+1

向右移动

0b1100

11→00

+14

不可能的运动

0b1101

11→01

+1

向右移动

0b1110

11→10

-1

向左移动

0b1111

11→11

0

没有动静

然后该rotary函数更新lrsum包含当前聚合的变量。当达到中性状态时,该功能相应地起作用。

树莓派的 Python 代码

import pigpiopi = pigpio.pi()# -1: left transition, +1: right transition, 0: no transition and 14: impossible transitionTRANS = [0, -1, 1, 14, 1, 0, 14, -1, -1, 14, 0, 1, 14, 1, -1, 0]LEFT = 16RIGHT = 20PUSH = 21def rotary():    global lrmem    global lrsum    l = pi.read(LEFT)    r = pi.read(RIGHT)    lrmem = (lrmem % 4)*4 + 2*l + r    lrsum = lrsum + TRANS[lrmem]    # encoder not in the neutral state    if(lrsum % 4 != 0): return(0)    # encoder in the neutral state    if (lrsum == 4):        lrsum=0        return(1)    if (lrsum == -4):        lrsum=0        return(-1)    # lrsum > 0 if the impossible transition    lrsum=0    return(0)pi.set_mode(LEFT, pigpio.INPUT)pi.set_mode(RIGHT, pigpio.INPUT)pi.set_mode(PUSH, pigpio.INPUT)pi.set_pull_up_down(LEFT, pigpio.PUD_UP)pi.set_pull_up_down(RIGHT, pigpio.PUD_UP)pi.set_pull_up_down(PUSH, pigpio.PUD_UP)lrmem = 3lrsum = 0num = 0print(num)while(True):    res = rotary()    if (res!=0):        num=num + res        print(num)    if(pi.read(PUSH)==0):        break

请注意,不需要额外的电子组件,因为脚本使用内置的 Raspberry Pi 上拉电阻。

Arduino的C代码

#define LEFT 2#define RIGHT 3#define PUSH 4uint8_t lrmem = 3;int lrsum = 0;int num = 0;int8_t rotary(){   static int8_t TRANS[] = {0,-1,1,14,1,0,14,-1,-1,14,0,1,14,1,-1,0};   int8_t l, r;   l = digitalRead(LEFT);   r = digitalRead(RIGHT);   lrmem = ((lrmem & 0x03) << 2) + 2*l + r;   lrsum = lrsum + TRANS[lrmem];   /* encoder not in the neutral state */   if(lrsum % 4 != 0) return(0);   /* encoder in the neutral state */   if (lrsum == 4)      {      lrsum=0;      return(1);      }   if (lrsum == -4)      {      lrsum=0;      return(-1);      }   /* lrsum > 0 if the impossible transition */   lrsum=0;   return(0);}void setup(){   pinMode(LEFT, INPUT);   pinMode(RIGHT, INPUT);   pinMode(PUSH, INPUT);   pinMode(LEFT, INPUT_PULLUP);   pinMode(RIGHT, INPUT_PULLUP);   pinMode(PUSH, INPUT_PULLUP);   Serial.begin(9600);   Serial.println(num, DEC);}void loop(){   int8_t res;      res = rotary();   if (res!=0)   {      num = num + res;      Serial.println(num);   }   if (digitalRead(PUSH) == 0)   {      Serial.println(num);      delay(250);   }}

标签: #旋转屏幕算法