モータのPWM制御

 ここでは、小型のDCモータの回転制御を行います。小型DCモータは玩具にもよく利用されています。多くの小型DCモーターは電池1、または、2本(1.5-3.0V)で電流 0.3-0.5A 程度です。

  1. DCモーターの原理・構造

     多くの小型DCモーターは外側に永久磁石があり、内部(回転子)に巻かれたコイルの発生する電磁力で回転します。「整流子」に「ブラシ」を接触させて回転するコイルに電流を供給しています。磁場の中で電流を流すと、磁場と電流の作る面と垂直方向に力が働き、回転力を生み出します。


      モーターの基本構造(図は http://www.jeea.or.jp/より)
     
    2分割の「整流子」ではコイルが垂直方向の時、電源短絡の恐れがありますから、実際には下のように、整流子を3分割し、3極構造とします。また、通常鉄心にコイルを巻きますから、回転力も鉄心に磁化による、吸引・反撥と考えます。ブラシより下側の回転子の鉄心はN極、上側の鉄心はS極に磁化され、外側の永久磁石との間で回転力を発生します。
     
       実際の構造 (図は http://www.semicon.toshiba.co.jp/ より)

  2. DCモータの特性(RE140)

     DCモータは負荷がない場合(軸に何も接続されていない場合)、電流は少ないですが非常に高回転になり、軸やブラシを傷めます。回転数が上がると、コイルの発電作用による、逆起電圧のため、電源からの電流が下がり平衡点で釣り合います。負荷が重すぎる場合回転数が落ち、逆起電圧が減少するため高い電流が流れます。電流が適正値を越えると、発熱して故障の原因になります。
     DCモータの回転力は通常トルク(gF/cm)であらわします。標準の回転数のときのトルクを適正負荷といいます。DCモータの回転数は高いので、通常、ギヤ(歯車)で回転数を落として使用します。回転数*トルク が仕事量になります。回転数を 1/100 にすると、トルクは100倍になります。
     ここで使用する小型DCモーター(マブチ RE140)は電源1.5Vのとき、適正回転数は約6000(rpm)、トルクは 5gcm 程度です(回転中心から5cmの場所で5gに相当する力)。
  3. DCモータのPWN制御

     モータに流れる電流は電圧が一定であれば、回転数で定まり外部から制御することは困難です。電圧をかえると、直線的にトルクが増し回転数も増加しますが、流れる電流が多い場合電圧の制御は簡単ではありません。
     そこで、PWM: Pulse Width Modulation 制御がよく利用されます。 通電幅を0にすればオフ、繰り返し期間と通電期間を同じにすれば、完全オン状態になります。PWM制御は少々荒っぽい手法なので、制御可能な対象は限定されますが モータの電力制御にはよく利用されます。
     小型 DCモーターの電流は数百mAになりますから、UNO の出力信号端子では直接制御できません。(UNO の出力端子の許容電流は20mA程度です)。DCモーター専用のICもありますが、ここでは、スイッチング用の MOS トランジスタ:2SK2925 を利用します。トランジスタはデジタル回路の基礎となる素子で、G、D、S の3種の端子があります。G に HIGHレベルの電圧をかけると 、D と S の間が導通し、D から S 方向に電流が流れます(「電源・電力制御」の章参照)。
     下図は DC モーターの制御回路です。D に DC モータが接続されています(モーターの他端はモーター用の電源(電池+側)を接続します)。UNO から D11 端子に HIGH 電圧がかかると、D-S 間が導通しますからモーターに電流が流れます。
        
          DCモータ制御回路            実際の配線

  4. 保護用ダイオード

     DCモーターの制御回路で、モーターの左に LED(発光ダイオード)に似た記号があります。これはトランジスタを保護するために接続した「ダイオード」とよばれる素子です。DCモーターは内部の巻き線により磁力を発生し、モーターを回転させます。 巻き線(コイルとも呼びます)の電流を切断すると、モーターの巻き線に蓄えられた磁気エネルギーが電流の流れを継続させようとして、瞬間的に大きな電圧が発生します。この電圧を吸収するため、モータにダイオードを接続します。
     ダイオードは半導体で、特定の方向にだけ電流を流します。図はスイッチング用のダイオードで、左から右(青色マーク側)に電流を流します。トランジスタがオフになると、モーターのコイル周辺の磁界は上から下方向に電流を流そうとします。トランジスタがオフのままでは、電流は行き場を失い高い電圧を発生し、トランジスタに損傷を与える恐れがあります。この電流を、モーター横のダイオードが吸収し、高い電圧の発生を抑えます。トランジスターがオンのときは、モーターの上側が + のためダイオードには電流は流れません。
     

     ダイオード

  5. ソース

     UNOの D6 のアナログ端子(mtr)に、analogWrite(mtr,pwr) をします。pwr が出力をする度合いで、255 のときが 100% の出力になります。 ここでは、50から180までを5秒単位に増加し、200をこえたら50以下になるまで減少させます(DCモーターが1.5V標準ですから、電流が過大になります)。
    //DCモータPWM制御
    //トランジスタ利用
    int ipwr = 50,pwr;  
    int inc = 5;   //変化量 
    int mtr=11;   //PWM端子
    
    void setup()  {
      //
      Serial.begin(9600);
      pinMode(mtr, OUTPUT);//
      pwr=ipwr;
    }
    
    void loop()  {
      Serial.println(pwr);
      analogWrite(mtr, pwr);   
      pwr = pwr + inc;
      //50以下、180以上で折り返す
      if (pwr < ipwr || pwr >= 180) {
        inc = -inc ;
      }    
      //   
      delay(500);  
    }

  6. Hブリッジと制御モジュール

     DCモータの回転方向の制御には、「Hブリッジ」と呼ばれる回路構造が利用されます。下図で左上の Tr1 と右下の Tr4 をオンにすれば、M(モータ)には左から右に電流が流れます。逆に、右上の Tr3 と左下の Tr2 をオンにすれば、逆方向に電流が流れます。



     「Hブリッジ」の回路を直接構成するのは手間なので、I2C で接続する小形DCモーター用制御モジュール(DRV8830)を利用します(I2C の詳細は 「I2C接続」の章を参照してください)。モジュールの電圧は最大6V、 最大電流は1A 程度で、Hブリッジによる反転機能を内蔵しています。
     SCL.SDA が I2C の端子で、A1、A0 の接続で I2C のアドレスを設定できます(今回無接続)。VCC、GND は制御回路用の電源で、UNOの5VとGND に接続します。モーターは 左の +、- の間に接続します。DCモーターの最大電圧は 3V ですが、制御モジュールで電力を調整できます。FAULT の接続は不要です。

      DRV8830モジュール

    電流が300mAを超える場合、UNO の電源は USB ではなく、ACアダプタから供給する必要があります。

  7. DCモーター反転制御プログラム

     以下は Wire.h を利用した、サンプルプログラムです。制御は 0 レレジスタの 0,1 ビットで回転方向、2-7 ビットで速度を指定します。プログラムでは dir で方向、val で駆動力(PWM)を指定し、これを 以下のように合成します。
    iv=(val<<2) + dir;
     << は左シフト演算で、残った2ビットに dir を加えて合成します。これを Wire.write(iv) でモジュールに送ります。他の Wire の命令は、「I2C接続方式」の章を参照してください。

    //I2Cアドレス 0x64 (ジャンパーない(open)とき)
    //内部レジスタ0にコマンド書き込み
    //先頭6bitが電圧、下位2bitが制御
    // V=0x6:0.48V 0x10:1.29V 0x20:2.57V
    // 0x30:3.86V 0x3F 5.0V
    //下位2bit 00:standby 01:時計回り 10:反時計回り 11;Brake
    
    //接続
    //ard.SCL>mc.SCL>2kpull up
    //ard.SDA>mc.SDA>2k pull up
    //ard.VCC>mc.VCC(5V)
    //ard.GND>mc.GND
    
    //Arduino SCL:A5: SDA:A4:
    
    #include <Wire.h>
    int address = 0x64;
    int val=0,iv,inc;
    int dir=1;
    
    void setup () {
      Wire.begin();
      Serial.begin(9600);
      Serial.println("start");
      val=4;
      inc=2;
    }
    
    void loop(){
      val=val+inc;
      if(val<4) {
        inc=-inc;
        dir++;
        if(dir==3) dir=1;
      }
    
      if(val>0x20) {//RE140の時0x20
        inc=-inc;
      }
      //
      Serial.print(val);
      iv=(val<<2) + dir; 
      Serial.print(",");
      Serial.println(iv,HEX);
    
      Wire.beginTransmission(address);
      Wire.write(0x0);
      Wire.write(iv);//速度と方向を指定
      Wire.endTransmission();
      delay(1000);
    
    }

  8. フォトインタラプタ

     モーターの軸に穴付きのスリット板を取り付け、フォトインタラプタで光の通る時間間隔を調べます。
    フォトインタラプタ(TLP1602)は発光部と受光部を持ち、その間でスリット板を回転させて、光の通過を検出するデバイスです。左側から赤外LEDで赤外光光を出します(目には見えません)。受け側にはフォトトランジスタで、光を受光すると、上下のCとE間が導通し、UNO の D11 端子の電圧が HIGH に上がります。。
       
       インタラプタ-         裏からの端子

     上の端子は 裏から見た図で、1ピンは LED のアノード、2ピンがカソード側になります。3ピンは受光部の電源端子(+) で 5ピンが GND端子で UNO の 5V, GNDに接続します。4 ピンが出力端子で UNOの D11端子に接続します。3ピンと4ピンの間に、1kオーム に抵抗をつけます。発光側はUNOの5Vから 330オームの抵抗を通して1ピンに接続、2ピンはUNOのGNDに接続します。

         インタラプタ接続回路

     下図が全体図で、右下に UNO と DCモーターのモジュールが、左上に 小型のバイスでモータ-をクリップしています。右が、回転検出部です。モーター軸に円盤を取り付け、円盤にはフォトインタラプタの通過用の穴を開けておきます。
     
        回転時間検出                       通過検出部

  9. 通過時間計測

     フォトインタラプタを利用して、回転時間を測定します。時間は短いので、メモリーに一度記録し、100回の計測が終了したら表示します。停止後計測を開始すれば、回転が速くなるようすを確認できます。
     setup() の set_motorSpeed(18,1); でモーターへの速度を設定します。loop() の先頭で、インタラプタの立ち下がりを検出し、現在の時刻 ct と 前の時刻との差 diff を求め、配列に記憶します。
     あらかじめ、配列に入れておくのは、送信時間が回転時間より遅くなるときの対策もありますが,立ち上がりの経過を残すのが狙いです。
    //起動時の回転時間の測定
    #include <Wire.h>
    #define mx 100
    
    int motor = 0x64;
    int sltt=9;
    
    long ct,pt;
    int cs,ps;
    int cst,pst,diff;
    long slt[mx];
    int dft[mx];
    int cnt,i;
    int first;
    
    void setup () {
      Wire.begin();
      Serial.begin(9600);
      Serial.println("start");
      delay(3000);
    //
     set_motorSpeed(18,1);  
      pt=millis();
      ps=HIGH;
      pst=0;
      cnt=0;
      first=1;
    }
    
    void loop(){
      
      cs=digitalRead(sltt);
      if(cs==LOW && ps==HIGH){
        ct=millis();
        diff=ct-pt;
        if(cnt<mx){
          slt[cnt]=ct;
          dft[cnt]=diff;
          cnt++;
        }
       else {
          for(i=0;i<mx;i++){
            Serial.print(i);
            Serial.print(",");         
            Serial.print(slt[i]);
            Serial.print(",");
            Serial.println(dft[i]);
          }
          set_motorSpeed(0,1);    
        }
        pt=ct;
        //pst=cst;
      }
      ps=cs;
    }
    
    void set_motorSpeed(int val,int dir){
      Wire.beginTransmission(motor);
      Wire.write(0x0);
      Wire.write((val<<2)+dir);
      Wire.endTransmission();
      }
     起動以後、次第に回転周期(3番目の数値)が短くなります。
    //速度指定 18
    2,3096,49
    3,3125,29
    4,3148,23
    5,3169,21
    6,3187,18
    7,3204,17
    8,3220,16
    9,3234,14
    10,3249,15
    11,3262,13
    12,3275,13
    13,3289,14
    14,3301,12
    15,3313,12
    16,3324,11
    17,3337,13
    18,3348,11
    19,3359,11
    20,3371,12
    21,3381,10

  10. 発展

     
    1. 回転速度や走行距離を知るにはどうしますか?

       細かいスリットのついた円板を車軸に取り付け、スリットの通過回数を数えます。
    2. モーターを回すとシステムが停止することがありますが

       多分、モーター駆動で発生するノイズ(雑音)のためと思われます。モーター制御の場合、ブレッドボードでの配線は適当でありません。GND の配線の抵抗を下げる、モーター系の電源の配線と制御系の配線はできる限り分離するなどの配慮が必要です。モーターの電源とケースの間に 0.1μF 程度のコンデンサを取り付けることを有効です。
    3. ギヤ付きのモータでよいものがありませんか?

       小型のものでは Tamiya の「ミニモータ標準ギヤボックス」があります。少し強力なものでは Tamiya のギヤヘッドとギヤヘッド用モーター(380/540)があります。