圖片
運作
超音波測距模組用來測量前方障礙物的距離. HC-SR0這型號有四支針腳,
VCC : +5V
Trig : 接到GPIO04, 設為Output
Echo : 接到GPIO05, 設為Input
Gnd : 接地
Trig 先啟動3V, 加入電壓約10ms後再關掉. 過了一段時間準備後, Echo 針腳狀況會變成High, 此時就可以開始計時(t1), 因為此時開始發射8個40kHz的方型超音波.
當接收到回波後, 此針腳就狀態就會變成Low, 此時就可以結束計時(t2)
t2-t1就是聲波來回的時間, 所以單程時間為 (t2-t1)/2
音速
音速依當時溫及氣壓有所不同. 但差異不多, 所以可以依 340m/s的速度來計算. 也就是每秒會跑340公尺=34000cm.
所以1cm需要1/34000秒 = 2.9412 * 10-5秒 = 2.9412 * 10-2 ms = 29.412 微秒
另一個思考方式
1 sec : 34000cm (1秒 34000公分)
1 ms : 34cm (1毫秒 34公分)
1微秒 : 0.034cm (1微秒 0.034公分)
1奈秒 : 0.000034cm (1奈秒 0.000034公分)
Java Time Method
Java有System.currentTimeMillis() 可以取得 1970/01/01 0:0:0am到現在所經過的毫秒數(西洋稱為Time Stamp). 但音速是精準到微秒, 所以需使用另一個方法 System.nanoTime() 取得某段時間到現在的奈秒數. 此方法跟時間是沒什麼關係, 因為某段時間的起始值依不同vm而不同. 所以只能計算二段之間的奈秒差
請注意, Java官方說法, 此方法是計算二段時間的nano second, 也就是奈秒. 但台灣許多人翻譯成毫微秒.
ps : 毫微秒這個名詞, 可能是台灣人自創的, 因為這名詞在大陸也查不到.
距離計算
所以上述的(t2-t1)/2, 為單程的奈秒數, (t2-t1)/2/1000為單程的微秒數,
(t2-t1)/2/1000/29.412 即為單程距離的cm值.
當然也可以使用 (t2-t1)/2/1000*0.034 cm
精準度
本模組的精準度真的是會嚇死人, 規格如下
輸出電位( 1/ 0):5V/ 0V
精度:3mm
距離範圍:2 ~ 450cm
有效的角度:<15o
觸發輸入信號:10uS TTL pulse
接線方式
分流
請注意, Echo 輸出也是5V. 是接進GPIO裏的. 所以需要使用並聯的方式進行分流. 接個150Ω 再接進GPIO, 然後並聯300Ω接進GND. 這樣板子比較不容易燒毀.
分流的電阻值也不一定要按上面值, 只要是1:2即可
程式範例
底下的程式碼, 示範接了一個蜂鳴器及超音波測距器, 可應用於倒車雷達上.
當距離為5公分內, 蜂鳴器會一直叫, 然後依10, 20, 50, 100, 150公分, 而有不同的鳴叫時間間隔
按下PowerButton後, 整個程式就會停止執行
package ultrasonic; import com.pi4j.io.gpio.GpioController; import com.pi4j.io.gpio.GpioFactory; import com.pi4j.io.gpio.GpioPinDigitalInput; import com.pi4j.io.gpio.GpioPinDigitalOutput; import com.pi4j.io.gpio.PinPullResistance; import com.pi4j.io.gpio.PinState; import com.pi4j.io.gpio.RaspiPin; import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent; import com.pi4j.io.gpio.event.GpioPinListenerDigital; import java.util.logging.Level; import java.util.logging.Logger; public class UltraSonicTest { public static double distance=0; public static boolean closeFlag=false; public static void main(String[] args){ GpioController gpioController =GpioFactory.getInstance(); GpioPinDigitalInput buttonPower=gpioController.provisionDigitalInputPin(RaspiPin.GPIO_00, PinPullResistance.PULL_DOWN); GpioPinDigitalOutput pinSpeaker=gpioController.provisionDigitalOutputPin(RaspiPin.GPIO_03, "Speaker", PinState.LOW); UltraSonic ultraSonic=new UltraSonic(gpioController); ultraSonic.start(); buttonPower.addListener(new GpioPinListenerDigital(){ @Override public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) { PinState state=event.getState(); if(state.isHigh()){ closeFlag=true; } } }); Thread speaker=new Thread(()->{ while(!closeFlag){ int duration=0; if(UltraSonicTest.distance<=5){ pinSpeaker.setState(PinState.HIGH); } else{ if(UltraSonicTest.distance<=10)duration=100; else if(UltraSonicTest.distance<=20)duration=150; else if(UltraSonicTest.distance<=50)duration=200; else if(UltraSonicTest.distance<=100)duration=300; else if(UltraSonicTest.distance<=150)duration=600; else duration=1000; if(duration>=1000) pinSpeaker.setState(PinState.LOW); else pinSpeaker.blink(duration, 500, PinState.HIGH); try { Thread.sleep(600); } catch (InterruptedException ex) {} } } }); speaker.start(); while(!closeFlag){ try { Thread.sleep(500); } catch (InterruptedException ex) {} } buttonPower.removeAllListeners(); ultraSonic.close(); try {Thread.sleep(2000);} catch (InterruptedException ex) {} buttonPower.setShutdownOptions(true, PinState.LOW); pinSpeaker.setShutdownOptions(true, PinState.LOW); gpioController.shutdown(); System.out.println("App Close"); } } class UltraSonic extends Thread{ private GpioPinDigitalOutput sensorTriggerPin ; private GpioPinDigitalInput sensorEchoPin ; boolean runFlag=true; public UltraSonic (GpioController gpio){ //Trigger pin為Output sensorTriggerPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_04); //Echo pin為Input sensorEchoPin = gpio.provisionDigitalInputPin(RaspiPin.GPIO_05,PinPullResistance.PULL_DOWN); } public void run(){ while(runFlag){ try { sensorTriggerPin.high(); //Trig變更為High Thread.sleep(10);// 延遲10ms sensorTriggerPin.low(); //Trig變更為Low //等待ECHO pin變更為High while(sensorEchoPin.isLow()){} long startTime= System.nanoTime();//開始計時 while(sensorEchoPin.isHigh()){}//等待Echo變更為Low long endTime= System.nanoTime();//結束計時 UltraSonicTest.distance=(endTime-startTime)/1000.0/2 * 0.034; System.out.println(String.format("Distance : %.3f cm", UltraSonicTest.distance)); Thread.sleep(300); } catch (InterruptedException e) {} } } public void close(){ runFlag=false; this.interrupt(); } }