超音波測距模組

      在〈超音波測距模組〉中尚無留言

圖片

hc-sr0-1 hc-sr0-2

運作

超音波測距模組用來測量前方障礙物的距離. 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

接線方式

hcsr04-001_bb

ultrasonic

分流

請注意, Echo 輸出也是5V. 是接進GPIO裏的. 所以需要使用並聯的方式進行分流. 接個150Ω 再接進GPIO, 然後並聯300Ω接進GND. 這樣板子比較不容易燒毀. 

分流的電阻值也不一定要按上面值, 只要是1:2即可

ultraSonic_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();
    }
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *