# Arduino 教學 6:超音波測距模組
> 作者:王一哲
> 日期:2016/5/10
## 超音波測距模組運作原理
模組先發射超音波,超音波撞到物體反射回模組,測量發射、反射、接收所需要的時間,再由時間計算物體與模組間的距離。由於物體必須反射超音波,物體最好有一個不算太小、平滑的反射面。在網路上找到的範例程式通常會用以下的程式碼計算距離
```c
cm = pulseIn(echoPin, HIGH) / 29.41 / 2.00
```
上式當中 **pulseIn(echoPin, HIGH)** 會讀取指定的接腳 echoPin 的電壓值為高電位的時間(單位為微秒,microsecond, μs),也就超音波測距模組發出訊號到訊號反射回來被接收到所經過的時間,但我們只需要發出訊號到撞到物體所經過的時間 t ,因此需要將回傳的數值除以 2。29.41 則是超音波在空氣中前進 1cm 所花的時間(單位為μs),將 t 除以 29.41 即為物體與模組間的距離(單位為 cm)。
29.41 的來源如下
$$t_0 = \frac{0.01}{340} \approx 2.941 \times 10^{-5} ~\mathrm{s} = 29.41 ~\mathrm{\mu s}$$
如果需要更精準的數據,可以由氣溫計算空氣中的聲速
$$v = 331 + 0.6 T ~\mathrm{m/s}$$
再將較準確的聲速代入上式中。另外也可用改用帶有溫度補償的模組 US-100,但是需要的程式碼就會有點不同。
<img height="40%" width="40%" src="https://i.imgur.com/iMhB4MP.jpg" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">超音波測距模組 HC-SR04,售價約80元。</div>
</br>
<img height="40%" width="40%" src="http://www.playrobot.com/2262-thickbox_default/us-100-.jpg" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">超音波測距模組帶溫度補償 US-100,售價約150元。</div>
<div style="text-align:center">(圖片來源:<a href="http://www.playrobot.com/2262-thickbox_default/us-100-.jpg" target="_blank">http://www.playrobot.com/2262-thickbox_default/us-100-.jpg</a>)</div>
</br>
## 電路圖及程式碼
這個實驗只需要用到4個接腳,VCC接到板子上的5V,GND接到板子上的GND,另外我選擇將Trig接到板子上的6號,Echo接到板子上的5號,最後用USB線將板子連接到電腦即可。
<img height="100%" width="100%" src="https://lh6.googleusercontent.com/_MEB_lpvkZpDA7fvGp8-wXe0KhLz4t_EDUXJFG-Ix4t-Fj5rybVe4wdCSsPRgn2N9qZieeTzCtK14lsq-xZR-ld_VacWLfV6APeuP_Kz6IuZ3znS0C8u1ogpUQ0nVNyQpB32jQEZ" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">HC-SR04 實驗電路圖</div>
</br>
```c=
/* 實驗4:超音波測距 *
* 使用HC-SR04超音波感測器,可探測距離2cm-400cm *
* 精度為 0.3 cm,感應角度為 15 度 *
* 日期:Feb. 1, 2016 *
* 作者:王一哲 */
const int trigPin = 6;
const int echoPin = 5;
float cm;
void setup() {
// put your setup code here, to run once:
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
// 輸入低、高、低電位給trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
/* 計算距離值
* 音速340m/s時前進1cm所需時間 t = 0.01/340 = 29.41 microsedonds
* pulseIn 測得的時間為訊號發出、反射、接收所需時間,要除以2
* distance = pulseIn(echoPin, HIGH) / 29.41 / 2.00
*/
cm = pulseIn(echoPin, HIGH) / 29.41 / 2.00 ; //將回波時間換算成cm
//cm = (int(cm*100.0))/100.0; //保留2位小數
Serial.print(cm);
Serial.println(" cm");
delay(1000);
}
```
</br>
Arduino的程式碼主要分為3個部分:
1. **void setup() { }**:在 {} 內的程式碼只會在程式剛開始時被執行一次,直到板子被重新啟動為止,適合用來設定接腳狀態或其它只需要執行一次的指令。
2. **void loop() { }**:在 {} 內的程式碼不斷地被重複執行。
3. 在整個程式的最前面:設定全域變數。
在 Arduino 的程式碼中也有兩種註釋格式:
1. **/\* */**:多行註釋,在 /\* \*/ 之間的程式碼不會被編譯。
2. **//**:單行註釋,在 // 之後到行末為止的程式碼不會被編譯。
## 將資料匯出為純文字檔
最簡單的方法:利用 [Tera Term](https://ttssh2.osdn.jp/)、[PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) 之類的終端機軟體開啟板子連接到電腦上的 USB 連接埠,將連接埠接收到的資料存成 log file。以 PuTTY 為例:
1. Session 設定
a. **Serial line** 設定為板子所用的連接埠,可以從 Arduino IDE 裡看到編號,在本例中我用的連接埠為 **COM9**。
b. **Speed** 預設值為 **9600**,在本例中不需要更改。
c. **Connection type** 設定為 **Serial**。
<img height="80%" width="80%" src="https://i.imgur.com/fsIlLLz.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">PuTTY 設定:Session</div>
</br>
2. **Session => Logging** 設定
a. **Session logging** 設定為 **All session output**。
b. **Log file name** 按下右側的 **Browse… 選擇存檔路徑與檔名。
c. 設定完後按下最下方的 **Open**。
<img height="80%" width="80%" src="https://i.imgur.com/kuwOUNZ.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">PuTTY 設定:Logging</div>
</br>
<img height="100%" width="100%" src="https://i.imgur.com/2xqlz0F.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">PuTTY 讀取資料視窗</div>
</br>
<img height="100%" width="100%" src="https://i.imgur.com/V27VcRD.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">PuTTY 儲存的 log file</div>
</br>
## 利用試算表軟體 LibreOffice Calc 處理數據
1. 匯入 log file 的資料到 Calc
a. 以文字編輯器開啟 log file
b. 選取測量資料並按 **Ctrl+C** 複製資料,在本例中 **time(ms) distance(cm)** 此行開始才是測量資料。
c. 開啟 LibreOffice Calc,按 **Ctrl+V** 貼上資料,此時會自動跳出**匯入文字**視窗。
<img height="100%" width="100%" src="https://i.imgur.com/xc9zagS.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 匯入文字</div>
</br>
<img height="100%" width="100%" src="https://i.imgur.com/gkjEiuF.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 匯入文字後的試算表</div>
</br>
2. 利用 Calc 篩選出不合理的數據
a. 在本例中,物體與感測器間的距離約在 3 ~ 160cm 之間,超出太多的數據一定是錯誤的。
b. 選取 B 欄的資料,由工具列:**資料 → 更多篩選 → 標準篩選**
c. 由下拉式選單設定欄位名稱為 **distance(cm)**、條件為 **>** 、 值為 1000,甚至可以改為300。
d. 按下**確定**,列出不合理的數據,選取整列後按右鍵選擇**刪除列**。
e. 刪除後選擇畫面中最上方兩列,按右鍵選擇**顯示列**。
<img height="100%" width="100%" src="https://i.imgur.com/kDtyuxR.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 篩選功能</div>
</br>
<img height="60%" width="60%" src="https://i.imgur.com/7EWWBvL.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 標準篩選選項</div>
</br>
<img height="100%" width="100%" src="https://i.imgur.com/hqxjiFS.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 篩選後列出特別不合理的數據</div>
</br>
<img height="60%" width="60%" src="https://i.imgur.com/ckLnVl7.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 顯示隱藏的資料列</div>
</br>
3. 利用 Calc 計算速度、加速度並作圖
a. 將所有的時刻數據平移,以第1個位置對應的時刻為 0秒。
b. 將時刻、位置數據的單位皆改為 SI 制。
c. 以相鄰兩時刻的位置求平均速度,由於本例中每隔 0.1秒即測量一次位置,經過的時間相當短暫,因此這段時間內的平均速度與時間中點的瞬時速度應該不會相差太多。
d. 同理,可找出加速度與對應的時刻。
<img height="80%" width="80%" src="https://i.imgur.com/SwYSF4X.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 繪製的 x - t 圖</div>
</br>
<img height="80%" width="80%" src="https://i.imgur.com/1YaY7Of.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 繪製的 v - t 圖</div>
</br>
<img height="80%" width="80%" src="https://i.imgur.com/rZVvzQy.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">LibreOffice Calc 繪製的 a - t 圖</div>
</br>
---
###### tags:`Arduino`