旋转编码器是如何工作的,如何与Arduino一起使用

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

概述


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

旋转编码器模块

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

旋转编码器的分类

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

旋转编码器如何工作


让我们仔细看看编码器,看看它的工作原理。编码器有一个具有均匀间隔接触区的磁盘,连接到公共引脚C和其他两个单独的接触引脚a和B,如下图所示。

旋转编码器的工作原理亚博88下载

当圆盘逐步旋转时,引脚A和B开始与公共引脚接触,产生两个方波输出信号。

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

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

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

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

旋转编码器Arduino示例


让我们使用Arduino进行实际的例子。我将在此示例中使用的特定模块来到一个突破板上,它有五个引脚。第一引脚是输出A,第二引脚是输出B,第三引脚是按钮引脚,当然还有其他两个引脚是VCC和GND引脚。

旋转编码器Arduino教程示例

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

您可以从下面的链接获取此Arduino教程所需的组件:

yaboAG娱乐城披露:这些是联盟链接。作为亚马逊助理,我从合格购买中获得。

源代码


下面是Arduino代码:

/* Arduino Rotary Encoder Tutorial * * by Dejan Nedelkovski, www.亚搏手机版官方下载HowToMechatronics.com * */ #define outputA 6 #define outputB 7 int counter = 0;int立场;int aLastState;void setup() {pinMode (outputA,INPUT);pinMode (outputB、输入);系列。开始(9600);//读取outputA的初始状态aLastState = digitalRead(outputA);} void loop() {state = digitalRead(outputA);/ /读取“当前”outputA / /如果前面和outputA的当前状态是不同的,这意味着一个脉冲发生如果(处于! = aLastState){/ /如果outputA outputB状态是不同的状态,这意味着编码器旋转顺时针如果(digitalRead (outputB) ! =立场){计数器+ +; } else { counter --; } Serial.print("Position: "); Serial.println(counter); } aLastState = aState; // Updates the previous state of the outputA with the current state }

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

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

这就是这个例子所需的一切。如果上传代码,请启动串行监视器并开始旋转编码器,我们将开始获取串行监视器中的值。我已经制作30的特定模块计算每个完整周期。

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


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

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

以下是此示例的源代码:

/ *步进电机使用旋转编码器* * by dejan nedelkovski,www.www.kuaixg.com * * /亚搏手机版官方下载 #include  //包括液体库液晶LCD(1,2,4,5,6,7);//创建一个LC对象。参数:( RS,ENABLE,D4,D5,D6,D7)//定义引脚编号#define STEPPIN 8 #DEFINE DIRPIN 9 #DEFINE OUTPORA 10 #DEFINE OUTPORB 11 INT计数器= 0;int角度= 0;int立场;int aLastState;void setup(){//将两个引脚设置为输出pinmode(steppin,输出);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); }

随意询问以下意见部分中的任何问题。

49回复

  1. 杜邦公司注册在芳族聚酰胺纤维商品上的注册商标

    我不确定你为什么要把角度乘以1.8,如果一个完整的旋转包含200步(200*1.8 = 360度),这不是有意义的吗?但是你提到一个完整的旋转是由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.8degrees(1步)

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

    回复
    • 德扬Nedelkovski

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

      回复
  3. 贾米尔

    做得好的朋友!我理解得很好。我在机器elecronic遇到了问题。你能解决它吗?
    我在一个电网工作,那里有HVDC站。在这个高压直流站,有晶闸管(SCR)阀组。在交流到直流转换期间,这个可控硅被加热。Hench,一个冷却系统被合并冷却这个晶闸管。冷却系统由4台冷却器组成,顶部设有水雾喷嘴,底部设有轴流风机电机,强制风冷。
    这四个冷却器是自动模式。也就是说,当温度较高时,冷却器开始一个接一个地投入使用,以保持温度在预设范围内,反之亦然。
    当温度开始掉落时,通过向PLC发送命令,冷却器开始逐个(首先在第一输出偏差中)。
    每个冷却器都安装了阻尼器。这阻尼器有三个位置:开放,中间和关闭。让我们现在可以使用4个冷却器。因此,当温度开始下降(由于环境温度或减少),PLC发送命令冷却器以关闭其阻尼器从完全开放到一半开放。假设PLC将命令发送到冷却No.1以关闭其阻尼器到一半。因此,冷却器NO:1阻尼器电机将旋转阻尼器轴,当阻尼器达到半闭位置时,PLC(通过微动开关)和PLC向阻尼电机发送停止命令。然后PLC将监测温度。如果在温度下进一步减少,PLC将命令发送到冷却器NO:1阻尼器,以完全关闭阻尼器并推出喷雾泵和风扇电机。HVDC冷却系统的主要原理。
    现在我们面临的问题是冷却器不能在自动模式下运行,因为阻尼雕像没有发送到PLC。我们也没有得到OEM的支持。
    我有一个主意,安装一个编码器阻尼电机轴。注意阻尼器电机是一个缓慢移动的电机。将风门从全开位置移动到全关位置需要大约3分钟(反之亦然)。编码器(配合一些微处理器如audrino)会感应阻尼器的位置,并向PLC发送三个位置命令(开、中、关)。
    我想让一个照片类型使用光学编码器& audrino uno / mega和测试它。你能在编程方面帮助我吗?我应该选择哪种编码器?

    问候
    贾米尔、印度

    回复
    • 德扬Nedelkovski

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

      回复
  4. 约翰

    我是一名退休的电子工程师和业余无线电操作员(叫N1ABE),有很多经验;然而,作为那次经历的一部分,我学会了不要白费力气。也就是说,我正在设计一个基于Arduino Uno的直接数字合成器,使用的是我从亚马逊得到的DDS9850模块。到目前为止,我已经能够通过串口使用它。我原本打算使用一个编译好的机器人基本应用程序,但我想要一个独立的设置,最好是电池供电。我想到的是使用一个旋转编码器来设置频率。不幸的是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个引脚(Septpin和Dirpin)连接的那个。您是否有更改28byJ-48电机的代码?

  6. Leem Aseng

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

    谢谢。
    问候,
    Leem。

    回复
    • 德扬Nedelkovski

      一切都已经解释好了。你可以从本教程中找出如何连接编码器,如果你检查我的步进电机控制教程,你可以找到连接驱动器和步进电机的电路原理图。

      回复
  7. 安娜

    你好!
    很棒的项目,真的很喜欢!
    我只是想知道你们用来求轴角的方程是什么。是基于ppr吗?我正在使用1024ppr增量编码器,我还没有找到匹配的轴角和计数器值。
    谢谢!

    回复
  8. Ertugrul.

    嗨,德扬,

    谢谢你的伟大教程。也适用于I2C和SPI。

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

    我的增量总是2而不是1.我也添加了几个电路来消除去抖动但没有办法。

    你能帮我一下吗?

    回复
      • 迈克C

        德国使用的编码器可能只有2个纠葛只有2个过渡,而你的有4个?当你转动旋钮时,2个引脚状态GO 00,10,11,01等。一些编码器当引脚在11时具有棘爪,当时00 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.

    我认为没有人可以这样做,因为纽扣队不无所事事。当我们都使用不同的步进驱动器时需要电路图。最好的是在赋予指导方面写下这一点。
    一开始,我很兴奋,但4个小时后,我只感到头痛。

    回复
    • 德扬Nedelkovski

      我没有在例子中使用ButtonPin,但它只是一个简单的按钮。至于步进例子,你可以在我的A4988驱动详细教程中找到电路原理图。

      回复
  11. JukkaKilpiö.

    嗨,德扬!

    我认为在第一个代码示例中有一个小错误。if语句" if (state != aLastState) "捕获编码器时钟脉冲的上升沿和下降沿。这意味着一个旋转编码器步骤将对计数器进行两次更改。如果你将" If (state != aLastState) "替换为" If (state > aLastState) ",你将只计算上升边。

    回复
    • Jaromir办公室

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

      回复
  12. 胡安Aguirre

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

    回复
    • 德扬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;

    void loop(){
    bool A = digitalRead(pin_rotaryB), B = digitalRead(pin_rotaryB);

    if(b!= prevb)计数器+ =(b-prevb)*(a?+1:-1);
    else if (A != prevA) counter += (A-prevA) * (B ?1: + 1);
    否则退货;//没有任何改变:退出

    prevA =一个;
    prevb = b;
    serial.println(计数器);
    }
    ####################################

    如果以正常速度转动旋转编码器,则此操作非常棒。But if you turn it too fast or you do other stuff in your loop() that takes longer time you will miss a step and it will jump from 11 to 00 or from 10 to 01. Then it can’t know, which direction it was turned, so the counter will get slightly incorrect.

    但是你可以通过检查它之前的哪个方向并相应地增加或减少反击来计数器。
    或者您可以使用中断而不是检查循环中的引脚状态()中的状态,以确保未错过步骤。

    回复
      • Lluch琼

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

        ####################################
        int counter = 0;
        字节encoderSt = 0;
        无效循环()
        {
        字节a = digitalRead(pinA);
        字节b = digitalRead(pinB);
        字节st =(b << 1)|一种;
        if (encoderSt != st)
        {
        如果((encoderSt = = 0 & &圣= = 2)| | (encoderSt圣= = 0)= = 1 & & | | (encoderSt = = 2 & &圣= = 3)| | (encoderSt = = 3 & &圣= = 1))计数器-;
        else counter ++;
        系列。println(柜台);
        Encoderst = St;
        }
        }
        ####################################

    • yvan beguin

      使用仅二进制运算符更有效的代码

      ####################################
      int计数器;
      bool preva = 1,prevb = 1;

      void loop(){
      bool A = digitalRead(pin_rotaryB), B = digitalRead(pin_rotaryB);

      counter += (A ^ prevA) | (B ^ prevB)?^ prevB ?1: -1: 0;

      prevA =一个;
      prevb = b;
      serial.println(计数器);
      }
      ####################################

      回复
  14. 尼古拉

    你的辅导课对我很有帮助。
    但我需要一个非常精确的马达来每步达到1度。你有怎样实现它的想法吗?那么,我是否会用减排来实现这一目标呢?
    大regads
    Поздрав

    回复
  15. Joe Apache.

    嗨,德扬,
    谢谢你提供了这么棒的教程。感谢你分享你的知识,创造一个更美好的世界。
    Eng Apache

    回复
  16. 安德烈亚斯•克劳斯

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

    回复
  17. 约翰尼尔森

    嗨伟大的教程,,,,我不确定显示屏上的所有组件。There is the Arduino, the screen, the rotary s witch, the breadboard, jumpers, But there is a little item with what looks like a heat sink,,,,I don’t know what that is… Also where do I find the wiring diagram?
    非常感谢你出色的解释。点赞并订阅。
    干杯
    约翰尼尔森

    回复
    • 德扬Nedelkovski

      嗨,谢谢!您正在谈论的项目是在第二个例子中,这是A4988步进电机驱动程序。有关它的更多详细信息以及如何使用Arduino控制步进电机,您可以检查我的特定教程。干杯!

      回复
  18. Lluch琼

    您的示例中的编码器代码仅占编码器滴答的一半。这是因为柜台仅在引脚改变后更新,而不是两个改变时。如果您想利用编码器的完整分辨率,它仍然可以仍然可以。

    回复
  19. Naresh.

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

    我们如何在电力的功率后从先前的编码位置开始。

    回复
    • 德扬

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

      回复
      • Naresh.

        嗨,德扬,

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

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

        问候,
        Naresh。
        祝你有美好的一天!!

    • 威廉·P奥沙利文

      我可能发生这种情况的唯一方法是如果某种方式将编码器移动回0,那么从最后的存储位置就是。您可以使用伺服或其他电机。这将需要很多工作。我想你想要“旋钮”点击电源上电?
      / s / wp

      回复
  20. 奈杰尔

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

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

    谢谢你的一个非常好的,简单的教程

    回复
  21. 奥斯卡

    大家好!
    我要造一个测量工具来测量不同物体的长度。我能用这个技术来测量长度吗?

    还有,那是什么屏幕?我很喜欢,哪里可以找到类似的?

    回复

留下一个回复

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

推荐

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

最适合初学者和爱好者的示波器

推荐

2019年针对初学者的8个最佳Arduino入门工具包

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

推荐

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

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