在本教程中,我们将学习旋转编码器如何工作以及如何与Arduino使用它。您可以观看以下视频或阅读下面的书面教程。
旋转编码器是一种位置传感器,用于确定旋转轴的角度位置。根据旋转运动,它产生电气信号,模拟或数字。
有许多不同类型的旋转编码器,由输出信号或传感技术进行分类。我们将在本教程中使用的特定旋转编码器是增量旋转编码器,它是最简单的定位传感器来测量旋转。
该旋转编码器也称为正交编码器或相对旋转编码器,其输出是一系列方波脉冲。
旋转编码器是如何工作的
让我们仔细看看编码器,看看其工作原理。以下是如何产生方波脉冲的:编码器具有圆盘,该盘具有均匀间隔的接触区域,该磁盘连接到公共引脚C和另外两个单独的触头A和B,如下所示。
当圆盘逐步旋转时,引脚A和B开始与公共引脚接触,产生两个方波输出信号。
如果我们只计算信号的脉冲,则可以使用两个输出中的任何一个来确定旋转位置。但是,如果我们也希望确定旋转方向,我们需要同时考虑两个信号。
我们可以注意到两个输出信号以90度的相位彼此错位。如果编码器顺时针旋转,输出A将在输出B之前。
所以如果我们计算每次信号变化时的步数,从高到低或从低到高,我们可以注意到在那个时候两个输出信号有相反的值。反之亦然,如果编码器逆时针旋转,则输出信号具有相等的值。因此,考虑到这一点,我们可以很容易地编程我们的控制器读取编码器的位置和旋转方向。
旋转编码器Arduino示例
让我们使用Arduino进行实际的例子。我将在此示例中使用的特定模块来到一个突破板上,它有五个引脚。第一引脚是输出A,第二引脚是输出B,第三引脚是按钮引脚,当然还有其他两个引脚是VCC和GND引脚。
我们可以将输出引脚连接到Arduino板的任何数字引脚。
你可以从下面的链接获得这个Arduino教程所需的组件:
- 旋转编码器模块 ...................亚马逊/伯格多德/aliexpress.
- Arduino电路板 .................................亚马逊/伯格多德/aliexpress.
- 面包板和跳线.........亚马逊/伯格多德/aliexpress.
必威外围提钱披露:这些是联盟链接。作为亚马逊助理,我从合格购买中获得。
源代码
下面是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 }
代码描述:因此,首先我们需要定义我们的编码器连接的引脚,并定义程序所需的一些变量。在设置部分中,我们需要将两个引脚定义为输入,启动串行通信以在串行监视器上打印结果,以及读取输出A的初始值并将值放入变量AlaStState中。
然后在循环部分中,我们再次读取输出,但现在我们将值放入Astate变量。因此,如果我们旋转编码器并生成脉冲,这两个值会有所不同,并且第一个“如果”语句将变为真实。在之后,使用第二个“if”语句,我们确定旋转方向。如果输出B状态与输出不同的状态,则计数器将增加一个状态,否则它将减小。最后,在串行监视器上打印结果后,我们需要使用Astate变量更新AlaStState变量。
这就是这个例子所需的一切。如果上传代码,请启动串行监视器并开始旋转编码器,我们将开始获取串行监视器中的值。我已经制作30的特定模块计算每个完整周期。
示例2 - 使用旋转编码器控制步进电机
除了这个基本的例子,我还做了一个控制a步进电机使用旋转编码器定位。
下面是这个例子的源代码:
/*步进电机使用旋转编码器* *由Dejan Nedelkovski, www.HowToMechatronics.com * */ #包括bet188官方网站//包括LiquidCrystal库液晶(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(){//设置两个引脚为Outputs pinMode(stepPin,OUTPUT);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); }
随意询问以下意见部分中的任何问题。
我不确定你为什么要把角度乘以1.8,如果一个完整的旋转包含200步(200*1.8 = 360度),这不是有意义的吗?但是你提到一个完整的旋转是由30步引起的,就像在计数器变量中看到的那样。看来系统显然能够检测小于12度(30*12 = 360度)的变化。
例如,一个完全旋转会使计数器从0到30带,角度为0到30,这将与0到54度(30 * 1.8)相关。我想知道我在这里出了问题。
任何澄清都很好!
是的,你是对的。
旋转编码器全周期为30个步骤。因此,如果一个旋转编码器步骤是一个步进电机步骤,您将需要200个步骤,以充分的电机旋转,或200/30= 6.666个编码器循环1个电机循环。根据这个,你可以编程Arduino做任何你想做的。
例如,如果你想要1个编码器循环等于1个电机循环,你需要对Arduino进行编程,使其对编码器的每一步发送6.66666个步进电机,以此类推……
在你的例子中,当你移动编码器一个位置是否意味着你的步进电机移动了1.8度(1步)
如果是,屏幕如何以1度增量显示
例如,如果你移动编码器从一个初始零位置1周期
如果代码打印到液晶显示器的角度为1.8°
我对你用的数学很不确定
一个真正的初学者
这是真的,每个编码器位置步进移动1步或1.8度。在LCD上打印度时,我使用步骤* 1.8表达式来获得度。例如,50个编码器位置,或50步* 1.8 = 90度。
做得好朋友! !我非常理解。我的电子机器出了问题。你能解决吗?
我在有HVDC站的电网工作。在这个HVDC站中,有晶闸管(SCR)阀门银行。在AC到DC转换期间,这种晶闸管得到加热。Hechm,冷却系统包含用于冷却该晶闸管。冷却系统由4个NOS冷却器组成,顶部和轴向风扇电机在底部的水喷嘴,用于强制空气冷却。
这四个冷却器处于自动模式。也就是说,当温度高时,冷却器开始一个接一个地使用,以将温度保持在预设的限制和反之亦然。
当温度开始下降时,冷却器开始通过向PLC发送命令一个接一个地切断(先进先出的偏差)。
每个冷却器都安装了阻尼器。这阻尼器有三个位置:开放,中间和关闭。让我们现在可以使用4个冷却器。因此,当温度开始下降(由于环境温度或减少),PLC发送命令冷却器以关闭其阻尼器从完全开放到一半开放。假设PLC将命令发送到冷却No.1以关闭其阻尼器到一半。因此,冷却器NO:1阻尼器电机将旋转阻尼器轴,当阻尼器达到半闭位置时,PLC(通过微动开关)和PLC向阻尼电机发送停止命令。然后PLC将监测温度。如果在温度下进一步减少,PLC将命令发送到冷却器NO:1阻尼器,以完全关闭阻尼器并推出喷雾泵和风扇电机。HVDC冷却系统的主要原理。
现在我们正面临一个问题,即冷却器无法在自动模式下操作,因为阻尼雕像不发送到PLC。我们也没有得到OEM的支持。
我有一个想法将编码器安装到阻尼电机轴上。请注意,阻尼电机是慢动移动的电机。它需要大约3分钟移动阻尼器从完全打开到完全关闭位置(和vISE VERSA)。编码器(与奥迪诺这样的一些微处理器合作)将感知阻尼器的位置,并发送三个位置命令(打开,中间和关闭)到PLC。
我想让一个照片类型使用光学编码器& audrino uno / mega和测试它。你能在编程方面帮助我吗?我应该选择哪种编码器?
问候
贾米尔、印度
谢谢贾米尔!你的主意听起来不错,而且可能行得通。然而,我很抱歉,但我不能帮助你,因为我不从事自定义项目。bet188me
我们可以用旋转编码器来测量线性长度吗?
当然。
我是一名退休的电子工程师和业余无线电操作员(叫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.
很棒,我很高兴你发现我的文章很有用!
嗨,谢谢你的伟大的工作…我现在在一个项目使用旋转编码器与液晶显示的角度。我有例子2的完整示意图吗?谢谢你!
谢谢!嗯,我没有特定的电路原理图,但我对每个组件具有单独的电路原理图,旋转编码器,液晶显示屏和伺服电机控制,因此您不应有任何问题。
我使用的是28byJ-48步骤电机,该电机与视频中使用的不同之处。28byj步进电机通过4个数字引脚连接到Arduino,但您只能通过2个引脚(Septpin和Dirpin)连接的那个。您是否有更改28byJ-48电机的代码?
嗨Dejan,
我有兴趣,想要建立这个项目,你能给我有使用的原理图和模块的细节。
谢谢。
问候,
莱姆。
好吧,一切都已经解释道。您可以弄清楚如何从本教程中连接编码器,如果您检查步进电机控制教程,可以找到用于连接驱动器和步进电机的电路原理图。
你好!
伟大的项目,真的很喜欢它!
我只是想知道你们用来求轴角的方程是什么。是基于ppr吗?我正在使用1024ppr增量编码器,我还没有找到匹配的轴角和计数器值。
谢谢!
谢谢。是的,方程是基于ppr的。在我的情况下,旋转编码器有30 ppr。
嗨Dejan,
感谢您的精彩教程。也适用于I2c和SPI。
但我有一个关于编码器读取的问题。
增量总是2而不是1。我还加了几个电路来消除弹跳,但没办法。
请你帮助我好吗 ?
谢谢。可能是编码器出了问题…
这可能是编码器,Dejan使用只有2过渡每个止动和你有4?当你转动旋钮时,两个引脚状态依次为00、10、11、01等。当引脚在11时,一些编码器有扣动器,而当它在00时。有些人在十点和十一点有毒品我怀疑德扬有一个。
所以,德扬的开始,也许是在00,一个停顿(2个过渡,即10,11)带他到11,所以这是他的程序中的一个“步骤”。在他的下一次点击时,它再次转换到01,然后00,再做一个“步骤”。你的代码将从00开始并进行4次转换,即10、11、01、00,所以他的代码在你的编码器上数2“步”,而在他的编码器上只有1步。你的数据可能被设置为11,而不是00,但原理是一样的。您将不得不对这段代码进行一些修改,以使其忽略额外的步骤。
伟大的项目几乎是我需要的。是否有可能arduino记住了电机的最后位置(比如68度)?这样,如果arduino被关闭,然后重新启动,它会“记住”的位置,并在LCD上读取68 ?
是的,这是可能的。您可以使用Arduino的EEPROM永久存储数据。
我不认为任何人可以做到这一点,因为纽扣针无处可去。一个电路图是需要的,因为我们都使用不同的步进驱动器。最好是在Instructables中写下这一点。
起初,我很兴奋,但现在在4个小时后我只有头疼。
我没有在示例中使用该按钮,但它只是简单的按钮。至于步进示例,您可以在“A4988驱动程序”的详细教程上找到电路原理图。
嗨Dejan!
我认为第一个代码示例中有一个小错误。IF语句“如果(agraite!= AlastState)”捕获编码器时钟脉冲的上升和下降沿。这意味着一个旋转编码器步骤将使两个变化进行计数器。如果您替换“如果(agrate!= alaStstate)”,“如果(agrate> alaStstate)”只计算上升沿。
我同意。如果您使用条件(state != aLastState), Counter会为轴的一个步骤改变两次。如果你使用(aState > aLastState)或(aState < aLastState),它对我很有效。这两种情况“”都是可能的,因为CLK边缘以这种方式改变:
1 -> 0 -> 1。
嗨,我来自阿根廷。伟大的项目!!
我照你说的做了。虽然我有一个问题!如果我缓慢地转动它,它便能够有效地反击,但如果我快速地转动它,它便会失去控制并重复步骤!
我使用了来自EPSON打印机的编码器。
会不会是因为编码器的分辨率太高了?
是否能够使用此编码器?
从已经非常感谢你!
来自阿根廷的问候!!
问题可能是在代码中,这不是那么优化。这只是一个简单的示例代码,它可能需要因此优化,以实现更好的结果。
该方法仅使用旋转编码器的分辨率的一半,因为每个周期有四个不同的状态(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_rotarya),B = DigitalRead(Pin_rotaryB);
if (B != prevB) counter += (B-prevB) * (A ?+ 1: 1);
否则if(a!= preva)计数器+ =(a-preva)*(b?-1:+1);
其他的回报;/ /没有改变:退出
preva = a;
prevB = B;
以(柜台);
}
####################################
这工作真的很棒,如果你把旋转编码器在一个正常的速度。但如果你把它转得太快,或者你在循环()中做其他需要更长的时间的事情,你会错过一个步骤,它会从11跳到00或从10跳到01。这样它就无法知道自己转向了哪个方向,所以计数器就会出现轻微的错误。
但是你可以通过检查它之前的哪个方向并相应地增加或减少反击来计数器。
或者,您可以使用中断而不是在loop()中检查引脚的状态,以确保没有遗漏任何步骤。
这是一个很好的评论。谢谢你的贡献!
一个更清晰,但更有效的方法来获得编码器的完整分辨率,这是。它的效率更高,因为它不使用任何整数算术,而且它利用了逻辑运算符的“短路”求值规则,该规则在大多数情况下会跳过大部分代码。
####################################
int counter = 0;
字节encoderSt = 0;
void循环()
{
字节a = digitalRead(pinA);
字节B = DigitalRead(PINB);
字节st =(b << 1)|一种;
如果(Encoderst!= St)
{
如果((encoderSt = = 0 & &圣= = 2)| | (encoderSt圣= = 0)= = 1 & & | | (encoderSt = = 2 & &圣= = 3)| | (encoderSt = = 3 & &圣= = 1))计数器-;
其他柜台+ +;
系列。println(柜台);
encoderSt =圣;
}
}
####################################
只使用二进制运算符的更高效代码
####################################
int计数器;
bool prevA = 1, prevB = 1;
void loop(){
BOOL A = DigitalRead(PIN_rotarya),B = DigitalRead(Pin_rotaryB);
计数器+ =(a ^ preva)|(b ^ prevb)?a ^ prevb?1:-1:0;
preva = a;
prevB = B;
以(柜台);
}
####################################
你的辅导课对我很有帮助。
但我需要一个非常精确的电机,每步获得1度。你有什么想法如何实现它吗?所以我将使用减少来实现这一目标吗?
大regads
Поздрав
嗯,也许您可以使用MicroRoStepping以增加电机的分辨率,或者当您说使用输出比为1.8 :: 1.0的额外齿轮箱。
嗨Dejan,
谢谢你这么伟大的教程。感谢您分享您的知识并制作更好的世界。
Eng Apache.
谢谢你,先生。你帮了我很多。现在Fanuc A860-0201-T001编码器从1990年与我的项目工作。
很高兴听你这么说,谢谢!
很好的辅导,我的朋友们。继续更新。
嗨伟大的教程,,,,我不确定显示屏上的所有组件。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?
非常感谢卓越的解释。竖起大拇指和订阅。
干杯
约翰·尼尔森
嗨,谢谢!您正在谈论的项目是在第二个例子中,这是A4988步进电机驱动程序。有关它的更多详细信息以及如何使用Arduino控制步进电机,您可以检查我的特定教程。干杯!
您的示例中的编码器代码仅占编码器滴答的一半。这是因为柜台仅在引脚改变后更新,而不是两个改变时。如果您想利用编码器的完整分辨率,它仍然可以仍然可以。
编码器每次通电时都从零开始计数,无论轴在哪里或之前的位置。
我们如何在电力的功率后从先前的编码位置开始。
嗯,编码器本身没有这样的能力。但是,您可以通过将其存储在Arduino的EEPROM中的位置来实现这一点。因此,下次电源您将从EEPROM读取存储的值并继续。
嗨Dejan,
首先感谢您的回复。
我是新手,使用Arduino Atmega 2560。
我已连接编码器5540直流电机轴,增量编码器有两个通道连接到i /O引脚。编码器读取电机位置,(编码器反馈)如何存储在EEPROM。
请给我任何示例代码或例程。
问候,
Naresh。
祝你今天过得愉快 ..!!
你好,
无计划电源关闭后如何在家庭位置进行编码器?
唯一能发生这种情况的方法就是,用某种方法把编码器从is最后存储的位置,移回0。你可以使用伺服或其他电机。这需要很多工作。我猜你想让“旋钮”在通电时指向家里?
/ s / WP
一切都很简单和和谐……直到我添加了一个I2C OLED显示屏。我希望刷新屏幕的延迟会最终干扰脉冲检测的时间。
我使用Arduino NANO和一个屏蔽,这意味着我只有引脚9、10和11可用,所以我不能连接一个ISR…我非常想使用旋转编码器
谢谢你提供的一个非常好的、简单的教程
大家好!
我要造一个测量工具来测量不同物体的长度。我能用这个技术来测量长度吗?
另外,那是什么屏幕?我喜欢它,我在哪里可以找到类似的?
嘿,理论上是的,你可以用这种技术做一个长度测量装置。