製品レビュー|電子機器6:超音波距離センサー(HC-SR04)
1.概要
購入した製品の使い方および感想用記事です。
今回は「超音波距離センサー HC-SR04(300円/個(税込))」をレビューしました。
1-1.製品の仕様
超音波距離センサー HC-SR04は超音波(音速)の反射時間を利用して非接触で測距するモジュールです。外部からトリガパルスを入力すると超音波パルス(8波)が送信され、出力された反射時間信号をマイコンで計算することによって距離を測ることができます。
データシートが全部中国語のため分かりにくいですが、できる範囲で仕様を抽出しました。
1-1-1.基本仕様
基本仕様は下記参照。
電源電圧:3~5.5V
仕様よりRaspberry Piの3.3V電源でも動作可
測定距離:0.02~4.5m
電流量:2.2~3mA(平均2.2mA)
周波数:40kHz
インターフェイス:GPIO・I2C・UART
HC-SR04にあるTrigとEchoピンでGPIO/I2C/UARTを選べる??
動作温度min.:-10~70℃
1-1-2.内部動作
今回はGPIO方式を使用します。わかる範囲で数式を書きました。
$$
距離[m]=パルス幅時間(脉宽时间)[s]\times\frac{音速[m/s]}{2}
$$
$$
温度補正の音速[m/s] = 331.45 + 0.61\times t(環境温度)[℃] \\
(0-40℃での誤差は7%前後)
$$
2.製品原理
超音波センサに関する原理を紹介します。
2-1.音速の温度依存性
音速(音の速度)には下記式の温度依存性があり、温度が高くなるほど早くなる。
$$
音速=331.5+0.6\times 摂氏温度[℃] (@1atm)
$$
音は空気そのものが移動しているわけではなく、空気の振動が近くの空気を振動させることにより伝わっていく。つまり音速とは振動が伝わる速さである。
導出は省略しますが、結論として(ピストンの中にある)空気はばねと同じような弾性的性質を示す[1]。
[1] 音速について考えてみよう! 金沢工業大学 中村晃
$$
\begin{aligned}
F &=(P-P_0)S'
\\&=\Delta PS'
\\&=\frac{P_0\gamma \Delta d}{\Delta x}S'
\end{aligned}
$$
ピストンの変位量:$${\Delta d}$$、ピストンを押す力:$${F}$$
ピストンが連結したチューブを仮定すると、空気が局部的に圧縮,膨張することにより空気の振動である音は伝わっていくと考えることが出来る。
2-2.超音波センサ
2-2-1.超音波とは
「超音波」とは音波の一種であり、20kHz以上の耳に聞こえない音のことを言います。
超音波の発生/検出方法として、圧電セラミック使用する方法があります。
2-2-2.超音波センサの概念
超音波式センサとは、超音波を使用して距離を測定するセンサです。センサヘッドから超音波を発信し、対象物から反射してくる超音波を再度センサヘッドで受信します。超音波式センサは、発信から受信までの「時間」を計測することで対象物までの距離を測定しています。
超音波を用いれば周波数帯によって気体、液体(水中用)、固体、あらゆる媒体を伝わることができますが、伝搬速度は物質の音響インピーダンスによって異なります。
距離を求める計算式は下記の通りです。超音波は対象物に反射して移動(往復距離)するため、対象物までの(片道)距離を計算するために2で割る必要があります。
$$
距離L= \frac{音速C \times 時間t}{2}
$$
2-2-3.物体検出
HC-SR0には送信センサ(Trig)と受信センサ(Echo)があり、送信センサからの超音波が反射して受信側が検知することで物体の有無を検知できます。
3.部材購入
3-1.購入品
部品は本体のみ購入しました。
3-2.準備必須品
その他必需品は下記の通りです。
マイコン/シングルボード(Raspberry Pi/Pico)
ブレッドボード
ジャンピングワイヤー
4.環境構築
4-1.マイコン準備
センサを制御するためのシングルボードやマイコンの準備を行います。
Raspberry PiやPicoの準備は下記記事参照のこと
Raspberry PiにGPIOを制御するためのライブラリが無い場合は”RPi.GPIO”を事前にインストールしておきます。
Picoの場合はMicropythonを使用できるようにしておきます。
[Terminal]
pip install rpi.gpio
4-2.ライブラリ
今回は組み込み関数と標準ライブラリで対応できるため、追加の環境構築は不要です。
5.使用前の準備
5-1.はんだ付け
本製品の既にピンがつけられているため、はんだ付けは不要です。
5-2.部品の組付け
部品の組付けはジャンパー線を使用して下記の通り繋ぎました。
HC-SR04|VCC▶Pico|36pin(3.3V)
HC-SR04|GND▶Pico|38pin(GND)
HC-SR04|Trig▶Pico|GP14
HC-SR04|Echo▶Pico|GP15
5-3.詳細仕様の確認
追加で確認する仕様はありません。
6.MicroPythonスクリプト(Pico)
6-1.任意:デバイス接続の確認
今回はシリアル通信は使用しないため、配線が正しくつながっているか確認するだけとなります。
[Terminal]
-
6-2.コードの設計思想
設計思想は下記の通りです。
Trig端子をHighにして超音波を発生後、EchoがHighになるまでの時間を計測し、この時間を計測
Echoピンの値(0/1)を読み取り、0▶1になるまでの時間を計測
下図より(PWM信号みたいに)Trigに10μs間電圧をかけると40kHzで信号を出力してくれる。
単位を計測時間[μs=$${10^{-6}}$$]と距離[cm=$${10^{-2}}$$]にするため$${10^{-4}}$$で換算
Micropythonのutimeを利用
音速は温度センサなどで数値補正できるように別関数で作成
動作確認用でverbose引数を追加し、動きを確認
6-3.スクリプト実行
結果は下記の通りであり、問題なく動作しました。
数値としてはそこそこの精度(仕様書では±2%)。人が近づいてきた くらいの値としては利用できそう。
送信センサから対象物までの角度がずれるとたまに変な値になる。
[IN]
from machine import Pin, time_pulse_us
import utime
#GPIOピンの設定
No_Pin_Trigger = 14
No_Pin_Echo = 15
Pin_trig = Pin(No_Pin_Trigger, Pin.OUT) #トリガーピン
Pin_echo = Pin(No_Pin_Echo, Pin.IN) #エコーピン
Pin_trig.value(0) #トリガーピンをLOWにしておく
utime.sleep(1)
print(f'PINの初期状態: Trig={Pin_trig.value()}, Echo={Pin_echo.value()}', end='\n\n')
#音速の計算(T:周囲温度[℃])
def calc_sonic_speed(T:float=25.0):
return 331.45 + 0.61 * T
def calc_distance(speed_sonic:float, verbose=False):
#トリガーパルスの送信
Pin_trig.value(1) #トリガーピンをHIGHにしてパルスを送信
utime.sleep_us(10) #10μs▶40kHzのパルスを送信
Pin_trig.value(0) #トリガーピンをLOWに戻す
#受信機のOFF→ON時間を計測
while Pin_echo.value() == 0:
sigoff = utime.ticks_us() #エコー信号の立ち下がり時刻
while Pin_echo.value() == 1:
sigon = utime.ticks_us() #エコー信号の立ち上がり時刻
dist = (sigon - sigoff) * speed_sonic / 2 / 10000 #距離[m]
if verbose:
print(f'sigon={sigon}, sigoff={sigoff}')
print(f'time={sigon-sigoff}us')
return dist
while True:
#音速の計算
speed_sonic = calc_sonic_speed(T=25.0) #音速[m/s]
dist = calc_distance(speed_sonic, True) #計測した距離[cm]
print(f'Distance={dist:.1f}cm')
utime.sleep(1)
[OUT]
PINの初期状態: Trig=0, Echo=0
sigon=164064535, sigoff=164064031
time=504us
Distance=8.7cm
sigon=165068495, sigoff=165068254
time=241us
Distance=4.2cm
sigon=166072330, sigoff=166072091
time=239us
Distance=4.1cm
sigon=167076053, sigoff=167075856
time=197us
7.Pythonスクリプト(Raspberry Pi)
参考までにRaspberry Piでも実行しました。配線は前述と同等に配線しました。こちらも同様に計測できました。
HC-SR04|VCC▶ラズパイ|1pin(3.3V)
HC-SR04|GND▶ラズパイ|6pin(GND)
HC-SR04|Trig▶ラズパイ|GPIO27
HC-SR04|Echo▶ラズパイ|GPIO17
[IN]
import RPi.GPIO as GPIO
import time
# GPIOピンの設定
TRIG_PIN = 27
ECHO_PIN = 17
GPIO.setmode(GPIO.BCM) # GPIO番号で指定
GPIO.setup(TRIG_PIN, GPIO.OUT)
GPIO.setup(ECHO_PIN, GPIO.IN)
GPIO.output(TRIG_PIN, False) # トリガーピンをLOWにしておく
time.sleep(1) # 1秒待つ
# 音速の計算(T:周囲温度[℃])
def calc_sonic_speed(T=25.0):
return 331.45 + 0.61 * T
# 距離計算
def calc_distance(speed_sonic, verbose=False):
# トリガーパルスの送信
GPIO.output(TRIG_PIN, True) # トリガーピンをHIGHにしてパルスを送信
time.sleep(0.00001) # 10μs
GPIO.output(TRIG_PIN, False) # トリガーピンをLOWに戻す
# エコーパルスの時間計測
while GPIO.input(ECHO_PIN) == 0:
pulse_start = time.time()
while GPIO.input(ECHO_PIN) == 1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * speed_sonic * 100 / 2 # 距離[m]をcmに変換
if verbose:
print(f'Pulse duration: {pulse_duration*1000000:.1f}μs')
print(f'Distance: {distance:.1f}cm')
return distance
try:
while True:
speed_sonic = calc_sonic_speed(T=25.0) # 音速[m/s]
distance = calc_distance(speed_sonic, verbose=False) # 距離計測
print(f'Distance: {distance:.1f} cm')
time.sleep(1) # 1秒待つ
except KeyboardInterrupt:
print("Measurement stopped by User")
GPIO.cleanup() # GPIOをクリーンアップ
[OUT]
Distance: 5.7 cm
Distance: 5.7 cm
Distance: 6.6 cm
Distance: 7.2 cm
Distance: 9.6 cm
Distance: 50.9 cm
Distance: 38.5 cm
Distance: 52.9 cm
Distance: 16.3 cm
Distance: 17.9 cm
8.所感
簡単な所感は下記の通り
通信が無いため理解は非常に分かりやすい
精度はそこそこのためホビーや簡易センサには適用できそう
どこかで似たようなもの見たことあると思ったらレゴのMINDSTORMだった。しかもいつの間にか生産終了してたのもびっくり。
参考資料
あとがき
このくらいすんなりいくと楽でうれしい