Arduino で モーターの回転数を取得する

Arduino で モーターの回転数を取得する

今回は、オリエンタルモーターの M540-401 とスピードコントローラーがセットになった、 US540-401 の回転数をArduinoで取得して、LCDに表示する例を紹介します。

そもそも何故回転数が知りたいのか

現在、写真のような実験的な設備を作っているところです。
なんの設備かは、ちょっと秘密ですが、手前から8個のモーターが独立して設置されています。
これにそれぞれスピードコントローラーが付いているのですが、少しケチって安いスピコンセットにしてしまったため、
ツマミで回転数をコントロールするのですが、回転数が表示されないタイプのものになっています。


しかし、この設備ある程度回転数をそれぞれ同じにする必要があり、しかたないのでArduinoで回転数を表示するということにしました。

どのArduinoにするか?

モーターが8個あるので Arduino Uno ではポート数が足りません。ですので、Arduino Mega2560 を採用することにしました。
UNO用のLCDシールドは通信のピンアサインの違いからそのまま利用できません。この対応については、別の投稿に書きましたのでそちらを参照してください。

モーターの出力


スピコンの裏を見ると、「SPEED OUT」と書かれた端子があります。
どんな信号が出ているのか、テスターを当ててみてみました。
すると、3.3V あたりで針がとまっています。ツマミで回転数を落としていくと、
テスターの針が少し下がってはまた3.3Vというのを繰り返すようになったため、

出力は3.3V のパルス

と断定。

電圧パルスの取得方法は?

ArduinoのGPIO のデジタルピンの入力は簡単に言えばスイッチのON/OFF で、対象のピンとGNDが結線したらON という感じでありますので、無電圧接点にする必要があります。一方でモーターからの出力は3.3V のパルスということで、両者の間にリレーを挟む必要があります。

リレーの選定

リレーの選定条件は、3.3Vで開閉すること、開閉の回数が非常に多くなるので寿命が長いこととなります。
そうなると、ソリッドステートリレーということになります。ソリッドステートリレーは、内部の光センサーでON/OFF しますので、メカニカルな電磁石のリレーと違って、非常に寿命が長いです。

今回は、Amazon で 8チャンネルのソリッドステートリレーを購入しました。


結線はこんな感じ
モーターからのパルス出力を写真下の端子台に結線すればOK。
左から8箇所にパルスの +(プラス) 側を結線。
GNDは、8個の – (マイナス)側を1つにまとめて結線。

Arduino の 30~37 に信号をいれました。

制御盤への設置

制御盤のカバーにLCDの窓を切り抜いて、ネジで固定。

パルスの取得プログラム

対象となるピンのON/OFFの回数を一定時間カウントすることで、単位時間あたりのパルス数を計算します。
別の投稿でも言及したGPIOの値取得の高速化を行えば、ある程度のスピードまではArduinoでも信号の取りこぼしなく
正確に取得できると思います。

下記の例では、読みやすいように少し冗長に記述してあります。

void setup(void) {
  //パルス取得用ピンをプルアップに設定
  for (int i=0;i<8;i++) {
    pinMode(pin[i], INPUT_PULLUP);    
  }
}

void loop(void) {
  int val;

  for (int k=0;k<8;k++) {
    cnt[k]=0;
    onoff[k]=0;
  }

  //それぞれのポートのパルスをカウント
  startTime = micros();
  // ポートをダイレクトに読むようにする (処理3サイクルかな?) Read部分は14倍高速になる (全体としては3.5倍程度)
  // ちなみに Mega2560 のピンアサインは、https://www.arduino.cc/en/Hacking/PinMapping2560 参照
  // 今回利用のPin30~37は、PinC の8bit にアサインされている。

  for (long i=0;i<10000;i++){
    for (long j=0;j<8;j++) {
      val = PINC & _BV(7-j);
      if (val==0 && onoff[j]==0) {
        onoff[j]=1;
      } 
      //pin30
      if (val==B10000000 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin31
      if (val==B01000000 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin32
      if (val==B00100000 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }
      else
      //pin33
      if (val==B00010000 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin34
      if (val==B00001000 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin35
      if (val==B00000100 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin36
      if (val==B00000010 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0;
      }  
      else
      //pin37
      if (val==B00000001 && onoff[j]==1) {
        cnt[j]++;
        onoff[j]=0; 
      }  
    }
  }

  endTime = micros();

  for (int r=0;r<8;r++) {
    rpm[r] = (1000000/(endTime-startTime)*cnt[r]*60)/12.686; //11.743は計測値のMAXから割り出した
  }
  for (int r=0;r<8;r++) {
    rpm[r] = (1000000/(endTime-startTime)*cnt[r]*60)/12.686; //12.686は計測値のMAXから割り出した
  }
}

今回は、モーター + ギアヘッド ということもあり、1パルスあたりの回転角を計算するのがちょっと面倒だったので、
回転をMAXにしたときのパルス数とモーターの仕様書の最大rpm から12.686 という定数をだして利用しています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です