ホーム < 電子工作やってみた


Arduino編

その8 距離センサーを使ってみる


 光センサーの値を音にするという訳の分からない仕組みを作り、すっかりセンサーが楽しくなってしまった私。次なるセンサーと選んだのは「距離センサー」。その名の通り距離を測定するセンサーです。世に距離センサーは沢山ありますが、手に入れたのは簡易距離センサーである「HC-SR04」。40kHzという高い周波数の超音波を出して、それが反射して戻って来るまでの時間から距離を計測するセンサーです。まずは、このセンサーを使って実際に距離を測るまでをやってみたいと思います。



@ HC-SR04

2つの突起が特徴的な距離センサー。カタログ(PDF)はこちら。説明書などが無く上の基盤だけが届きました。男気溢れてます(笑)。ちなみにお値段は500円位でした(Amazonで買って送料無料)。使い方がわからないのでWebであれこれ調べて見ると、どうやら次のように使用するようです。

 写真にある4つのピンを拡大してみます:

 左のVccが電源入力で定格は直流5Vだそうです。これはArduinoの電源の電圧そのものなので有りがたい限りです。左がら2番目の「Trig」というのはトリガー(Trigger)です。ここにパルス的に電圧を掛けます。時間は10μ秒以上との事。パシッという感じですね(^-^;。すると2つのスピーカーから40kHzという超音波が非常に短い間で8回放たれます。放出した超音波は対象物に当たりセンサー側に戻ってきます。戻ってきたら、右から2番目の「Echo」というピンにそのかかった時間分電圧が出力されます(HIGH状態)。よって、EchoがHIGHになっている時間と音波が空気中を伝わる速さから、その距離が計算できる。そんな仕組みのようです。

 とりあえず、ArduinoのPowerにある5VピンをVccに繋ぎ、GNDはGNDへ、デジタルピン2番を出力用に設定してTrig、デジタルピン3番を入力用にしてEchoに繋いでみる事にします:



A パルス波時間を取得する「pulseIn関数」

 次は動作を与えるプログラムを考えてみます。
2番ピンに10μ秒以上のトリガーパルスを与える為にdigitalWrite( 2, HIGH )とスイッチONにします。
その後10μ秒以上待ちます。これはdelayMicrosecond関数というμ秒単位でウェイト出来る関数を用いると良いと思います。
待った後digitalWrite( 2, LOW )でトリガーパルスを切ります。この切った瞬間に距離センサーは大変に短い40kHzの超音波を8回放出します。
その間にpluseIn( 3, HIGH )とプログラムを進めます。pulseIn関数は呼ばれた段階から指定のピンを監視し、電圧がHIGHになって再びLOWに戻るまでの時間を測定して返してくれます。正にこのセンサーの為にあるかのような便利関数です(^-^)。いつまでも待ってはくれなくて、デフォルトでは1秒経つと関数が戻ってきます。

  戻り値のパルス時間(μ秒単位)から距離を計算します。まず音は1秒間で空気中をおよそ340m位伝わります。この速度は温度など周りの環境で随分と変わってしまいます。詳しくはWikipedia(音速)で。例えば春先のやや肌寒い15度くらいだと340mですが、夏の暑い30度だと349mと9mも変わってしまいます。より正確に距離を計るには温度をファクターとして入れた方が良いのですが、今は340mで測ってみます。

 超音波が放出して反射して戻って来るまでの時間をtμ秒とすると、1000000μ秒=1秒で340m伝わるのですから、tμ秒だと、340m×t/1000000で往復の距離(m)、その半分で反射した物までの距離が計算できます。もし距離をcm単位にするなら340*t/1000000*100 / 2 = 340 * t / 10000 / 2 = 0.017 * t です。簡単ですね。

 以上を加味したArduino側へ送るプログラムを書くとこんな感じになります:

int interval = 0;
double distance = 0;

void setup() {
    pinMode( 2, OUTPUT );
    pinMode( 3, INPUT );
    Serial.begin( 9600 );
}

void loop() {

    if ( Serial.available() > 0 ) {

        Serial.read();

        // pulse !
        digitalWrite( 2, HIGH );
        delayMicroseconds( 100 );
        digitalWrite( 2, LOW );

        // mesure the interval
        interval = pulseIn( 3, HIGH );

        distance = interval * 0.017; // cm

        Serial.print( interval, DEC );
        Serial.print( "\t" );
        Serial.print( distance, 4 );
        Serial.print( "\n" );
    }
}

シリアルポートから「測定しなさい」という何かをArduino側に送信します。それを受信すると(Serial.available関数)if文の中を実行します。



B 測定してみた

 さて、先程の回路とAのプログラムをArduino基板に仕込み、実際に距離を測定してみました。

 センサーの向こうに適当な段ボールを置いて、Arduino IDEのシリアルモニターからトリガーとなるデータを送信します。すると…

うお!出た!往復で8876μ秒かかり、段ボールまでの距離は150.8920cmと計測されました!

 で、実際距離センサーから段ボールまでの距離はどのくらいなのか?メジャーで計測してみます。…153.4cm。ん?距離センサーの結果は2.5cmくらい短い…。も、もう一度測定してみます:

んーー平均で150.96cm。153.4cmには及びません。

 ここで、室温を計ってみると21.3度、湿度は44%でした。4月下旬ですが今日は温かい日和。で、21.3度の時に音はどのくらいの速さで伝わるのか?これを表す近似式があります。v = 331.5m + T * 0.61。Tは温度です。ここにT=21.3を入れてみると344.49m。先のプログラムではこれを340.0mとしていました。つまり、実際の超音波は設定値よりももっと速く伝わっていたというわけです。

 プログラム中の0.017という値は、340.0m / 20000という計算で出てきます。これを344.49 / 20000 = 0.017225に変更して再度計測してみます:

 あー、やっぱりかなり変わりました。平均で152.79cmで、実測値の153.4cmより6mm程短い結果になっていますが、最初よりもはるかに実測値に近付きました。どうやら温度のファクターは測定にかなりな影響を与えるようです。先程の式は乾燥した空気での近似式で、湿度があると音はさらに速くなるそうなので、その辺りも加味すると実測にさらに近付くかもしれません。ちなみに、湿度も加えた音速の近似式は見当たりませんでした。Wikipedia(音速)にらしい式があるのですが、かなり難しそうな感じです…。

 温度の影響はかなりあるようなので、それなりな精度ではかろうと思ったら温度センサーも一緒にくっつけてあげないといけなさそうです。まぁ、それは追々ですが(^-^;。でも、高々500円のセンサーで、凄く簡単な回路とプログラムを組むだけで結構な精度の距離が出るのは面白いですね。このセンサーを使ってどう遊ぶか、ちょっと考えてみます(^-^)


(2014. 4. 27追記)
C HC-SR04の検査角度

 HC-SR04で色々な場所の距離を測定していて、たまに「あれ?」と思う距離が返される事がありました。1.5m先くらいに狙いを定めているはずが50cm位が返って来るなど。状況から、どうやら対象と思っている物よりも近い壁や床、障害物などに反射した超音波が原因のようです。

上の写真は左にHC_SR04を高さ16.1cmの所に設置し、右側の対象物の距離を測ろうとしている様子です。対象物が正面と上にずらした箇所に一つずつあります。手前の対象物を正面の位置から少しずつ上にずらしていって、どの段階で距離が右端の対象物になるかを検査してみました。結果は次の通り:

 正面からおよそ12.7度分ずらした所で計測値が正面の対象物に移行しました。測定する時は左右のこの範囲に物が入らないようにする必要がありそうです。一方上下は正面から9.7cm下に障害物を置いてテストすると40.3cmで測定値が切り替わりました。角度はおよそ13.5度。測定誤差が結構ありますので、まぁざっくり15度くらいの範囲には何も無いようにするべき何だなと思いました。