Styr unipolär stegmotor med Arduino

Unipolära stegmotorer är ganska ovanliga nuförtiden eftersom de generellt inte är lika kraftfulla som bipolära motorer av samma fysisk storlek. De är däremot enklare att driva och kräver enklare elektronik. I den här guiden visar vi hur man styr en liten unipolär stegmotor, t.ex. en 28BYJ-48, med en billig modul med ett ULN2003-chip.

Kopplingen

Hur unipolära stegmotorer fungerar

Stegmotorer skiljer sig från traditionella motrer i att de roterar inte av sig själva när man ger ström till dem. De har flera sladdar och om man skickar ström genom två av dem så hoppar motorn framår eller bakåt ett litet steg. För att få dem att rotera behöver man skicka ström genom deras anslutningar i rätt ordning. Fördelen med detta är att man kan styra motorns position väldigt exakt. Om man roterar motorn 10 steg åt ena hållet och sedan 10 steg tillbaka så kommer den att komma tillbaka till exakt samma position. De vanligaste typerna av stegmotorer är bipolära och unipolära. De bipolära är numera de absolute vanligaste eftersom de är generellt starkare, men unipolära har fördelen att de kräver enklare elektronik för att styra.

En unipolär stegmotor har 4 spolar och därmed 8 anslutningar, men de flesta motorer har två eller tre anslutningar ihoppkopplade inne i motorn och har därför bara 5 eller 6 sladdar. Bilden här intill visar hur spolarna är kopplade i en unipolär motor med 5 anslutningar, t.ex. 28BYJ-48 som vi använder här.

Beskrivning av koden

Grundprincipen för koden är enkel. Vi behöver bara definiera 4 utgångar och sedan sätta dem till hög en efter en. Men stegmotorer kan inte snurra hur snabbt som helst så vi behöver kontrollera hastigheten på vår kod. Det går att göra med vanliga delay()-anrop, men det låser koden så att vi inte kan göra något annat under tiden. Vi använder istället tricket från vår guide om multitasking genom att läsa ut Arduinos timer-värde som räknar antalet millisekunder som förflutit sedan start och jämför det med ett lagrat värde för när vi senast gjorde något. Om tillräckligt mycket tid har förflutit vet vi att det är dags att agera. I vårt exempel fyra millisekunder. För att demonstrera kraften med denna lösning så har vi två olika timers, en som skickar pulser till motorn och en som är betydligt längre som byter rotationsriktning på motorn med jämna mellanrum (var femte sekunder).

Det är viktigt att notera att stegmotorer kan inte rotera lika snabbt som likströmsmotorer. Högsta hastigheten för 28BYJ-48 verkar vara ca 2 ms mellan varje puls. Vissa motorerer klarar beytlidgt mer, andra mindre. För att uppnå högsta hastighet på en stegmotor behövar man dessutom starta långsamt och sedan accelerera upp till önskad hastighet. Detta är extra vitkigt om motorn är hårt belastad och behöver flytta på en stor massa.

Koden

// Konstant för hur många millisekunder vi väntar mellan varje steg
const int step_interval = 4;
// Konstant för hur många millisekunder länge vi kör motorn åt vart håll
const int switch_interval = 5000;

// Dessa konstanter specifierar vilka pinnar på Arduino-kortet som
// är anslutna till motor-driv-modulen.
const int motor_pin1 = 2;
const int motor_pin2 = 3;
const int motor_pin3 = 4;
const int motor_pin4 = 5;

void setup() {
  // Ställ in de fyra motor-pinnarna till att vara utgångar.
  pinMode(motor_pin1, OUTPUT);
  pinMode(motor_pin2, OUTPUT);
  pinMode(motor_pin3, OUTPUT);
  pinMode(motor_pin4, OUTPUT);
}

// Global variabel för att hålla reda på vilken fas för
// pulserna till motorn vi är i.
int phase = 0;
// Global variabel för att hålla reda på när vi skickade ut
// pulser till motorn senaste.
unsigned long last_step = 0;
// Global variabel som håller reda på när vi bytte håll
// på motorn senast.
unsigned long last_switch = 0;
// Global variabel som håller reda på vilket håll motorn
// roterar på. +1 betyder ena hållet och -1 andra.
int direction = 1;

void loop() {
  // Hämta ut aktuell tid (antal millisekunder sen uppstart)
  unsigned long current_time = millis();

  // Kolla om det är dags att skicka ut en ny puls till motorn.
  if (current_time - last_step > step_interval) {
    // Uppdatera tid-variabeln
    last_step = current_time;
    
    // Hoppa fram eller bak en fas. direction-variabeln innehåller
    // antingen +1 eller -1 vilket innebär att fasen antingen ökar
    // med ett eller minskar med ett beroende på vilket håll motorn
    // ska rotera.
    phase = phase + direction;
    // Se till att fas-variabeln alltid ligger mellan 0 och 3.
    // Om den är större än tre sätter vi den till noll, och om den är
    // mindre än noll sätter vi den till tre.
    if (phase > 3) {
      phase = 0;
    }
    else if (phase < 0) {
      phase = 3;
    }
    
    // Switch väljer ut en av 4 möjliga alternativ baserat på
    // vad variabeln fas är satt till. Varje fas skickar ut ström
    // till en av de fyra spolarna i stegmotorn. För att motorn
    // ska rotera behöver vi skicka ut pulserna i rätt ordning:
    // 1, 2, 3, 4, 1, 2, 3, ... osv  för ena hållet och omvänt
    // 4, 3, 2, 1, 4, 3, ... för andra hållet.
    switch(phase) {
      case 0:
        digitalWrite(motor_pin1, HIGH);
        digitalWrite(motor_pin2, LOW);
        digitalWrite(motor_pin3, LOW);
        digitalWrite(motor_pin4, LOW);
        break;
      case 1:
        digitalWrite(motor_pin1, LOW);
        digitalWrite(motor_pin2, HIGH);
        digitalWrite(motor_pin3, LOW);
        digitalWrite(motor_pin4, LOW);
        break;
      case 2:
        digitalWrite(motor_pin1, LOW);
        digitalWrite(motor_pin2, LOW);
        digitalWrite(motor_pin3, HIGH);
        digitalWrite(motor_pin4, LOW);
        break;
      case 3:
        digitalWrite(motor_pin1, LOW);
        digitalWrite(motor_pin2, LOW);
        digitalWrite(motor_pin3, LOW);
        digitalWrite(motor_pin4, HIGH);
        break;
      default:
        phase = 0;
        break;
    }
  }

  // Kolla om det är dags att byta håll på motorn
  if (current_time - last_switch > switch_interval) {
    // Uppdatera timer-värdet
    last_switch = current_time;
    // Vi byter håll genom att sätta direction variabeln till
    // minus sig själv. Så om den är 1 blir den -1, och om den
    // är -1 blir den 1. Vi använder det här värdet längre upp i koden
    // för att öka eller minska phase variabeln.
    direction = -direction;
  }
}

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *