22. Kaksisuuntainen moottorin ohjaus

Aiemmissa osissa on tulleet tutuiksi mm. moottorin ohjaus pwm:llä, mutta vain yhteen suuntaan. Tässä osassa laajennetaan esimerkkien osalta tietämystä siitä, mitä tarvitaan jos halutaan ohjata moottoria kahteen eri suuntaan.

Periaatteessa kaksisuuntainen moottorinohjaus ei ole sen kummallisempi asia kuin aikaisemmin käsitelty moottorin ohjaus PWM:llä. Moottorin läpi täytyy päästää virtaa kulkemaan, mikä aiheuttaa moottorin pyörimisen yhteen suuntaan. Kun moottorin läpi kulkee virtaa toiseen suuntaan, niin moottorikin pyörii toiseen suuntaan. Helppoa eikös juu! Käytännössä tarvitaan vain hieman enemmän elektroniikkaa ja jonkin sortin ohjauslogiikkaa - ja sehän meiltä käy.

Kaksisuuntaisessa moottorinohjauksessa elektroniikan ytimenä, joka varsinaisesti sallii moottorin läpi kulkevan virran suunnan muuttumisen, toimivat edelleen transistorit kuten on aiemmin opittu. Tässä tapauksessa transistoreja tuleekin 4 kappaletta ja tarvitaan sekä P-tyypin että N-tyypin transistoreita (olivatpa ne mosfetteja tai BJT tyyppisiä). Kyseiset 4 transistoria kytketään H-siltaan ja moottori sillan keskelle. Sopivasti transistoreita ohjaamalla saadaan moottori pyörimään haluttuun suuntaan tai jarruttamaan. Lisää teoriaa kytkennän toiminnasta voit lukea H-silta sivuilta. Koska teoriaa on kirjoitettuna valmiiksi jo muualla, sivuutetaan suurempi teoriaosuus tässä tapauksessa ja siirrytään elektroniikan pariin.

Tarvittavat osat

Ohjauskytkennäksi muodostuu näkkärille väsätty L298N moottorinohjainpiirilevy. Kyseinen IC-piiri kykenee ohjaamaan kahta moottoria yhtäaikaisesti ja 5 voltin ohjauslogiikkaa voidaan käyttää 3,3 voltin mikrokontrollerilla. Kytkennän rakentamiseksi tarvitaan siis seuraavia osia:

  • L298N Moottoriohjainpiiri (myös muunlainen käy)
  • 1N4007 Diodeja (myös muunlaiset diodit käy)
  • 7805 5-voltin regulaattori
  • 4 kpl 1.21 ohmin vastuksia (nämä eivät tällä hetkellä ole pakollisia)
  • 2 kpl 1 kilo-ohmin vastuksia
  • 2 kpl vihreä LED
  • 2 kpl punainen LED
  • 2 kpl 100 nF kondensaattoreita
  • Johtimia
  • Launchpad + MSP430G2231 mikrokontrolleri
  • DC-sähkömoottori
  • >8 voltin jännitelähteen moottorille ja kytkennälle (mikrokontrollerin käyttöjännite otetaan launchpadilta)

Moottoriohjaimen kytkeminen mikrokontrolleriin

Kytkentäkuva on lähestulkoon samanlainen kuin rakenteluissa esiintyneessä moottoriohjaimessa, missä kerron hieman enemmän käytetystä IC-piiristä. Sen verran kuitenkin eroa tuli, että muutamat kondensaattorit jätin pois ja lisäyksenä moottoreiden syöttöjännitteestä tehdään 7805 regulaattorilla vaadittava 5 voltin logiikkajännite ohjaukselle. Tästä syystä moottoreiden ohjausjännite tulee olla aina vähintään 8 volttia, jotta tämä kyseinen kytkentä toimii oikein (5-voltin regulaattori vaatii pari volttia regulointijännitettä suuremman käyttöjännitteen). Tarkka kytkentäkaavio moottorin ohjaimelle löytyy PDF-tiedostona tästä linkistä. Alle olen piirtänyt havainnekuvan moottoriohjaimen ja mikrokontrollerin kytkemisen yhteen, sekä sähkömoottorin suojadiodeineen. Mikrokontrollerilta käytetään vain portteja P1.7 ja P1.6 moottorin ohjaamiseen. Tämän lisäksi maapinnit yhdistetään oikean toiminnan varmistamiseksi.

Koska ohjauspinnit tarvitsevat vain loogisia "1" tai "0" tiloja, niin mikä tahansa pinni voidaan tähän käyttöön valjastaa. Lähdön sallintapinni ENA kytketään kiinteästi 5 voltin ohjausjännitteeseen, jolloin moottorin ohjaus on sallittu koko ajan. Tällöin moottorilla voi halutessaan jarruttaa, mutta sen ei voi antaa pyöriä vapaasti ellei poista moottorin ohjausjännitettä. Moottorille ohjausjännite otetaan +12 voltin jännitelähteestä.

Alla olevassa kuvassa nähdään moottorinohjauslevy kytkettynä launchpadiin. Moottorina toimii Mabuchin RS-545PH harjallinen sähkömoottori, jonka olen joskus vanhasta printteristä purkanut. Koekytkentälevyllä on myös punainen ja vihreä led osoittamassa kumpaan suuntaan moottori pyörii.

Moottorinohjaimelta pystyisi myös mittaamaan, kuinka paljon virtaa moottori ohjaa ja tätä tarkoitusta varten kytkentäkaavioon on laitettu vastukset R1-R4. Kun moottorin läpi kulkee virtaa, niin tämä virta muodostaa jännitteen kyseisten vastuksien yli. Tämä jännite voidaan mitata AD-muuntimella ja tutkia esimerkiksi onko moottori jumissa (stall) vai pyöriikö se vapaasti. Tästä aiheesta lisää kuitenkin joskus myöhemmin, sillä tässä osassa keskitytään vain yksinkertaiseen eteen ja taakse sekä suunnanvaihto toimintoon.

Esimerkki 1: Moottori eteen ja taakse, suunnanvaihto kytkimellä

Seuraavaksi tehdään ohjelma, joka ohjaa moottorin pyörimissuuntaa eteen ja taakse. Kun käyttäjä painaa Launchpadin kytkintä S2 (P1.3), niin moottori pysäytetään ja sen pyörimissuuntaa vaihdetaan. Koodi alla:

#include <msp430g2231.h>
// Ohjelmamuistin koko tavuina (byte) Flash/RAM = 446/12

#define LED_RED                      (BIT0)
#define LED_GREEN                   (BIT6)
#define INIT_LAUNCHPAD_LEDS  (P1DIR |= LED_RED+LED_GREEN)
#define LED_OFF                       (P1OUT &= ~(LED_RED + LED_GREEN))

// Moottorin ohjaukseen liittyviä defineitä
#define FORWARD       1
#define BACKWARD     -1
#define STOP              0

// Moottorin ohjauspinnit
#define MOTOR_CTRL_PIN1   (BIT7)
#define MOTOR_CTRL_PIN2   (BIT6)
#define MOTOR_INIT             (P1DIR |= MOTOR_CTRL_PIN1+MOTOR_CTRL_PIN2)

// Globaalit muuttujat
volatile unsigned int button = 0; // asetetaan keskeytyksessä

// Launchpad funktiot
inline void InitLaunchpad();

// Moottorinohjausfunktiot
inline void InitMotor();
void SetMotorDirection(signed int direction);

void main(void)
{
     signed int motorDirection = STOP;
     WDTCTL = WDTPW + WDTHOLD;    // watchdog pysäytys
     InitLaunchpad();
     InitMotor();
     __enable_interrupt();
     while(1)
     {
         if(button == 1)
          {
               if(motorDirection == STOP)
               {
                    // Jos moottori ei liiku (ensimmäinen käynnistys)
                    // niin asetetaan moottori eteenpäin
                    SetMotorDirection(FORWARD);
                    motorDirection = FORWARD;
               }
               else if(motorDirection == FORWARD)
               {
                    // jos moottori liikkui eteenpäin, pysäytetään se
                    // ja odotetaan hetki ja asetetaan moottori
                    // liikkumaan taaksepäin
                    SetMotorDirection(STOP);
                    while(button++ < 10)
                    {
                         // keinotekoinen viive
                         __delay_cycles(100000);
                    }
                    SetMotorDirection(BACKWARD);
                    motorDirection = BACKWARD;
               }
               else
               {
                    // moottori liikkui taaksepäin, pysäytetään se
                    // ja odotetaan hetki ja asetetaan moottori
                    // liikkumaan eteenpäin
                    SetMotorDirection(STOP);
                    while(button++ < 10)
                    {
                         // keinotekoinen viive
                         __delay_cycles(100000);
                    }
                    SetMotorDirection(FORWARD);
                    motorDirection = FORWARD;
               }
          // nollataan nappi ettei jäädä suorittamaan tätä koko ajan
         button = 0;
          }
     }
}

inline void InitLaunchpad()
{
     INIT_LAUNCHPAD_LEDS; // Ledien alustus
     LED_OFF;  // LED1 ja LED2 pois päältä
     // S2 (P1.3) kytkin tuloksi ylösvetovastuksella
     P1DIR &= ~BIT3;
     P1IE |= BIT3;
     P1IES |= BIT3;
     P1REN |= BIT3;
     P1OUT |= BIT3;
    // alustetaan CPU:n kello 1 Mhz
     BCSCTL1 = CALBC1_1MHZ;
     DCOCTL = CALDCO_1MHZ;
     // BCSCTL3 = XCAP_3; // kiteen alustus on kommentoitu koska sitä ei nyt tarvita
}

inline void InitMotor()
{
     // alustetaan porttipinnit
     MOTOR_INIT;
     // Asetetaan ohjaus nollille
     P1OUT &= ~(MOTOR_CTRL_PIN1+MOTOR_CTRL_PIN2);
}

void SetMotorDirection(signed int direction)
{
     if(direction == FORWARD)
     {
          P1OUT |= MOTOR_CTRL_PIN2;
          P1OUT &= ~MOTOR_CTRL_PIN1;
     }
     else if(direction == BACKWARD)
     {
          P1OUT |= MOTOR_CTRL_PIN1;
          P1OUT &= ~MOTOR_CTRL_PIN2;
     }
     else
     {
          P1OUT &= ~(MOTOR_CTRL_PIN1+MOTOR_CTRL_PIN2);
     }
}

// P1 keskeytysrutiini
#pragma vector = PORT1_VECTOR
__interrupt void Port1_ISR(void)
{
     if(!(P1IN & BIT3))
     {
          /* P1IFG.3 */
          // Launchpadin nappia painettu
          button = 1;
          __delay_cycles(100000);
     }
     // nollataan liput
     P1IFG = 0;
}

Lataa tämän esimerkin CCSv5 projekti tästä.

Ohjelman toiminta

Ohjelmassa suoritetaan ensin pakolliset alustukset, jonka jälkeen siirrytään tarkkailemaan milloin nappia painetaan. Moottorin alustusrutiini on tyypiltään inline void, joka tarkoittaa ettei funktio palauta mitään (void) ja että funktiota ei itse asiassa kutsuta, vaan kääntäjä lisää kyseisen funktion sisältämän koodin siihen kohtaa ohjelmaa, missä sitä kutsuttiin.

'Taikasana' inline ei siis ole tämän kummoisempi käyttää. Inline tyypitystä ei ole pakko käyttää, mutta jos funktiota kutsutaan vain kerran ohjelman ajon aikana, niin sillä säästetään 2 tavua kooditilaa, sillä funktiokutsu vie juuri sen verran. Asiaa voit tutkia ottamalla inline määrityksen pois koodista, kääntämällä ja lataamalla ohjelman uudelleen mikrokontrollerille, jolloin Console -ikkunaan tulee tietoa ohjelman koosta ja käytetyn muistin määrästä. Tämä riittää tästä tällä erää, jatketaanpa toiminnan kuvausta.

Launchpadin napin S2 painallus aiheuttaa keskeytyksen ja keskeytyksessä asetetaan globaali muuttuja ilmaisemaan, että nappia on nyt painettu. Tämän jälkeen pääohjelma suorittaa edellä kuvatun logiikan mukaiset tarkastelut ja suorittaa tarvittavat toimenpiteet. Koodia on kommentoitu, joten tähän lienee turha selittää rivi kerrallaan mitä mikäkin tarkoittaa.

Jos koodia vertaa edellisiin tuotoksiin, niin tällä kertaa koodissa nähdään se, että ainoastaan kommentit on kirjoitettu suomeksi ja muu koodi on englantia. Tämä tulee olemaan jatkossakin näin, johtuen siitä että englannin kieli on minulle luonteva tapa koodata.

Alta löytyy kuvaamani video, missä nähdään kuinka homma sitten käytännössä toimii.

Voit kokeilla muuttaa ohjelman toimintaa esimerkiksi siten, että moottori olisi pysäytettynä pidempään tai että Launchpadin lediä vilkutetaan hetken aikaa, ennen kuin moottori vaihtaa suuntaansa. Teetpä niin tai näin, niin tärkeintä olisi että keksit tästä sovelluksesta jonkun oman version.