超音波距離センサーHC-SR04の使い方

HC-SR04 超音波距離センサー センサー

超音波距離センサーHC-SR04を使って距離を測定する方法を紹介します。

HC-SR04モジュールは、電気信号を超音波へ変換して物体に放射し、物体から反射した超音波を電気信号に変換します。この放射と反射の時間差を測定して物体までの距離を計算します。

Raspberry Piとプログラム言語Pythonを使って、HC-SR04へ電気信号を送る処理と時間を測定するサンプルプログラムを紹介します。

準備

HC-SR04の購入

下の写真の様に基板に実装された状態で販売されており、秋月電子通商で購入しました。今回は、このモジュールを使用したサンプルプログラムを紹介します。

HC-SR04 写真

HC-SR04とRaspberry Piの接続

HC-SR04とRaspberry Piを接続するときに注意点があります。
HC-SR04動作電圧は5Vですが、Raspberry Piの信号の電圧は3.3Vです。
壊さないように電圧を分圧します。

今回は、下図の様に10kΩと6.8kΩの抵抗で、5Vを3Vに分圧しました。

接続図

ブレッドボードを使用したHC-SR04とRaspberryPiの接続

抵抗による分圧
V = 5V × 10kΩ / (10kΩ + 6.8kΩ) ≒ 3V

抵抗による分圧 5V → 3V

接続写真

ブレッドボードを使用したHC-SR04の接続写真 1
ブレッドボードを使用したHC-SR04の接続写真 2

Pythonの操作方法

Pythonの基本操作(コーディングおよびデバック)などを解説しています。参考にしてください。

GPIO制御プログラミング

プログラムコード

Pythonプログラムです。

import RPi.GPIO as GPIO
import time

#測定環境温度
TEMP = 20

#GPIO設定
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(17, GPIO.OUT)
GPIO.setup(27, GPIO.IN)

#繰り返し
while True:
    
    #トリガ信号出力
    GPIO.output(17, GPIO.HIGH)
    time.sleep(0.00001)
    
    GPIO.output(17, GPIO.LOW)
    
    #返送HIGHレベル時間計測
    while GPIO.input(27) == GPIO.LOW:
        soff = time.time()    #LOWレベル終了時刻
    
    while GPIO.input(27) == GPIO.HIGH:
        son = time.time()    #HIGHレベル終了時刻
    
    #HIGHレベル期間の計算
    clc = son - soff
    
    #時間から距離に変換(TEMPは測定環境温度)
    clc = clc * (331.50 + (0.6 * TEMP)) / 2 * 100
    
    #画面に表示
    print(str(clc))
    
    #一時停止
    time.sleep(0.1)

プログラムの説明

プログラムの流れです。

  1. 初期設定
  2. GPIOの設定
  3. HC-SR04から距離データを取得
    1. 測定開始のトリガ信号をHCーSR04へ送る
    2. HIGHレベル信号をHC-SR04から受信して時間を測定
  4. データを物理量に変換し画面に表示
  5. 3.~4.を繰り返します

1.初期設定

import RPi.GPIO as GPIO
import time

import RPi.GPIO as GPIO
asは、毎回”RPi.GPIO”と記入せず”GPIO”と省略するためです。

#測定環境温度
TEMP = 20

TEMP = 20
20は、実際に測定する環境の温度です。
距離変換計算に必要なパラメータで、プログラミング時に事前に記述します。

サンプルプログラムでは20℃にしています。実際の測定環境の温度すると測定誤差を少なく出来ます。

2.GPIOの設定

#GPIO設定
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(17, GPIO.OUT)
GPIO.setup(27, GPIO.IN)

GPIO.setwarnings(False)
「ワーニングを表示しない」にしています。

GPIO.setmode(GPIO.BCM)
信号の指定を基板上のピン番号ではなくGPIOの信号名にします。
ピン番号で指定するときは、GPIO.BCMGPIO.BOARDにします。

GPIO.setmode
GPIO.BOARD GPIO.BCM
11番ピン GPIO 17
13番ピン GPIO 27

GPIO.setup(17, GPIO.OUT)
GPIO 17を出力にします。

GPIO.setup(27, GPIO.IN)
GPIO 27を入力にします。

3.HC-SR04から距離データを取得

3-1.測定開始のトリガ信号をHC-SR04へ送る

#トリガ信号出力
GPIO.output(17, GPIO.HIGH)
time.sleep(0.00001)
    
GPIO.output(17, GPIO.LOW)

GPIO.output(17, GPIO.HIGH)
GPIO 17をHIGHレベルにします。

time.sleep(0.00001)
10μsの間、HIGHレベルを維持します。

GPIO.output(17, GPIO.LOW)
GPIO17をLOWレベルにします。

3-2.距離に比例したHIGHレベル信号をHC-SR04から受信して時間を測定

#返送HIGHレベル時間計測
while GPIO.input(27) == GPIO.LOW:
    soff = time.time()    #LOWレベル終了時刻
    
while GPIO.input(27) == GPIO.HIGH:
    son = time.time()    #HIGHレベル終了時刻
    
#HIGHレベル期間の計算
clc = son - soff

while GPIO.input(27) == GPIO.LOW:
  soff = time.time()
GPIO 27がLowレベルの間は、変数soff に現在の時刻を代入し続けます。
HIレベルになると代入を終了します。この変数がHIGHレベルの開始時刻となります。

while GPIO.input(27) == GPIO.HIGH:
  son = time.time()

GPIO 27がHIGHレベルの間は、変数son に現在の時刻を代入し続けます。
LOWレベルになると代入を終了します。この変数がHIGHレベルの終了時刻です。

clc = sonsoff
HIGHレベルの終了時刻からHIGHレベルの開始時刻を引いて、実際にHIGHレベルであった期間を算出します。

※注意点
動作確認するとわかりますが、短い距離の測定がうまく出来ない事があります。

OS上でプログラムが動いているので、時間の計測で誤差が発生したり、プログラムの処理と実際のGPIO出力に時間的なズレが発生したりする可能性が考えられます。

トリガ信号10μs時間の精度に関しては、信号の立下りエッジから測定を開始するので(エッジ検出)、影響はほとんど無いと思われます。

4.データを物理量に変換し画面に表示

#時間から距離に変換(TEMPは測定環境温度)
clc = clc * (331.50 + (0.6 * TEMP)) / 2 * 100

clc = clc * (331.50 + (0.6 * TEMP)) / 2 * 100
時間を距離に変換します。*100でcm表記にしています。

#画面に表示
print(str(clc))

print(str(clc))
距離データを画面に表示します。

5.3.~4.を繰り返します

#繰り返し
while True:

while True:
Stopボタンが押されるまで繰り返します。

※この『while True:』は、15行目のwhile文です。

プログラムの実行結果

以下の手順でプログラムを実行します。

①Runボタンを押します。
②距離データを0.1秒間隔で画面に表示します。
③Stopボタンを押すとプログラムは終了します。

PythonのRunボタンとStopボタン
HC-SR04のプログラムの実行結果

以上、Raspberry PiでGPIOを制御してHC-SR04モジュールで距離を測定するサンプルでした。

まとめ

このHC-SR04は、センサーへ出力する信号のハイレベルの期間や、センサーから受信した信号のハイレベル期間の測定など、どれだけ時間を正確に制御できるかがカギとなります。

サンプルプログラムは、センサーからのハイレベル出力測定がポーリングなので、Pythonの割り込み処理を試しに使用しましたが、自分の実力不足もあり、割り込みが発生から次の割り込みまで1msec以上の割り込みしか出来ず、ポーリングより誤差の大きい結果となりました。

プログラミングやソフトウェアの記事です。

コメント