星期四, 4月 24, 2014

Raspberry Pi 筆記(二十):MCP3008 讀取類比訊號測溫度與光度

[2014/04/22]
兩三個星期前到台北光華商場電子材料行找 MCP3008 這顆 IC,竟然問了三家都沒有賣這個IC,還是上網去買才買到。為什麼要使用這個 IC 呢? 主要是因為Raspberry Pi沒有支援類比訊號輸入,例如要用Raspberry Pi去讀取溫度或光度偵測的類比訊號,是無法達成的。MCP 3008這個 IC的功能就是將類比訊號轉換成數位訊號(Analogue-to-digital converter, ADC),它有8通道 ,每個通道可依類比設備的輸入值傳回一個10位元的數值。MCP3008可使用SPI介面跟Raspberry Pi連接,以下就來看看如何運用MCP3008偵測溫度和光度。


[MCP3008]

MCP3008讀取ADC數值時,會傳回一個10-bit的數字,介於0到1023之間,可以根據輸入電壓與傳回值的電壓,計算出類比訊號的值,再根據類比設備的特性得到所需的資訊。可參考MCP3008 Datasheet 。

圖片來源:MCP3008 Datasheet

MCP3008 pinout description (接腳說明)
來源:MCP3008 Datasheet

Digital Ground (DGND):Digital ground 連接至內部數位電路
Analog inputs (CH0 - CH7):類比通路0 - 7
Chip Select/Shutdown (CS/SHDN):CS/SHDN pin當設定為低電壓時,被用來啟動設備間的通訊;設定為高電壓時,停止設備間的通訊進入等待狀態。CS/SHDN pin在通訊時必須設定為高電壓才能進行通訊。
Serial Data Output (DOUT):SPI串列通訊時資料輸出,資料會因為設備間通訊的時序變化而改變。
● Serial Data Input (DIN):SPI Port串列資料輸入,用來載入設定資料給通訊設備。
● Serial Clock (CLK):SPI clock pin被用來啟動通訊。
來源:MCP3008 Datasheet

[溫度感測元件LM35]

LM35是一個常見的溫度感測IC,根據技術文件說明LM35輸出電壓與攝氏溫標呈線性關係,0℃時輸出為零,每提高1℃輸出就增加10mV。由此特性,我們可以根據輸出電壓換算測得的溫度,例如:測得電壓0.24V時,表示當時溫度為24℃。可參考LM35 Datasheet 。

  來源:網路

[光敏電阻(Photocell)]

光敏電阻是一種特殊的電阻,簡稱光電阻,又名光導管。它的電阻和光線的強弱有直接關係。當有光線照射時,電阻內原本處於穩定狀態的電子受到激發,成為自由電子。所以光線越強,產生的自由電子也就越多,電阻就會越小。在光線越暗時,電阻值會越高。
  來源:網路

[材料]

• Raspberry Pi 主板 x1
• MCP3008 IC  x1
• LM35 IC x1
• 光敏電阻 x1
• 10K電阻 x1
• 連接線  x N條

[線路連接與電路圖]

• MCP3008 CH0接光敏電阻,光敏電阻另一隻腳接地(GND)
• MCP3008 CH0接10K電阻,10K電阻另一隻腳接3.3V
• MCP3008 CH1接LM35中間接腳,LM35另外兩隻腳分別接3.3V及接地
• MCP3008 pin16(VDD)及pin15(VREF)接3.3V,pin14(AGND)及pin9(DGND)接地
• MCP3008 pin13(CLK)接Pi pin23(SCLK);pin12(DOUT)接Pi pin21(SPI0_MISO);pin11(DIN)接Pi pin19(SPI0_MISI);pin10(CS/SHDN)接Pi pin24(SPI0_CE0)

[2017/02/21] 更新上述接線,改為表格。


MCP3008
Pi
Pin 1 (CH0)

Pin 2 (CH1)

Pin 3 (CH2) 

Pin 9 (DGND)
Pin 6 (Ground)
Pin 10 (CS/SHDN)
Pin 24 SPI0_CE0 (GPIO8)
Pin 11 (DIN)
Pin 19 SPI0_MISI (GPIO10)
Pin 12 (DOUT)
Pin 21 SPI0_MISO (GPIO9)
Pin 13 (CLK)
Pin 23 SCLK (GPIO11)
Pin 14 (AGND)
Pin 6 (Ground)
Pin 15 (VREF)
Pin 1 (3.3V)
Pin 16 (VDD)
Pin 1 (3.3V)



[程式碼]

import spidev
import time
import os

# open(bus, device) : open(X,Y) will open /dev/spidev-X.Y
spi = spidev.SpiDev()
spi.open(0,0)

# Read SPI data from MCP3008, Channel must be an integer 0-7
def ReadADC(ch):
    if ((ch > 7) or (ch < 0)):
       return -1
    adc = spi.xfer2([1,(8+ch)<<4,0])
    data = ((adc[1]&3)<<8) + adc[2]
    return data

# Convert data to voltage level
def ReadVolts(data,deci):
    volts = (data * 3.3) / float(1023)
    volts = round(volts,deci)
    return volts

# Calculate temperature from LM35 data
def ConvertTemp(data,deci):
    temp = data * 100
    temp = round(temp,deci)
    return temp

# Define sensor channels
light_ch = 0
temp_ch  = 1

# Define delay between readings
delay = 3

while True:

  # Read the light sensor data
  light_data = ReadADC(light_ch)
  light_volts = ReadVolts(light_data,2)

  # Read the temperature sensor data
  light_data = ReadADC(light_ch)
  light_volts = ReadVolts(light_data,2)

  # Read the temperature sensor data
  temp_data = ReadADC(temp_ch)
  temp_volts = ReadVolts(temp_data,4)
  temp       = ConvertTemp(temp_volts,2)

  # Print out results
  print "Temp  : ",temp_data, " (",temp_volts ,"V) -->",temp,"~C    Light : ",light_data," (",light_volts,"V)"

  # Delay seconds
  time.sleep(delay)

*註:data = ((adc[1]&3)<<8) + adc[2] 其中<< 因造成網頁編碼錯誤,改用全型小於符號,如需複製程式使用請改為半型

[程式解說]

程式中有一行spi.xfer2,他會送出3 Bytes 給Device,第一個位元是1,相當於二進位的00000001,″8+ch″表示Device的頻道位置,變成"00001000",″<<4″往左移 4個位元(bits),變成 ″10000000",最後一個字元是0,亦即 "00000000"。而程式中 "spi.xfer2([1,(8+channel)<<4,0])"會送出 " 00000001 10000000 00000000" 給接收設備,設備回應三個Bytes回來,而傳回值會放在最右邊10個Bits位置,該值介於0跟1023之間。我們可根據這個數字,判斷光度、溫度等類比的訊號。

[執行結果]


[參考資料]

Raspberry Pi Cookbook
Raspberry Pi Spy : Analogue Sensors On The Raspberry Pi Using An MCP3008
● 維基百科 : 光敏電阻
Share:

星期二, 4月 08, 2014

Raspberry Pi 筆記(十九): Webcam 拍照與瀏覽串流媒體

[2014/04/03]
RaspBerry Pi官方推出直接安裝在 Pi主機的攝影鏡頭,使用軟性排線插在主機板上,而非使用USB介面。考量Webcam的多用途性,我買了相容性比較高的 Logitech Webcam C310,畫質稍好,價格又不會太高。Webcam有兩個用法,一是拍照存檔成jpeg檔,另一個功能是拍攝成影片,前者安裝 fswebcam就可以達成,要作為監視器使用,則需安裝 motion 軟體。

[安裝fswebcam]

下載安裝fswebcam軟體:
$ sudo apt-get install fswebcam

拍照存成 test.jpg
$ fswebcam test.jpg

拍成的照片,畫質不佳,如果要改變畫質,可以在同目錄下建立conf 檔:
$ vi .fswebcam.conf
設定檔內容如下:
device /dev/video0
input 0
loop 15
skip 20
background
resolution 640x480
set brightness=60%
set contrast=13%
top-banner
font /usr/share/fonts/truetype/msttcorefonts/arial.ttf
title "EvilEye cam-O-tron"
timestamp "%d-%m-%Y %H:%M:%S (%Z)"
jpeg 95
save /home/pi/fswebcam/viewcam.jpg

執行fswebcam結果如下:




[安裝影像軟體 Motion]

先檢查插在USB的 Webcam 是否已經驅動:
$ sudo lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 005: ID 046d:081b Logitech, Inc. Webcam C310
Bus 001 Device 004: ID 0bda:8179 Realtek Semiconductor Corp.

安裝 motion 軟體
$ sudo apt-get install motion

安裝完成後,修改設定檔 motion.conf ,將DAEMON OFF改為ON,設定為自動啟動motion,Webcam_localhost ON改為 OFF,不從Raspberry Pi連線至Webcam
$ sudo vi /etc/motion/motion.conf
daemon on
webcam_localhost = off

[2017/12/11]
沒找到上述第二行,改成:
steam_localhost  off

# Web連線使用8081 Port
webcam_port 8081
# 管理用的連線使用8080 Port
control_port 8080

#如果要修改畫面大小,可修改
# 影像寬度 (pixels). 預設: 320
width 640
# 影像高度 (pixels). 預設: 240
height 480
# 影像品質(百分比). 預設: 50
webcam_quality 100

 
640*480, 畫質75% 畫面

修改 /etc/default/motion 將 start_motion_daemon=no 改為 yes
$ sudo vi /etc/default/motion
start_motion_daemon=yes

重新啟動 motion 服務
$ sudo service motion start

 如果要查詢您的 USB WebCam是否支援Raspberry Pi,可以到以下網站查詢:
http://elinux.org/RPi_USB_Webcams

剛開始我使用 IE 連線時,會要我下載檔案,然後下載了2-3mb還是無法看到影像,在論壇上找了很久,有網友告知使用 Firefox 或 Safari 就可以看到影像畫面了。可參考:Raspberry Pi Forum : can't view streaming in browser

參考資料
Raspberry Pi Cookbook
Pi Cam
● R3uk.com: Webcam capture using fswebcam
Share:

星期一, 4月 07, 2014

Raspberry Pi 筆記(十八):模擬DOS環境

[2014/04/07]
大約在1980年代,電腦都是從DOS開始學起,看著 C:\>的符號,輸入指令,感覺很復古又很熟悉。現在 Raspberry Pi 系統也可以模擬DOS環境,也可以執行DOS程式及玩遊戲。最懷念的是以前學習 Basic 語言及 DBASE III 資料庫系統,竟然在RaspBerry Pi系統可以執行DBASE III程式,真是感動。在Raspberry Pi我安裝兩種模擬DOS的程式,一是 rpix86,另一套是DOSBOX,若以執行的功能而言,我會推薦 DOSBOX,它在 X-Win 的環境下,可正常執行VGA畫面的程式。以下就來看看如何在RPi安裝DOS模擬程式:


[DOSBOX]

下載安裝:
$ sudo apt-get install dosbox

執行時需在X-Windows環境下,在LXTerminal終端機輸入dosbox:
$ sudo dosbox
即可看到以下畫面:

此時,鍵盤對應有問題,按鍵無法對應正確的英文字,必須修改Conf 檔(以0.74版為例):
$ vi /root/.dosbox/dosbox-0.74.conf

找到usescancodes 將 true 改成 false
usescancodes=false

預設Z:\>僅只有系統檔案,如果要將/home/pi掛載進來,可修改.conf 檔,找到[autoexec]哪段,加入以下紅字部分即可。
[autoexec]
# Lines in this section will be run at startup.
# You can put your MOUNT lines here.
mount c /home/pi
c:


或執行以下指令掛載磁碟機:
Z:\> mount c /home/pi

下載 Chess Genius 3 進行測試,可以成功執行,只是速度稍微慢一點。

有名的正宗台灣十六張麻將2,DOS版。


[rpix86]


rpix86特點如下:
• rpix86 模擬 80486 CPU 大約 20MHz 速度
• rpix86 模擬 Super-VGA 介面卡,可以執行 640x480  256 色解析度
• rpix86 模擬 SoundBlaster 2.0音效卡
• 支援 US鍵盤及兩鍵滑鼠
• 支援 COM1串列Port

下載安裝 rpix86 DOS模擬程式
$ wget http://rpix86.patrickaalto.com/rpix86.tar.gz

解壓縮並執行程式
$ tar -xf rpix86.tar.gz
$./rpix86

此時會出現以下畫面,要求下載4DOS程式,回覆 Y

執行DOS指令及程式
我下載GWBASIC測試,結果V3.23這個版本可以正常執行,其他一些VGA畫面的DOS遊戲都無法執行,改天找時間再來測試看看。

執行GWBASIC後發現只要有用到Shift按鍵的字元都無法呈現,不知如何解決?

執行DBASE III畫面
如果要瞭解支援哪些程式,可到以下網站查看清單:DSx86 Compatibility WIKI


參考資料
rpix86:http://rpix86.patrickaalto.com/index.html
DOSBOX:http://www.dosbox.com/
Share:

星期一, 3月 31, 2014

Raspberry Pi 筆記(十七):使用MAX7219 控制 8x8 LED Matrix

[2014/03/28]
在使用Arduino時,買了一個8x8的LCD Matrix模組,可是放了好久都沒有時間去瞭解它的應用,剛好在瀏覽樹莓派相關文件時,看到一篇如何運用Python來驅動8x8 LED Matrix,於是就動手接線路,同時也瞭解SPI的使用方法。

[基本知識]

SPI,是Serial Peripheral interface的縮寫,顧名思義就是串列外圍設備介面。最早是Motorola首先在其MC68HCXX系列處理器上定義的。

SPI介面主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。SPI,是一種高速的,全雙工,同步的通信,並且在晶片的接腳上只佔用四根線,節約了晶片的管腳,同時為PCB的佈局上節省空間。

SPI的通信原理很簡單,它以主從方式工作,這種模式通常有一個主設備和一個或多個從設備,需要至少4根線,事實上3根也可以(單向傳輸時)。也是所有基於SPI的設備共有的,它們是SDI(數據輸入),SDO(數據輸出),SCK(時鐘),CS(片選)。
(1)SDO     – 主設備數據輸出,從設備數據輸入(Serial Data Out)
(2)SDI      – 主設備數據輸入,從設備數據輸出(Serial Data In)
(3)SCLK   – 時鐘信號,由主設備產生(Serial Clock)
(4)CS        – 從設備使能信號,由主設備控制(Chip Select)
其中CS是控制晶片是否被選中,也就是預先讓這個接腳產生信號時(高電位或低電位元),對此晶片的操作才有效。這就允許在同一裝置上連接多個SPI設備成為可能。

負責通訊的3根線,通訊是通過數據交換完成的,SPI串列通訊協議,讓數據是一個位元一個位元傳輸。這就是SCK時鐘線存在的原因,由SCK提供時鐘脈衝,SDI,SDO則基於此脈衝完成數據傳輸。數據輸出透過 SDO線,數據在SCK電位上升或電位下降時改變,在緊接著的下降電壓或上升電壓被讀取。完成一位數據傳輸,輸入也使用同樣原理。這樣,在至少8次時鐘信號的改變(上升電位和下降電位為一次),就可以完成8位數據的傳輸。

要注意的是,SCK信號線只由主設備控制,從設備不能控制信號線。同樣,在一個基於SPI的設備中,至少有一個主控設備。

SPI還是一個數據交換協議:因為SPI的數據輸入和輸出線獨立,所以允許同時完成數據的輸入和輸出,不同的SPI設備的實現方式不盡相同。
在點對點的通信中,SPI介面不需要進行尋址操作,且為全雙工通信,顯得簡單高效。在多個從設備的系統中,每個從設備需要獨立的使能信號,硬體上比I2C系統要稍微複雜一些。

下圖說明SPI主和從的接線及資料傳輸方式:
圖片來源:維基百科

[材料]

• Raspberry Pi 主板 x1
• 8x8 LED Matrix模組  x1
• 連接線  x5

[線路連接與電路圖]

• VCC(+5V Power) 接第 2 Pin(+5V)
• GND(Ground)    接第 6 Pin(GND)
• DIN(Data In)   接第 19 Pin(GPIO10, MOSI)
• CS(Chip Select) 接第 21 Pin(GPIO8, SPI_CS0)
• CLK(clock)     接第 23 Pin(GPIO11,SPI_CLK)


要執行程式之前要先安裝 max7219 Python套件,可以先到以下網址下載,下載前先建立一個max7219目錄。

$ mkdir max7219
$ cd max7219
$ git clone https://github.com/rm-hull/max7219.git
$ sudo python setup.py install

[程式碼]

#!/usr/bin/env python

import max7219.led as led
import max7219.canvas as canvas
import max7219.transitions as transitions
import time
from random import randrange

led.init()
led.show_message("Hello world!", transition = transitions.left_scroll)

for x in range(256):
    led.letter(x)
    time.sleep(0.1)

while True:
    for x in range(500):
        canvas.set_on(4, 4)
        canvas.scroll(randrange(8))
        canvas.render()
        time.sleep(0.01)

我將上述程式改成顯示當時時間,以跑馬燈的方式,向左方捲軸顯示:
import max7219.led as led
import max7219.canvas as canvas
import max7219.transitions as transitions
import time
import datetime
from random import randrange

led.init()

while True:
    t = time.time()
    ctime = datetime.datetime.fromtimestamp(t).strftime('%Y-%m-%d %H:%M:%S')
    led.show_message(ctime, transition = transitions.left_scroll)

顯示結果:

[參考資料]

RasPi.TV:8 x 8 LED array driven by max7219 on the Raspberry Pi via python
程序員聯合開發網:read.pudn.com‎


Share:

星期四, 3月 27, 2014

Raspberry Pi 筆記(十六):製作多媒體伺服機:使用 Samba 及 minidlna

[2014/3/27]
大約在半年前購置一部Pioneer 藍光播放機,主要購買的目的是要能使用外接硬碟碟播放影片。在選單中,除了USB選項外,還多了一個名為DLNA的選項,對於這個功能是毫無所悉。搜尋一下網路資訊,才知道「DLNA是數位生活網路聯盟 (Digital Living Network Alliance ,DLNA)的簡稱,他是由一般消費性電子、行動電話,以及電腦廠商組成的聯盟,該組織的目標在於建立一套可以使得各廠商的產品互相連接,互相適應的工業標準,從而為消費者實現數位化生活。」(來源:維基百科)如果能使用Raspberry Pi 安裝Samba做網路檔案分享,進行影音檔案管理,並結合DLNA Server,方便影音播放機遠端播放串流影音。於是就將一個1T的3.5"外接硬碟,透過USB接到Raspberry Pi,以下就是軟體安裝程序與步驟:


步驟一:安裝Samba軟體
$ sudo apt-get install samba samba-common-bin

如果外掛硬碟是NTFS系統,還要安裝以下套件,才能對檔案或資料夾有寫入權限,不然會出現:mount: warning: /home/pi/shares seems to be mounted read-only.的警告訊息。
$ sudo apt-get install ntfs-3g

NTFS-3G  的功能主要是為 Linux 提供 NTFS 的的驅動程式。讓Linux系統可以讀取NTFS的檔案格式。

步驟二:備份並修改設定檔 /etc/samba/smb.conf
$ sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.old
$ vi /etc/samba/smb.conf 

修改以下幾個地方:
(1) 將 security = share前的#刪掉, 將 user 改成 share
 security = share

(2) 將以下整段文字加入檔案內[homes]之後或適當位置
[myusb]
   comment = Public Storage
   path = /home/pi/shares
   writeable = yes
   browseable = yes
   create mask = 0777
   directory mask = 0777
   read only = no
   guest only = yes
   guest ok = yes

步驟三:重新啟動Samba
$ sudo /etc/init.d/samba stop
$ sudo /etc/init.d/samba start

步驟四:掛載外接硬碟到smb.conf內path指定目錄
$ sudo mount -t ntfs /dev/sda1 /home/pi/shares

這樣就可以透過網路芳鄰對外接硬碟進行檔案存取。


網路芳鄰只是方便檔案複製,並不能直接播放分享資料夾的檔案,如果要遠端播放媒體,必須安裝DLNA Server軟體,我使用的是 minidlna,以下是安裝步驟:

步驟一:安裝minidlna
$ sudo apt-get install minidlna

步驟二:備份並修改設定檔 /etc/minidlna.conf
$ sudo cp /etc/minidlna.conf /etc/minidlna.conf.old
$ sudo vi /etc/minidlna.conf

修改媒體目錄如下:
media_dir=V,/home/pi/shares/Media/Movies
media_dir=P,/home/pi/shares/Media/Picture
media_dir=A,/home/pi/shares/Media/Music

我將USB外接硬碟 mount 到 /home/pi/shares,在硬碟建立 Media 目錄,分成三個子資料夾,分別存放影片、照片及音樂檔。修改後存檔,重新啟動 minidlna。

步驟三:重新啟動 minidlna服務
$ sudo service minidlna force-reload   或
$ sudo service minidlna stop
$ sudo service minidlna start

minidlna設定檔中指定的Port 是 8200,如果你要看媒體目錄可以透過瀏覽器連線到http://<Raspberry IP>:8200,以我的Pi 為例:
http://192.168.1.107:8200

顯示畫面如下:

Pioneer 藍光播放機的選單已經加入Raspberrypi:minidlna,可用遙控器進行播放媒體。

[參考資料]

elinux.org: R-Pi_NAS
TechSwamp: Setting Up a Raspberry Pi-powered Headless Media Server and NAS
Share:

星期二, 3月 18, 2014

Raspberry Pi 筆記(十五):超音波測距離

[2014/03/18]
看到機器小車上大多會裝上一個超音波測距模組,看起來像是兩個眼睛,引發我的好奇,如何能利用超音波來測距離呢?於是網購買了幾個套件,利用上班空閒之餘來研究一下這幾個模組的特性。以下是超音波模組含溫度補償功能的US-100。
上一篇提到智能小車除了用鍵盤控制方向外,還可以透過距離偵測感應轉彎,避免碰撞前方物體,本篇就來瞭解超音波測距的一些功能及測試結果。



[基礎知識:超音波測距]

超音波測距的方式是發射一個電波,當電波遇到物體反射回來,再被測距儀偵測到反射電波,利用來回時間與音波的速度算出距離,計算公式如下:

距離=(音波發射與接收時間差 * 聲音速度(340M/S))/2;

聲音的速度,在一般空氣中約為每秒340公尺,因來回時間要將距離除以二,才是單程的距離。實際的聲音速度決定於好幾個環境因素,其中一個是溫度,計算時,需將環境因素考慮在內,才能更精確計算距離。

我在網路上購買的是US-100這個型號,根據規格文件,這個模組最遠可測得2公分~4.5公尺, 輸入電壓大約 2.4V ~ 5.5V,其偵測廣度大約是15度。這個模組具有溫度感測,距離值已經溫度調校,無需再根據環境溫度對超音波聲速進行校正。



在這個模組背面有一個Jumper,來控制兩種模式:
• open:將Jumper拔起來,此時為GPIO 模式(電位觸發模式)
• short:將Jumper 套上,此時設定為UART串列通訊模式

US-100有五個pin腳,說明如下:
• VCC:接電源(範圍2.4V~5.5V)。
• Trig/TX:UART 模式下,接外部電路UART 的TX 端;為GPIO模式時,為訊號發送端 Trigger。
• Echo/RX:UART 模式下,接外部電路UART 的RX 端;為GPIO模式時,為訊號接收端 Echo 。
• GND:接地,沒有使用。
• GND:電路接地。

工作方式:
透過Trig接腳發出一個10us(10^-6 秒)以上的高電位,此時等待Echo高電平輸出,一旦有輸出就可以開始計時,此時模組會發送8個40khz的方波,並開始自動檢測是否有返回信號;當偵測到反射訊號時,此時Echo接腳變為低電位。計算持續高電位的時間,也就是這次測距的時間。如果加上迴圈,就可以一直偵測前方移動物體的距離。

[材料]

• Raspberry Pi 主板 x1
• US-100超音波模組 x1
• 連接線  x4

[線路連接與電路圖](圖片以HC-SR04替代)

• US-100 VCC接pin2(+5V),GND接pin6(GND)
• US-100 Trig/TX接Pin16(GPIO23),Echo/RX接Pin18(GPIO24)


[程式碼]

import RPi.GPIO as GPIO
import time
trigger_pin = 23
echo_pin = 24

GPIO.setmode(GPIO.BCM)
GPIO.setup(trigger_pin, GPIO.OUT)
GPIO.setup(echo_pin, GPIO.IN)

def send_trigger_pulse():
    GPIO.output(trigger_pin, True)
    time.sleep(0.001)
    GPIO.output(trigger_pin, False)

def wait_for_echo(value, timeout):
    count = timeout
    while GPIO.input(echo_pin) != value and count > 0:
        count = count - 1

def get_distance():
    send_trigger_pulse()
    wait_for_echo(True, 5000)
    start = time.time()
    wait_for_echo(False, 5000)
    finish = time.time()
    pulse_len = finish - start
    distance_cm = pulse_len * 340 *100 /2
    distance_in = distance_cm / 2.5
    return (distance_cm, distance_in)

while True:
    print("cm=%f\tinches=%f" % get_distance())
    time.sleep(1)

[測試結果]

我在超音波偵測頭前放一把尺,然後在刻度位置放置一個物體,程式回報測得的數據跟尺的刻度非常接近,誤差不到一公分,以物體感應來說,算是相當準確。

[參考資料]

• Arduino 超音波測距機設計與製作(作者:曹永忠、許智誠、蔡英德)
Raspberry Pi Cookbook

Share:

星期五, 3月 14, 2014

Raspberry Pi 筆記(十四):用鍵盤透過無線網路控制智能車

[2014/03/13]
在學習Arduino的時候,一直想要組一部智能小車,可以透過藍牙或紅外線遙控,可是礙於車體壓克力版、車輪等問題,想要自己製作,又沒有工具及材料,一直遲遲無法完成。一個多月前在逛光華商場時,看到智能小車的車體套件,包括四個馬達含輪子及一個壓克力版車體,價格有貴一點點,還是買了,想說之前購買的L298N電機馬達驅動模組及電池盒,應該就可以組合起來讓小車行走。在組合之前還是要改裝一下,主要是我買的L298N只能控制兩組馬達,因此將前面兩個輪子改裝成可360度旋轉的單輪,這個材料是在Homebox買的。
過程中為了讓車子的能離開電源插座,特別外接一個小的行動電源,增加車輛的移動性。同時也使用USB無線網路,才能透過遠端登入的方式,使用鍵盤控制車輛的前進、倒退與左右方向。以下就來看看我是怎麼做的:


基礎知識:L298N機電馬達驅動模組
L298N採用15腳封裝。主要特點是:工作電壓高,最高工作電壓可達46V;輸出電流大,瞬間峰值電流可達3A,持續工作電流為2A;額定功率25W。內含兩個H橋的高電壓大電流全橋式驅動器,可以用來驅動直流電動機和步進電動機、繼電器線圈等感性負載。
使用L298N驅動電機,可以驅動一台兩相馬達或四相馬達,也可以驅動兩台直流馬達。

這個L298N模組提供5V供電。當+12V輸入電壓為7V-35V時,可以提供供電給 Raspberry Pi的主機板使用。如果+12V電壓輸入7V以下,僅適合用作推動馬達的電壓,Pi主機板的電源,建議另外提供電源使用。

這個模組有2路H橋驅動,可同時驅動兩個馬達,接法如下圖:
Enable A短路連接器連接時可控制IN1、IN2,Enable B可控制IN3、IN4,其意義代表控制馬達轉動的方向。舉例來說,當IN1為高電位,IN2低電位時,通知馬達正轉,如果要反轉時,則讓IN2為高電位,IN1低電位,馬達則會向反方向轉動。如下表:


[材料]

• Raspberry Pi 主板 x 1
• 智能車壓克力板 x1
• 差速馬達  x2
• 360度迴轉軸輪 x1
• L298N電機馬達驅動模組 x 1
• 6V(1.5V x 4)電池盒 x 1個
• 連接線 x 6條
• 行動電源 x 1

[線路連接與電路圖]

• L298N 兩側兩條線路分別接到左右兩邊的馬達
• 電池盒的負極(黑色)接 L298N 接地GND,正極(紅色)接 L298N +12V電源輸入
• Raspberry Pi pin2(+5V)接到L298N +5V電源輸入,pin6(GND)接到L298N GND接地
• Raspberry Pi pin11(GPIO 17)、pin12(GPIO18)、pin15(GPIO 22)、pin16(GPIO23)分別接到IN1~IN4

程式中有個比較特別的地方是我用迴圈並偵測是否按了鍵盤按鍵(不需按Enter)的一個函數getkey(),需要 import curses,也必須設定 stdscr = curses.initscr(),才能透過getey取得鍵盤按鍵。鍵盤控制方式如下:
• q 結束程式
• w 前進
• x 後退
• d 向右轉
• a 向左轉

[程式碼]

import RPi.GPIO as GPIO
import curses
import time
from curses import wrapper

GPIO.setmode(GPIO.BCM)

GPIO.setup(17, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(22, GPIO.OUT)
GPIO.setup(23, GPIO.OUT)

stdscr = curses.initscr()
stdscr.clear()

while True:
    ch = stdscr.getkey()
# Quit 
    if ch == 'q':
       curses.endwin()
       GPIO.output(17, False)
       GPIO.output(18, False)
       GPIO.output(22, False)
       GPIO.output(23, False)
       break

# Forward
    if ch == 'w':
       GPIO.output(17, False)
       GPIO.output(18, True)
       GPIO.output(22, False)
       GPIO.output(23, True)

# Backward
    if ch == 'x':
       GPIO.output(17, True)
       GPIO.output(18, False)
       GPIO.output(22, True)
       GPIO.output(23, False)

# Turn Right
    if ch == 'd':
       GPIO.output(17, False)
       GPIO.output(18, True)
       GPIO.output(22, False)
       GPIO.output(23, False)

# Turn Left
    if ch == 'a':
       GPIO.output(17, False)
       GPIO.output(18, False)
       GPIO.output(22, False)
       GPIO.output(23, True)

[執行結果]


接下來還有些控制智能小車的想法,例如加裝避免碰撞的感應器讓小車自動轉彎、使用網頁操控小車、透過藍牙控制等方法,等有空時,再慢慢來實驗。
Share:

星期二, 3月 11, 2014

Raspberry Pi 筆記(十三):使用藍牙USB連接GPS

[2014/03/11]
在網路尋找 Raspberry Pi 相關的資訊時,看到有關 Pi 如何透過藍牙跟其他裝置連線,想到幾年前公司曾送給同仁一個 GPS,這個GPS是跟 PDA連接使用,也是透過藍牙來連線。想說試看看是否可以透過 Pi來連接這個 GPS。於是找一個藍牙 USB 接在 Pi,正確安裝驅動程式後,是否能讀取 GPS 相關資訊。


[安裝程序]


安裝藍牙主程式及工具:
$ sudo apt-get install bluetooth bluez-utils blueman

安裝完成後,看看系統是否能讀取藍牙USB:
$ sudo lsusb

顯示結果如下:(藍色那一行就是藍牙USB的位址及製造廠商)
Bus 001 Device 015: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 016: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 017: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter
Bus 001 Device 018: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)


檢視藍牙程式是否正常運作:
$ sudo /etc/init.d/bluetooth status

[ ok ] bluetooth is running.

如果要掃描其他藍芽裝置,可輸入以下指令:
$ sudo hcitool scan

Scanning ...
        00:02:78:14:24:41       Leadtek 9559 series BT GPS

找到開周邊啟藍芽的GPS,設備位址 00:02:78:14:24:41會不一樣。

如果要查詢USB藍牙的設備位址,可以輸入以下指令查詢:
$ sudo hciconfig

Ping 藍牙裝置看看是否回應 (以下範例是我的GPS設備位址)
$ sudo l2ping -c 3 00:02:78:14:24:41

Ping: 00:02:78:14:24:41 from 00:15:83:15:A3:10 (data size 44) ...
44 bytes from 00:02:78:14:24:41 id 0 time 51.27ms
44 bytes from 00:02:78:14:24:41 id 1 time 25.57ms
44 bytes from 00:02:78:14:24:41 id 2 time 27.74ms
3 sent, 3 received, 0% loss

顯示可以正常回應,但是這還不能接收GPS資訊,只是表示與GPS通訊正常而已。如果要接收資料需要建立通訊Port及啟動GPS Deamon。

步驟一:修改 /etc/bluetooth/rfcomm.conf
$ sudo nano /etc/bluetooth/rfcomm.conf

# RFCOMM configuration file.
rfcomm0 {
#      Automatically bind the device at startup
        bind yes;
#      Bluetooth address of the device
        device 00:02:78:14:24:41;
#      RFCOMM channel for the connection
        channel 1;
#      Description of the connection
        comment "Example Bluetooth device";
}

預設值都加了#當作註解,要將#拿掉。

步驟二:啟動GPS Deamon
gpsd /dev/rfcomm0

執行上述兩個步驟後,就可以啟動GPS程式。在SSH視窗執行 cgps 啟動GPS視窗:
$ cgps -s
-s  : 是安靜模式,不要將GPS原始資料顯示在視窗

在x-windows可執行 xgps 啟動GPS視窗
$ xgps


[參考資料]

豆腐腦:Raspberry Pi 安裝USB Bluetooth Dongle
Ubuntu Community :Using Bluetooth GPS
Share:

星期四, 2月 27, 2014

Raspberry Pi 筆記(十二):控制步進馬達

[2014/02/26]
先前寫一篇文章 Arduino筆記(八):控制步進馬達 提到如何用 Arduino 控制步進馬達,這幾天同時有兩三位網友問了相關問題,因此決定用 Raspberry Pi 來執行步進馬達控制方法,也對照一下Arduino的連接圖,轉為Raspberry Pi的線路圖。

今天晚上的實作,發生幾個問題:一開始 ULN2003APG接到 Raspberry Pi的接腳差一格,從pin2 ~ pin5,執行程式的結果就是只能正轉,怎麼樣都不能倒轉;仔細檢查後發現才改回來 pin1~ pin4。執行程式結果還是只能正轉,包括執行 backwards 那段程序也正轉,仔細檢查發現是程式中的接腳順序錯了,a1, a2, b1, b2順序對調,等修正後,終於能正確控制正反轉了。



[步進馬達]

步進馬達的種類依照結構來分可以分成三種:
• 永久磁鐵 PM 式 (permanent magnet type)
• 可變磁阻 VR 式 (variable reluctance type)
• 複合式 (hybrid type)

PM式步進馬達的轉子是以永久磁鐵製成,其特性為線圈無激磁時,由於轉子本身具磁性故仍能產生保持轉矩。

VR式步進馬達的轉子是以高導磁材料加工製成,由於是利用定子線圈產生吸引力使轉子轉動,因此當線圈未激磁時無法保持轉矩,此外,由於轉子可以經由設計提高效率,故VR式步進馬達可以提供較大之轉矩,通常運用於需要較大轉矩與精確定位之工具機上,VR式的步進角一般均為15°。

複合式步進馬達在結構上,是在轉子外圍設置許多齒輪狀之突出電極,同時在其軸向亦裝置永久磁鐵,可視為PM式與VR式之合體,故稱之為複合式步進馬達,複合式步進馬達具備了PM式與VR式兩者的優點,因此具備高精確度與高轉矩的特性,複合式步進馬達的步進角較小,一般介於1.8°~3.6°之間,最常運用於OA器材如影印機、印表機或攝影器材上。

步進馬達依定子線圈的數目可分成2相,3相,4相及5相式,小型步進馬達以4相式較普遍,高速型步進馬達則以5相式為主。4相步進馬達頂部和底部,兩側是一對,如下圖:
即(相與相)和(相與相 ),同一線圈繞在同一磁極上、兩組線圈所繞的方向相反,只需對其中一組線圈激磁,便可以改變定子磁場的極性,因此不可將A相與-A相 (或B相與-B相 ) 線圈同時激磁。

馬達正轉時,依序從( )改變線圈磁性,即可讓步進馬達正轉,如下圖:




馬達反轉時,依序從( )改變線圈磁性,即可讓步進馬達反轉,如下圖:


[材料]

• 麵包板 x 1
• Raspberry Pi Model B主板 x 1 (使用無線網卡)
• ULN2003APG x 1
• 步進馬達 x 1
• 連接線 x N條

[線路連接與電路圖]

• Pi Pin2接到麵包版 + 端,再接到步進馬達紅色線。
• Pi Pin6接到 ULN2003APG(以下簡稱2003) Pin8(GND),Pi Pin8(GPIO14)接到 2003 Pin1(IN1),Pin10(GPIO15)接到 2003 Pin2(IN2),Pin11(GPIO17)接到 2003 Pin3(IN3),Pin12(GPIO18)接到 2003 Pin4(IN4)。
• 步進馬達藍色線接到 2003 Pin14(OUT3),黃色線接到 2003 Pin13(OUT4),橘色線接到 2003 Pin15(OUT2),粉紅色線接到 2003 Pin16(OUT1)。

上面這樣說明是不是看到眼都花了,整理成下表,比較容易瞭解:

• ULN2003APG與步進馬達連接線路
ULN2003APG
Raspberry Pi
步進馬達
Pin 8  (Ground)
Pin 6 (Ground)

VCC   (5V)
Pin 2 (3.3V)
紅色線
Pin1 (IN1)
Pin8 (GPIO14)

Pin2 (IN2)
Pin10 (GPIO15)

Pin3 (IN3)
Pin11 (GPIO17)

Pin4 (IN4)
Pin12 (GPIO18)

Pin14 (OUT3)

藍色
Pin13 (OUT4)

黃色
Pin15 (OUT2)

橘色
Pin16 (OUT1)

粉紅色


[程式]

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

a1_pin = 14
a2_pin = 15
b1_pin = 17
b2_pin = 18

GPIO.setup(a1_pin, GPIO.OUT)
GPIO.setup(a2_pin, GPIO.OUT)
GPIO.setup(b1_pin, GPIO.OUT)
GPIO.setup(b2_pin, GPIO.OUT)

forward_seq = ['1010', '0110', '0101', '1001']
reverse_seq = ['1001', '0101', '0110', '1010']

def forward(delay, steps):
    for i in range(steps):
        for step in forward_seq:
            set_step(step)
            time.sleep(delay)

def backwards(delay, steps):
    for i in range(steps):
        for step in reverse_seq:
            set_step(step)
            time.sleep(delay)

def set_step(step):
    GPIO.output(a1_pin, step[0] == '1')
    GPIO.output(a2_pin, step[1] == '1')
    GPIO.output(b1_pin, step[2] == '1')
    GPIO.output(b2_pin, step[3] == '1')

while True:
    set_step('0000')
    delay = raw_input("Delay between steps (milliseconds)?")
    steps = raw_input("How many steps forward? ")
    forward(int(delay) / 1000.0, int(steps))

    set_step('0000')
    steps = raw_input("How many steps backwards? ")
    backwards(int(delay) / 1000.0, int(steps))

[執行結果]



[參考資料]

Raspberry Pi Cookbook by Simon Monk
• The Hobby Electronic:Operation principle of stepper motor
黃兄知識庫
Share: