Rotační enkoder

20.09.2021 Arduino #arduino #enkoder

Příklady pro použití rotačního enkoderu s Arduinem.


Rotační enkodér je typ snímače polohy, který převádí úhlovou polohu (otáčení) knoflíku na výstupní signál, který se používá k určení směru otáčení knoflíku.

Díky své robustnosti a jemnému digitálnímu ovládání se používají v mnoha aplikacích včetně robotiky, CNC strojů a tiskáren.

Existují dva typy rotačních enkodérů - absolutní a přírůstkové. Absolutní enkodér nám udává přesnou polohu knoflíku ve stupních, zatímco inkrementální enkodér hlásí, o kolik přírůstků se hřídel posunula.

Rotační enkodér použitý v tomto článku je přírůstkového typu.

Rotační enkodéry vs. potenciometry

Rotační enkodéry jsou moderním digitálním ekvivalentem potenciometru a jsou univerzálnější než potenciometr.

Mohou se plně otáčet bez koncových dorazů, zatímco potenciometr se může otáčet pouze asi o 3/4 kruhu.

Potenciometry jsou nejlepší v situacích, kdy potřebujete znát přesnou polohu knoflíku. Rotační enkodéry jsou však nejlepší v situacích, kdy potřebujete znát změnu polohy místo přesné polohy.

Jak rotační enkodéry fungují

Uvnitř kodéru je drážkovaný disk připojený ke společnému uzemňovacímu pinu C a dvěma kontaktním pinům A a B, jak je znázorněno níže.

 

vnitřní struktura rotačního kodéru

 

Když otočíte knoflíkem, A a B dostanou se do kontaktu se společným uzemňovacím kolíkem C v určitém pořadí podle směru, kterým knoflíkem otáčíte.

Když přijdou do styku se společnou zemí, vydávají signály. Tyto signály jsou navzájem posunuty o 90° mimo fázi, protože jeden kolík přichází do kontaktu před druhým kolíkem. Toto se nazývá kvadraturní kódování.

 

rotační kodér fungující animace.gif

 

Když otočíte knoflíkem ve směru hodinových ručiček, nejprve se připojí pin A a poté pin B. Když otočíte knoflíkem proti směru hodinových ručiček, nejprve se připojí pin B a poté pin A.

Sledováním, kdy se každý kolík připojuje a odpojuje od země, můžeme pomocí těchto změn signálu určit, ve kterém směru se knoflík otáčí. Můžete to udělat jednoduchým pozorováním stavu B, když A změní stav.

Když A změní stav:

 

Pokud B! = A, pak byl knoflík otočen ve směru hodinových ručiček.

výstupní impulzy rotačního kodéru ve směru hodinových ručiček

 

Pokud B = A, pak byl knoflík otočen proti směru hodinových ručiček.

výstupní impulzy rotačního kodéru při otáčení proti směru hodinových ručiček

 

Piny rotačního enkodéru

Vývody rotačního kodéru jsou následující:

rotary-encoder-module-pinout 

GND je zem.

VCC je kladné napájecí napětí, obvykle 3,3 nebo 5 voltů.

SW je aktivní výstup spínače s nízkým tlačítkem. Když stisknete knoflík, napětí klesne na NÍZKÉ.

DT (výstup B) je stejný jako výstup CLK, ale zpožďuje CLK o 90° fázový posun. Tento výstup lze použít k určení směru otáčení.

CLK (výstup A) je primární výstupní impuls pro určení velikosti otáčení. Pokaždé, když se knoflík otočí o jednu zarážku (kliknutí) v libovolném směru, výstup „CLK“ projde jedním cyklem přechodu HIGH a poté LOW.

Výše uvedený popis pinů je dostupný ve speciální verzi enkodéru, které jsou součástí kompletního obvodu s pžadovanými rezistory. Rotační enkodér, ale lze zakoupit i v "holém stavu" a potom se musí celý obvod zapojit podle následujícího schématu:

encoder-schema 

Zapojení rotačního kodéru k Arduinu

Nyní, když víme vše o rotačním kodéru, je čas jej použít!

Pojďme připojit rotační kodér k Arduinu. Připojení je poměrně jednoduché. Začněte připojením pinu +V na 5V na pinu Arduino a GND k zemi.

Nyní připojte piny CLK a DT k digitálnímu pinu #2 a #3. Nakonec připojte SW pin k digitálnímu pinu #4.

Následující obrázek ukazuje zapojení.

 

wiring-rotary-encoder-with-arduino-uno 

 

Arduino kód - čtení rotačních enkodéru

Nyní, když máte připojený enkodér, budete potřebovat program, aby vše fungovalo.

Následující program detekuje, kdy se enkodér otáčí, určuje, kterým směrem se otáčí, a zda se stiskne tlačítko.

// Rotary Encoder Inputs
#define CLK 2
#define DT 3
#define SW 4

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;

void setup() {
	
	// Set encoder pins as inputs
	pinMode(CLK,INPUT);
	pinMode(DT,INPUT);
	pinMode(SW, INPUT_PULLUP);

	// Setup Serial Monitor
	Serial.begin(9600);

	// Read the initial state of CLK
	lastStateCLK = digitalRead(CLK);
}

void loop() {
	
	// Read the current state of CLK
	currentStateCLK = digitalRead(CLK);

	// If last and current state of CLK are different, then pulse occurred
	// React to only 1 state change to avoid double count
	if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

		// If the DT state is different than the CLK state then
		// the encoder is rotating CCW so decrement
		if (digitalRead(DT) != currentStateCLK) {
			counter --;
			currentDir ="CCW";
		} else {
			// Encoder is rotating CW so increment
			counter ++;
			currentDir ="CW";
		}

		Serial.print("Direction: ");
		Serial.print(currentDir);
		Serial.print(" | Counter: ");
		Serial.println(counter);
	}

	// Remember last CLK state
	lastStateCLK = currentStateCLK;

	// Read the button state
	int btnState = digitalRead(SW);

	//If we detect LOW signal, button is pressed
	if (btnState == LOW) {
		//if 50ms have passed since last LOW pulse, it means that the
		//button has been pressed, released and pressed again
		if (millis() - lastButtonPress > 50) {
			Serial.println("Button pressed!");
		}

		// Remember last button press event
		lastButtonPress = millis();
	}

	// Put in a slight delay to help debounce the reading
	delay(1);
}

Pokud je vše v pořádku, měli byste vidět níže výstup na sériovém monitoru.

 

výstup rotačního kodéru na sériovém monitoru

 

Arduino kód - pomocí přerušení

Aby rotační enkodér fungoval, musíme nepřetržitě sledovat změny signálů DT a CLK.

Abychom zjistili, kdy k takovým změnám dochází, můžeme je průběžně dotazovat (jako jsme to dělali v našem předchozím příkladu). Z níže uvedených důvodů to však není nejlepší řešení.

  • Musíme neustále provádět kontrolu, abychom zjistili, zda se hodnota změnila. Pokud se úroveň signálu nezmění, bude docházet ke ztrátě cyklů.
  • Od doby, kdy se událost stane, do doby, kdy to zkontrolujeme, bude existovat latence. Pokud potřebujeme okamžitě reagovat, budeme s touto latencí zdrženi.
  • Je-li doba změny krátká, je možné zcela vynechat změnu signálu.

Široce přijímaným řešením je použití přerušení.

S přerušeními nemusíte neustále přemýšlet o konkrétní události. Tím se Arduino uvolní k provedení jiné práce, aniž by se událost zmeškala.

// Rotary Encoder Inputs
#define CLK 2
#define DT 3

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";

void setup() {
	
	// Set encoder pins as inputs
	pinMode(CLK,INPUT);
	pinMode(DT,INPUT);

	// Setup Serial Monitor
	Serial.begin(9600);

	// Read the initial state of CLK
	lastStateCLK = digitalRead(CLK);
	
	// Call updateEncoder() when any high/low changed seen
	// on interrupt 0 (pin 2), or interrupt 1 (pin 3)
	attachInterrupt(0, updateEncoder, CHANGE);
	attachInterrupt(1, updateEncoder, CHANGE);
}

void loop() {
	//Do some useful stuff here
}

void updateEncoder(){
	// Read the current state of CLK
	currentStateCLK = digitalRead(CLK);

	// If last and current state of CLK are different, then pulse occurred
	// React to only 1 state change to avoid double count
	if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

		// If the DT state is different than the CLK state then
		// the encoder is rotating CCW so decrement
		if (digitalRead(DT) != currentStateCLK) {
			counter --;
			currentDir ="CCW";
		} else {
			// Encoder is rotating CW so increment
			counter ++;
			currentDir ="CW";
		}

		Serial.print("Direction: ");
		Serial.print(currentDir);
		Serial.print(" | Counter: ");
		Serial.println(counter);
	}

	// Remember last CLK state
	lastStateCLK = currentStateCLK;
}

Všimněte si, že hlavní smyčka tohoto programu je prázdná, takže Arduino nebude ničím zaneprázdněno.

Tento program mezitím sleduje digitální pin 2 (odpovídá přerušení 0) a digitální pin 3 (odpovídá přerušení 1) pro změnu hodnoty. Jinými slovy, hledá změnu napětí z HIGH na LOW nebo LOW na HIGH, což se stane, když otočíte knoflíkem.

Když k tomu dojde, zavolá se funkce updateEncoder (často nazývaná rutina služby přerušení nebo jen ISR ). Spustí se kód v rámci této funkce a pak se program vrátí zpět k tomu, co dělal předtím.

Za tím vším jsou zodpovědné dva řádky. Tato funkce se jmenuje attachInterrupt(), která říká, jaký pin monitorovat, který ISR ​​provést, pokud je aktivováno přerušení, a jaký typ spouště hledat.

attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);

 

Ovládání servomotor pomocí rotačního enkodéru

Pro náš další projekt použijeme rotační enkodér k ovládání polohy servomotoru.

Tento projekt může být velmi užitečný v mnoha situacích, například když chcete ovládat rameno robota, protože vám umožní přesné umístění paže a jejího úchopu.

V případě, že nejste obeznámeni se servomotorem, zvažte přečtení (alespoň skimming) níže uvedeného tutoriálu.

Schéma zapojení

Jak ukazuje schéma zapojení, budete potřebovat servomotor. Připojte červený vodič servomotoru k externímu napájení 5V, černý/hnědý vodič k zemi a oranžový/žlutý vodič ke kolíku 9 povoleného PWM.

Samozřejmě můžete použít výstup Arduino 5V, ale mějte na paměti, že servo může indukovat elektrický šum na 5V linku, kterou Arduino používá, což nemusí být to, co chcete.

Proto doporučujeme použít externí napájecí zdroj.

 

wiring-for-controlling-servo-motor-with-rotary-encoder 

 

Arduino kód

Zde je kód pro přesné ovládání servomotoru pomocí rotačního kodéru. Při každém otočení knoflíku o jednu zarážku (kliknutí) se poloha ramene serva změní o jeden stupeň.

// Include the Servo Library
#include <Servo.h>

// Rotary Encoder Inputs
#define CLK 2
#define DT 3

Servo servo;
int counter = 0;
int currentStateCLK;
int lastStateCLK;

void setup() {
	
	// Set encoder pins as inputs
	pinMode(CLK,INPUT);
	pinMode(DT,INPUT);
	
	// Setup Serial Monitor
	Serial.begin(9600);
	
	// Attach servo on pin 9 to the servo object
	servo.attach(9);
	servo.write(counter);
	
	// Read the initial state of CLK
	lastStateCLK = digitalRead(CLK);
}

void loop() {
	
	// Read the current state of CLK
	currentStateCLK = digitalRead(CLK);
	
	// If last and current state of CLK are different, then pulse occurred
	// React to only 1 state change to avoid double count
	if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){
		
		// If the DT state is different than the CLK state then
		// the encoder is rotating CCW so decrement
		if (digitalRead(DT) != currentStateCLK) {
			counter --;
			if (counter<0)
				counter=0;
		} else {
			// Encoder is rotating CW so increment
			counter ++;
			if (counter>179)
				counter=179;
		}
		// Move the servo
		servo.write(counter);
		Serial.print("Position: ");
		Serial.println(counter);
	}
	
	// Remember last CLK state
	lastStateCLK = currentStateCLK;
}

Zdroj: https://lastminuteengineers.com/rotary-encoder-arduino-tutorial/