概要

超音波センサーHC-SR04等を用いてArduinoで距離計測を行いたいときに、Trigピンで超音波を発生させた後にEchoピンで、超音波が反射されてくるまでの時間を計測することで距離を計測できます。その際、pulseInという関数で時間を計測できます。

https://rb-station.com/blogs/article/hc-sr04-arduino

サンプルコードの詳細は上記の記事をご確認ください。

 digitalWrite(TRIG, LOW); 
delayMicroseconds(2);
digitalWrite( TRIG, HIGH );
delayMicroseconds( 10 );
digitalWrite( TRIG, LOW );
duration = pulseIn( ECHO, HIGH ); // 往復にかかった時間が返却される[マイクロ秒]

上記はサンプルコードの抜粋ですが、pulseInで超音波が反射して戻ってくるまでの時間を計測します。しかし、pulseInを実行している間、他の処理は止まってしまいます。

数マイクロ秒なので、気にならないことも多いですが、例えば同時にステッピングモータを動作させているときはモータ動作がpulseInをしている間止まってしまって滑らかでなくなってしまいます。

そこで、pulseInは使わず、他の処理は止めることなく超音波センサでの距離計測ができる方法を紹介します。

関数を自作する

https://arduino.stackexchange.com/questions/28816/how-can-i-replace-pulsein-with-interrupts

上記の記事内容がほぼ答えになっていますが、pulseInのように入力があるのを待っているのではなく、定期的なループごとに入力があるかを毎回チェックする形で対応できます。

/*
 * Non-blocking pulseIn(): returns the pulse length in microseconds
 * when the falling edge is detected. Otherwise returns 0.
 */
unsigned long read_pulse(int pin)
{
    static unsigned long rising_time;  // time of the rising edge
    static int last_state;             // previous pin state
    int state = digitalRead(pin);      // current pin state
    unsigned long pulse_length = 0;    // default return value

    // On rising edge: record current time.
    if (last_state == LOW && state == HIGH) {
        rising_time = micros();
    }

    // On falling edge: report pulse length.
    if (last_state == HIGH && state == LOW) {
        unsigned long falling_time = micros();
        pulse_length = falling_time - rising_time;
    }

    last_state = state;
    return pulse_length;
}

このread_pulse関数を用いると、入力があったタイミングでそれまでの時間を返却してくれるので、ループ処理で毎回呼び出して、0より大きい数値が返されたときに距離計算をします。

例えば、下記のような形で、他の処理をブロックせずに常に距離計測を行う実装ができます。Trigからは400msごとに超音波を発生させ、Echoからの入力値読み取りは100μsごとに行う形にしています。

long nextTrigPulse = 0;
long currentMicros = 0;

void loop() { int duration = read_pulse(ECHO); if(duration > 0){ int distance = (duration / 2) * speedOfSound * 100 / 1000000; Serial.print("Distance:"); Serial.print(distance); Serial.println(" cm"); }
currentMicros = micros();
// 一定時間ごとに超音波センサのTrigをコールする
if(currentMicros > nextTrigPulse){
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite( TRIG, LOW );
nextTrigPulse = currentMicros + 400000;
} // 何かしらの定期処理 delayMicroseconds(100); }

注意点

この方法のデメリットはread_pulseを呼び出す間隔が長くなってしまうと、精度が下がってしまいます。

例えば、1msごとにread_pulseを呼び出すとすると、1ms以内に超音波が反射してきても、次の1msまで気づくことはできません。音速は340.29m/sなので、1msで34cm進みますので、往復34cm = 約17cmの誤差が生じることになります。

正確性の方が重要な場合はpulseIn関数を使うべきかと思われます。

Related Posts

DCモータ制御で配線が複雑になる場合はDCモータコントローラシールドMD04を使うと便利!
DCモータ制御で配線が複雑になる場合はDCモータコントローラシールドMD04を使うと便利!
概要 DCモータを動作させる際は、モータコントローラを用いると便利ですが、それでも複数のモータを動作させようとしたときには配線がごちゃごちゃになってしまいがちです。そのような時は、シールドタイプのDCモータコントローラを使えば、マイコ...
Read More
Arduino Nano互換ボードで書き込めない時はプロセッサを確認
Arduino Nano互換ボードで書き込めない時はプロセッサを確認
概要 安価なArduino Nano互換ボードを使っていると、Arduino IDEで書き込みができずにエラーになってしまうことがあります。本記事ではその対処法について解説をします。 対処法 書き込み時にエラーが出る原因はさまざまな...
Read More
ブレッドボードに5V/3.3Vの電源をMB102で供給する
ブレッドボードに5V/3.3Vの電源をMB102で供給する
概要 ブレッドボードには電源を流すことに主に用いられる、両脇の赤と青のラインがあります。Arduinoなどのマイコンから5Vや3.3Vの電源を供給することもできますが、色々な用途に使っていると電流が足りなくなってしまったりするので、別...
Read More