【ESP32專欄】運用超音波與蜂鳴器實做「倒車雷達」

作者:尤濬哲

現在的汽車大部分都有配備倒車雷達,就是倒車時,會依據車子與障礙物之間的距離發出不同頻率的嗶嗶聲,用來指引駕駛避免撞到別人的車子,而這套倒車雷達我們也可以使用ESP32來實做。本章分成兩個部份,第一節我們先來了解超音波測距的原理,第二節再實做蜂鳴器與倒車雷達。

超音波距離感測原理

爬山時,如果我們對著遠處的山頭大喊「你好」,過了幾秒就會聽到有人也對你喊著「你好」,筆者小時候一直以為是對面的登山客跟你在打招呼,後來才知道這叫做回音。

回音的原理

那麼回音與超音波距離感測器有什麼關係呢?

所謂的回音就是聲音傳遞路徑上有障礙物時,聲音就會反彈到原來發出聲音的人,而聲音在空氣中傳遞的速度約340公尺/秒,因此若我們計算發出(trigger)時間與聽到回音(echo)的時間差,就可以大致推算出發聲者與障礙物之間的距離了,我們可以將公式表示為:

距離(m)=(時間(s) x 340) / 2

數字340是音速,而要除2則是因為聲音去一次、回一次,一共跑了兩次所以要除2,而這也就是後來在二次大戰中廣泛使用的雷達的原理,不同的地方是雷達用的是電磁波,而我們在本次實驗用是超音波(Ultrasound)模組,所謂的「超」音波是指「超出人類可以聽到的聲音頻率」,一般人類的耳朵可以聽到的聲音頻率是在16Hz~20KHz之間,而超音波測距模組則設計使用20KHz以上的頻率,目的是不要在測距時發出惱人的噪音,也因為這樣這個測量距離的模組就稱為超音波測距模組,市面上常見的型號是HC-SR04如下圖。


HC-SR04超音波模組

超音波感測器有兩個大大的「眼睛」,很多機器人或小車結構都會利用這個感測器做避障功能,不過其實與其說是眼睛,不如說是「耳朵」,左下角標示的「T」是TX的意思,代表左邊的孔負責傳送(Transport)超音波,而右下角標示「R」是RX代表右側的耳朵負責接收(Receive)超音波回音,也就是左側是嘴巴負責發出聲音,而右側是耳朵負責聽回音,兩者缺一不可。

下方四個腳位則依序為VCC、Trig、Echo、GND,其中Trig代表嘴巴,決定何時發出聲音,Echo則代表耳朵,用來計算聽到回音的時間,再透過公式就可以計算距離了,而VCC與GND則與以往相同,接在5V及GND腳位,這裡說明一下目前超音波有多個版本,有少數版本僅能使用5V,而大多數是5V、3.3V都可用,因此個人建議接在5V的位置。

另外一個要注意的地方是超音波感測器可量測的範圍約在2cm~500cm之間,低於2cm則無法感測,超過500cm則會相當不準確,還有就是如果現場有多個超音波感測器同時作用,則會造成聲波之間的互相干擾,因此不要讓多個超音波同時進行測距。

本節我們就使用超音波感測器來製作倒車雷達,也就是說,利用超音波測量距離,並利用蜂鳴器發出聲音來指引駕駛,讓駕駛知道車子與障礙物之間的距離。不過我們先分別測試超音波與蜂鳴器是否正常,然後再將功能合併。

倒車雷達實做

1. 使用超音波模組測量距離

本部份我們先展示如何使用超音波模組進行距離測量,接線部份請參考下圖。

超音波距離測量

除了VCC、GND之外,我們將Trig接在GPIO12(麵包版左側7),而Echo接在GPIO14(麵包版左側8),程式的概念則是在Trig發出一小段音波後,就在Echo等候回音回傳,若收到回音,則Echo腳位會發出高電位,因此我們測量Echo轉成高電位的時間,最後再利用公式換算即可。

本案例有兩個新的語法,delayMicroseconds及pulseIn,分別介紹如下:

1.暫停n微秒:delayMicroseconds(n);

之前我們常用的暫停是delay(1000),在delay內的數字是毫秒ms(MilliSeconds),也就是1/1000秒,因此delay(1000)是暫停1秒,但是若我們需要暫停時間比1/1000還小時,就要改用delayMicroseconds(n),而內部數字n代表的是微秒(百萬分之一秒),通常用來進行更精確測量,例如本次使用超音波測距,常溫下音速每秒約340公尺,若使用1/1000秒,誤差將會超過30cm,因此須改用百萬分之一秒為單位進行測量。

範例:

delayMicroseconds(5);//暫停百萬分之5秒=5微秒

2. 計算腳位的收到符合電壓的時間差:pulseIn(腳位,電壓);

pulseIn就是用來計算時間,例如說當程式執行到pulseIn(14, HIGH);時,代表我們要詢問14號腳位何時收到高電位,以本例而言,當超音波模組收到回音時,就會將Echo轉HIGH,因此我們利用這個語法,就可以求得收到回音的時間,此語法所取得的時間值單位為微秒。

範例:

EchoTime=pulseIn(14, HIGH);//計算14號腳位收到高電位的時間

了解本次的兩個新程式語法後,我們將程式完成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int Trig =12;//發出聲波
int Echo =14;//接收聲波
void setup(){
Serial.begin(115200);
pinMode(Trig, OUTPUT);
pinMode(Echo, INPUT);
}
void loop() {
digitalWrite(Trig, LOW); //關閉
delayMicroseconds(5);
digitalWrite(Trig, HIGH);//啟動
delayMicroseconds(10);
digitalWrite(Trig, LOW); //關閉
float EchoTime = pulseIn(Echo, HIGH); //傳回時間
float CMValue = EchoTime * 34 / 1000 / 2; //轉換成距離
Serial.println(CMValue);
delay(50);
}

在loop內,我們先將trig關閉5微秒,然後開啟10微秒,之後就立即關閉,這個「關、開、關」的步驟的目的讓超音波模組初始化避免受到干擾,完成後之後便會發出一段超音波,接下來就是利用pulseIn計算收到回音的時間,最後再利用公式將時間轉換程距離即可。

CMValue = EchoTime * 34 / 1000 / 2

這裡的公式內的”34″是轉換成每1/1000秒,音速能跑約34公分,而除1000則是將百萬分之一秒轉成1/1000秒,最後再除2則是因為聲音去一次、回一次花了兩倍距離,除2就可以得到真實的距離。

下圖為本次計算的結果,使用者可以用手放在超音波模組的前方,並前後移動來觀測所獲得的距離。

2. 完成倒車雷達

要完成倒車雷達就必須再安裝一個新的感測器,就是蜂鳴器Buzzer,蜂鳴器在我們日常生活中很常見,例如電腦開機時會嗶一聲,或者火災時超級大聲的警報也是一種蜂鳴器,目前市面上實驗用的蜂鳴器可分成兩種無源蜂鳴器及有源蜂鳴器,兩者的主要差異在於發出聲音的結構不同,此處所謂的無「源」或有「源」的源是指「電源」的意思,無源蜂鳴器是利用供電的頻率(PWM)來改變蜂鳴器的聲音,因為不須接VCC,因此被稱為無源,另一種有源蜂鳴器則是接上VCC就會叫,聲音頻率是固定的,兩種各有用途,而本例則是採用無源蜂鳴器。

有源及無源蜂鳴器兩者外觀上沒有差異,因此購買前請跟賣家確認規格,避免買錯材料。其外觀如下圖,一般上方可能會有一張貼紙,記得實驗前先用筆戳破中間的洞即可,若完全撕開可能會在發低音時破音,蜂鳴器有兩隻腳,有些蜂鳴器會透過長短腳來區分正負極(長正短負),如果您所購買的沒有分長短腳,可觀察正面會標示(+)的符號,也可區分正負極。

無源蜂鳴器外觀

要控制蜂鳴器發出的聲音就要使用到另外一個程式庫:ESP32Servo,這也是一個控制PWM的工具,除了要用來控制蜂鳴器之外,後續我們也會使用他控制伺服馬達Servo來模擬開門,請選擇上方功能表/草稿碼/匯入程式庫/管理程式庫,開啟程式庫管理員如下圖,在上方關鍵字處輸出”ESP32Servo”,便可找到本程式庫,點選下方的安裝後,等候約一分鐘即可完成安裝。

程式庫管理員安裝ESP32Servo程式庫

程式庫安裝完畢後,我們先寫一個簡單能發出「小蜜蜂」音樂的程式進行聲音測試,在ESP32Servo中,控制蜂鳴器的語法是tone,說明如下

  • 發出一段時間的聲音:tone(pin, frequency, ms);

tone語法一共有三個參數,第一個是腳位pin,就是指蜂鳴器接在ESP32的哪一個腳位,第二個參數是frequency,則代表發出某個頻率的聲音,一般我們會用音樂的音階Do Re Mi來代表,關於音階與頻率之間的變換,可參考下表,例如中音Do頻率就是262,Re就是294,而Me則是330,因此發出Do, Re, Mi各半秒鐘,其程式如下所示:

1
2
3
tone(pin, 262, 500);//發出Do
tone(pin, 294, 500);//發出Re
tone(pin, 330, 500);//發出Me

頻率音階對照表

接下來我們將蜂鳴器接上ESP32,我們將蜂鳴器正級(+)腳接在GPIO 17,也就是麵包版右側編號9的位置,而另外一隻腳則接在GND的位置。

我們先透過一個簡單範例,發出小蜜蜂的第一段來檢查蜂鳴器是否正常,小蜜蜂的第一段為:
|G E E -|F D D -|C D E F|G G G -|

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include
int buzzer= 17;
void setup() {
Serial.begin(115200);
}
void loop() {
tone(buzzer, 392, 500);//G(So)
tone(buzzer, 330, 500);//E(Me)
tone(buzzer, 330, 500);//E(Me)
delay(500);
tone(buzzer, 349, 500);//F(Fa)
tone(buzzer, 294, 500);//D(Re)
tone(buzzer, 294, 500);//D(Re)
delay(500);
tone(buzzer, 262, 500);//C(Do)
tone(buzzer, 294, 500);//D(Re)
tone(buzzer, 330, 500);//E(Me)
tone(buzzer, 349, 500);//F(Fa)
tone(buzzer, 392, 500);//G(So)
tone(buzzer, 392, 500);//G(So)
tone(buzzer, 392, 500);//G(So)
delay(3000);
}

為了簡化實驗,我們將超音波所檢測的距離分成四種狀態:

  1. 安全:100cm內無障礙物,不發出聲音
  2. 注意:距離100~50cm之間,發出低音Do提醒使用者
  3. 小心:距離50~10cm之間,發出中音Do提醒使用者
  4. 危險:距離10~0cm之間,發出高音Do提醒使用者

透過改變聲調來提醒使用者,音調越高代表障礙物越接近,可避免撞到造成造成損失。本部份的程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include
int Trig = 12; //發出聲波
int Echo = 14; //接收聲波
int buzzer = 17;//蜂鳴器
void setup() {
Serial.begin(115200);
pinMode(Trig, OUTPUT);
pinMode(Echo, INPUT);
pinMode(buzzer, OUTPUT);
}
void loop() {
//步驟1:使用超音波測量距離
digitalWrite(Trig, LOW); //關閉
delayMicroseconds(5);
digitalWrite(Trig, HIGH);//啟動
delayMicroseconds(10);
digitalWrite(Trig, LOW); //關閉
float EchoTime = pulseIn(Echo, HIGH); //傳回時間
float CMValue = EchoTime * 34 / 1000 / 2; //轉換成距離
Serial.println(CMValue);
//步驟2:使用蜂鳴器發出指定聲音
if (CMValue < 100 && CMValue >= 50) {
tone(buzzer, 33, 100); //注意:發出低音Do
}
if (CMValue < 50 && CMValue >= 10) {
tone(buzzer, 523, 100); //小心:發出中音Do
}
if (CMValue < 10) {
tone(buzzer, 4186, 100); //危險:發出高音Do
}
delay(50);
}

小結

除了改變高低音調提醒使用者之外,也可以利用距離改變發出聲音的間隔,例如距離比較遠時就每次嗶聲之間間隔較久,而很接近時,發出的嗶聲音較為緊湊,例如:

tone(buzzer, 4186, CMValue);

也就是發出的聲音間隔剛好是距離,此時很靠近時就可以發出幾乎連續的嗶聲,這也是另外一種常見的方式。

(作者為本刊共筆作者,其專欄文章同步發表於作者部落格;責任編輯:歐敏銓)

Author: 尤濬哲

身兼助理教授/專欄作家/知名部落客,以及點點滴滴科技研發總監等身份,專長包括人工智慧、多媒體互動(Unity)、智慧互動裝置(APP、Arduino)、虛擬實境與擴增實境互動、IoT 實做開發。 學歷:中山大學資訊管理研究所 博士

Share This Post On

發表

跳至工具列