Arduinoで超音波距離センサを使う

Arduino

超音波距離センサ

超音波を用いて距離を求める原理

超音波距離センサとは、超音波のパルスを放出し、対象物で反射して戻ってくるまでの時間を測定することで対象物までの距離を測定するセンサです。

『超音波距離センサ』としてユニット化されているものは、超音波用の送信機(スピーカ)と受信器(マイクロフォン)が近い距離で、同じ方向を指向するように配置されています。

送信機からは短い時間・限られた波数の音波が送信されます。対象物で反射して戻ってきた音波を受信器が検出したとき、超音波パルスが対象物まで往復するのにかかった時間=送信から受信まで(音波の送信開始から受信開始まで、または音波の送信終了から受信終了まで)の時間を測定します。この時間は音波を反射した物体までの距離に比例します。

音速を \(V\) 、超音波パルスが対象物まで往復するのにかかった時間を \(\Delta t\) とすると、対象の物体までの距離 \(L\) は、

\[L=\displaystyle\frac{V\times \Delta t}{2}\]

で表されます。

この原理は、魚群探知機やソナーに利用されています。またレーダーも、超音波ではなく電磁波を使用しますが基本的な原理は同じです。

音速についての補足

空気中での音速 \(V\) は、簡易的な計算では 340 m/s とすることが多いですが、この値は気温により大きく変化します( 340 m/s は気温15℃のときの値です)。
気温(℃) \(T\) に対応した音速 \(V\) をもとめる式は、\(R\) を気体定数、\(M\) を空気の平均分子量、\(\gamma\) を空気の比熱比とすると、以下のようになります。

\[
V=\displaystyle\sqrt\frac{\gamma R\ (T+273.15)}{M}
\]

この式に \(R =8.314\) m2kg s-2K-1mol-1 、\(M =0.02897\) kg/mol、\(\gamma=1.402\) を代入すると、

\begin{align}
V&=\displaystyle\sqrt\frac{\gamma R\ (T+273.15)}{M}\\ \\
&=\sqrt\frac{1.402\times 8.314\times (T+273.15)}{0.02897}\\ \\
&\simeq 20.06\sqrt{T+273.15}
\end{align}

となります。

さらに \(T\) が 0 ℃ 付近(\(|\frac{T}{273.15}|\)が1より充分小さい)ならば、

\begin{align}
20.06\sqrt{T+273.15} &= 20.06\times\sqrt{273.15}\left(1+\displaystyle\frac{T}{273.15}\right)^{\frac{1}{2}}\\ \\
&\simeq 20.06\times\sqrt{273.15}\left(1+\displaystyle\frac{1}{2}\cdot\frac{T}{273.15}\right)\\ \\
&\simeq 331.5+0.61T
\end{align}

と、さらに簡略化できます。一般にはこの式がよく知られています。人間が生活している空間の気温ならば、これで実用上充分な精度の値が得られるでしょう。

気温は比較的簡単に測定可能・安価なセンサが入手可能なので、組み合わせて使用すればより正確な距離測定が可能になるでしょう。

製作&実行

それでは、超音波で距離を測定する装置を製作してみましょう。

使用部品

品名(型番)個数備考
超音波距離センサモジュール
HC-SR04
1
ブレッドボード1小型のものでOK
ジャンパ線
(オス-オス)
4赤×1本、黒×1本、黄×1本、緑×1本
超音波距離センサモジュール HC-SR04

HC-SR04 はホビー用として定番の超音波距離センサモジュールです。秋月電子通商、Amazon などで取り扱われていて入手は比較的容易です。また価格も1個 1000円未満と安価です。

外観

HC-SR04 はコンパクトなモジュールです。写真の基板のサイズは 45 × 20 mm、厚みは送受信素子を入れても 15 mm ほどしかありません。4本の端子(ピン)は間隔がICピッチ(2.54 mm)で、ブレッドボードやユニバーサル基板で使用しやすいです。

仕様

仕様は以下の通りです。

電源電圧3 ~ 5.5 V
動作電流2.2 mA
測定範囲(距離)2 ~ 450 cm
距離分解能0.3 cm
測定範囲(角度)センサ正面より 15° 以内
端子

HC-SR04には4つの端子があります。

端子名役割
VCC電源(+)に接続する
必要なのは 3 ~ 5.5 V / 2.2 mA なので、Arduino の 5 V 端子から供給可
Trig超音波パルス発信のトリガ信号を入力する
TTLレベルなので Arudino のデジタル出力端子に直結可
Echo反射した超音波パルスを受信した時にパルスを出力する
TTLレベルなので Arduino のデジタル入力端子に直結可
GND電源および信号のグラウンドに接続する
Arduino の GND 端子に接続
使用法

超音波で距離を測定するには、超音波パルス生成と反射波の受信を行い、そのう時間を測定する必要がありますが、HC-SR04 ではそのほとんどをモジュール内で行ってくれます。

HC-SR04 での距離測定の手順は以下のようになっています。

1.Trig 端子にパルス(HIGH の時間が 10 μs 以上)を入力する
2.超音波パルス(40 kHz、パルス波 × 8個)が出力される
3.反射波を受信すると、Echo 端子よりパルスが出力される。パルスの幅 \(\Delta t\) は、超音波パルスを出力してから反射波を受信するまでの時間に等しい

となっています。Arduino がすべきなのは、1. で HC-SR04 の Trig 端子へパルスを送信するのと、3. で HC-SR04 の Echo 端子に出力されるパルスの幅を計測することです。

回路

今回の実験に用いる回路はこの図の通りです。
Trig 端子、Echo 端子ともに HIGH = 5 V のデジタル信号なので Arduino の入出力端子に直結可能、
電源も Arduino の 5 V 端子から供給可能、
…というわけで、非常にシンプルな回路です。

Trig には D2 端子(出力に設定)、Echo には D3 端子(入力に設定)を使用しましたが、D2 ~ D13のどれでも、後のプログラムの定数設定を書き換えるだけで変更可です。ただし D0 と D1 は PCに測定結果を送信するシリアル通信の都合上使用できません。

配線図

配線は図のようにしました。HC-SR04 は回路的には Arduino と直結可能なので、メス-オスのジャンパ線を使用すればブレッドボードがなくても接続できますが、今回は HC-SR04 の設置台も兼ねて小型のブレッドボードを使用しました。

実物の写真はこちら。装置の右にあるのは、測定ターゲット用に100円ショップで購入したアニメキャラのアクリルスタンドです。固い素材で表面が平らなものの方が超音波をよく反射しそうなので。

プログラム1(標準の関数のみで作成)

まず、以下のようなプログラムで試してみます。

C++
#define TRIG_PIN 2
#define ECHO_PIN 3

double sonic_speed;

void setup() {
  sonic_speed = 340;
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(TRIG_PIN, LOW);
  delay(200);

  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned int result = pulseIn(ECHO_PIN, HIGH, 200000);

  if(result>0){
    double distance=sonic_speed*result/1000000/2*100;
    Serial.print(distance);
    Serial.println("cm");
  }
}

プログラムの解説

定数設定
C++
#define TRIG_PIN 2
#define ECHO_PIN 3

HC-SR04 の TRIG 端子に接続した Arduino のデジタル出力端子と、HC-SR04 の ECHO 端子に接続した Arduino のデジタル入力端子の番号を、それぞれ定数 TRIG_PINECHO_PIN として定義しています。

何らかの理由で Arduino の仕様端子を変更した場合は、この定数定義をそれにあわせて下さい。

初期設定
C++
double sonic_speed;

void setup() {
  sonic_speed = 340;
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  Serial.begin(9600);
}

変数 sonic_speed は音速(単位は m/s )を表しています。この例では setup() 関数の中で 340 m/s を設定していますが、気温に合わせて変更可能です。

2つの pinMode() 関数では、定数 TRIG_PIN の表す端子を出力に、定数 ECHO_PIN の表す端子を入力に設定しています。

結果をPCのシリアルモニタで表示するため、Serial.begin(9600)でシリアル通信の設定を行っています。

前回のパルス送出と間隔をあける
C++
void loop() {
  digitalWrite(TRIG_PIN, LOW);
  delay(200);

データシートよるとパルス送出の間隔を 200 ms 以上あける必要があるようなので、念のため Trig を LOW にしてから 200 ms 待っています。

パルス送信
C++
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

超音波パルスを送信するためには、HC-SR04 の TRIG 端子に幅 10 μs 以上のパルスを入力する必要があります。そのため、

Arduino の TRIG_PIN を HIGH にする
delayMicroseconds(10) で 10 μs だけ待つ
Arduino の TRIG_PIN を LOW にする

という手順でパルスを Arduino から HC-SR04 へ送出しています。

ECHOのパルスを受信
C++
  unsigned int result = pulseIn(ECHO_PIN, HIGH, 200000);

HC-SR04 の ECHO 端子からは、超音波パルスの送信から反射波の受信までの時間と等しいパルス幅が出力されます。Arduino でパルス幅を計測するには pulseIn() 関数が最適です。書式は以下の通りです。

unsigned long pulseIn(pin, value, timeout)

引数:

名前意味
pinintパルスを入力するピン番号
valueintパルスの種類( HIGH または LOW を指定)
timeoutunsigned longタイムアウトまでの時間を μs で指定する
省略可で、デフォルト値は1,000,000 μs(=1秒)

返却値:

意味
unsigned longパルスの幅を μs 単位で返す
タイムアウトした場合は 0 となる

pulseIn() 関数は、引数 pin で指定された入力ピンにパルスが入力される(引数 value が HIGH ならLOW → HIGH → LOW、引数 value が LOW なら HIGH → LOW → HIGH となる)のを待ち、パルスの幅をμs単位で測定して返します。ただし timeout で指定した時間以内にパルスが入力されなかった場合には0を返します。

SR-HC04 では、HIGH のパルスなので、pin に ECHO_PIN、value に HIGH を指定しています。timeout はデフォルト値でもいいのですが、ここでは超音波パルスの送出最小間隔である2 00,000 μs = 200 ms を指定しています。

距離の計算と表示
C++
  if(result>0){
    double distance=sonic_speed*result/1000000/2*100;
    Serial.print(distance);
    Serial.println("cm");
  }

最初の if(result>0) は、測定結果が有効である(タイムアウトしていない)ことの確認です。

result には超音波パルスが対象物まで往復するのにかかった時間が μs 単位で格納されているので、距離を計算して変数 distance に格納します。

先に解説したように、音速を \(V\) 、超音波パルスが対象物まで往復するのにかかった時間が \(\delta t\) とすると、距離 \(L\) は

\[L=\frac{V\cdot\Delta t}{2}\]

で表されます。
このプログラムでは音速(m/s)は sonic_speed 、往復にかかった時間(μs)は result なので、距離(cm)を distance とすると、

\[\bf{distance}=\frac{\bf{sonic\_speed}\times(\bf{result}\times 10^{-6})}{2}\times 10^2 \]

となります。result を μs から s に換算するために \(\times 10^{-6}\) 、計算結果を m から cm に換算するために \(\times 10^2\) としています。

実際のプログラムでは『\(\times 10^{-6}\) 』の部分を『/1000000』と記述します。

C++
    double distance=sonic_speed*result/1000000/2*100;

計算結果は Serial.print() 関数、Serial.println() 関数でPCに送信し、シリアルモニタで表示できるようになっています。

プログラム1の実行

それでは実行してみましょう。

このプログラムでは温度補正をしていませんが、そこそこの精度は出ているようです。

プログラム2(ライブラリを使用する)

HC-SR04 を用いて距離測定を行う場合、専用のライブラリを利用するとプログラムを簡潔に記述することができます。Arduino 公式サイトにある HC-SR04 用のライブラリを使用してみましょう。

ライブラリのインストール

ダウンロード

下記のリンク先からライブラリをダウンロードして下さい。

HCSR04 ultrasonic sensor - Arduino Reference
The Arduino programming language Reference, organized into Functions, Variable and Constant, and Structure keywords.
インストール

メニューバーの『スケッチ』→『ライブラリをインクルード』→『ZIP型式のライブラリをインクルード』を順に選択し、『追加したいライブラリの入ったファイルを選択』ダイアログで

HCSR04_ultrasonic_sensor-○.○.○.zip』(○.○.○にはバージョンの数字が入る)を選択して『開く』をクリック

プログラム

ライブラリを使用した場合のプログラムは以下の通りです。loop()関数内の処理が大幅に減りました。

C++
#include <HCSR04.h>
#define TRIG_PIN 2
#define ECHO_PIN 3

HCSR04 sr04(TRIG_PIN, ECHO_PIN);

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.print(sr04.dist());
  Serial.println("cm");
  delay(200);
}

プログラムの解説

ライブライの読み込みとSR04オブジェクトの生成
C++
#include <HCSR04.h>
#define TRIG_PIN 2
#define ECHO_PIN 3

HCSR04 sr04(TRIG_PIN, ECHO_PIN);

HC-SR04 制御用の関数群は、HCSR04.h 内で定義されています。

定数定義はプログラム1と同じです。

HC-SR04 制御用の関数群は、HCSR04 クラスのメンバ関数として定義されていますので、まず HCSR04 クラスのオブジェクトを生成します。コンストラクタの書式は以下の通りです。

HCSR04::HCSR04(int echoPin, int triggerPin)

引数:

引数意味
echoPinintHC-SR04 の Echo 端子に接続する Arduino の入力端子番号
triggerPinintHC-SR04 の Trig 端子に接続する Arduino の出力端子番号

初期設定
C++
void setup() {
  Serial.begin(9600);
}

setup()関数の内容は、距離の測定とは直接関係のない処理です。PCのシリアルモニタで結果を表示するため、シリアル通信の初期化をしています。

距離の測定と表示
C++
void loop() {
  Serial.print(sr04.dist());
  Serial.println("cm");
  delay(200);
}

距離の測定には、HCSR04::dist() 関数を使用します。書式は以下の通りです。

float HCSR04::dist(void)

引数:

なし

返却値:

意味
float距離を cm 単位で返す

この関数一つだけで、超音波パルスの送信トリガから距離の計算まですべてやってくれるので非常に簡単です。ただし、音速が 340 m/s に固定されていて、温度補正ができません。

計算結果は Serial.print() 関数、Serial.println() 関数で PC に送信し、シリアルモニタで表示できるようになっています。

最後の delay(200) は、プログラム1と同じく超音波パルスの送信間隔を 200 ms 空けるためのものです。

プログラム2の実行

プログラム2はプログラム1とまったく同じ動作をするので、動画は省略します。プログラム1と違って音速の調節ができないので(自分でライブラリのソースに手を入れれば可能ですが…)、極端に寒い部屋や暑い部屋だと誤差が大きくなると思われます。

ライブラリのインストールディレクトリ内、HCSR04.cppの最後の方、HCSR04::dist(int n) 関数の定義内に

C++
	float d = pulseIn(this->echo[n], HIGH, 23529.4); // max sensor dist ~4m
	interrupts();
	return d / 58.8235;

という部分があります(バージョンによっては違うかもしれません)。

このうち、23529.4 という数値は『超音波が4mを往復するのにかかる時間(μs)』、つまり

\[\frac{4\times 2}{340} \times 10^6=23529.4117\cdots\]

です。

また、58.8235 という数値は『超音波が 1μs に進む距離(cm)の逆数の2倍』、つまり

\[\displaystyle\frac{1}{340\times 10^{-6}\times 100}\times2=58.823529\cdots\]

です(なぜ除算としてコードを書いたんだろう…)。このようにこのライブラリでは音速が 340 m/s で固定になっているのですが、ここをいじれば温度補正や最大測定距離の延長ができます(センサ自体が4m以上を保証していませんが)。

まとめ

  • 超音波を使って距離を測ることができる
  • 簡単なプログラムで利用できる超音波距離センサモジュールがある

今回は超音波距離測定モジュールHC-SR04を使用して距離を測定する実験を行いました。非常に簡単な回路とプログラムで距離の計測が可能で、モジュール自体も安価で入手しやすいので、模型の制御などにいろいろ応用できそうです。

コメント

タイトルとURLをコピーしました