我的ESP32實做書籍:我出書了 ESP32 物聯網專題
博客來網址:https://www.books.com.tw/products/0010901195
實做說明
超音波與蜂鳴器:倒車雷達
現在的汽車大部分都有配備倒車雷達,就是倒車時,會依據車子與障礙物之間的距離發出不同頻率的嗶嗶聲,用來指引駕駛避免撞到別人的車子,而這套倒車雷達我們也可以使用ESP32來實做。本章分成兩個部份,第一節我們先來了解超音波測距的原理,第二節再實做蜂鳴器與倒車雷達。
超音波距離感測原理
爬山時,如果我們對著遠處的山頭大喊「你好」,過了幾秒就會聽到有人也對你喊著「你好」,筆者小時候一直以為是對面的登山客跟你在打招呼,後來才知道這叫做回音。
那麼回音與超音波距離感測器有什麼關係呢?
所謂的回音就是聲音傳遞路徑上有障礙物時,聲音就會反彈到原來發出聲音的人,而聲音在空氣中傳遞的速度約340公尺/秒,因此若我們計算發出(trigger)時間與聽到回音(echo)的時間差,就可以大致推算出發聲者與障礙物之間的距離了,我們可以將公式表示為:
距離(m)=(時間(s) x 340) / 2
數字340是音速,而要除2則是因為聲音去一次、回一次,一共跑了兩次所以要除2,而這也就是後來在二次大戰中廣泛使用的雷達的原理,不同的地方是雷達用的是電磁波,而我們在本次實驗用是超音波(Ultrasound)模組,所謂的「超」音波是指「超出人類可以聽到的聲音頻率」,一般人類的耳朵可以聽到的聲音頻率是在16Hz~20KHz之間,而超音波測距模組則設計使用20KHz以上的頻率,目的是不要在測距時發出惱人的噪音,也因為這樣這個測量距離的模組就稱為超音波測距模組,市面上常見的型號是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則會相當不準確,還有就是如果現場有多個超音波感測器同時作用,則會造成聲波之間的互相干擾,因此不要讓多個超音波同時進行測距。
本節我們就使用超音波感測器來製作倒車雷達,也就是說,利用超音波測量距離,並利用蜂鳴器發出聲音來指引駕駛,讓駕駛知道車子與障礙物之間的距離。不過我們先分別測試超音波與蜂鳴器是否正常,然後再將功能合併。
一、超音波測量距離
本部份我們先展示如何使用超音波模組進行距離測量,接線部份請參考圖
超音波距離測量程式說明
除了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號腳位收到高電位的時間
了解本次的兩個新程式語法後,我們將程式完成如下:
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就可以得到真實的距離。
下圖為本次計算的結果,使用者可以用手放在超音波模組的前方,並前後移動來觀測所獲得的距離。
二、倒車雷達
要完成倒車雷達就必須再安裝一個新的感測器,就是蜂鳴器Buzzer,蜂鳴器在我們日常生活中很常見,例如電腦開機時會嗶一聲,或者火災時超級大聲的警報也是一種蜂鳴器,目前市面上實驗用的蜂鳴器可分成兩種無源蜂鳴器及有源蜂鳴器,兩者的主要差異在於發出聲音的結構不同,此處所謂的無「源」或有「源」的源是指「電源」的意思,無源蜂鳴器是利用供電的頻率(PWM)來改變蜂鳴器的聲音,因為不須接VCC,因此被稱為無源,另一種有源蜂鳴器則是接上VCC就會叫,聲音頻率是固定的,兩種各有用途,而本例則是採用無源蜂鳴器。
有源及無源蜂鳴器兩者外觀上沒有差異,因此購買前請跟賣家確認規格,避免買錯材料。其外觀如下圖,一般上方可能會有一張貼紙,記得實驗前先用筆戳破中間的洞即可,若完全撕開可能會在發低音時破音,蜂鳴器有兩隻腳,有些蜂鳴器會透過長短腳來區分正負極(長正短負),如果您所購買的沒有分長短腳,可觀察正面會標示+的符號,也可區分正負極。
要控制蜂鳴器發出的聲音就要使用到另外一個程式庫:ESP32Servo,這也是一個控制PWM的工具,除了要用來控制蜂鳴器之外,後續我們也會使用他控制伺服馬達Servo來模擬開門,請選擇上方功能表/草稿碼/匯入程式庫/管理程式庫,開啟程式庫管理員如下圖,在上方關鍵字處輸出”ESP32Servo”,便可找到本程式庫,點選下方的安裝後,等候約一分鐘即可完成安裝。
無源蜂鳴器程式說明
程式庫安裝完畢後,我們先寫一個簡單能發出「小蜜蜂」音樂的程式進行聲音測試,在ESP32Servo中,控制蜂鳴器的語法是tone,說明如下
1. 發出一段時間的聲音:tone(pin, frequency, ms);
tone語法一共有三個參數,第一個是腳位pin,就是指蜂鳴器接在ESP32的哪一個腳位,第二個參數是frequency,則代表發出某個頻率的聲音,一般我們會用音樂的音階Do Re Mi來代表,關於音階與頻率之間的變換,可參考下表,例如中音Do頻率就是262,Re就是294,而Me則是330,因此發出Do, Re, Mi各半秒鐘,其程式如下所示:
tone(pin, 262, 500);//發出Do
tone(pin, 294, 500);//發出Re
tone(pin, 330, 500);//發出Me
2. 頻率音階對照表
音名 | C | C# | D | D# | E | F | F# | G | G# | A | A# | B |
---|---|---|---|---|---|---|---|---|---|---|---|---|
音階 | Do | Re | Mi | Fa | So | La | Si | |||||
低音 | 33 | 35 | 37 | 39 | 41 | 44 | 46 | 49 | 52 | 55 | 58 | 62 |
65 | 69 | 73 | 78 | 82 | 87 | 93 | 98 | 104 | 110 | 117 | 123 | |
中音 | 131 | 139 | 147 | 156 | 165 | 175 | 185 | 196 | 208 | 220 | 233 | 247 |
262 | 277 | 294 | 311 | 330 | 349 | 370 | 392 | 415 | 440 | 466 | 493 | |
523 | 554 | 587 | 622 | 659 | 698 | 740 | 784 | 831 | 880 | 932 | 988 | |
高音 | 1046 | 1109 | 1175 | 1245 | 1319 | 1397 | 1480 | 1568 | 1661 | 1760 | 1864 | 1976 |
2093 | 2217 | 2349 | 2489 | 2637 | 2794 | 2960 | 3136 | 3322 | 3520 | 3729 | 3951 | |
4186 | 4435 | 4699 | 4978 | 5274 | 5588 | 5920 | 6272 | 6645 | 7040 | 7459 | 7902 |
接下來我們將蜂鳴器接上ESP32,我們將蜂鳴器+腳接在GPIO 17,也就是麵包版右側編號9的位置,而另外一隻腳則接在GND的位置。
我們先透過一個簡單範例,發出小蜜蜂的第一段來檢查蜂鳴器是否正常,小蜜蜂的第一段為:
|G E E -|F D D -|C D E F|G G G -|
#include <ESP32Servo.h>
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);
}
倒車雷達程式說明
上述程式測試成功後,我們則來整合超音波感測及蜂鳴器來製作倒車雷達,為了簡化實驗,我們將超音波所檢測的距離分成四種狀態
安全:100cm內無障礙物,不發出聲音
注意:距離100~50cm之間,發出低音Do提醒使用者
小心:距離50~10cm之間,發出中音Do提醒使用者
危險:距離10~0cm之間,發出高音Do提醒使用者
透過改變聲調來提醒使用者,音調越高代表障礙物越接近,可避免撞到造成造成損失。本部份的程式如下
#include <ESP32Servo.h>
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);
也就是發出的聲音間隔剛好是距離,此時很靠近時就可以發出幾乎連續的嗶聲,這也是另外一種常見的方式。