2019年6月29日土曜日

ESP32で回転計を作ってみた。

最近モータをいじったりしていると回転計が欲しくなってしまったので、反射型の光センサが安く売っていたのでESP32で回転計を作ってみた。
ドローンやっていた頃からあったほうが便利かなぁと思っていたんだけどそこまで必要性を感じていなかったので結局買ってなかった…

今回はライントレースとかに使われている反射式の光センサをESP32に入力して回転数を計算させてみた。光センサモジュール自体にはコンパレータが内蔵されている(D0出力)のでモータに白とか黒とか反射率が異なるテープを張ってコンパレータの可変抵抗を調整して一回転に一回HIGHが出るように調整する。

ソフトの方はESP32のArduino Coreを使用してGPIO割り込みで回転数計算を行ってみた。光センサモジュールのデジタル出力をESP32のGPIOに入力して、割り込み時の時間を使って回転数を計算する方式にしてみた。パルスをカウントするより応答性高くて高精度なんじゃないかなと。

#define PLS 22 //入力Pin設定

#define aveNum 20
#define filtNum 5
unsigned long lastPulse = 0;
uint16_t aveRPM[aveNum];
uint8_t aveCnt = 0;
uint8_t aveDone = 0;

void IRAM_ATTR pulse() {
  unsigned long currTime = micros();
  static unsigned long fixedTime;
  for (int i = 0; i <= filtNum; i++) {
    delayMicroseconds(10);
    if (digitalRead(PLS) != HIGH)
    {
      return;
    }
  }
  lastPulse = fixedTime;
  fixedTime = currTime;

  float rawRPM = 60000000.00 / (fixedTime - lastPulse);
  aveRPM[aveCnt] = (uint16_t)(rawRPM + 0.5);
  aveCnt++;
  if (aveCnt > aveNum) {
    aveCnt = 0;
    aveDone = 1;
  }
}

uint16_t getRPM() {
  if (lastPulse + 2000000 <= micros())  {
    aveCnt = 0;
    for (int i = 0; i < aveNum; i++) {
      aveRPM[i] = 0;
    }
    aveDone = 0;
    return 0;
  } else {
    float average = 0;
    switch (aveDone) {
      case 0:
        for (int i = 0; i < aveCnt; i++) {
          average += aveRPM[i];
        }
        average = average / (float)aveCnt;
        break;
      case 1:
        for (int i = 0; i < aveNum; i++) {
          average += aveRPM[i];
        }
        average = average / (float)aveNum;
        break;
    }
    return (uint16_t)(average + 0.5);
  }
}

void setup() {
  pinMode(PLS, INPUT);
  attachInterrupt(PLS, pulse, RISING);//入力ピン割り込み設定
  Serial.begin(115200);
}

void loop() {
  static unsigned long lastRun = 0;
  if (lastRun + 200 <= millis())//200msごとにRPMをシリアルコンソールに表示
  {
    lastRun = millis();//次回実行のために値更新
    Serial.println(getRPM());
  }
}

ちょっとしたノイズが入っても回転数が乱れるのでノイズ対策として割り込みの中でノイズ対策として何回か入力Pinの状態を確認するようにしてみた。割り込みの中でdelayMicroseconds使ってるけど一応動いてるからよし…
これでだいぶノイズが少なくなった。センサとか測定対象に合わせて確認回数(filtNum)とかdelayMicrosecondsを変更してみるともっと安定するかも。あんまりdelayを大きくすると割り込み処理が終わらなくなってESP32がリセットしてしまう。

あとは回転数の移動平均を取るようにしたので回転数を読みやすくなった。センサが悪いのかモータが悪いのかわからないけど結構バラバラ動いて見にくかったので。

とりあえずこれでArduinoのシリアルコンソールとかシリアルプロッタで回転数が見れるようになったので気軽にモータの回転数が測れる。LCDとかつけてスタンドアロンにしても便利かも。

センサも今回は光学式を使ったけど、ホールセンサとかエンコーダとかパルスが発生できれば何でも良さそう。低速回転なら1回転に多数のパルスが出るエンコーダとかのほうが精度良く測れるかも。

0 件のコメント:

コメントを投稿