2016年10月24日 星期一

[ Raspberry Pi 3 Model B ]
Project1 - 簡易型倒車雷達 Parking sensors

在一段時間慢慢摸索 Raspberry Pi 以 Python 控制周邊 GPIO 及相關硬體後,總算可以將些許小東西結合在一起當作個小專題,功能類似簡易版的倒車雷達!

[ Preparation ]
開始之前先將硬體及周邊電子零組件準備完成!
硬體部分:
1. Raspberry Pi 3 Model B
2. HC-SR04 (超音波距離感測模組)
3. 麵包版 x 1
4. LED x 3 (紅黃綠)
5. 1 K 歐姆 電阻 x 4、2 K 歐姆 電阻 x 1
6. 他激式蜂鳴器 x 1 (可發出不同頻率的聲音)
7. 杜邦線 公/母 數條 (約10-15條)
軟體部分:
首先說明一下,因為原本後期就會用到較多 GPIO 來做較多的控制,而在 Raspberry Pi 2 時似乎只有一個 GPIO 的 pin 腳能當作 PWM 使用,而在 Pi 3 似乎就沒這個限制,我就順便測試了將 GPIO 中 SPI 的模組關掉 來當作一般的 GPIO 且使用PWM來當作不同音調的控制!
1. 所以一開始要先確定關掉 GPIO 的 SPI 模組
    (如要使用一般GPIO pin 腳則可省略此步驟)
    打開終端機打上下列指令 (也可以直接開啟桌面圖示調整)
$ sudo raspi-config
    選擇 7 Advanced Option → A6 SPI → 是否 enable → <No>
    這樣就可以確定 SPI 模組為關閉的了
2. 這裡我使用 Python 來完成此次小專題

[ Purpose ]
雖然此次小專題只是將基本所學的及練習的GPIO設置及相關硬體結合起來,但是在兜電路及撰寫程式前也是要先想想我們的目的及需要的功能!
既然是倒車雷達,也就是要偵測到特定距離範圍時會有不同的警示燈及聲音提示!
以下我們用流程圖作為程式草稿比較淺而易懂
程式流程圖
大概構想完程式流程後就可以先將實際電路架設起來!

[ Hardware information ]
但是架設電路前要先了解到所使用到的硬體及模組資訊
才能正確連接以及依所需功能作調整!
LED及電阻就不多作介紹,特別要說明的是下列兩個:
1. 他激式蜂鳴器 (無源,底部有綠色電路板,腳位等長但有正負之分)
2. HC-SR04

他激式蜂鳴器:
需要震盪方波當作輸入,可發出不同頻率的聲音
這裡我們在 Raspberry Pi 上以 PWM (Pulse Width Modulation) 來實現方波
將 Duty cycle 設定為 50% 就能達成方波的效果,並將頻率設定為自己想要的音調
(會在 coding 部分再詳細說明如何設定)

HC-SR04:
四腳位 (Vcc, Trig, Echo, Gnd) 依照下列電子參數表來連接
Working Voltage (Vcc) DC 5 V
Working Current 15 mA
Working Frequency 40 Hz
Max Range 4 m
Min Range 2 cm
Measuring Angle 15 degree
Trigger Input Signal (Trig) 10 uS TTL pulse
Echo Output Signal (Echo) Input TTL lever signal and the range in proportion
Dimension 45*20*15 mm
可以看到 Trig 為 Input (Pi→HC-SR04),而 Echo 為 Output (HC-SR04→Pi)
也看到其工作電壓為 5 V,所以在 trigger 收到高電位 (Pi 的 GPIO 輸出及容忍電壓都為 3.3 V) 後會發射超音波及接收,而 Echo 隨後會從低電位提升到高電位 (HC-SR04 的工作電壓),但 Pi 容忍電壓僅為 3.3 V 所以我們要將 Echo 接上分壓電路降壓至3.3 V 左右,分壓電路說明如下,而後兩張則為 HC-SR04 的工作示意圖及時序圖:
分壓電路圖
工作示意圖 (圖片來源)
時序圖 (圖片來源)


[ Setting ]
接下來將電路都兜起來後再開始撰寫程式
實際接線示意圖
電路概要圖
接腳示意圖 (參考圖片網址)
實際接線圖 1 (麵包版部分)
實際接線圖 2 (Raspberry Pi 部分)
實際接線圖 3 (整體)

因為我後來會將這距離感測安裝在遙控車專題上所以就直接安裝在車體上了!
電路圖時 2.2 K 電阻代替 2 K 電阻,實際仍以 2 K 電阻為連接
這樣接完硬體部分就大功告成準備撰寫code來控制~

[ Coding-Python ]
這裡主要使用 Python 作為程式控制 (GitHub連結)
#Project: Parking sensors
#RaspberryyPi 3 Model B+
#Hardware: LED*3(green,yellow,red), 1K-resistance*4, 2K-resistance*1, buzzer*1
#IC: HC-SR04 Ultrasonic Ranging Module
#Editor: NORTHPC

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)

echo_pin=22
trigger_pin=24
BUZZER_pin=26
LED1_pin=19 #GREEN
LED2_pin=21 #YELLOW
LED3_pin=23 #RED

GPIO.setup(trigger_pin, GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(echo_pin, GPIO.IN)
GPIO.setup(BUZZER_pin, GPIO.OUT)
pwm_buzzer = GPIO.PWM(BUZZER_pin,523) #freq=523 Melody DO
pwm_buzzer.start(0) #pwm start as dutycycle=0
GPIO.setup(LED1_pin, GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(LED2_pin, GPIO.OUT,initial=GPIO.LOW)
GPIO.setup(LED3_pin, GPIO.OUT,initial=GPIO.LOW)

v=343 #331+0.6T, T=Celsius

def detection():
    GPIO.output(trigger_pin, GPIO.HIGH)
    time.sleep(0.00001)#10u seconds TTL Trigger Single
    GPIO.output(trigger_pin, GPIO.LOW)
    pulse_start=0
#---Response level output have proportional with detection to the distance---
    while GPIO.input(echo_pin)==0: #wait for the echo pin turns high
        pulse_start=time.time() #record the time point before echo pin turns high
    while GPIO.input(echo_pin)==1: #wait for the echo pin turns low
        pulse_end=time.time() #record the time point before echo pin turns low
#-----------------------------------------------------------------------------
    t=pulse_end-pulse_start
    d=(t*v)/2
    return d*100

def detection_average():
    d1=detection()
    time.sleep(0.065)

    d2=detection()
    time.sleep(0.065)

    d3=detection()
    time.sleep(0.065)

    distance = (d1+d2+d3)/3
    return distance

def alarm(distance):
    if distance>12:
        warning=0
        pwm_buzzer.ChangeDutyCycle(0)
        GPIO.output(LED3_pin, GPIO.LOW)
        GPIO.output(LED1_pin, GPIO.HIGH)
        time.sleep(0.6)
        GPIO.output(LED1_pin, GPIO.LOW)
    elif distance<=12 and distance>7:
        warning=0
        pwm_buzzer.ChangeDutyCycle(0)
        GPIO.output(LED3_pin, GPIO.LOW)
        pwm_buzzer.ChangeDutyCycle(50)
        GPIO.output(LED2_pin, GPIO.HIGH)
        time.sleep(0.3)
        pwm_buzzer.ChangeDutyCycle(0)
        GPIO.output(LED2_pin, GPIO.LOW)
    elif distance<=7 and distance>2:
        GPIO.output(LED3_pin, GPIO.HIGH)
        pwm_buzzer.ChangeDutyCycle(50)

try:
    while True:
        for i in xrange(0,4,1):
            distance=detection_average()
            alarm(distance)
        print "Distance = %.1f cm\n" % distance

except KeyboardInterrupt:
    print "\nException: KeyboardInterrupt\n"

finally:
    pwm_buzzer.stop()
    GPIO.cleanup()

程式解說:
  7~26: 都是在前置初始設定,此次專題使用實體腳位
      28: 音速約為 331+0.6T m/s,T 為攝氏溫度,而預設為 T = 20
30~43: 偵測距離的 function,監聽 Echo pin 的變化並計算距離
45~56: 偵測三次取平均值增加準確度,間隔為建議時間差 60ms 以上
58~77: 警示判斷觸發 LED 及蜂鳴器
Distance (D, cm) LED BUZZER
D > 12 Green (slow) X
12  D > 7 Yellow (fast) O (fast)
  7  D > 2 Red (continuously) O (continuously)
79~84: 為主程式,記錄偵測距離後進入警示判斷,迴圈後印出距離,迴圈的目的只                 是延長印出距離間的週期,免得畫面印出距離過快
86~87: 接住例外,這程式主要以鍵盤中斷為終止指令 (Ctrl+c)
89~91: 最後停止 PWM 並清空 GPIO

特別說明:Pulse Width Modulation (PWM)
先將 PWM 相關程式都寫在一起
BUZZER_pin=26
GPIO.setup(BUZZER_pin, GPIO.OUT)
pwm_buzzer=GPIO.PWM(BUZZER_pin,523) #freq=523 Melody Do
pwm_buzzer.satrt(0) #pwm start as dutycycle=0
pwm_buzzer.ChangeDutyCycle(50)
pwm_buzzer.stop()
第三行: 將已設為輸出的 pin 腳指定為 PWM 並名為 pwm_buzzer,並設定頻率為 523
第四行: 啟動 PWM 並設定 Duty cycle 為 0 (0 < Duty Cycle < 100)
第五行: 改變 PWM 的 Duty cycle 為 50
第六行: 停止 PWM

PWM 是藉由改變工作週期以達到改變電壓如下圖
圖片來源
假如 Duty Cycle 剛好為 50% 時就是方波
而變化的電壓算法就為高電位乘上 Duty Cycle
圖片來源
而我們藉由將 Duty Cycle 調整為 50% ,再設定想要的頻率(音調)就能讓他激式(無源)蜂鳴器發出不同頻率的聲音!

[ Results ]
硬體設置完成,程式撰寫完畢,那就來執行看看我們的倒車雷達囉!
為了比較準確度順便用尺做了距離示意圖如下
先用尺量好並繪好圖
黏在桌上準備 DEMO


示範影片

這樣就完成簡易型的倒車雷達啦~
看起來真的是蠻準的!

[ 參考網站 ]
[產品] GPIO 遊戲機學習套件
(不是葉佩雯XD,只是裡面的投影片讓我了解不少程式的概念及樹梅派的相關資訊)
Ultrasonic Ranging Module HC - SR04
HC-SR04 超音波感測器介紹
ATmega168A Pulse Width Modulation – PWM
SCHEMATICS - HOW H-BRIDGES WORK

沒有留言:

張貼留言