Подключение энкодера к ардуино
Содержание:
- Простое приложение
- Счет
- Registers
- Rotary Encoder Arduino Example
- Source Code
- Initializing
- Как использовать энкодер?
- Initialization
- Example 2 – Controlling a Stepper Motor Using a Rotary Encoder
- Энкодер
- Other Useful Functions
- How the VEX Encoders Work
- How Rotary Encoder Works
- Arduino Code – Using Interrupts
- Подключение энкодера промышленного назначения к Arduino
Простое приложение
Мы создадим приложение, демонстрирующее, как использовать поворотный энкодер в проекте на Arduino. Мы будем использовать энкодер для навигации, ввода данных и выбора. Ниже приведена принципиальная схема приложения.
Принципиальная схема примера приложения с использованием поворотного энкодера на Arduino
Схема построена на базе платы Arduino Uno. Для графического интерфейса используется LCD дисплей Nokia 5110. В качестве средств управления добален механический поворотный энкодер с кнопкой и RC-фильтрами.
Собранная схема примера использования поворотного энкодера на Arduino
Мы разработаем простое программное меню, в котором и продемонстрируем работу поворотного энкодера.
Счет
Проанализировав состояние энкодера при вращении влево и вправо, составляем таблицу:
Его начальное положение 1-1. При повороте вправо произошел щелчок, единица стала логическим нулем. Новое значение this State vfd равно 01. Согласно команды данный результат суммируется со значением переменной Position.
Из-за того, что произошел дребезг, позиция стала 11, после перерасчета порядковый номер стал 7. После того, как дребезг закончился, нужно фиксировать новое положение 01 и к предыдущему нулю добавляется единица. При повороте энкодера произошел один щелчок, и значение переменной Position стало единицей.
Происходит второй щелчок при повороте энкодера направо, и вместо позиции 01 мы имеем позицию 00. После того, как весь дребезг закончится, на выходе управления также имеем значение единицы. При четвертом щелчке, когда позиция с 10 стала 11, мы имеем значение 6. После окончания дребезга остается 6.
В некоторых энкодерах имеет применение кнопка панели. При ее нажатии и отпускании тоже будет дребезг контактов, нужно применить библиотеку Bounce. Функции этой библиотеки нужны для задания pin, к которому будет подключена кнопка, задач времени задержки в миллисекундах. Если произошло нажатие на кнопку, то функция мощности (кВт) возвращает векторное значение true, если нет, то false vfd.
Registers
You can use the registers defined in the spec to read position and
speed of the encoder. Other registers are used to write configuration
data such as changing the address, changing the termination state or
re-zeroing the encoder.
Reading Registers
Using the Wire library to read bytes from a register on a
device with address is as simple as:
Wire.beginTransmission(addr); Wire.write(reg); Wire.endTransmission(); Wire.requestFrom(address, N); while (Wire.available()) { Wire.read(); // Do something with each byte. }
Writing Registers
Using the Wire library to write byte to a register on a
device with address is as simple as:
Wire.beginTransmission(addr); Wire.write(reg); Wire.write(b); Wire.endTransmission();
Rotary Encoder Arduino Example
Let’s make a practical example of it using the Arduino. The particular module that I will use for this example comes on a breakout board and it has five pins. The first pin is the output A, the second pin is the output B, the third pin is the Button pin and of course the other two pins are the VCC and the GND pin.
We can connect the output pins to any digital pin of the Arduino Board.
You can get the components needed for this Arduino Tutorial from the links below:
- Rotary Encoder Module………………. Amazon / Banggood
- Arduino Board …………………………… Amazon / Banggood
- Breadboard and Jump Wires ……… Amazon / Banggood
Disclosure: These are affiliate links. As an Amazon Associate I earn from qualifying purchases.
Source Code
Here’s the Arduino code:
/* Arduino Rotary Encoder Tutorial * * by Dejan Nedelkovski, www.HowToMechatronics.com * */ #define outputA 6 #define outputB 7 int counter = 0; int aState; int aLastState; void setup() { pinMode (outputA,INPUT); pinMode (outputB,INPUT); Serial.begin (9600); // Reads the initial state of the outputA aLastState = digitalRead(outputA); } void loop() { aState = digitalRead(outputA); // Reads the "current" state of the outputA // If the previous and the current state of the outputA are different, that means a Pulse has occured if (aState != aLastState){ // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise if (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 }
Description of the code: So first we need to define the pins to which our encoder is connected and define some variables needed for the program. In the setup section we need to define the two pins as inputs, start the serial communication for printing the results on the serial monitor, as well as read the initial value of the output A and put the value into the variable aLastState.
Then in the loop section we read the output A again but now we put the value into the aState variable. So if we rotate the encoder and a pulse is generated, these two values will differ and the first “if” statement will become true. Right after that using the second “if” statement we determine the rotation direction. If the output B state differ from the output A state the counter will be increased by one, else it will be decreased. At the end, after printing the results on the serial monitor, we need to update the aLastState variable with aState variable.
That’s all we need for this example. If upload the code, start the Serial Monitor and start rotating the encoder we will start getting the values in the serial monitor. The particular module that I have makes 30 counts each full cycle.
Initializing
The order in which you initialize the encoders is very important!
First, the wire library must be started by calling ,
then you must call the of each encoder method in the order
that they are chained together. The one plugged into the Arduino
first, then the one plugged into that and so on until the last encoder.
The first argument of the method is should convert encoder
revolutions to output rotations. Three of these are defined by
default:
- MOTOR_269_ROTATIONS
- The 269 motor and it’s matching encoder.
- MOTOR_393_SPEED_ROTATIONS
- The 393 motor and it’s matching encoder
when geared for speed. - MOTOR_393_TORQUE_ROTATIONS
- The 393 motor and it’s matching encoder
when geared for torque.
These can be augmented to take into account your gear ratio by
multiplying by a conversion factor. This will affect both what value
you the speed gives you and your position. For example, if your wheel
spun once every 3 time your 269s out It also supports dealing with
automatically dealing with conversion put shaft did, you could use
and your speed would be measured in
rpm of the wheel, while position would in rotations of the
wheel. Alternatively, if you want your measurements in terms of feet
moved and the circumference of you wheel is 1/2 foot, you can use
and now your position is
measured in feet and your speed is in feet-per-minute.
The second argument is a conversion factor for the time-delta of the
encoder. These are separate for the 269 encoders and 393
encoders. Simply select or
depending on your motor choice.
I2CEncoder encoder; Wire.begin(); encoder1.init(MOTOR_269_ROTATIONS, MOTOR_269_TIME_DELTA);
Как использовать энкодер?
Энкодеры бывают разных типов. Некоторые могут определять абсолютную позицию/угол поворотной ручки, не следя за ее перемещением. Но KY-040 гораздо проще. Считывая сигналы, идущие на два контакта микроконтроллера, мы можем определить, в какую сторону был повернут потенциометр – влево или вправо. При помощи третьего контакта можно определить состояние кнопки. Форма волны на двух «поворотных» контактах выглядит примерно так:
Форма волны энкодера при повороте по часовой стрелке
Форма волны энкодера при повороте по против часовой стрелки
Таким образом, когда вы поворачиваете ручку вправо, первой в состояние HIGH переходит линия B, а лишь затем – линия A. После этого, соответственно, линия B первой переходит в состояние LOW, а следом за ней – линия A. В результате последовательность сигналов при повороте ручки по часовой стрелке получается такой: 00, 01, 11, 10, 00. Но если повернуть ручку против часовой стрелки, то последовательность получается такой: 00, 10, 11, 01, 00. Более подробно смотрите на картинках выше.
Таким образом, аккуратно отслеживая эти сигналы, вы можете определять направление, в котором вращается ручка энкодера, а также определять 4 промежуточных состояния между двумя кликами. Если ваше устройство поддерживает прерывания, то с их помощью можно выводить уведомления об изменении сигнала на линиях, но для этого также понадобится дополнить программный код. Если прерывания не поддерживаются, можно воспользоваться техникой под названием «поллинг» (от англ. «polling»), при которой выполняется частое считывание сигнала, чтобы как можно быстрее определить его изменение.
Но есть еще одна трудность – мы живем в неидеальном мире (на тот случай, если вы не в курсе :D). Механические контакты KY-040 время от времени «дают осечку», и причина этого дефекта может быть, например, в том, что на контакт попала пыль, или в том, что на медном припое есть какая-то выбоина. В результате микроконтроллер может получить «грязный» сигнал и сделать неверное «умозаключение». Этот дефект зовется «дребезгом контактов». Справиться с дребезгом контактов можно и на аппаратном, и на программном уровне. Аппаратное решение – это воспользоваться маленьким конденсатором, способным немного смягчить шум сигнала. Программное решение – это задать временной период, в течение которого ожидается изменение сигнала, и в нашем проекте эту задачу будет выполнять библиотека «Encoder»
Я специально заострил ваше внимание на этой проблеме, чтобы вы знали, что вы можете столкнуться с нею в своем проекте.
Initialization
When the encoder receives power it starts up. It does not retain it’s
previous address, position or most other data from before it was
powered down. When it comes back on, it is set to a default
address. To initialize the device, it must be assigned a new
address. Once it has been assigned an address it is said to be
initialized. From this point, you can read it’s speed, position and
change other configuration options. The most important configuration
to make sure you change when necessary is to disable the termination
of the encoder if there are any other I2C devices after the encoder.
Otherwise, you can’t communicate with them. If the next device is an
encoder, you just repeat this process to initialize it too. As a
result of this initialization process, the order you plug encoders
into each other is very important.
Example 2 – Controlling a Stepper Motor Using a Rotary Encoder
In addition to this basic example, I made one more example of controlling a stepper motor position using the rotary encoder.
Here’s the source code of this example:
/* Stepper Motor using a Rotary Encoder * * by Dejan Nedelkovski, www.HowToMechatronics.com * */ #include <LiquidCrystal.h> // includes the LiquidCrystal Library LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LC object. Parameters: (rs, enable, d4, d5, d6, d7) // defines pins numbers #define stepPin 8 #define dirPin 9 #define outputA 10 #define outputB 11 int counter = 0; int angle = 0; int aState; int aLastState; void setup() { // Sets the two pins as Outputs pinMode(stepPin,OUTPUT); pinMode(dirPin,OUTPUT); pinMode (outputA,INPUT); pinMode (outputB,INPUT); 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); }
Feel free to ask any question in the comments section below.
Энкодер
Энкодер – это так называемый датчик угла поворота, то есть, устройство, которое предназначено чтобы преобразовать угол поворота вала (измеряемого объекта) в электрические импульсы, по которым можно определить: угол поворота, скорость вращения, направление вращения, и текущее положение относительно начальной точки работы.
Датчики угла поворота (далее энкодеры) нашли широкое применение в различных механизмах, в которых необходимо точно знать текущее положение. Такими механизмами могут быть: промышленные манипуляторы, сервоприводы и т.д.
Рисунок 1 — Внешний вид энкодера
Энкодеры имеют разделение на :
– инкрементальные;
– абсолютные.
По характеру исполнения подразделяются на :
– Резисторные;
– Магнитные;
– Оптические.
По своей сути инкрементальный энкодер – это счетчик импульсов, которые возникают при вращении вала. Устанавливают энкодер непосредственно на вал, или соединяют их через гибкую переходную муфту.
Внутри энкодера расположен диск с рисками, где с одной стороны располагается источник света, а с другой — фотоприёмник. При вращении диска изменяется количество света, проходящего через риски диска на фотоприемник, далее сигнал преобразуется и передается на дискретный выход. Необходимо заметить, что выходной сигнал состоит из двух каналов, в которых импульсы имеют сдвиг на 90 градусов относительно друг друга, что позволяет нам определять направление вращения вала. Количество импульсов может быть от нескольких импульсов до десятков тысяч импульсов на один оборот – так называемое «разрешение энкодера». Например, если диск будет иметь 2000 рисок на оборот, то за 1000 импульсов вал повернулся на 180 градусов.
Рисунок 2 — Диаграмма импульсов энкодера смещенных на 90 градусов.
Чтобы привязать отсчет положения относительно начала координат, датчики так же имеют референтную метку (указатель нулевой отметки/импульс, который отвечает за полный оборот). То есть, при каждом обороте вала, на выходе будет еще один импульс начальной (нулевой) позиции. Этот выход обычно используется для сброса внешнего счетчика, который отвечает за текущее положение.
Абсолютный энкодер
Абсолютный энкодер по своему исполнению является оптическим.
В первую очередь они разделяются на однооборотный, в котором текущая координата определяется в рамках одного оборота, и многооборотные.
Абсолютный энкодер можно отнести к отдельному типу энкодеров, отличительной особенностью которых является уникальный код , сформированный для каждой позиции вала. Так же разница от инкрементального энкодера: в данном датчике не нужен счетчик импульсов, потому что мы всегда знаем угол поворота. Выходной сигнал абсолютного энкодера формируется как во время покоя, так и во время вращения вала. Внутренней отличительной особенностью является диск с несколькими концентрическими дорожками, каждой из которых получается уникальный двоичный код для определенной позиции вала. Абсолютный энкодер при потере питания не теряет своего значения, что говорит о том, что нам не нужно возвращение в начальную позицию. Сигнал абсолютного энкодера устойчив к помехам, что говорит о том, что для него не требуется точная установка вала. Данный тип датчиков хорошо устойчив к вибрациям.
Рисунок 3 — Диск абсолютного энкодера с несколькими дорожками
Наиболее распространёнными выходными сигналами являются:параллельный код, код Грея, интерфейсы Profibus-DP, LWL, DeviceNet, SSI, CANopen, через которые также можно осуществить программирование датчиков.
Магнитный энкодер
Магнитный энкодер улавливает полюса вращающегося магнитного элемента, который находится вблизи чувствительного элемента, преобразуя эти влияния в соответствующий цифровой код.
Недостаточно прав для комментирования
Other Useful Functions
- Sets whether or not to
reverse the position of this encoder. - Get the raw velocity bits from
the encoder. These represent the time-delta in between
revolutions of the encoder. - This returns the position of the encoder
in terms of ticks. - Tells the encoder to pass I2C messages along
to any device down the line from it. - Tells the encoder to stop passing I2C messages
along to any device down the line from it. - Returns the 7-bit I2C address of
this encoder for sending your own messages.
How the VEX Encoders Work
This section describes how VEX Encoder I2C protocol works with respect
to Arduino. It does not describe how I2C works. If you want to know
how I2C itself works, there are plenty of other good guides. It also
does not go into detail on the register addresses and other
information that can be found in spec. Instead, it highlights the
interesting mis-matches between the VEX Encoder I2C and I2C as
implemented by the Arduino Wire library. It also goes into further
detail on termination and initialization.
How Rotary Encoder Works
Let’s take a closer look at the encoder and see its working principle. Here’s how the square wave pulses are generated: The encoder has a disk with evenly spaced contact zones that are connected to the common pin C and two other separate contact pins A and B, as illustrated below.
When the disk will start rotating step by step, the pins A and B will start making contact with the common pin and the two square wave output signals will be generated accordingly.
Any of the two outputs can be used for determining the rotated position if we just count the pulses of the signal. However, if we want to determine the rotation direction as well, we need to consider both signals at the same time.
We can notice that the two output signals are displaced at 90 degrees out of phase from each other. If the encoder is rotating clockwise the output A will be ahead of output B.
So if we count the steps each time the signal changes, from High to Low or from Low to High, we can notice at that time the two output signals have opposite values. Vice versa, if the encoder is rotating counter clockwise, the output signals have equal values. So considering this, we can easily program our controller to read the encoder position and the rotation direction.
Arduino Code – Using Interrupts
In order for rotary encoder to work, we need to continuously monitor changes in DT and CLK signals.
To determine when such changes occur, we can continuously poll them (like we did in our previous sketch). However, this is not the best solution for below reasons.
- We have to busily perform checking to see whether a value has changed. There will be a waste of cycles if signal level does not change.
- There will be latency from the time the event happens to the time when we check. If we need to react immediately, we will be delayed by this latency.
- It is possible to completely miss a signal change if the duration of the change is short.
A solution widely adopted is the use of an interrupt.
With interrupts you don’t need to constantly poll the specific event. This frees the Arduino to get some other work done while not missing the event.
Wiring
As most Arduinos (including Arduino UNO) have only two external interrupts, we can only monitor changes in the DT and CLK signals. That’s why we removed the connection of the SW pin from the previous wiring diagram.
So now the wiring looks like this:
Some boards (like the Arduino Mega 2560) have more external interrupts. If you have one of them, you can keep the connection for SW pin and extend below sketch to include code for the button.
Arduino Code
Here’s the sketch that demonstrates the use of the interrupts while reading a rotary encoder.
Notice that the main loop of this program is kept empty so Arduino will be busy doing nothing.
Meanwhile, this program watches digital pin 2 (corresponds to interrupt 0) and digital pin 3 (corresponds to interrupt 1) for a change in value. In other words, it looks for a voltage change going from HIGH to LOW or LOW to HIGH, which happens when you turn the knob.
When this happens the function (often called the interrupt service routine or just ISR) is called. The code within this function is executed and then the program returns back to whatever it was doing before.
Below two lines are responsible for all this. The function tells the Arduino which pin to monitor, which ISR to execute if the interrupt is triggered and what type of trigger to look for.
Подключение энкодера промышленного назначения к Arduino
Наша задача суметь управлять скоростью асинхронного двигателя с помощью программы на компьютере. У нас имеется преобразователь частоты (частотник):
Для домашних заданий такая информация не нужна. На фотографии энкодер промышленного назначения для асинхронного двигателя управления мощностью (кВт) станков:
В станкостроении энкодеры широко применяются для преобразователей частоты асинхронных двигателей. Они монтируются как датчики обратной связи по своей скорости. Такие энкодеры имеют большую дискретность от 100 импульсов на оборот до 1 млн импульсов на оборот. У этой марки дискретность равна 500 имп. на оборот.
Энкодеры подразделяются на виды задач по принципу действия на частотные преобразователи. Они бывают абсолютными и инкрементальными. Наш энкодер выполняет обычную функцию – выдает сигнал дифференцирования при отключении мощности питания, и ее подачи снова. Раннее состояние не сохраняется.
Энкодеры абсолютного вида имеют внутреннюю память, которая помнит последние положения. Зачем нужна память, и зачем сохранять эти данные? В заводских условиях станкостроения перед перемещением определенного устройства в первую очередь указывают нулевую точку. Такой процесс называется реферированием, то есть, выход в нуль.
Применение датчика абсолютного вида дает возможность уйти от этой процедуры на второй раз, сократить время при условии, что система имеет ограничения для перемещений.
Рассмотрим энкодеры синуса и косинуса. Они выдают выходной сигнал косинуса или синуса. Далее, с помощью устройства интерполятора мощности образуют из них импульсы. Сигналы такого вида можно изменять в размерах. Питание энкодера осуществляется от напряжения 5 вольт.
Сигнал «А» — это сигнал импульса прямого типа. Количество импульсов с этого сигнала приходит на каждом обороте. Оно равно 500 (дискретность датчика).
Сигнал «В» — тоже прямой сигнал импульса. С него на каждом обороте поступает число импульсов по дискретности датчика, который смещен от канала «А» на 90 градусов (500).
Сигнал «R» — это сигнал метки «нуль». С одного оборота датчика получается один импульс.
В энкодерах промышленного назначения используется сигнал дифференцирования, для работы с частотным преобразователем (частотником). Название у него сложное, а на самом деле все просто. Все каналы отдельно копируются своей инверсией. Это необходимо для отдавания сигнала на значительные расстояния. Выходной канал энкодера подсоединяется к приемнику специального назначения, сделанному на усилителях операционного вида. Импульс в итоге определяется в совокупности двух сигналов.