Raspberry Pi B+ 入手順便讓他唱小蘋果

以下會簡單介紹 Raspberry Pi 的用途,安裝 Raspbain 作業系統,最後寫一個 Python 程式讓 Raspberry Pi 透過蜂鳴器唱出世界名曲-小蘋果。廢話不多說直接先 po 成果:


流水帳

Raspberry Pi 出一陣子了,突然想買是因為最近出二代了,價錢不變但 CPU 變四核心,也就還蠻心動的,在 RS 上買含運也不到1200元, 但下完單才發現三月中才能拿到(靠!我是想買來過年玩的誒),就在機器人王國又花了一千七百多買了Raspberry Pi B+ 套餐(多外殼,5V2A 電源 + 金士頓 16G micro SD 卡),現在算算反正我一時用不到很多輸出,應該就直接花五百單買出清中的 Raspberry Pi B 就夠了。總共我買了以下設備:

2015-02-13 15.11.49
  • Raspberry Pi 2 B(還在海上...)
  • Raspberry Pi B+
  • b+ 透明外殼(可用在 2 上)
  • 5V2A 電源
  • 金士頓 class 10 16G micro SD 卡
  • 羅技無線鍵盤 k400r(含觸碰板)
  • 麵包板
  • 杜邦線公+母
  • LED
  • 電阻
  • 蜂鳴器

Raspberry Pi 能做啥?

反正出發點跟百元筆電一樣,是希望大家能以比較低的價格擁有一個能寫程式的硬體,基本上可以想成一台像信用卡大小的電腦,上面跑 Linux 的作業系統,插上滑鼠鍵盤再用 HDMI 輸出到螢幕上就是一台電腦。

因為價格實在太便宜了,除了拿來當電腦用以外,有人會拿來安裝軟體/作業系統,把 Raspberry Pi 搖身一變當成 Web Server,家庭娛樂中心,NAS,電動模擬器來使用。

2015-02-14 11.20.25

另外 Raspberry Pi 版子上有一組 GPIO 輸入輸出界面,裝上感應器/攝影機當輸入,裝上馬達/蜂鳴器/LED Matrix 當輸出,輸出輸入都可以透過程式(Python,Java...)的方式來控制,對軟體工程師來說,瞬間突破了只能用鍵盤當輸入,螢幕顯示當輸出的限制,感覺又可以幹很多壞事了...

安裝 OS

我選的是最多人用的 Raspbain,參考官方說明絕對不會錯,大概步驟如下:
  1. 格式化 SD 卡
  2. 下載 Raspbain
  3. 透過特殊軟體將 Raspbain 寫到 SD 卡上
  4. SD 卡裝到 Raspberry 後開機
  5. 第一次開機會進入設定畫面(鍵盤,語系,開啟 SSH...etc)
裝完後,基本上你就有一台圖形化的 Linux 電腦可用了。

第一支 Script

因為之後這台 Raspberry Pi 可能會拿來拿去,不想每一次都要接上螢幕鍵盤進去看 IP,所以想要一開機就自己把自己取得的 IP 寄到我的 Gmail 信箱,詳細步驟如下:
  1. 寫一個 Python Script - send_ip.py (程式碼參考下面)取得 IP 透過 Gmail 寄到你指定的信箱。
  2. 寫一個 Script - laucher.sh 內容為執行 send_ip.py。
  3. 將 laucher.sh 設定成開機時會自動執行。
    1. 將 launcher.sh 拷貝到 /etc/initd
    2. sudo update-rc.d launcher.sh defaults # 新增開機執行
    3. sudo chmod +x /etc/init.d/launcher.sh # 增加執行的權限
這樣每次開機就會收到 Raspberry 取得的 IP,我就可以用這 IP 來連 SSH。如果屌一點應該要改成用外接 LED 跑馬燈的方式來顯示取得的 IP。

#!/usr/local/bin/python
import commands
def getIpList():
ipList = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
"awk {'print $2'} | sed -ne 's/addr\:/ /p'")
return ipList
import smtplib
def sendViaGmail(title, message):
fromaddr = 'foo@gmail.com'
toaddrs = 'bar@gmail.com'
msg = "\r\n".join([
"From: foo@gmail.com",
"To: bar@gmail.com",
"Subject: " + title,
"",
message
])
username = 'your_gmail_id@gmail.com'
password = 'your_gmail_password'
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
import socket
message = socket.gethostname() + ":\n" + getIpList()
title = socket.gethostname() + " wake up now"
print "Sending mail..."
sendViaGmail(title, message)
view raw send_ip.py hosted with ❤ by GitHub

小蘋果

書看再多還不如動手做比較印象深刻,我買 Raspberry Pi 主要是想玩一些硬體的東西,未來搭配程式可以做一些小玩具,第一支程式的目標是讓 Raspberry Pi 唱出小蘋果,當然一開始是完全沒頭緒,只知道用 Python 可以控制 GPIO,GPIO 的訊號可以控制蜂鳴器發出聲音。

一開始是直接 SSH 連進去用 vim 寫 Python,好處是直接在上面跑結果,但 vim 對我來說還是有些難用。後來想改用在 macbook pro 上用 IDE 寫,然後透過 git 兩邊作同步的方式,但實際應用每次修改都要上 commit / push,Raspberry Pi 又要 pull 下來才能執行,感覺更麻煩了。

最終改用 FTP + git 的方式來開發,Raspberry Pi 上裝 vftpd 當作 FTP Server,在 macbook pro 上開發透過 FTP 上傳到 Raspberry Pi(部署至硬體),Raspberry Pi 執行成功在 commit 到 git 上(版本控管)。FTP 上傳這段,應該有 IDE 支援,不過過年時間有限 + 還不確定未來都是用 Python 來開發,就先這樣。

上網找到這影片如下,最後我的接法跟他差不多。


  • 硬體部分:透過 GPIO 接上蜂鳴器當輸出。
  • 軟體部分:透過 Python (程式碼如下)控制 GPIO 接上蜂鳴器的針腳,改變其發生頻率和播放時間。
最終就可以聽到小蘋果了!

#!/usr/local/bin/python
import time
import RPi.GPIO as GPIO
# http://coopermaa2nd.blogspot.tw/2010/12/arduino-lab6.html
B0 = 31
C1 = 33
CS1 = 35
D1 = 37
DS1 = 39
E1 = 41
F1 = 44
FS1 = 46
G1 = 49
GS1 = 52
A1 = 55
AS1 = 58
B1 = 62
C2 = 65
CS2 = 69
D2 = 73
DS2 = 78
E2 = 82
F2 = 87
FS2 = 93
G2 = 98
GS2 = 104
A2 = 110
AS2 = 117
B2 = 123
C3 = 131
CS3 = 139
D3 = 147
DS3 = 156
E3 = 165
F3 = 175
FS3 = 185
G3 = 196
GS3 = 208
A3 = 220
AS3 = 233
B3 = 247
C4 = 262 # Do
CS4 = 277
D4 = 294 # Re
DS4 = 311
E4 = 330 # Mi
F4 = 349 # Fa
FS4 = 370
G4 = 392 # So
GS4 = 415
A4 = 440 # La
AS4 = 466
B4 = 494 # Si
C5 = 523 # Do
CS5 = 554
D5 = 587 # Re
DS5 = 622
E5 = 659 # Mi
F5 = 698 # Fa
FS5 = 740
G5 = 784 # So
GS5 = 831
A5 = 880 # La
AS5 = 932
B5 = 988 # Si
C6 = 1047 # Do
CS6 = 1109
D6 = 1175 # Re
DS6 = 1245
E6 = 1319 # Mi
F6 = 1397 # Fa
FS6 = 1480
G6 = 1568 # So
GS6 = 1661
A6 = 1760 # La
AS6 = 1865
B6 = 1976 # Si
C7 = 2093 # Do
CS7 = 2217
D7 = 2349
DS7 = 2489
E7 = 2637
F7 = 2794
FS7 = 2960
G7 = 3136
GS7 = 3322
A7 = 3520
AS7 = 3729
B7 = 3951
C8 = 4186
CS8 = 4435
D8 = 4699
DS8 = 4978
M_1 = C4
M_2 = D4
M_3 = E4
M_4 = F4
M_5 = G4
M_6 = A4
M_7 = B4
H_1 = C5
H_2 = D5
H_3 = E5
H_4 = F5
H_5 = G5
H_6 = A5
H_7 = B5
'''
http://www.chaodikong.com/article/2014/0917/article_26645.html
'''
def playLittleApple():
GPIO.setmode(GPIO.BOARD)
#GPIO.setmode(GPIO.BCM)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50) # pin12(GPIO.BOARD) = GPIO14(GPIO.BCM)
p.start(15) # 0 <= DV <= 100
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, M_6, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_6, 4)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, M_6, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, H_1, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_6, 4)
play(p, M_6, 0.5)
play(p, M_6, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, H_1, 0.5)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, M_7, 1.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 2)
play(p, M_6, 0.5)
play(p, M_6, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, H_1, 0.5)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, M_7, 1.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 0.5)
play(p, M_6, 0.5)
play(p, M_7, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, H_1, 1)
play(p, H_1, 1)
play(p, H_1, 1)
play(p, H_1, 1)
play(p, H_3, 1)
play(p, H_1, 1)
play(p, H_2, 1)
play(p, M_6, 1)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, H_2, 0.5)
play(p, M_6, 2)
play(p, H_3, 1)
play(p, H_1, 1)
play(p, H_2, 1)
play(p, H_2, 1)
play(p, H_5, 0.5)
play(p, H_3, 0.5)
play(p, M_7, 1)
play(p, H_1, 1)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 1)
play(p, M_7, 0.5)
play(p, H_1, 0.5)
play(p, H_2, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 1)
play(p, H_6, 0.5)
play(p, H_5, 0.5)
play(p, H_3, 0.5)
play(p, H_5, 0.5)
play(p, H_3, 1)
play(p, H_2, 1)
play(p, H_1, 1)
play(p, H_2, 0.5)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_5, 0.5)
play(p, H_5, 1)
play(p, H_5, 1)
play(p, H_5, 1)
play(p, H_5, 1)
play(p, H_3, 1)
play(p, H_1, 1)
play(p, H_2, 1)
play(p, M_6, 1)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, H_1, 0.5)
play(p, H_2, 0.5)
play(p, M_6, 2)
play(p, H_3, 1)
play(p, H_1, 1)
play(p, H_2, 1)
play(p, H_2, 0.5)
play(p, H_2, 0.5)
play(p, H_5, 0.5)
play(p, H_3, 0.5)
play(p, M_7, 1)
play(p, H_1, 1)
play(p, H_1, 0.5)
play(p, M_7, 0.5)
play(p, M_6, 1)
play(p, M_7, 0.5)
play(p, H_1, 0.5)
play(p, H_2, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 1)
play(p, H_6, 0.5)
play(p, H_5, 0.5)
play(p, H_3, 0.5)
play(p, H_5, 0.5)
play(p, H_3, 1)
play(p, H_2, 1)
play(p, H_1, 1)
play(p, H_2, 0.5)
play(p, H_3, 0.5)
play(p, H_2, 0.5)
play(p, M_5, 0.5)
play(p, M_5, 1)
play(p, M_6, 1)
play(p, M_6, 0.5)
play(p, H_1, 0.5)
play(p, M_6, 1)
play(p, M_6, 1)
p.stop
GPIO.cleanup()
def play(p, frequency, tempo):
p.ChangeFrequency(frequency)
time.sleep(0.5 * tempo)
def playDoReMi():
GPIO.setmode(GPIO.BOARD)
#GPIO.setmode(GPIO.BCM)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50) # pin12(GPIO.BOARD) = GPIO14(GPIO.BCM)
p.start(25) # 0 <= DV <= 100
print "Do"
p.ChangeFrequency(523)
time.sleep(1)
print "Re"
p.ChangeFrequency(587)
time.sleep(1)
print "Mi"
p.ChangeFrequency(659)
time.sleep(1)
p.stop()
GPIO.cleanup()
#playDoReMi()
#playDoReMi()
playLittleApple()
參考:

結語

整篇文章看完,我們可以得到以下結論:
  • Raspberry Pi 不會很貴!
  • Raspberry Pi 可以拿來當 Linux Server 用!
  • 透過 Raspberry Pi 的 GPIO,程式設計師可以有更多種輸入/輸出的選擇!

Sketch 3 - MAC 上的向量繪圖軟體

原本做圖都是用 inkscape,優點是開源軟體(沒有盜版問題)/免費/跨平台(Linux,MAC,windows都吃),但自從轉用 macbook 以後,MAC 版的 inkscape 要跑在 X11上,動不動要更新,要不就是開很久根本不知道是不是開不起來,還有我比較笨,一些功能都要找一下,久沒用又要花時間想上次是去哪裡打開的(比如圖層,物件的對齊...)。

有時候只是要做簡單的海報或是示意圖,大概都是用 Google Doc 裏的簡報,優點是雲端存取/簡單好用/物件對齊很直覺,不過就沒辦法做些漸層/陰影/光線...等可以增加質感的設計。

某天在推特上看到推友這一篇 - My Must-Have Mac Apps, 2014 Edition(漫步版),裡面提到

Sketch,这应该是今年对我来说最重要的、让我收获最多的软件了。这是一个矢量设计软件,应该很多人都已经听过或用过,它见长于 Web Design、Mobile Design,它让我一个不懂 PS 的人也可以尝试去画一些东西,比如网站的界面,手机 app 界面和图标等,我现在也用它来画原型(线框图、高保真、低保真图等)。
想到我每次用 inkscpae 都用到很卡很度爛,Google Doc 功能又不夠強大,就怒買一套裝在 macbook 裡了,一套台幣三千多,沒錢買的或是要找破解的可以離開了...

用了幾天下來,心得如下:
  • 想要的功能都有,對齊/光影/遮罩...
  • 功能放的位置蠻直覺的,不會找不到。
  • 網路上有許多別人提供的專案範本,打開來複製頁面就可以用了。
  • inkscape 可以 uninstall 了...
順手寫了投影片,讓大家快速了解 Sketch 3 的功能/介面/相關資源,沒啥內容但足夠讓你判斷要不要去買一套來裝了。