Python × Pico 電子工作 | #09 超音波で距離を測ろう

今回は HC-SR04 超音波センサー を使って、目の前にある物体までの距離(cm) を測ります。コウモリやイルカが暗闇でも障害物を避けられるのと同じ仕組みで、音波を発射して、跳ね返ってくるまでの時間 から距離を割り出します。ロボットコンテストや自動運転車のセンサーとして定番の部品です。

  • HC-SR04 の動作原理(音波の往復時間で距離を測る)
  • TRIG(10μs パルスで発射トリガ)と ECHO(反射波の戻り時間を返す)の役割
  • 距離計算式 距離(cm) = エコー時間(μs) ÷ 58 の意味
  • HC-SR04 の 3.3V 版と 5V 版 の違い・分圧抵抗の必要性
  • 距離をしきい値で判定して LED 点灯やブザー警告に使う応用

PycoBlocks(MicroPythonモード) を開き、左カテゴリ「センサー」の 「超音波距離」(変数代入型)と 「超音波距離(cm)」(値ブロック)が今回の主役です。前回までで学んだ 条件分岐(if-else)・LED 点灯・ブザー と組み合わせて、距離センサーを使った自動制御を作っていきます。

超音波で距離を測ろう

HC-SR04 の仕組み:音波の往復時間で距離を測る

HC-SR04 は 2 つの円い金属スピーカー(送信用の T = Transmitter と受信用の R = Receiver)を持つセンサーで、次の流れで距離を測ります。

  1. Pico が TRIG ピン に 10μs(0.00001 秒)の HIGH パルスを送る → HC-SR04 が 40 kHz の超音波バースト(8 周期分) を発射
  2. 超音波が 物体に当たって反射 し、戻ってくる
  3. HC-SR04 が反射波を検出 → ECHO ピンの HIGH 時間として「音波の往復にかかった時間」を Pico に返す
  4. Pico は ECHO の HIGH 時間(μ秒)を計測し、距離(cm)に換算する
HC-SR04 が超音波を発射し、物体で反射して戻る往復時間で距離を測る原理図
HC-SR04 は超音波を発射し(①)、物体で反射して戻る(②)までの時間を測る。音波は往復しているので、片道の距離 d は往復時間の半分から求める。

計算式の導出:音は空気中を 約 343 m/s(20℃) で進みます。ECHO が HIGH の時間 t(μ秒)は 音波が往復した時間 なので、片道距離は t × 343 ÷ 2 ÷ 10000(cm に換算)です。整理すると次の シンプルな式 になります。

計算ステップ式結果(例:t = 580μs)
音速 × 時間343 m/s × 580μs0.199 m = 19.9 cm(往復)
片道距離÷ 29.95 cm
近似式距離(cm) = t ÷ 5810.0 cm(≈ 9.95cm)

÷ 58 という不思議な数字は、音速 343 m/s を cm/μs に換算して 1/2 した結果(0.0343 cm/μs ÷ 2 = 0.01715、その逆数が ≈ 58.3)です。PycoBlocks の 「超音波距離」 ブロックは 内部でこの計算を自動でやってくれるので、皆さんは「変数 dist にセンチメートル単位の距離が入る」と覚えるだけで OK です。

配線:HC-SR04 を Pico につなぐ(3.3V 版と 5V 版の違い)

HC-SR04 には 2 つの種類 があり、配線方法が変わります。高専生が買うモジュールは 3.3V〜5V の両対応版(HC-SR04+ / HC-SR04P など)が多いので、本記事では 3.3V 直結 を前提に解説します。

種類VCCECHO 出力電圧必要な追加部品
HC-SR04+ / HC-SR04P(3.3V 版)Pico の 3V3 に直結3.3Vなし(推奨)
HC-SR04(5V 専用版)Pico の VBUS(5V)5V(要分圧)分圧抵抗(例:1kΩ + 2kΩ)

🚫 5V を Pico の GPIO に直接入れると壊れる

Pico の GPIO は 3.3V ロジック なので、入力ピンに 5V を加えるとマイコンが壊れる可能性がある。5V 版 HC-SR04 の ECHO 出力は 5V なので、抵抗 2 本で分圧(5V → 3.3V) してから ECHO を Pico の GP15 に入れること。
# 5V 版を使う場合の ECHO 分圧(参考)
#
#   HC-SR04 ECHO ─[ 1kΩ ]─┬─→ Pico GP15
#                          │
#                       [ 2kΩ ]
#                          │
#                         GND
#
# 分圧比 = 2k / (1k + 2k) = 2/3
# 5V × 2/3 = 3.33V  → Pico の HIGH しきい値(≈ 2.0V)を超え、ロジックは確実に HIGH と認識
HC-SR04 を Pico に接続した実体配線図
配線(3.3V 版前提):HC-SR04 VCC→Pico 3V3、GND→GND、TRIG→GP14、ECHO→GP15。5V 版を使う場合は VCC を VBUS に、ECHO を 1kΩ+2kΩ の分圧抵抗を通して GP15 に接続します。(実体配線図は Fritzing の部品画像をもとに作図・CC BY-SA 3.0)

ステップ1:距離を 1 回だけ測ってみよう

まずは 1 回だけ距離を測定 し、結果を print で表示します。ブロックは 「超音波距離」(変数 dist に結果を入れる)と 「値を表示」 の 2 つだけ。Thonny のシェルに数値が 1 行だけ出力されます。

HC-SR04 で 1 回距離を測定して print するブロック
ブロック構成:超音波距離 TRIG:GP14 ECHO:GP15 → 変数:dist → 値を表示:dist。
from machine import Pin
import utime
def _us_dist(tr, ec):
    t=Pin(tr,Pin.OUT); e=Pin(ec,Pin.IN)
    t.value(0); utime.sleep_us(2); t.value(1); utime.sleep_us(10); t.value(0)
    while e.value()==0: pass
    t0=utime.ticks_us()
    while e.value()==1: pass
    return utime.ticks_diff(utime.ticks_us(),t0)/58
dist = _us_dist(14, 15)
print(dist)

コードのポイント:ブロック1 個から生成される MicroPython は意外と長く、_us_dist 関数 の中で「10μs パルス送信 → ECHO の HIGH 開始を待つ → ticks_us で時間計測 → HIGH 終了を待つ → 経過時間を 58 で割る」という一連の流れを行っています。皆さんはこの関数の中身を覚える必要はなく、「超音波距離」ブロックを置けば dist 変数に cm が入る と覚えれば OK です。

ステップ2:0.5 秒ごとに連続して距離を表示しよう

1 回測るだけでは 動いている物体 を追えません。「ずっと繰り返す」 ブロックの中に超音波測定を入れて、0.5 秒ごとに距離を表示 し続けるようにしましょう。Thonny のシェルにずらりと数字が並んで、手を近づけたり遠ざけたりすると数値が変化するのが見えます。

0.5秒ごとに距離を測定して表示するループブロック
ブロック構成:ずっと繰り返す → 超音波距離 → 変数 dist 表示 → 0.5 秒待つ。
from machine import Pin
import utime
def _us_dist(tr, ec):
    t=Pin(tr,Pin.OUT); e=Pin(ec,Pin.IN)
    t.value(0); utime.sleep_us(2); t.value(1); utime.sleep_us(10); t.value(0)
    while e.value()==0: pass
    t0=utime.ticks_us()
    while e.value()==1: pass
    return utime.ticks_diff(utime.ticks_us(),t0)/58
while True:
    dist = _us_dist(14, 15)
    print(dist)
    utime.sleep(0.5)

📝 測定範囲は約 2cm〜400cm

HC-SR04 のデータシート上の測定範囲は 2cm〜400cm。2cm より近いと反射波が早すぎて測れず、400cm を超えると反射波が弱すぎて検出できない。実際には 3cm〜300cm 程度が安定して測れる範囲と思っておくと良い。

⚠️ うまく測れないとき

  • 柔らかい物(布・スポンジ)は超音波を吸収するので測れない
  • 斜めの面は反射波が別方向に逃げて返ってこない
  • センサーの正面(円錐状に広がる視野)に物体が入っていないと反応しない

演習課題

課題3-9-1:5V → 3.3V 分圧回路の抵抗値を計算しよう

5V 版の HC-SR04 を Pico につなぐとき、ECHO の出力 5V を 3.3V 以下に下げるために分圧抵抗を使います。次の条件で、上側抵抗 R1 と下側抵抗 R2の 分圧比 を計算してみよう。

分圧の公式: Vout = Vin × R2 ÷ (R1 + R2)
(Vin = ECHO 出力電圧、Vout = Pico に入る電圧、R1 = 上側、R2 = 下側)

問1: R1 = 1kΩ、R2 = 2kΩ のとき、Vin = 5V なら Vout は何 V になる?
問2: Vout を 正確に 3.3V にしたいとき、R1 = 1kΩ なら R2 は何 Ω が理想?
問3: なぜ 合計抵抗を 1kΩ 以上 に保つのが望ましいか?(ヒント:電流消費・センサー出力の駆動能力)

▶ 模範解答と解説を見る
# 問1: R1=1k, R2=2k, Vin=5V
Vout = 5 * 2000 / (1000 + 2000)
# Vout = 5 * 2/3 = 3.333V  →  3.3V とほぼ同じで OK

# 問2: Vout=3.3V を厳密に出したい
# 3.3 = 5 * R2 / (1000 + R2)
# 3.3 * (1000 + R2) = 5 * R2
# 3300 + 3.3*R2 = 5*R2
# 3300 = 1.7*R2
# R2 = 3300 / 1.7 ≈ 1941Ω
# 実際は E12系列で 1.8kΩ または 2kΩ を選ぶ

# 問3: 合計抵抗を 1kΩ 以上に保つ理由
# - 電流 I = V/R = 5V/(R1+R2) を小さく抑える → センサー出力の負荷を軽減
# - 例:合計 100Ω だと 50mA も流れ、HC-SR04 出力ピンが過電流で壊れる可能性

解説: 解説:分圧抵抗の選び方は 「比」だけでなく「合計抵抗」 も大事です。比だけ正しくても合計が小さすぎると過電流で部品が壊れます。1kΩ + 2kΩ(合計 3kΩ、電流 ≒ 1.7mA) は HC-SR04 の駆動能力に対して余裕があり、Pico の HIGH 入力しきい値(≒ 2.0V)も十分超えるバランスの良い組み合わせです。抵抗のカラーコード:

  • 1kΩ:茶・黒・赤・金(4 色帯)
  • 2kΩ:赤・黒・赤・金
ロボコン用工具箱に E12 系列の抵抗セット(10Ω〜1MΩ 各 10 本入り)を 1 つ用意しておくと、今後の電子工作で何度も活躍します。

課題3-9-2:10cm より近づいたら警告 LED を点灯しよう

距離センサーの典型的な応用です。変数 dist が 10 未満なら内蔵 LED(GP25)を点灯 し、10 以上なら消灯。「ずっと繰り返す」 の中に 「もし dist < 10 だったら / そうでなければ」 を入れて、0.1 秒間隔で判定します。

▶ 模範解答と解説を見る

ブロックの組み合わせ例:

距離が10cm未満なら内蔵LEDを点灯するブロック
ブロック構成:ずっと繰り返す → 超音波距離 dist → もし dist < 10 なら LED(GP25)点灯、そうでなければ消灯 → 0.1秒待つ。
from machine import Pin
import utime
def _us_dist(tr, ec):
    t=Pin(tr,Pin.OUT); e=Pin(ec,Pin.IN)
    t.value(0); utime.sleep_us(2); t.value(1); utime.sleep_us(10); t.value(0)
    while e.value()==0: pass
    t0=utime.ticks_us()
    while e.value()==1: pass
    return utime.ticks_diff(utime.ticks_us(),t0)/58
while True:
    dist = _us_dist(14, 15)
    if dist < 10:
        Pin(25, Pin.OUT).value(1)
    else:
        Pin(25, Pin.OUT).value(0)
    utime.sleep(0.1)

解説: 動作確認のコツ:手のひらをセンサーの正面に近づけたり遠ざけたりすると LED が点いたり消えたりします。10cm の境界付近 ではチラチラと揺れるかも。これは センサーのノイズで、毎回の測定値が少し揺れるためです。発展:

  • しきい値を変数化:変数 thresh = 20 を使えばコード書き換え不要で範囲を調整できる
  • チラつき防止(ヒステリシス):「8cm 以下で点灯、12cm 以上で消灯」のように 2 つのしきい値を使うと安定する(境界付近のノイズに強くなる)
  • 外付け LED で警告灯化:#02 で学んだ外付け LED を別の GPIO につけて、Pico を駐車支援センサー風に

課題3-9-3:距離に応じてブザーの音色を変える警告装置を作ろう

「もし/そうでなくもし/そうでなければ」 の elif を使った3 段階判定 です。10cm 未満:880Hz の高音(緊急)、30cm 未満:440Hz の中音(注意)、30cm 以上:無音(安全)。車のバックセンサーの「ピッ…ピッ…ピピピッ!」を Pico で再現できます。ブザーは GP15 だと ECHO と衝突するので GP16 に挿し替えてください。

▶ 模範解答と解説を見る

ブロックの組み合わせ例:

距離に応じて3段階のブザー音を鳴らすブロック
ブロック構成:ずっと繰り返す → 超音波距離 dist → if dist<10: ブザー(GP16) 880Hz 0.2秒、elif dist<30: ブザー(GP16) 440Hz 0.2秒、else: 0.5秒待つ(無音)。
from machine import Pin, PWM
import utime
def _us_dist(tr, ec):
    t=Pin(tr,Pin.OUT); e=Pin(ec,Pin.IN)
    t.value(0); utime.sleep_us(2); t.value(1); utime.sleep_us(10); t.value(0)
    while e.value()==0: pass
    t0=utime.ticks_us()
    while e.value()==1: pass
    return utime.ticks_diff(utime.ticks_us(),t0)/58
while True:
    dist = _us_dist(14, 15)
    if dist < 10:
        _bz = PWM(Pin(16))
        _bz.freq(880); _bz.duty_u16(32768)
        utime.sleep(0.2); _bz.deinit()
    elif dist < 30:
        _bz = PWM(Pin(16))
        _bz.freq(440); _bz.duty_u16(32768)
        utime.sleep(0.2); _bz.deinit()
    else:
        utime.sleep(0.5)

解説: 3 段階判定の流れ:if-elif-else は 上から順に評価 されます。dist = 8 なら 1 つ目の dist < 10 で True になり、そこで判定終了(2 つ目以降は評価されない)。dist = 25 なら 1 つ目は False、2 つ目の dist < 30 で True になり 440Hz が鳴る。dist = 100 なら全部 False で else に進み無音。ブザー GP16 への変更:#06 ではブザーを GP15 に挿していましたが、今回は GP15 が HC-SR04 の ECHO に使われているので、ブザーを GP16 に挿し替えます。Pico の GPIO は基本どれも PWM 出力にできるので、ピン番号さえ変えれば動作は同じです。発展:

  • 4 段階・5 段階に増やす:elif を + ボタンで追加して、「5cm未満:1320Hz、10cm未満:880Hz、20cm未満:660Hz、30cm未満:440Hz」のように段階的に音程を変える
  • 距離を周波数に連動:freq(int(2000 - dist * 30))のように距離から計算した周波数を使うと、距離に応じて連続的に音程が変化する「テルミン風」楽器になる(cs_b ブロックで生 Python を書く必要あり)
  • LCD(#08)に距離値を表示:今回のブザー警告に加えて「距離 cm」を LCD に出せば、本格的な距離計+警告装置に

HC-SR04 + ブザーを Pico に接続した実体配線図
課題3-9-3 の配線:HC-SR04 は基本配線(VCC→3V3、GND→GND、TRIG→GP14、ECHO→GP15)、パッシブブザーを GP16 と GND に追加。GP15 と GP16 がぶつからないように注意。

まとめ

  • HC-SR04 は 40kHz の超音波の往復時間で距離を測るセンサー。範囲は約 2〜400cm。
  • 計算式 距離(cm) = エコー時間(μs) ÷ 58 は 音速 343m/s と往復の ÷2を整理した近似式。PycoBlocks のブロックが内部で自動計算してくれる。
  • 3.3V 版(HC-SR04+ / HC-SR04P) は Pico の 3V3 に直結 OK。5V 専用版は ECHO に 分圧抵抗(1kΩ + 2kΩ) が必要。
  • 距離をしきい値で判定して LED 点灯・ブザー警告・3 段階の if-elif-else など多彩な応用に使える。
  • 柔らかい物・斜めの面・センサー正面以外は 反射波が返ってこないので測れないという物理的な制約も覚えておく。

次の記事は #10「温湿度センサー(DHT11)」。1 本の信号線でデジタル通信する温度・湿度センサーを使って、今回学んだ LCD と組み合わせて 気象モニタ を作ります。

トップへ戻る