前回はフォトリフレクタを扱い、その性質を利用してプログラムを作成してみました。今回は、フォトリフレクタと同じ距離を測るセンサとして利用される超音波センサを取り上げてみたいと思います。フォトリフレクタは数センチの至近距離を計測するのに比べ、今回利用する超音波センサでは大体2cm〜4mまで測ることができます。
目次
今回の電子工作レシピ
完成までの時間目安:90分
必要なパーツ
- Arduino(アルディーノ)本体(Arduino Uno R3)http://www.switch-science.com/catalog/789/
- ブレッドボード http://www.switch-science.com/catalog/313/
- 超音波距離センサモジュール (HC-SR04 https://www.switch-science.com/catalog/1606/)
- 温度センサ(LM61CIZ http://akizukidenshi.com/catalog/g/gI-11160/)
- 3桁7セグメントLED (ROHM LB-303MA https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4K5Z)
- 抵抗220Ω
超音波センサとは?

写真1 超音波センサ
超音波センサとはいったいどのようなものでしょうか?今回利用する超音波距離センサモジュールHC-SR04では、40kHzの周波数をモジュールに2つ取り付けられているうちの片方の超音波スピーカーから出力し、その反射された音をもう片方の超音波マイクで受信する仕組みになっています。超音波を出力してから物体に反射して、受信するまでの時間を計測することで距離を計測することができます。
具体的な距離の計測方法は、超音波は「音」なので出力してから受信するまでの時間に音速を掛けることで距離を求めることができます。音の空気中の速度は公式「331.5 + 0.6 t (m/sec) tは摂氏温度」で求めることができます。
超音波センサを使ってみる
さっそく超音波センサを使ってみます。前回のフォトリフレクタ等の電子回路部品と違い、今回はモジュールとして必要な回路が全て超音波センサモジュールに組み込まれているので、Arduino(アルディーノ)とモジュールをそのまま接続することができます。

写真2 超音波センサの接続端子
超音波センサは下記の端子を持っています。
- Vcc – 電源入力
- Trig – トリガー 超音波出力用の信号を送信
- Echo – エコー 超音波入力用の信号を受信
- GND – グランド
手軽にArduino(アルディーノ)と接続する場合は、下記の回路のように接続します。

図1 超音波センサモジュールとArduino(アルディーノ)の接続

写真3 超音波センサモジュールのテスト回路
実際にプログラムを作成していきます。この超音波センサモジュールの使い方をサイトで確認してみるとトリガ端子(Trig)を10μsec(マイクロ秒)HIGHで出力すると、40kHzのパルスが8回出力されるそうです。それをエコー端子(Echo)で取得すればよいということですが、実際にプログラムは下記となります。
※今回は、音速の計測に温度は考慮せずに音速=340m/秒で計算します。
//******************************************************************** //*超音波センサを使って距離を表示するプログラム //******************************************************************** //******************************************************************** //*超音波センサを使って距離を表示するプログラム //******************************************************************** #define echoPin 2 // Echo Pin #define trigPin 3 // Trigger Pin double Duration = 0; //受信した間隔 double Distance = 0; //距離 void setup() { Serial.begin( 9600 ); pinMode( echoPin, INPUT ); pinMode( trigPin, OUTPUT ); } void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite( trigPin, HIGH ); //超音波を出力 delayMicroseconds( 10 ); // digitalWrite( trigPin, LOW ); Duration = pulseIn( echoPin, HIGH ); //センサからの入力 if (Duration > 0) { Duration = Duration/2; //往復距離を半分にする Distance = Duration*340*100/1000000; // 音速を340m/sに設定 Serial.print("Distance:"); Serial.print(Distance); Serial.println(" cm"); } delay(500); }
赤色で示した部分が今回超音波センサモジュールを利用する肝となる部分です。
始めに下記3行で超音波を10マイクロ秒だけ出力します。
digitalWrite( 2, HIGH ); //超音波を出力
delayMicroseconds( 10 ); //
digitalWrite( 2, LOW );
そうすると仕様に書いてある通り8回パルスが出力されるので、そのパルスを受信する為に、次のpulseInという関数で発信された超音波のパルスをキャッチします。
Duration = pulseIn( 3, HIGH ); //センサからの入力
pulseIn関数はHIGHにした瞬間から時間の計測を始め、指定したピンに入力されるパルスがLOW=オフになるまでの時間を計測して返します。
実際にプログラムを動かしたら、シリアルモニターで確認しながらセンサの前に手をおいて前や後ろに動かすと数値の変化が確認できます(図2)。

図2 シリアルモニターで入力値を確認
もっと正確に超音波センサで距離を計測してみる
上記の例では音速を340m/秒で計算していますが、音速は温度の影響を受けやすいため、もう少し正確に超音波センサで距離を測ってみたいと思います。
※本格的に計測する場合は、気圧や湿度等も考慮する必要があります。式等はWikipedia(音速)を参照のこと

図3 温度センサを加えた回路

写真4 温度センサを加えた場合
//******************************************************************************* //*超音波センサと温度センサを使って距離を表示するプログラム //******************************************************************************* double Duration = 0; //受信した間隔 double Distance = 0; //距離 void setup() { Serial.begin( 9600 ); pinMode( 2, INPUT ); pinMode( 3, OUTPUT ); pinMode( 4, OUTPUT ); pinMode( 5, INPUT ); } void loop() { int ans , temp , tv ; //温度計測用の変数 ans = analogRead(0) ; //アナログ0番ピンからセンサ値を読込む tv = map(ans,0,1023,0,5000) ; //センサ値を電圧に変換する temp = map(tv,300,1600,-30,100) ; //電圧から温度に変換する(LM61は-30度から100度まで計測) Serial.print("temp:"); Serial.print(temp); //温度を表示 Serial.print("c"); digitalWrite( 2, HIGH ); //超音波を出力 delayMicroseconds( 10 ); // digitalWrite( 2, LOW ); Duration = pulseIn( 3, HIGH,5000 ); if (Duration > 0) { Distance = Duration/2; float sspeed = 331.5+0.6*temp; Serial.print("\tspeed:"); Serial.print(sspeed); Serial.print("m/sec"); Distance = Distance*sspeed*100/1000000; // Serial.print("\tDistance:"); Serial.print(Distance); Serial.print("cm"); } Serial.println(""); delay(500); }

図4 温度センサを加えた回路での計測結果

写真5 定規を使って距離を計測
実験環境では温度が21度だったので、音速は331.5+0.6×21=344.1m/秒になりました。実際に先ほどの音速340m/秒と比べた場合、差が出ていますね。写真5は実際に定規を置いて計測した結果になります。設置した物体の角度や形状による音の反射などが理由で若干のぶれは出ますが、ほぼ定規で示した距離と同じ値を示しています。
簡易距離計として実装してみる
超音波センサの扱い方がわかってきたところで、簡易距離計として実装をしてみたいと思います。第8回で説明した7セグLEDを使って、超音波センサで取得した距離を7セグLEDで確認できるようにします。今回は3桁表示が可能な7セグLED RPR-220(ローム)を利用してみます。
ROHM 3桁LED数字表示器 – LB-303MAのデータシートはこちら

写真6 簡易距離計の実装
//***************************************** //* 簡易距離計プログラム //***************************************** double Duration = 0; //受信した間隔 double Distance = 0; //距離 void setup() { Serial.begin( 9600 ); //超音波センサー用 pinMode( 2, INPUT ); pinMode( 3, OUTPUT ); //7セグLED用 pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); pinMode(13,OUTPUT); } //LEDレイアウトを定義 boolean Num_Array[10][7]={ {1,1,1,1,1,1,0}, //0 {0,1,1,0,0,0,0}, //1 {1,1,0,1,1,0,1}, //2 {1,1,1,1,0,0,1}, //3 {0,1,1,0,0,1,1}, //4 {1,0,1,1,0,1,1}, //5 {1,0,1,1,1,1,1}, //6 {1,1,1,0,0,1,0}, //7 {1,1,1,1,1,1,1}, //8 {1,1,1,1,0,1,1} //9 }; //LED表示関数を定義 void NumPrint(int Number){ Number = Number - 48; Serial.println(Number); for (int w=0; w<=6; w++){ digitalWrite(w+4,-Num_Array[Number][w]); } } //全てのLEDを非表示にする void off7SegLED(){ digitalWrite(4,LOW); digitalWrite(5,LOW); digitalWrite(6,LOW); digitalWrite(7,LOW); digitalWrite(8,LOW); digitalWrite(9,LOW); digitalWrite(10,LOW); } void on7SegLED(){ digitalWrite(11,HIGH); digitalWrite(12,HIGH); digitalWrite(13,HIGH); } void view7SegLED(int n){ String str = String(n); //2桁の場合 0を埋める if(100 > n){ str = "0"+str; } //1桁の場合 00を埋める if(10 > n){ str = "00"+str; } on7SegLED(); digitalWrite(12,LOW); NumPrint(str.charAt(0)); delay(20); on7SegLED(); digitalWrite(13,LOW); NumPrint(int(str.charAt(1))); delay(20); on7SegLED(); digitalWrite(11,LOW); NumPrint(int(str.charAt(2))); delay(20); on7SegLED(); } void loop() { int ans , temp , tv ; //温度計測用の変数 ans = analogRead(0) ; //アナログ0番ピンからセンサー値を読込む tv = map(ans,0,1023,0,5000) ; //センサー値を電圧に変換する temp = map(tv,300,1600,-30,100) ; //電圧から温度に変換する(LM61は-30度から100度まで計測) Serial.print("temp:"); Serial.print(temp); //温度を表示 Serial.print("c"); Distance = 0; digitalWrite( 2, HIGH ); //超音波を出力 delayMicroseconds( 10 ); // digitalWrite( 2, LOW ); analogWrite(9,0); Duration = pulseIn( 3, HIGH,5000 ); if (Duration > 0) { Distance = Duration/2; float sspeed = 331.5+0.6*temp; Serial.print("\tspeed:"); Serial.print(sspeed); Serial.print("m/sec"); Distance = Distance*sspeed*100/1000000; // Serial.print("\tDistance:"); Serial.print(Distance); Serial.print("cm"); int val = 1023 - Distance*50; analogWrite(9,val); } //ミリ表示で7セグLEDに表示 view7SegLED(Distance*10); Serial.println(""); // delay(500); }
赤文字で記した部分のview7SegLED()関数に距離(ミリ単位)を渡すことで、7セグLEDに距離を表示することができます。
View7SegLED()関数の内部では、delay(20)ごとに各桁数の表示・非表示を切り替えてそれぞれの桁の数字を表示しています。
超音波センサで検出できる物体について
超音波センサは音なので、音を吸収する物体については正確に検出することができません。
図5では布を超音波センサの前に置いた時の結果になります。センサの値が入力できたりできていなかったりとうまく取得できていないことがわかります。
実際にこのセンサを利用する場合は、音を反射する物体(プラスチックや木、ガラス、金属等)に対して利用することをお勧めします。

写真7 布をおいて距離を測ってみる

図5 布を超音波センサの前に置いた結果
まとめ
今回は超音波センサモジュールを利用して距離を計測してみました。このセンサモジュールは予め距離を測る為の回路が組み込まれているので、手軽に利用することができます。このセンサモジュールは単純に距離を測る他、物体が目の前にあるかないかなどの判断をするためロボットの目の役割として利用されています。
このような利用方法以外にもアイデアを練ることで他の活用方法が見つかるかもしれませんので、ぜひいろいろと試行錯誤をしてみてください。