Raspberry PIを箱から出してGoアプリを動かす
Hello Raspberry!
8th gradeの長女(Mayaa)が最近いきなり電子工作に興味をもってブレッドボードなどを買ってきたので、対抗してRaspberry PIをはじめました。幸いにまだ臭いとかは言わないまでも、いずれ生ゴミ扱い仕掛けて来かねない思春期の娘に対して、父が一度はドヤ顔をする予定。
Raspberry PIを購入し、家にあるものかき集め
- Raspberry PI 3 model B、今回唯一の購入品。Amazon.comで新品$36.91
- micro SSD 4GBとSSDジャケット
- iPad用アダプタ 12wとmini USBケーブル。2.4Aなので推奨2.5A以上というのを満たさないが問題ない
- ルーターとLANケーブル、Comcastの引込み線が居間にあるうえ、Google OnHubなので有線ポートが一つしかないから設置条件が著しく制限されてるけど、一旦WiFi設定したら抜いて自室へ移動させるので問題ない
- MacBook Pro。一世代前のものなのでSSDが直接挿せる
- iPhone 5s。普段使いのスマホで、今回はOnHubを見るためのもの。
OS書き込み、起動
まずとにかくOSをダウンロードしてきて、SSDに書き込む。SSDが4GBしかないし、キーボードもモニターも余ってないのでヘッドレスで全部やることとして、GUIは諦めてRaspbianのJessie Liteの方にしました。MBPにジャケットを着せたmicro SSDを挿してOSインストールします。SSDはすでにFAT32でフォーマットしてあった。
Installing operating system images on Mac OS - Raspberry Pi Documentation
$ sudo diskutil unmountDisk /dev/disk2 $ sudo dd bs=1m if=~/2016-09-23-raspbian-jessie-lite.img of=/dev/rdisk2
SSDを抜き、Raspberry PI本体に挿す。LANケーブルとマイクロUSB電源ケーブルを接続すると、起動。
写真はインスタグラムにアップするために撮ったんだけど、実はこのときは書き込み失敗してたみたいでちゃんと上がってませんでした。書き込み成功すると勝手にマウントされるのでわかります。正常動作中は通電の赤LEDが常時点灯+動作状態表示の緑LEDが点滅します。
間違ってLinux PCでの作業ドキュメント読んでてddコマンドのパラメータでbs=4mとあったので1回目は間違ってそうしてましたがそれがいけなかったのか、それともフォーマットが悪かったのか。フォーマットしなおした後でbs=1mでの書き込みで成功しています。
SSHでアクセス
SSH using Linux or Mac OS - Raspberry Pi Documentation
iPhoneのOnHubアプリでIPを調べる。"raspberrypi"で見つかった。今回は192.168.86.107。
$ ssh pi@192.168.86.107 The authenticity of host '192.168.86.107 (192.168.86.107)' can't be established. ECDSA key fingerprint is SHA256:C3eTyJeoxwm5/+PgxlEwFy7bQYUSHn4v3beRUGiWg8E. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.86.107' (ECDSA) to the list of known hosts. pi@192.168.86.107's password: The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.
WiFiを起こす
Setting WiFi up via the command line - Raspberry Pi Documentation
pi@raspberrypi:~ $ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf
あらかじめ $ sudo wpa_passphrase P807NETWORK password でつくったnetwork設定ブレースを末尾にコピペ。P807NETWORKはウチのSSIDで、米国にくる前に住んでたマンションの部屋番号由来です。pskはところどころxでつぶしてます。
デフォルトではcountryがGBだったのでUSに変更。Raspberry PIはたしか英国発でしたね。
# /etc/wpa_supplicant/wpa_supplicant.conf country=US ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="P807NETWORK" psk=70a7fc3xx0aa1f72f8xfa58xxcd7aa833xxx6023e4xx1d621119cb9d3e20bd81 }
反映。
pi@raspberrypi:~ $ sudo ifdown wlan0 ifdown: interface wlan0 not configured pi@raspberrypi:~ $ sudo ifup wlan0
LANケーブルはもう抜いちゃう。
確認。
OnHubアプリでもう一回IPを探すと、同じ"raspberrypi"で今回は192.168.86.113にみつかりました。sshで再接続。
pi@raspberrypi:~ $ ifconfig eth0 Link encap:Ethernet HWaddr b8:27:eb:44:d1:0b UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:149 errors:0 dropped:2 overruns:0 frame:0 TX packets:39 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:25148 (24.5 KiB) TX bytes:6210 (6.0 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) wlan0 Link encap:Ethernet HWaddr b8:27:eb:11:84:5e inet addr:192.168.86.113 Bcast:192.168.86.255 Mask:255.255.255.0 inet6 addr: fe80::e987:c595:7e09:9dae/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:2449 errors:0 dropped:25 overruns:0 frame:0 TX packets:175 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:387234 (378.1 KiB) TX bytes:24169 (23.6 KiB)
ストレージのほうも確認しておきます。。。が、何をどう見ればいいんでしょうか。。。うーんと、fdisk。
pi@raspberrypi:~ $ sudo fdisk -l Device Boot Start End Sectors Size Id Type /dev/mmcblk0p1 8192 137215 129024 63M c W95 FAT32 (LBA) /dev/mmcblk0p2 137216 7774207 7636992 3.7G 83 Linux
4GBのSDカードだから、おそらくいじる必要ないんじゃないかな。
netatalkでファイル共有する
ファイルをリモートで共有することで、ssh上で書き物するめんどくささを解消する。
pi@raspberrypi:~ $ sudo apt-get update pi@raspberrypi:~ $ sudo apt-get install netatalk
あとはFinderで"移動" > "サーバへ接続..."のダイアログで、afp://192.168.86.113へ接続する。
時刻設定
/etc/ntp.conf を書き換え。http://www.pool.ntp.org/zone/us より、以下を書けといわれた。
# /etc/ntp.conf
(省略)
server 0.us.pool.ntp.org
server 1.us.pool.ntp.org
server 2.us.pool.ntp.org
server 3.us.pool.ntp.org
設定書き換えた後、ntpをリスタートする。
pi@raspberrypi:~ $ sudo service ntp restart
Go Raspberry!
まずは、Go SDKのディストロをダウンロードしてきて、MBPとRaspberry PIのファイル共有で転送します。ファイル大きくないし1個だからすぐ。
Downloads - The Go Programming Language
ファイルはarmv6lのフィックスが入ったファイル名のもの。最新1.7.3でもちゃんとありました。
pi@raspberrypi:~ $ sudo tar -C /usr/local/ -xzf ~/go1.7.3.linux-armv6l.tar.gz
展開はちょっと時間かかる。インストールは以上。
pi@raspberrypi:~ $ mkdir go pi@raspberrypi:~ $ mkdir go/vendor pi@raspberrypi:~ $ vi .bash_profile
Go関係の環境変数を設定します。
# .bash_profile export PATH=/usr/local/go/bin:$PATH export GOPATH=~/go/vendor:~/go
GOPATHはVendoring対応しときました。おもむろにgo getしてみようとしたら、gitがないって怒られた。
pi@raspberrypi:~ $ source .bash_profile
pi@raspberrypi:~ $ go version
go version go1.7.3 linux/arm
pi@raspberrypi:~ $ sudo apt-get install git
pi@raspberrypi:~ $ go get goji.io
予定通りきれいにgoji.ioのソース群がvendorフォルダの下に入ってくれました。
helloサーバー起動
goji.ioのトップにあるサンプルをそのままコピペしてgo runして。。。ブラウザから192.168.86.113:8000が見えない。接続が拒否された。。。sshで別に接続してローカルにcurlすると動く。。。あ、localhostの名前解決の問題か!
// ~/go/src/hello/hello.go package main import ( "fmt" "net/http" "goji.io" "goji.io/pat" ) func hello(w http.ResponseWriter, r *http.Request) { name := pat.Param(r, "name") fmt.Fprintf(w, "Hello, %s!", name) } func main() { mux := goji.NewMux() mux.HandleFunc(pat.Get("/hello/:name"), hello) http.ListenAndServe(":8000", mux) }
上記のようにGoソースを書き換えて、ビルド。
pi@raspberrypi:~ $ go build hello pi@raspberrypi:~ $ ./hello& [1] 15120
最初のgoji.ioサンプルはhttp.ListenAndServeの引数で"localhost:8000"と指定しているからダメでした。上記のように":8000"とポート番号だけにしておけばOK。ブラウザからhttp://192.168.86.113:8000/hello/masatakaをたたくと、ちゃんとでてきます。
GPIO, PMW
GPIO: Models A+, B+, Raspberry Pi 2 B and Raspberry Pi 3 B - Raspberry Pi Documentation
GitHub - sarfata/pi-blaster: PWM on the Raspberry pi - done properly (in hardware, stable)
ブレッドボードとつなぐのはGPIOというもの利用するんですね。汎用目的入出力。ブレッドボードのキットの方に繫ぐための線がついていました。ドキュメントにLED光らせるのがあるので、始めるならここからかな。そして抽象化したライブラリのGobotと、GobotのインフラとしてのPI-Blasterでコントロールする。。。
pi@raspberrypi:~ $ sudo apt-get install autoconf
pi@raspberrypi:~ $ git clone https://github.com/sarfata/pi-blaster.git
pi@raspberrypi:~ $ cd pi-blaster
pi@raspberrypi:~/pi-blaster$ ./autogen.sh
pi@raspberrypi:~/pi-blaster$ ./configure
pi@raspberrypi:~/pi-blaster$ make
pi@raspberrypi:~/pi-blaster$ sudo make install
PI-Blasterのドキュメントにあるとおりに$ sudo apt-get install pi-blaster でインストールしてみようとしたら、一時的なのかわかりませんが"E: Unable to locate package pi-blaster"とエラー出しましたので、githubからクローンしてRaspberry上でmakeする方法としています。ドキュメントのExampleから、PI-Blasterは標準入力でPINに命令を送る仕組みと理解しました。そんなこんなで知らない単語として「PWM」というのが出てきたので調べると。。。
PWM(Pulse Width Modulation)とは、半導体を使った電力を制御する方式の1つです。オンとオフの繰り返しスイッチングを行い、出力される電力を制御します。
。。。気をとりなおして、Gobotをgo get。
pi@raspberrypi:~/pi-blaster$ cd ~ pi@raspberrypi:~$ go get -d -u github.com/hybridgroup/gobot/... pi@raspberrypi:~$ go install github.com/hybridgroup/gobot/platforms/raspi
LEDチカチカ
// ~/go/src/blinker/blinker.go package main import ( "time" "github.com/hybridgroup/gobot" "github.com/hybridgroup/gobot/platforms/gpio" "github.com/hybridgroup/gobot/platforms/raspi" ) func main() { gbot := gobot.NewGobot() r := raspi.NewRaspiAdaptor("raspi") led := gpio.NewLedDriver(r, "led", "7") work := func() { gobot.Every(1*time.Second, func() { led.Toggle() }) } robot := gobot.NewRobot("blinkBot", []gobot.Connection{r}, []gobot.Device{led}, work, ) gbot.AddRobot(robot) gbot.Start() }
こちらのGobotページにあったサンプルをそのまま流し込みました。そしてビルド&実行。
pi@raspberrypi:~$ mkdir ~/go/src/blinker pi@raspberrypi:~$ vi ~/go/src/blinker/blinker.go pi@raspberrypi:~$ go build blinker pi@raspberrypi:~$ ./blinker 2016/11/12 01:41:39 Initializing Robot blinkBot ... 2016/11/12 01:41:39 Initializing connections... 2016/11/12 01:41:39 Initializing connection raspi ... 2016/11/12 01:41:39 Initializing devices... 2016/11/12 01:41:39 Initializing device led ... 2016/11/12 01:41:39 Starting Robot blinkBot ... 2016/11/12 01:41:39 Starting connections... 2016/11/12 01:41:39 Starting connection raspi... 2016/11/12 01:41:39 Starting devices... 2016/11/12 01:41:39 Starting device led on pin 7... 2016/11/12 01:41:39 Starting work... ^C2016/11/12 01:42:27 Stopping Robot blinkBot ...
Crrl+Cで止めました。きちんと動いているっぽいけど、LEDを接続まだしていないので見かけ変わらない。。。ここで長女登場でブレッドボードを組んでもらいました。
サンプルコードで、NewLedDriverの引数に渡されている「7」が物理pin番号の7。GPIOの7番ではない。この7番pinにプラス、39番pin(一番外側のground)にマイナスで、組んだ回路につなげて実行したら、プログラムどおりに1秒毎にトグルされてブレッドボードに刺したLEDがゆっくりとチカチカしました!
このとき注意ポイントは実行時にはsudoで実行すること。最初は知らずにしばらく沈黙してました。GPIO操作はルート権限。まあ、そうでしょうね。
電源オフ
pi@raspberrypi:~ $ sudo shutdown -h now
おー、久しぶりにこのコマンド叩いたよ!クラウド時代には絶対唱えないshutdown。しばらく基盤の緑LEDがチカチカしたのちに基盤の赤LEDのみ点灯となります。電源ケーブル抜いて、おしまい。
感想
想像以上に整備されちゃってて普通のLinux&普通のGoの世界まで速攻で来れちゃいました。今回程度のことなら容量もパワーも十分にあったのでRaspberry PIの上にSDKいれてgo getからアプリケーションビルドまでしましたが、クロスコンパイルする方が筋がよいかもしれません。
モニター&キーボードをつながないなら、Intel Edisonのほうが攻めてる感じになったかなと考えましたが、Raspberry PIのほうが価格が安く、それゆえかケースなどの周辺も充実してるんでOK。