旋转编码器如何运作以及如何与Arduino使用它

在本教程中,我们将学习旋转编码器如何工作,以及如何使用它与Arduino。你可以观看下面的视频或阅读下面的书面教程。

概述


旋转编码器是一种位置传感器,用于确定转轴的角度位置。它根据旋转运动产生模拟或数字的电信号。

旋转编码器模块

有许多不同类型的旋转编码器,由输出信号或传感技术进行分类。我们将在本教程中使用的特定旋转编码器是增量旋转编码器,它是最简单的定位传感器来测量旋转。

旋转编码器的分类

该旋转编码器也称为正交编码器或相对旋转编码器,其输出是一系列方波脉冲。

旋转编码器如何工作


让我们仔细看看编码器,看看其工作原理。以下是如何产生方波脉冲的:编码器具有圆盘,该盘具有均匀间隔的接触区域,该磁盘连接到公共引脚C和另外两个单独的触头A和B,如下所示。

旋转编码器如何运作工作原理betway

当圆盘开始逐级旋转时,A、B两个引脚开始与普通引脚接触,产生两个方波输出信号。

如果我们只计算信号的脉冲,则可以使用两个输出中的任何一个来确定旋转位置。但是,如果我们也希望确定旋转方向,我们需要同时考虑两个信号。

我们可以注意到,这两个输出信号在90度的相位上发生了位移。如果编码器顺时针旋转,输出A将在输出B之前。

旋转编码器输出信号工作原理照片

所以如果我们计算信号每次变化的步数,从高到低或者从低到高,我们可以注意到当时两个输出信号的值是相反的。反之亦然,如果编码器逆时针旋转,则输出信号具有相等的值。因此,考虑到这一点,我们可以很容易地编程我们的控制器读取编码器的位置和旋转方向。

旋转编码器Arduino示例


让我们用Arduino做一个实际的例子。我将在本例中使用的特定模块位于一个分接板上,它有五个引脚。第一个引脚是输出A,第二个引脚是输出B,第三个引脚是按钮引脚,当然其他两个引脚是VCC和GND引脚。

旋转编码器Arduino教程示例

我们可以将输出引脚连接到Arduino板的任何数字引脚。

你可以从下面的链接获得这个Arduino教程所需的组件:

必威外围提钱披露:这些是附属链接。作为一名亚马逊助理,我的收入来自符合条件的购买。

源代码


Arduino代码如下:

/ * Arduino旋转编码器教程* *由Dejan Nedelkovski,www.www.mfxpo.combet188官方网站 * * / #define Outputa 6 #define输出组7 int计数器= 0;int立场;int aLastState;void setup(){pinmode(outputa,输入);pinMode (outputB、输入);Serial.Begin(9600);//读取outputa AlastState = DigitalRead(Outputa)的初始状态;void循环(){Astate = DigitalRead(Outputa);//读取Outputa //如果outputa的当前状态不同的“当前”状态不同,这意味着发生脉冲(Astate!= AlastState){//如果输出态不同于outputa状态,这意味着编码器是顺时针旋转(DigitalRead(OutputB)!= Astate){Counter ++; } else { counter --; } Serial.print("Position: "); Serial.println(counter); } aLastState = aState; // Updates the previous state of the outputA with the current state }

代码描述:因此,首先我们需要定义编码器连接到的引脚,并定义程序所需的一些变量。在setup小节中,我们需要将两个引脚定义为输入,启动串行通信以在串行监视器上打印结果,以及读取输出A的初始值并将该值放入变量aLastState中。

然后在循环部分中,我们再次读取输出,但现在我们将值放入Astate变量。因此,如果我们旋转编码器并生成脉冲,这两个值会有所不同,并且第一个“如果”语句将变为真实。在之后,使用第二个“if”语句,我们确定旋转方向。如果输出B状态与输出不同的状态,则计数器将增加一个状态,否则它将减小。最后,在串行监视器上打印结果后,我们需要使用Astate变量更新AlaStState变量。

这就是我们在这个例子中所需要的。如果上传代码,启动串行监视器并开始旋转编码器,我们将开始获取串行监视器中的值。我的特定模块在每一个完整的循环中做30次计数。

例2 -使用旋转编码器控制步进电机


除了这个基本的例子,我还做了一个控制a的例子步进电机使用旋转编码器定位。

使用旋转编码器控制步进电机

下面是这个例子的源代码:

/*使用旋转编码器的步进电机* * by Dejan Nedelkovski, www.HowToMechatronics.com * */bet188官方网站 #include <液晶。h> //包含液晶库lcd(1,2,4,5,6,7);//创建一个LC对象。参数:(rs, enable, d4, d5, d6, d7) //定义引脚编号#define stepPin 8 #define dirPin 9 #define outputA 10 #define outputB 11 int counter = 0;int angle = 0;int立场;int aLastState;void setup(){//设置两个引脚为输出pinMode (dirPin、输出);pinMode (outputA、输入);pinMode (outputB、输入); aLastState = digitalRead(outputA); lcd.begin(16,2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display } } void loop() { aState = digitalRead(outputA); if (aState != aLastState){ if (digitalRead(outputB) != aState) { counter ++; angle ++; rotateCW(); } else { counter--; angle --; rotateCCW(); } if (counter >=30 ) { counter =0; } lcd.clear(); lcd.print("Position: "); lcd.print(int(angle*(-1.8))); lcd.print("deg"); lcd.setCursor(0,0); } aLastState = aState; } void rotateCW() { digitalWrite(dirPin,LOW); digitalWrite(stepPin,HIGH); delayMicroseconds(2000); digitalWrite(stepPin,LOW); delayMicroseconds(2000); } void rotateCCW() { digitalWrite(dirPin,HIGH); digitalWrite(stepPin,HIGH); delayMicroseconds(2000); digitalWrite(stepPin,LOW); delayMicroseconds(2000); }

请在下面的评论部分提出任何问题。

48回应

  1. 凯夫拉尔

    我不确定为什么你要将角度乘以1.8,如果一个完整的旋转包含200步(200*1.8 = 360度),这难道没有意义吗?然而,您提到完全旋转是由counter变量中看到的30个步骤引起的。看起来,系统显然能够检测到小于12度(30*12 = 360度)的变化。

    例如,一个完全旋转会使计数器从0到30带,角度为0到30,这将与0到54度(30 * 1.8)相关。我想知道我在这里出了问题。

    任何澄清将是伟大的!

    回复
    • 德扬Nedelkovski

      是的,你说得对。
      旋转编码器全周期是30个步骤。因此,如果一个旋转编码器步骤是一个步进电机步骤,则需要200步进行全电机旋转,或者为1个电机循环的200/30 = 6.666编码器周期。据此,您可以编制Arduino来做任何您想要的事情。
      例如,如果您希望将1个编码器周期为1个电机循环,则需要将Arduino程序编程到步进电机的步进步骤,为编码器等步骤等......

      回复
  2. 萨姆

    在你的例子中当你移动编码器一个位置是否意味着步进电机移动了1。8度(1步)

    如果是这样,屏幕如何以1度的增量显示
    例如,如果您将编码器从初始零位置移动1周期移动
    代码应该打印1.8度的角度到液晶显示器?
    我非常不确定你使用过的数学数学
    和一个真正的初学者在这里

    回复
    • 德扬Nedelkovski

      这是真的,每个编码器位置步进移动1步或1.8度。在LCD上打印度时,我使用步骤* 1.8表达式来获得度。例如,50个编码器位置,或50步* 1.8 = 90度。

      回复
  3. 贾米尔

    做得好朋友! !我很明白。我在机器电子方面出了问题。你能解决这个问题吗?
    我在有HVDC站的电网工作。在这个HVDC站中,有晶闸管(SCR)阀门银行。在AC到DC转换期间,这种晶闸管得到加热。Hechm,冷却系统包含用于冷却该晶闸管。冷却系统由4个NOS冷却器组成,顶部和轴向风扇电机在底部的水喷嘴,用于强制空气冷却。
    这四个冷却器处于自动模式。也就是说,当温度高时,冷却器开始一个接一个地使用,以将温度保持在预设的限制和反之亦然。
    当温度开始下降时,通过向PLC发送指令,冷却器开始逐个切断(先入先出偏差)。
    在每个冷却器中都安装了阻尼器。这个阻尼器有三个位置:打开,中间和关闭。让我们假设4个冷却器现在正在使用。因此,当温度开始下降(由于环境温度或功率下降)时,PLC向冷却器发送命令,将其风门从全开关闭到半开。假设PLC向1号冷却器发送命令,将风门关闭到一半。因此冷却器1号减振器电机转动减振器轴,当减振器达到半关闭位置时,PLC感知该位置(通过微动开关),PLC向减振器电机发送停止命令。然后PLC将监控温度。如果温度进一步下降,PLC向冷却器1号减振器电机发送命令,以完全关闭减振器,并关闭喷油泵和风机电机。阐述了高压直流系统冷却系统的主要原理。
    现在我们正面临一个问题,即冷却器无法在自动模式下操作,因为阻尼雕像不发送到PLC。我们也没有得到OEM的支持。
    我有一个想法将编码器安装到阻尼电机轴上。请注意,阻尼电机是慢动移动的电机。它需要大约3分钟移动阻尼器从完全打开到完全关闭位置(和vISE VERSA)。编码器(与奥迪诺这样的一些微处理器合作)将感知阻尼器的位置,并发送三个位置命令(打开,中间和关闭)到PLC。
    我想通过使用光学编码器和奥德里诺uno / mega制作照片类型,并测试它。你能帮我编程吗?我应该选择哪种编码器?

    问候
    贾米尔、印度

    回复
    • 德扬Nedelkovski

      谢谢Jameel!你的想法听起来不错,有可能完成。然而,我很抱歉,但我无法帮助您,因为我不在自定义项目上工作。bet188me

      回复
  4. 约翰

    我是一个退休的EE和业余无线电操作员(叫N1ABE)有很多经验;然而,作为那次经历的一部分,我学会了不要重新发明轮子。也就是说,我正在设计一个基于Arduino Uno的直接数字合成器,使用的是我通过亚马逊得到的DDS9850模块。到目前为止,我已经能够通过串口使用它。我本来打算使用一个编译过的robot basic应用程序,但我想要一个独立的设置,最好是电池供电。我想到的是用一个旋转编码器来设定频率。不幸的是,Arduino的网站上并没有太多关于它们的信息所以我搜索了一下,找到了你们的网站。瞧!你有我要找的密码,谢谢。在其他地方还有其他使用中断的代码示例,但我想要一个不使用中断的版本。 I copied yours and it compiled without error. When I get the encoders I will integrate your code into mine. I am probably going to use a separate push button since the encoders I am getting do not have an integral switch. I am not at this time looking to add a display because my goal is to keep the project simple and will set the frequency with an o’scope. The DDS produces a stable signal up to 40 MHz and will make a nice lab bench signal source to compliment my home brew function generator. Once my project is done I will be more than happy to share my design with you and intend to attribute you in my final code.

    回复
  5. 丹尼尔

    嗨,谢谢你的伟大工作…我现在正在做一个项目使用旋转编码器与LCD显示的角度。我有例子2的完整示意图吗?谢谢你!

    回复
    • 德扬Nedelkovski

      谢谢!嗯,我没有特定的电路原理图,但我对每个组件具有单独的电路原理图,旋转编码器,液晶显示屏和伺服电机控制,因此您不应有任何问题。

      回复
      • 丹尼尔

        我用的是28BYJ-48步进电机,和你在视频里用的不一样。28BYJ步进电机通过4个数字引脚连接到Arduino,但您使用的那个只通过2个引脚连接(stepPin和dirPin)。你有任何想法改变28BYJ-48电机的代码吗?

  6. Leem Aseng

    嗨Dejan,
    我有兴趣和想要建立这个项目,可以让我借给我使用的原理图和模块的细节。

    谢谢。
    问候,
    莱姆。

    回复
    • 德扬Nedelkovski

      好吧,一切都已经解释道。您可以弄清楚如何从本教程中连接编码器,如果您检查步进电机控制教程,可以找到用于连接驱动器和步进电机的电路原理图。

      回复
  7. 安娜

    这就跟你问声好!
    伟大的项目,真的很喜欢它!
    我只是想知道你们用来求轴角的方程是什么。是以ppr为基础的吗?我用的是1024ppr增量编码器我没能找到匹配的轴角和计数器值。
    谢谢!

    回复
  8. ·埃

    嗨Dejan,

    谢谢你的指导。也用于I2c和SPI。

    但我有一个关于编码器阅读的问题。

    增量总是2而不是1。我还加了几个电路来消除反弹,但不行。

    请你帮助我好吗 ?

    回复
      • 迈克C.

        它可能是,Dejan使用的编码器只有2过渡每个缓冲器和你的有4?当你转动旋钮时,两个引脚的状态为00、10、11、01等等。有些编码器在引脚为11时有凹痕,有些则在00时有凹痕。有些在00点和11点有障碍我怀疑德扬也有一个。

        因此,德国的开始,也许在00和一个制动(2个过渡,即10,11)中将他带到11点,所以在他的节目中是一个“步骤”。在下次点击左右,它再次转换为01然后再次00,再次进行另一个“步骤”。您的代码将从00开始从00开始,即10,11,01,00,所以他的代码在编码器上计算2个“步骤”,只有一个在他身上。你的棘手队可能会设置为11,而不是00,但原则是一样的。您将不得不攻击此代码一点以使其忽略额外的步骤。

  9. 阿德里安

    伟大的项目几乎我需要的东西。Arduino会记住电机的最后位置是否有可能(比如68度)?因此,如果Arduino断电然后重新启动它将“记住”位置并在LCD上读取68?

    回复
  10. Arduinomaster

    我不认为任何人可以做到这一点,因为纽扣针无处可去。因为我们都使用不同的步进驱动器,所以需要一个电路图。最好是写在Instructables中。
    起初,我很兴奋,但现在在4个小时后我只有头疼。

    回复
    • 德扬Nedelkovski

      我没有在示例中使用该按钮,但它只是简单的按钮。至于步进示例,您可以在“A4988驱动程序”的详细教程上找到电路原理图。

      回复
  11. JukkaKilpiö.

    嗨Dejan!

    我认为第一个代码示例中有一个小错误。IF语句“如果(agraite!= AlastState)”捕获编码器时钟脉冲的上升和下降沿。这意味着一个旋转编码器步骤将使两个变化进行计数器。如果您替换“如果(agrate!= alaStstate)”,“如果(agrate> alaStstate)”只计算上升沿。

    回复
    • Jaromir办公室

      我同意。如果使用条件(Astate!= AlastState),则对轴的一步进行反击两次。如果你使用(Astate> AlastState)或(Astate 1 -> 0 -> 1。

      回复
  12. 胡安Aguirre

    大家好,我来自阿根廷。伟大的项目!
    我跟随你的步骤,它有效。虽然我有问题!如果我变得慢,它会很好地柜台,但如果我快速转弯,它是不受控制的并且重复步骤!
    我使用了来自EPSON打印机的编码器。
    这可能是因为编码器有很多分辨率吗?
    是否能够使用此编码器?
    从已经非常感谢你!
    来自阿根廷的问候!!

    回复
    • 德扬Nedelkovski

      问题可能是在代码中,没有得到很好的优化。这只是一个简单的示例代码,为了获得更好的结果,可能需要进行这样的优化。

      回复
  13. Max -Joseph.

    这种方法只使用旋转编码器的一半分辨率,因为每个周期有四个不同的状态(11,10,00,01),但你只检查每个方向的两个变化(如果从10到00或从01到11 - >计数器++;如果从11到01或从00到10 - >计数器-)。所以11到10,00到01,01到00,10到11。

    为了得到完整的分辨率,你必须检查每一个修改。示例代码(不容易阅读,但高效和紧凑):
    ##############################################
    int计数器;
    bool preva = 1,prevb = 1;

    无效循环(){
    BOOL A = DigitalRead(PIN_rotarya),B = DigitalRead(Pin_rotaryB);

    if (B != prevB) counter += (B) * (A ?+ 1: 1);
    否则if(a!= preva)计数器+ =(a-preva)*(b?-1:+1);
    其他的回报;/ /没有改变:退出

    preva = a;
    prevB = B;
    以(柜台);
    }
    ##############################################

    这工作真的很棒,如果你转动旋转编码器在一个正常的速度。但是如果你把它转得太快或者你在循环()中做了其他需要更长的时间的事情,你会错过一个步骤,它会从11跳到00或从10跳到01。这样它就不知道自己转向了哪个方向,所以计数器就会稍微出错。

    但你可以通过检查它之前转向了哪个方向并相应地增加或减少计数器2来进行反击。
    或者您可以使用中断来代替检查loop()中的引脚状态,以确保没有遗漏任何步骤。

    回复
      • lluch joan.

        更清晰,更有效的方法来获得编码器的全部分辨率。它更有效,因为它不使用任何整数算术,并且利用了逻辑运算符的“短路”评估规则,在大多数情况下,它将跳过大部分代码。

        ##############################################
        int counter = 0;
        字节encoderSt = 0;
        void循环()
        {
        字节a = digitalRead(pinA);
        字节B = DigitalRead(PINB);
        字节st = (b<<1) | a;
        如果(Encoderst!= St)
        {
        如果((encoderSt = = 0 & &圣= = 2)| | (encoderSt圣= = 0)= = 1 & & | | (encoderSt = = 2 & &圣= = 3)| | (encoderSt = = 3 & &圣= = 1))计数器-;
        其他柜台+ +;
        系列。println(柜台);
        encoderSt =圣;
        }
        }
        ##############################################

  14. 尼古拉

    你的指导对我很有帮助。
    但我需要一个非常精确的电机,每步获得1度。你有什么想法如何实现它吗?所以我将使用减少来实现这一目标吗?
    大regads
    Поздрав

    回复
  15. 乔Apache

    嗨Dejan,
    谢谢你这么伟大的教程。感谢您分享您的知识并制作更好的世界。
    Eng Apache.

    回复
  16. andreas kraus.

    谢谢你,先生。你帮了我很多。现在,1990年的Fanuc A860-0201-T001编码器正在与我的项目合作。

    回复
  17. 约翰尼尔森

    你好,伟大的教程,,,,我不确定所有的组件在显示上。有Arduino,屏幕,旋转的女巫,面包板,跳线器,但有一个小东西,看起来像散热器,,,,我不知道那是什么…还有,我在哪里可以找到接线图?
    非常感谢卓越的解释。竖起大拇指和订阅。
    干杯
    约翰尼尔森

    回复
    • 德扬Nedelkovski

      大家好,谢谢!您正在谈论的项目是在第二个例子中,那是A4988步进电机驱动器。有关它的更多细节,以及如何使用Arduino控制步进电机,您可以查看我的特定教程。干杯!

      回复
  18. lluch joan.

    示例中的编码器代码只占编码器节拍的一半。这是因为计数器只在A引脚改变后才更新,而不是当两个中的任何一个改变时。对于你的应用程序来说,它仍然是好的,但是如果你想利用编码器的全分辨率,它就不能被认为是好的。

    回复
  19. Naresh.

    每次编码器通电时,它开始从零计数,无论轴都是轴的或其先前的位置。

    我们如何从编码器之前的位置开始的功率的也。

    回复
    • 德国

      嗯,编码器本身没有这样的能力。但是,您可以通过将其存储在Arduino的EEPROM中的位置来实现这一点。因此,下次电源您将从EEPROM读取存储的值并继续。

      回复
      • Naresh.

        嗨Dejan,

        首先感谢您的回复。
        我是新手,使用Arduino atmega2560。
        我已将连接的编码器5540连接到直流电机轴,增量编码器有两个通道连接到I / O引脚。编码器读取电机位置,(编码器反馈)如何存储在EEPROM中。

        请给我任何示例代码或例程。

        问候,
        Naresh。
        祝你今天愉快 ..!!

    • William P O'Sullivan.

      我唯一能做到这一点的方法是将编码器从is的最后存储位置,移回0。你可以用伺服或其他马达。这要花很多功夫。我猜你想让“旋钮”在通电后指向家里?
      / s / wp

      回复
  20. 奈杰尔

    一切都很简单,和谐......直到我去了并添加了一个I2C OLED显示屏。我预计刷新屏幕的延迟是终端干扰脉冲检测的定时。

    我正在使用一个Arduino nano和一个盾牌,意味着我只有引脚9,10和11可用,所以我不能附加ISR ......我所希望使用旋转编码器......对我来说是划船按钮

    谢谢你的简单教程

    回复
  21. 奥斯卡

    嗨,大家好!
    我要做一个测量工具来测量不同物体的长度。我可以用这种技术来测量长度吗?

    另外,那是什么屏幕?我喜欢它,我在哪里可以找到类似的?

    回复

发表评论

您的电子邮件地址将不会被公布。

推荐的

2019年初学者和爱好者的最佳进入级示波器

为初学者和爱好者最好的示波器

推荐的

2019年初学者的8个最佳Arduino Starter Kits

8个最好的ARDUINO初学者工具包

推荐的

用于初学者和爱好者的最佳3D打印机 -  3D打印

初学者和爱好者的最佳3D打印机