部品屋根性(35) DCモータ(ブラシ付)、DRV8835でPWM駆動

Joseph Halfmoon

前回はマイクロサーボモータでしたが、今回はブラシ付DCモータを「回し」てみます。小型のものはプラモデルなんかで御馴染みさんのあれです。電源繋げばとりあえず回りますが、いざ制御しようとすると知識不足を痛感。今回はTIのモータドライバIC DRV8835を使わせていただきます。

※「部品屋根性」投稿順Indexはこちら

今回でモータ、3種類目となります。ステッパモータ(ステッピングモータ)については

などと同じモータで4回も投稿させていただいとります。マイクロサーボモータについては、前回

部品屋根性(34) マイクロサーボSG-90、UnoとNucleoでソース共通

にて取り上げさせていただいています。その割に「上っ面を撫でているだけ感」が強いのは、負荷もかけず開ループで回った回ったと喜んでいるだけ、であるためでしょう。大体、「サーボモータ」などというと厳めしいですが、肝心の「サーボ」の部分はモータ内蔵の制御回路に隠されていて外からはPWM波形を与えているだけなのですから。それにモータを回転させるべき電力についても別端子です。マイコン側はただPWM波形を垂れ流しているだけ。

ステッパモータの方は制御と回転させる動力の端子が一体化しているので、ただマイコンの波形をそのまま与えればよいというわけではなく、電流を流し出し、また、モータ(インダクタンス)の発生する「高電圧」で壊れないための回路が必要でした。上記では、TIのULN2003(ただし使用したKuman K4キット付属のボードでは東芝?)をドライバICとして使用いたしました。ULN2003は、出力クランプ・ダイオード付きのダーリントン・トランジスタ・アレイ、バイポーラICですな。データシートを読むと元々はリレー・ドライバ用のもの。

今回ブラシ付きのDCモータの駆動に使うICは、やはりTIのDRV8835、これは元々モータドライバ用のICであります。ステッパモータの駆動にも、DCモータの駆動にも使える

Dual Low-Voltage H-Bridge IC

であります。WSON12という2mm x 3mmの小さいパッケージのICなのでそのままではブレッドボードに刺し込むことができず。例によって秋月電子通商殿より「ブレークアウト」ボードを購入。

秋月電子通商DRV8835使用ステッピング&DCモータドライバモジュール

比較のため、秋月製のDRV8835のブレークアウトボード(左)と、お楽しみの中華部品キットKuman K4付属のULN2003ボード(右)の写真を掲げておきます。(ULN2003ボードの中ほどの白いコネクタはステッパモータ28BYJ-48を直結できるもの)

DRV8835_ULN2003Aさて、ステッパモータやマイクロサーボモータは制御波形を与えないと回らないですが、ぶっちゃけブラシ付DCモータは電源さえ与えれば勝手に回ってしまいます。子供の頃の工作にも使えた所以。マイコン制御で考えれば「最低線」以下のような制御が必要でしょう。

  • 回転方向制御(時計まわり、反時計まわり)
  • 回転速度制御
  • 停止(ブレーキ)

ここで行いますのは、「駆動用のHブリッジ回路をPWM信号で制御する」という方法であります。マイコンで生成したPWM信号をHブリッジ回路用のICに入力してモータへの電力供給を制御する、という形です。当然、立派な説明を繰り広げられておられるウエブサイト多数、素人の私が付け加えることもありません。各種ある中で、分かり易いな、勉強になるなと思いましたのは(個人の感想です)、以下のローム社のサイトであります。

Rohm社 Tech Web Motor 基礎編

すみません、今回実験に使っておりますドライバIC、DRV8835はTexas Instruments製です。(手に入ったらRohm社のICでもやってみたいと思います。)上のサイトはブラシ付きのDCモータの駆動の基礎から、PWM方式についても分かり易く解説されています。ローム社なので勿論日本語。特にPWM方式での「回生」の方法とか私のような素人には勉強になること疑いなし、であります。

実験に使いました回路はこんな感じ。PWM波形発生のマイコンボードはArduino業界標準機 Uno(互換機だけれども)であります。モータはこれまた秋月電子通商殿で手に入る「お手頃」でもっとも小さいクラスのもの。1.5Vから3V品。モータを駆動する電力は電池(単3二本の電池ボックスを別件micro:bitが使っているので、空いていた単4日本の電池ボックス使用。モータなのに。。。)また、回転速度とBRAKEは、アナログ端子で可変抵抗の位置をマイコンで読み取って行う(これは秋月電子通商殿のAE-DRV8835ボードのサンプルコードがそうなっていたので、そのままパクらせていただきました。)可変抵抗ついてますが、モータとは直接の関係はありません。回路をまとめるとこんな感じ。(下記図面、2021/2/25更新。当初図面に欠落あったため)

DCM_DRV8835_SCHfix現物はこんな感じ。かなりジャンパ線やらワニ口クリップやらで配線汚い。

DRV8835_DUTマイコン側のPWM信号の生成プログラムは、秋月殿のドライバモジュールのサンプルプログラムを元に、シリアルポートに動作状態を報告するように改造したもの。サンプルプログラム自体は上記の秋月殿のページからダウンロードできるようになっているので掲げませぬ。当方で勝手改造、追加した関数のみ末尾に掲げました。なお、秋月殿のサンプルのソースを読んでいて気付いたこと一つ。細かい話なんだけれどもコメントに”Break”と書かれているところあるのですが、” Brake”では。。。

なおソースを読む時に大事だと思う点は、

    • DRV8835には2つのモードがありMODE端子で切り替えできる
    • 今回はIN-INモード(MODE=LOW)を使用

IN-INモードの場合、対になる2本の入力信号が10で正転、01で反転、そして11になるとBrake(制動)、00でCoast(滑走)だと思います。一方の入力がPWM信号のHIGHで他方がLOWの状態では駆動電流が流れ、2本ともLOWになるPWMのLOW期間はCoast(ドライバはHiZになる)となり、2本ともHIGHにするとドライバは2本ともLOW-LOW(回っているモータから流れ込んでくる電力を消費)となる筈。

ビルドしてArduino Uno(互換機だけれども)にオブジェクトを書きこみます。シリアルモニタで「BRAKE」位置になるようにボリュームを調整しておき、モータ電源を与えます。ボリュームを左右に回すとCCW(カウンタークロックワイズ、反時計まわり)CW(時計回り)に回ります。なお、Arduino UnoのanalogWrite()関数は490Hz周期、1周期は8ビットの解像度です。手元の装置では、PWMのハイ期間の幅は1桁だと回らず10超える辺りから回転を始める感じで数字が大きくなるとブーンと元気よく音を立てて回ります。今のところ回転数など観察できないのが残念です。しかし、

大きな数字で元気よく回っているときに急激にボリュームを操作するとArduino Uno(互換機だけれども)が異常、シリアルモニタ出力が止まります。モータは回りつづけているのでタイマのPWM出力は動いているみたい。ソフトがハングしている?う~む、原因究明、対策しないと。。。(2021/2/26追記:原因究明はともかく、対策した結果はこちら

部品屋根性(34) マイクロサーボSG-90、UnoとNucleoでソース共通 へ戻る

部品屋根性(36) 006P安定化電源、ついでに電池ボックス

int pwmValue;
int stat;

void readVR() {
  int vr_value = analogRead(VRPIN);
  if ((vr_value == 0) || (vr_value == 1023)) {
    stat = MTR_COAST;
  }
  else if ((vr_value >= 500) && (vr_value <= 523)) {
    stat = MTR_BRAKE;
  }
  else if (vr_value < 500) {
    stat = MTR_CCW;
    pwmValue = map(vr_value, 1,499, 255, 1);
  } 
  else if (vr_value > 523) {
    stat = MTR_CW;
    pwmValue = map(vr_value, 524,1022, 1, 255);
  } 
}

void monitorMode() {
  switch(stat) {
    case MTR_BRAKE:
      Serial.println(F("BRAKE"));
      break;
    case MTR_CCW:
      Serial.print(F("CCW: "));
      Serial.println(pwmValue);
      break;
    case MTR_CW:
      Serial.print(F("CW:  "));
      Serial.println(pwmValue);
      break;
    case MTR_COAST:
      Serial.println(F("COAST"));
      break;
    defalut:
      Serial.println(F("UNEXPECTED mode"));
      break;
  }
}