星期一, 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: