本文是 AI 神經網路自走車 第二篇,分享如何使用 Raspberry pi pico (RP2040) 與 HC-SR04 超音波測距模組做底層的距離偵測。雖然最終會使用 camera 與 CNN 做 auto driving 的大腦,但加上距離資訊會更準確,就讓我們一起來學習吧!

準備硬體元件

這次製作需要準備的材料為:

  1. Raspberry pi pico
  2. HC-SR04

Step 1:了解超音波測距原理

原理非常簡單,還記得小時候在山裡對著遠方山谷大喊嗎?我們利用從發出聲音與聽到回音的時間間隔,乘上聲速,並除以二就可以得到距離!

    \[distance = \frac{\triangle{t}\times v}{2}\]

Step 2:了解 HC-SR04 模組工作原理

用 Raspberry pi pico 與 HC-SR04 做超音波距離測量

HC-SR04 只有 4 pin,分別是 VCC、GND、Trig、Echo。運作方式非常簡單,讓我們配著時序圖一起看:

  1. 向 Trig pin 送入一個至少 10us 長的方波
  2. 收到方波後模組被驅動,從音波發射端連續發出 8 個 40KHz 的方波
  3. 模組收到回音後,會將 Echo pin 輸出高電位,而後復位為低電位
  4. 測量 Echo pin 高電位的持續時間,即為超音波從發出到返回的時間
  5. 利用一開始提供的數學式,即可求得距離

Step 3:撰寫 Raspberry pi pico python 測試

了解原理後,就讓我們開始撰寫看看。首先將 pico 和 HC-SR04 模組相連,這邊只要是 GPIO pin 都可以使用,我們範例採用 GPIO 0 和 GPIO 1 來實作。

用 Raspberry pi pico 與 HC-SR04 做超音波距離測量

對照 pico 的 pinout 我們做以下連結

picoHC-SR04
GPIO 0Trig
GPIO 1Echo
3V3VCC
GNDGND

模組的 VCC 和 GND 可以直接拉到 pico 身上的 3V3 和任一的 GND pin 座相連。

硬體接線完畢,我們開始看 code

from machine import Pin, time_pulse_us
import time

# 宣告 trig 和 echo pin
trig_pin = Pin(0, Pin.OUT)
echo_pin = Pin(1, Pin.IN)

# 對 trig pin 送 10us 長的方波
trig_pin.high()
time.sleep_us(10)
self.trig_pin.low()

# 透過內建函數 time_pulse_us,計算 echo pin 方波持續時間
# 第一個參數給定要測量的 pin
# 第二個參數給定 1 表示計算 high 持續時間
# 第三個參數給定 timeout 時間
echo_t = time_pulse_us(echo_pin, 1, timeout_us=58000)

# 依照官方文件描述
# 如果回傳 -2 表示等 echo pin 拉高超時
# 如果回傳 -1 表示 echo pin 拉高時間太長而超時
if echo_t == -2:
    print('timeout to wait echo to be high.')
elif echo_t == -1:
    print('timeout to measure echo pulse width')
else:
    # 將 echo_t 轉換成距離,這邊單位為 cm
    # 另,除以 29 約等於乘 0.034
    distance = (echo_t / 2.0) / 29
    print('distance is", distance)

這邊稍微解釋一下 code 中對 distance 的算法,因為與一開始講的不一樣。

我們同時將 us 轉成 s,m 轉成 cm,把

常數處理後,就會得到 0.034 這個數字,而 29 則是 0.034 的倒數

    \[\begin{aligned} distance&=\frac{(\triangle{t}\times 10^-6)\times (340\times 10^2)}{2}\\ &=\frac{\triangle{t}}{2}\times (340\times 10^-4)\\ &=\frac{\triangle{t}}{2}\div 29 \end{aligned}\]

實際測試沒問題,我們將上述的 code refactor 成類別,以後呼叫比較方便!

Step 4:把 HC-SR04 模組的 code 包成類別

不多說,立刻看 code

from machine import Pin, time_pulse_us
import time

class HCSR04:

    def __init__(self, trig_pin: int, echo_pin: int):
        self.trig_pin = Pin(trig_pin, Pin.OUT)
        self.echo_pin = Pin(echo_pin, Pin.IN)

        self.trig_pin.low()

    def get_distance_in_cm(self):
        self._send_trig()
        echo_t = self._receive_echo()

        if echo_t >= 0:
            return (echo_t / 2.0) / 29  # 1 / 29 = 0.034
       
        # if timeout, return -1
        return -1

    def _send_trig(self):
        # send trig high
        self.trig_pin.high()
        time.sleep_us(10)

        # complete trig
        self.trig_pin.low()

    def _receive_echo(self):
        echo_t = time_pulse_us(self.echo_pin, 1, 58000)
        if echo_t == -2:
            print('timeout to wait echo to be high.')
        if echo_t == -1:
            print('timeout to measure echo pulse width')
        return echo_t

有了以上的包裝後,每一個 HCSR04 可以代表一個 sensor,使用上比較方便

sensor = HCSR04(0, 1)
distance = sensor.get_distance_in_cm()
print('distance is', distance)

有了基礎的距離偵測,我們就可以繼續往下邁進!如果覺得我文章內容對你有幫助的話,請在文章後面幫我按 5 個讚!讓我知道大家都喜歡什麼內容哦!

範例原始碼在此下載:github

AI 神經網路自走車
上一篇:用 Raspberry pi pico 做 PWM Motor Control
下一篇:如何用 Raspberry pi pico 做 I2C Slave? 使用 MicroPython 與 Raspberry pi

J
Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。