PIC AVR 工作室別館 arduinoの館->TopPage->接続くん->ステッピングモーター

ステッピングモーターをPWMでマイクロステップ駆動

ステッピングモーターとマイクロステップ駆動

arduinoのライブラリにはステッピングモーターを扱うものが公開されているので、もともと簡単にステッピングモーターを 扱うことが可能です。が、今回はちょっと違った方法でステッピングモーターを駆動してみようとおもいます。

普通のステッピングモーターの制御方法

ステッピングモーターを駆動するのに一般に用いられるのは、1-1相励磁か2-2相励磁の場合が多いかと 思います。もう少し微妙な角度で制御をする場合は1-2相励磁を用いる場合もあるでしょう。 (これらの励磁方法の詳細はひとまず端折ります)

1-1相励磁


2-2相励磁


これらの励磁方法に共通して言えるのは、モーター内の各コイルにONかOFFの信号を順々に入力するということです。 ONかOFFだけなので、中間的な磁力はありません。1-2相励磁を使っても、1-1や2-2の半分の角度の角度で 制御するのがせいぜいです。

そしてまた、このような制御方法でステッピングモーターを回した場合モーターの分解能(制御可能な最小の角度)単位で コチコチと回転します。丁度、1秒毎にコチコチとステップする時計の秒針と同じです。このコチコチという動作は 「停止」と「回転」を繰り返す動作なので、周期的な振動を発生させます。用途によってはこの振動が問題視されることがあります。

1秒おきに1ステップずつステップ動作を行った時のムービーです。普通はこんな風にコチコチ動いて振動が出ます↓。(クリックで再生します)

マイクロステップ駆動

そこで出てくるのがマイクロステップ駆動という方法です。詳しくは wikipediaなどをご覧頂きたいのですが、要はON、OFFの信号だけでなく、中間的な磁力を作り出すことで 中間の角度を作り出してしまおうというのがマイクロステップ駆動です。

通常、マイクロステップ駆動は流す電流の量をアナログ的に変化させることで行うのですが、流す電流を微妙に制御するのは ちょっと大変そうなので、もう少し手を抜くことを考えてみます。arduinoでアナログ出力といえば内蔵タイマーを使ったPWM によるアナログ出力機能が簡単に利用できます。お手軽なこれを使ってみることにします。

PWMでモーターを制御する応用例といえば、一般にはDCモーターの回転速度制御が多いようですが、 要はこれをステッピングモーターに使ってしまおうというわけです。

以前PICとステッピングモーターを組み合わせて工作したときに、ステッピング動作時の振動が気になって、 何とかできないかなぁといろいろ思い悩んでいたんですが、その際、改善方法として思いつき、いつか実験してみたいなぁと 考えていたのがこのPWMを使ったマイクロステップ駆動というものでした。マイクロステップ駆動って言う呼び方は最近まで 知らなかったんですが、ブログでその辺のことに触れた際、MWさんに教えてもらいました。

実験のゴール

ステッピングモーターの用途といっても色々有るのですが、あまり複雑なことは避けて比較的簡単なところをゴールにしたいと 思います。

上記で時計の秒針の話が出てきたので、この時計の秒針を1秒毎にコチコチ回転からスムーズ回転にしてみるということを ゴールにおいてみます。時計屋さんで見かけるようなスムーズに秒針が動く時計をイメージしてください。

これなら回転方向も1方向だけだし、動いたり止まったりせずずっと動きっぱなしなので、プログラム(スケッチ)が 簡単にできるだろうという目論見です。

PWMとタイマー割り込み

さて、時計の秒針みたいなものを作るというお話になったので、その核心部分の機能を実現する仕組みを考えることにします。 肝になるのは何と言っても正確な時間間隔を得るということと、ステッピングモーターの4つの入力端子に入れる 4つのアナログ信号の作り方でしょう。

arduinoでは、アナログ出力を行うにしても、正確な時間間隔で処理を行うにしても、どちらもタイマー機能を使うことになります。

arduinoにはタイマー機能は3つありますが、今回はあまり精度とか必要ないので、手を抜くためにarduinoの既存機能を そのまま利用する方向で考えます。

タイマー割り込み機能

まず正確な時間間隔で処理を行う機能…タイマー割り込みですが、これは公開されているライブラリMsTimer2を使うことに します。1/1000秒単位で任意の間隔で関数を呼び出すことが出来ます。扱いも超簡単。このタイマー割り込みライブラリは、 timer2を占有します。

アナログ出力機能

次にアナログ出力機能…PWMですが、残ったtimer0とtimer1の両方を使います。各タイマー共に出力ピンは2本ずつ 設けることが出来ます。ピン番号で言うと、digital5、digital6、digital9、digital10の合計4本です。

というわけで、3つのタイマーを使ってアナログ出力とタイマー割り込みを利用して時計の秒針的な機能を実現するという 方針にします。

通常、マイクロステップ動作に使うアナログ値は電圧の大小で制御することが一般的だと思うんですが、 arduinoのアナログ出力はPWMなので出力される電圧は正確に言うとONかOFFにしか制御できません。 でもまぁ、arduinoにしても何にしても、PWMでDCモーターを回している例はたくさんあるわけで、それが ステッピングモーターに置き換わったからといって内部の仕組みはそれほど大きな違いはありませんし (どちらもコイルが巻いてあるだけ)、PWMの周波数もそれほど高くないので、多分そこそこ動いてくれるんではないかと 期待して、先に進めることにします。

処理方法

要は、励磁の波形をどんな形状にしようかな、って言う話です。

通常の励磁の波形

ユニポーラのステッピングモーターなので、所詮は4つのコイルにどんな風に磁気を発生させるかという話に尽きます。 通常の1-1相励磁や2-2相励磁などでは4つのコイルの磁気をON/OFFし、磁気をシフトさせていくことで モーターをコチコチと順にステップさせていくわけです。

このように矩形波を順々に出力するのが通常の1-1相励磁の処理方法。水色のところが磁気が発生しているところ。 左側から右に向かって時間が進んでいくと思ってください。この磁気の中間状態を作り出せばいいわけです。

徐々に磁力がシフトしていく波形

ひとまず、1-1相励磁をベースに考えることにします。あるコイルから次のコイルに磁気が徐々にシフトしていくイメージです。 ある時点で出力している電力の合計が1-1相と同程度となるような波形を考えてみます。こんな感じ。

こんなふうに、ある時刻時点でグラフを縦に切ってみるとその時の水色部分の断面の長さが常に等しいという波形に してみようと思います。こうすると、消費電力の観点では1-1相励磁と一緒。発生するトルクは…ちょっと弱まって いるかもしれません。

この「徐々に出力を上げたり下げたり」するために、arduinoのアナログ出力機能を活用します。具体的には、1/10秒置きに タイマー割り込みを発生させて経過時間を正確にカウントし、その時刻に相当する波形をアナログ出力するという感じです。

回路図

回路図です。縮小表示しているので別窓で開きなおすか、保存してから別のソフトで再表示してください。

図の右側が一般的なユニポーラステッピングモーターです。今回はarduinoとは別電源とし、モーター用電源に9V のスイッチングアダプタを使いました。GNDはarduinoと共用です。

真ん中にあるMP4401はパワーMOSトランジスタを4つ内蔵したモジュールで、フライバックダイオードや 静電気防止用のツェナーダイオードも内蔵しているため、この手のモーター制御にはもってこいの便利な代物です。

FETのゲート端子は300Ωの発振防止抵抗を介してarduinoの出力端子に繋いでいます。抵抗値は適当に決めました。 というかLEDの電流制限抵抗に使っていたモノをそのまま流用しました。一応動いているので良しとしました。 ちなみに、抵抗を繋げずに動かそうとしたら上手く動かなかったので、適当に抵抗を挟んでおく必要があるみたいです。

モータードライブに使っているこのMP4401は既にディスコンなのですが、秋月にはまだ在庫があるのと、 このトランジスタアレイはFETタイプにしてもダーリントンTRタイプにしてもピンコンパチ品がいろいろ有る様なので これを利用することにします。1個200円で安いし…。なお、MP4401の内部回路自体は以下の通りシンプルなので ディスクリートで組んでも大して苦では無いかと思います。以下、MP4401の内部回路(抜粋)です。

ディスクリートで組むなら、秋月ではTND012NM(10個入り…2SKシリーズと同様に使えるFET)が200円で 売られているのでこれを4個使って、あとはフライバック用に整流ダイオードを4個足す方が安上がりかな?

もしくは、ダーリントントランジスタアレイ(FT5754M)が1個200円、2個なら単価150円(ともに秋月価格)なので、 これを使うのもいいかもしれません。MP4401とピンコンパチですし。(ただしダーリントントランジスタアレイを 使う場合はHFEを元に電流制限抵抗の計算が必要…HEFがデカいので適当に数百~1kΩ程度でいいと思いますが)

スケッチと実行結果

スケッチ

まず上記の励磁波形を出力するようなスケッチを書いてみます。半角の不等号は全角文字に置き換えてあるので、 全角に戻してからコンパイルしてください。

#include <MsTimer2.h>


volatile int iCount;


void counting() {
  iCount++;

  if (iCount==960) {
    iCount = 0;
  }
}


void setup() {
  Serial.begin(9600);
  
  pinMode(6, OUTPUT);  //oc0a (PD6) for X
  pinMode(5, OUTPUT);  //oc0b (PD5) for Y
  pinMode(9, OUTPUT);  //oc1a (PB1) for /X
  pinMode(10, OUTPUT);  //oc1b (PB2) for /Y

  iCount = 0;
  
  MsTimer2::set(100, counting); // 100ms period
  MsTimer2::start();
}


void loop() {

  int iReadtimer;
  int iStep_rot;
  int iStep;
  int iVar;
  int iOut_a;
  int iOut_b;
  
  iReadtimer = iCount;  //read timer from counter
  iStep_rot = iReadtimer / 10;  //step count
  
  iStep = iStep_rot % 4;  //step no (0..3)
  iVar = iReadtimer % (iStep_rot * 10);
          //variation in the step (0..9)
  
  iOut_a = 255 * iVar / 9;  //output data A
  iOut_b = 255 - iOut_a;  //output data B
  
  
  switch (iStep) {
  
    case 0:
      analogWrite(6, iOut_b);
      analogWrite(5, iOut_a);
      analogWrite(9, 0);
      analogWrite(10, 0);
      break;
    case 1:
      analogWrite(6, 0);
      analogWrite(5, iOut_b);
      analogWrite(9, iOut_a);
      analogWrite(10, 0);
      break;
    case 2:
      analogWrite(6, 0);
      analogWrite(5, 0);
      analogWrite(9, iOut_b);
      analogWrite(10, iOut_a);
      break;
    case 3:
      analogWrite(6, iOut_a);
      analogWrite(5, 0);
      analogWrite(9, 0);
      analogWrite(10, iOut_b);
    default:
      break;
  }
  
  Serial.print(iStep);
  Serial.print(iOut_b);
  Serial.println(iOut_a);
  
}

実行結果

上記のスケッチを実行した結果のムービーです。左は4つの出力ピンにそれぞれLEDをつないだ場合の動作。 右はモーターに繋いだ場合の動作です。

LEDの方のムービーをご覧頂くとスケッチの意味が一目瞭然ですね。で、実際にモーターに繋いで動かして 見た結果ですが、コチコチ感がなくなったのがお判りいただけるかと思います。

ただ、まだ少しスムーズさには欠けるかなぁ…。モーター本来の1ステップ分(このムービーの場合3.75度)毎に1秒のペース で進めているんですが、この周期で微妙に速くなったり遅くなったりしているようです。当初想定した通りでしたが…。

スケッチのバグというわけではなく、ステッピングモーターの構造上の特性ということだろうと思います。

あとトルク感について。回転軸を指で触って止めようとすると、1-1相励磁よりも極わずかトルクが出ていないような気がします。 1-1相励磁よりも少し弱い力で脱調する感じがします。

少し改良

回転のムラを減らしつつ、トルクももう少し向上させたいと思うので、改良を加えてみたいと思います。

励磁パターンの見直し

励磁パターンで一番トルクが出るものといえば、普通は2-2相励磁なのですが、このパターンをベースにして 徐々に流す電流をシフトしていくことを考えてみます。例えばXとYが両方オンになっている状態から、 Xが減って/Xが増えていくようなパターンを考えてみましょう。

Xと/Xの実態は、共通のコイルに反対向きに巻かれたコイルなので、ここに同時に電流を流すと単に磁力が 打ち消しあわれるだけで、有効な磁力として出力されません。というわけで、これはダメですね。

次に1-2相励磁を考えてみます。

この図の説明はちょっと厄介なんですが、1-2相の励磁パターンを応用して、スムーズに切り替わっていくイメージ を表したものです。上記の1-1相を応用したパターンと見比べて、その差を考えてみてください。

1-2相の応用なので、赤い矢印の部分では1相分だけしか電流が流れていない状態となり、トルクが1-1相と同じ(最低)になります。 それ以外の部分を見比べると、水色部分の面積が増えた分だけ平均トルクが増しています。で、実際に動かしたのがこれ。

当然コチコチ感は無く、先ほどのスムーズステップと比べても滑らかになっているような気がします。(ムービーでは判り難い???)

元々1-2相励磁自体はトルクアップのために使われるのではなく、通常の倍の精度でスムーズにコントロールすることが目的 だと思います。なので平均トルクが少し上がったからといって、決して脱調しにくくなるというわけでは無いような気がしますが、 指で触った感じでは少し脱調しにくくなっているような気がします。

評価

さて、通常の1-1相励磁と比べてどのくらい振動が小さくなっているのかを見てみたいと思います。スケッチを少々 修正し、割り込み間隔を10ミリ秒毎に設定しなおしました。(先ほどの10倍速)

左は普通の1-1相励磁、右はマイクロステップ駆動(1-2相励磁を応用)です。軸に挟んだワニ口クリップの 導線の震え方を眺めてみてください。

1-1相の方は結構ブルンブルンしているのが判るかと思いますが、右側は極めて静かです。1周96ステップのモーター としては極めて振動が小さいのがお判りいただけるのではないでしょうか。

まぁ、低い周波数の振動がなくなったというだけで、高周波(PWMのキャリア=490Hzの振動とか)の振動が新たに 加わっているので、一概に減ったとは言えないのですが。

スケッチ

1-2相を応用したスケッチです。先ほど同様に不等号は全角に変換してあるので、半角に戻して使ってください。(3文字あります)

#include <MsTimer2.h>


volatile int iCount;


void counting() {
  iCount++;

  if (iCount==960) {
    iCount = 0;
  }
}


void setup() {
  Serial.begin(9600);
  
  pinMode(6, OUTPUT);  //oc0a (PD6) for X
  pinMode(5, OUTPUT);  //oc0b (PD5) for Y
  pinMode(9, OUTPUT);  //oc1a (PB1) for /X
  pinMode(10, OUTPUT);  //oc1b (PB2) for /Y

  iCount = 0;
  
  MsTimer2::set(100, counting); // 100ms period
  MsTimer2::start();
}


void loop() {

  int iReadtimer;
  int iStep_rot;
  int iStep;
  int iVar;
  int iOut_a;
  int iOut_b;
  
  iReadtimer = iCount;  //read timer from counter
  iStep_rot = iReadtimer / 10;  //step count
  
  iStep = iStep_rot % 4;  //step no (0..3)
  iVar = iReadtimer % (iStep_rot * 10);
                  //variation in the step (0..9)
  
  if (iVar <= 4) {
    iOut_a = 255;  //output data B
    iOut_b = 255*iVar/5;  //output data A
  }else {
    iOut_a = 255 - ((iVar-5)*255/5);  //output data B
    iOut_b = 255  ;  //output data A
  }
  
  
  switch (iStep) {
  
    case 0:
      analogWrite(6, iOut_a);
      analogWrite(5, iOut_b);
      analogWrite(9, 0);
      analogWrite(10, 0);
      break;
    case 1:
      //analogWrite(6, 0);
      digitalWrite(6,LOW);
      analogWrite(5, iOut_a);
      analogWrite(9, iOut_b);
      analogWrite(10, 0);
      break;
    case 2:
      //analogWrite(6, 0);
      //analogWrite(5, 0);
      digitalWrite(6,LOW);
      digitalWrite(5,LOW);
      analogWrite(9, iOut_a);
      analogWrite(10, iOut_b);
      break;
    case 3:
      analogWrite(6, iOut_b);
      //analogWrite(5, 0);
      digitalWrite(5,LOW);
      analogWrite(9, 0);
      analogWrite(10, iOut_a);
    default:
      break;
  }
  
  Serial.print(iStep);
  Serial.print(iOut_b);
  Serial.println(iOut_a);
  
}

まとめ

PWMを使ったマイクロステップって本当に可能なのか心配でしたが、思った以上に上手く行った気がします。

モーターの仕組み上、2-2相に敵うトルクは出せませんでしたが、大電流が流せるモーターをチョイスすることで そこそこ実用レベルになるのではないかなぁという気がします。

回路的には普通のステッピングモーターと変わりませんし、スケッチもシンプルで済みましたし、 あとは4端子分のPWM出力機能があるマイコンなら応用も簡単に出来るかと思います。

トルクや振動を厳密に計測する環境は無いのでこれ以上の評価は出来ませんが、まぁ、いい感じの結果が出たと思います。

今回のスケッチでは、1ステップ分(3.75度)を時間軸で10等分した感じになっていますが、マイコンのPWMが許す範囲で もう少し細かい制御をしても面白いかもしれません。(角度の精度には寄与しないと思いますが、振動はさらに減らせるかも)