Servo ovládané rotačním enkodérem

Cílem tohoto projektu je vytvořit systém pro vzdálené a přesné polohování servomotoru pomocí rotačního enkodéru (tzv. "digitální ruční kolečko"). Projekt demonstruje využití hardwarových přerušení (interrupts) Arduina a přímé řízení šířky impulsu v mikrosekundách pro dosažení maximální plynulosti pohybu.

Seznam použitého materiálu:

  • Mikrokonrolér: Arduino Uno (nebo Nano/Mega)
  • Vstupní prvek: Rotační enkodér (KY-040)
  • Akční člen: Servomotor (SG90)
  • Propojovací vodiče: Typ Male-to-Male / Male-to-Female
  • Napájení: USB kabel nebo externí 5V

Schéma zapojení:

Komponenty jsou k Arduinu připojeny následovně:

Komponenta

Pin na Arduinu

Popis

Enkodér CLK

Pin 2

Signál A

Enkodér DT

Pin 3

Signál B

Enkodér GND

GND

Společná zem

Enkodér VCC

5V

Napájení logiky

Servo Signal

Pin 9

PWM řízení pohybu

Servo VCC

5V

Napájení motoru

Servo GND

GND

Společná zem

Kód pro Arduino:

#include <Servo.h>

// --- DEFINICE PINŮ ---
const int encoderPinA = 2; // Pin s podporou přerušení (Interrupt)
const int encoderPinB = 3; // Pin s podporou přerušení (Interrupt)
const int servoPin    = 9; // PWM pin pro servo

Servo mojeServo;

// --- NASTAVENÍ KALIBRACE ---
// Většina serv používá 544 us pro 0° a 2400 us pro 180°.
// Použití mikrosekund je mnohem přesnější než stupně 0-180.
const int minPuls = 544;  
const int maxPuls = 2400; 

// Standardní enkodér má 20 aretací (cvaknutí) na otáčku.
// Při 4x dekódování jedna plná otáčka = 80 "tiků".
// Tímto číslem měníte "převod" – jak moc se servo otočí na jednu otáčku enkodéru.
const int maxTiku = 80; 

// 'volatile' říká procesoru, že se proměnná může změnit kdykoliv (v přerušení)
volatile long poziceEnkoderu = 0; 
long posledniMapovanaPozice = -1;

void setup() {
  // Připojení serva s definovaným rozsahem pulzů pro lepší přesnost
  mojeServo.attach(servoPin, minPuls, maxPuls);
  
  // pull-up rezistory udrží signál stabilní (HIGH), když enkodér nespíná
  pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);

  // Aktivace přerušení na OBOU pinech při jakékoliv ZMĚNĚ (CHANGE).
  // Díky tomu zachytíme každý náběžnou i sestupnou hranu signálu.
  attachInterrupt(digitalPinToInterrupt(encoderPinA), nactiEnkoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(encoderPinB), nactiEnkoder, CHANGE);
  
  // Nastavení serva na střed při startu
  mojeServo.writeMicroseconds(1500); 
}

void loop() {
  // 1. Omezíme hodnotu enkodéru na fyzický rozsah serva.
  // Nechceme, aby se počítadlo točilo dál, když už je servo na dorazu.
  poziceEnkoderu = constrain(poziceEnkoderu, 0, maxTiku);

  // 2. Aktualizujeme servo pouze tehdy, pokud se enkodér pohnul.
  // Neustálé posílání stejného příkazu může způsobit cukání (jitter).
  if (poziceEnkoderu != posledniMapovanaPozice) {
    
    // 3. Přepočet (mapování) tiků enkodéru na mikrosekundy.
    // map(Hodnota, RozsahZ_Min, RozsahZ_Max, RozsahDo_Min, RozsahDo_Max)
    int sirkaPulsu = map(poziceEnkoderu, 0, maxTiku, minPuls, maxPuls);
    
    // 4. Poslání přímého časového signálu do servomotoru
    mojeServo.writeMicroseconds(sirkaPulsu);
    
    posledniMapovanaPozice = poziceEnkoderu; 
  }
}

/**
 * LOGIKA ENKODÉRU (Kvadraturní dekódování)
 * Tato funkce se spustí pokaždé, když pin 2 nebo 3 změní stav.
 * Porovnává aktuální stavy s předchozími pro určení směru.
 */
void nactiEnkoder() {
  static int minuleA = 0;
  static int minuleB = 0;
  
  int aktualniA = digitalRead(encoderPinA);
  int aktualniB = digitalRead(encoderPinB);
  
  if (aktualniA != minuleA || aktualniB != minuleB) {
    // Logika XOR určuje směr otáčení (fázový posun)
    if ((minuleA ^ aktualniB) & 1) {
      poziceEnkoderu++;
    } else {
      poziceEnkoderu--;
    }
  }
  
  minuleA = aktualniA;
  minuleB = aktualniB;
}

Teorie a algoritmus:

Program využívá tři klíčové techniky pro zajištění vysoké kvality ovládání:

  1. 4x Kvadraturní dekódování: Namísto pouhého počítání "kliknutí" enkodéru systém sleduje každou elektrickou změnu na obou signálních pinech (náběžnou i sestupnou hranu). Tím se čtyřnásobně zvyšuje rozlišení ovládání.
  2. Hardwarová přerušení (Interrupts): Arduino okamžitě reaguje na pohyb enkodéru bez ohledu na to, co právě dělá v hlavní smyčce. Tím je zajištěno, že systém neztratí ani jeden krok enkodéru i při rychlém otáčení.
  3. Microsecond Control: Standardní příkazy pro servo pracují s rozlišením 0–180 stupňů. Tento projekt využívá přímé adresování časování pulsu v mikrosekundách (544 µs až 2400 µs), což poskytuje jemnost přes 1800 kroků na celém rozsahu pohybu.

Další podobné články

Meteostanice

Projekt pokročilé meteostanice s důrazem na extrémně nízkou spotřebu a dlouhou výdrž na Li-ion článek. Postaveno na čipu ATmega328PB (8MHz, 3.3V).