Raspberry Pi3 と Stretch と Electron (2017-12-10)
Raspberry Pi 3 Model B をいまさらながら購入しました。すでにPi1B(256MB)、Pi1B(512MB)、Pi1B+、Pi2Bと持っていて、DragonBoard410C、Hikey、Orange Pi PC2、Orange Pi Zero と節操なく購入していたので、Pi 3 はパスと思っていました。しかし、独身の日(11/11)に安かった(Pi3、ケース、ファン、ヒートシンク、電源で5000円弱)ので、つい AliExpress でポチってしまいました。到着まで3週間ほどかかりましたが、無事入手できました。 5年前の初代 (Pi1B 256MB) と並べてみました。大きさ以外は別物ですね。
今回は Electron で作成された Etcher という Windows、Linux、macOS 用が用意された SD カードへの書き込みソフトでインストールしました。また、Raspbian 自体に Electron がインストールされていることを見つけたので使ってみたいと思います。 OpenGL ES2 の共有ライブラリ (Shared Library) の名称が変更されるという大胆な変更が入っているので、対策方法も紹介したいと思います。
Raspbian Stretch について
3か月ほど前に、Raspberry Pi の OS、Raspbian の新しいディスクイメージである 2017-09-07-raspbian-stretchが公開されました(現在の最新は 2017-11-29-raspbian-stretch)。 stretch というのは Raspbian のもとになっている Linux ディストリビューションの Debian 9.0 の別名です。 Raspberry Pi は2012年の春に最初に出てきたときには OS として Debian 7.0 (wheezy) を ARMv6 用にコンパイルされたものでした。 Raspbian は Debian 'armhf' (hard-float ABI) for Raspberry Pi? という mpthompson の公式フォーラムでの質問 (2012-3-12) から始まったRaspberry Pi専用のディストリビューションです。 Debian も 20 年を超えて、いまだに進化しています。ちょっと Debian のバージョンとコードネーム(Toy Story のキャラクタ) の歴史をDebian version historyからまとめてみました。 公開日はファイルの日付から持ってきたので公式なものではありません。
公開日 | バージョン番号 | コードネーム |
---|---|---|
1996/06/17 | 1.1 | buzz |
1996/12/12 | 1.2 | rex |
1997/07/05 | 1.3 | bo |
1998/07/24 | 2.0 | hamm |
1999/03/09 | 2.1 | slink |
2000/08/15 | 2.2 | potato |
2002/07/19 | 3.0 | woody |
2005/06/06 | 3.1 | sarge |
2007/04/08 | 4.0 | etch |
2009/02/14 | 7.0 | lenny |
2011/02/06 | 6.0 | squeeze |
2013/05/04 | 7.0 | wheezy |
2015/04/26 | 8.0 | jessie |
2017/06/17 | 9.0 | stretch |
2019/07/06 | 10.0 | buster |
2021/08/14 | 11.0 | bullseye |
2023?/xx/xx | 12.0 | bookworm |
2025?/xx/xx | 13.0 | trixie |
Raspberry Pi より wheezy のほうが新しいのは Raspbian が最初は Debian wheezy のベータ版を使っていたためです。
現時点 (2017-12-10) での Debian の最新版は 2017年10月7日に公開された Debian 9.2 です。
SDカードへのイメージの書き込み
Raspberry Piの公式サイト では、初心者は NOOBS でインストールしなさいというようなことが書かれていますが、英語を母国語としていなければ、Raspbianをインストールするほうが、速くて簡単と思います。色々なアプリが最初から入っているデスクトップ版の RASPBIAN STRETCH WITH DESKTOP (2017-11-29-raspbian-stretch) ) をインストールします。
これまでは dd コマンドを使って、SDカードにディスクイメージを書き込みましたが、 今回はターミナルからコマンドを実行せず、マウスで操作して簡単に SDカード にディスクイメージを書き込みできる Linux、Windows、MacOSX に対応した Etcher というアプリを使用することにします。 Linux や MacOSX ではコンソールから dd、Windows では Win32 Disk Imager と環境によって書き込みソフトが異なりましたが、 Etcher ならば、どの環境にも用意されていて、下のスクリーンショットのように使いやすくなっています。
Etcher は、ファイルイメージをSDカードやUSBメモリなどのメディアに書き込むオープンソースのツールで 2017/05/12 に バージョン 1.0.0 になりました。 Etcher は Electron で作成されています。 Electron は Node.js と Chrome (Chromium) を組み合わせたデスクトップアプリケーションの開発環境で、簡単にLinux、Windows、MacOSX に対応できるため最近よく使われています。ブラウザのすべての機能を含むアプリになるので配布するサイズが大きく (50MB〜) なるのが唯一の欠点です。
Windows版でも同じですが、MacOS X 版を起動すると次の画面が表示されます。使い方は、ファイルを選択、書き込み先を指定、書き込みと左から順番にクリックするだけと簡単です。
ディスクイメージ (2017-11-29-raspbian-stretch.zip) を選択します。zip のままでも自動的に展開して書き込まれます。
書き込み先は自動的に選択されますが、中央の「Change」を押して一応確認します。
「Flash」を押すと書き込みが始まります。
イメージを書き込んだ後に、元のファイルと書き込まれたイメージを比較する検証 (validation) も自動的に実行されます。
終了すると、続けて同じイメージを書き込むか、別のイメージを使うかを聞かれます。 ここではメニューから「終了」するか、メニューから [x] して終了します。
16GB のマイクロSDカードに書き込まれたイメージを確認します。 この時点では 5GB ほどが使われています。
Raspbian Stretch の起動
4Kテレビと無線キーボードマウスセットを繋いで、テレビの裏に置きました。
Raspberry Pi 3 をケースに入れた写真が次です。小さいながらもCPUに付けたヒートシンクの上から結構な風量で冷却します。写真の電源ケーブルは安物で電圧降下が大きく稲妻マークが表示されるので、別に購入した太いものに交換しました。 ヒートシンクもセットに入っていたものとは交換しています。
ケーブルがケースの1辺に2本 (電源と HDMI) 接続するだけなので、キレイに設置できます。 使っている CPU ファンの消費電力が 0.5W 程度ですが、Raspberry Pi3自身の消費電力が 2W ほどなので、ファンを切ると 20% 消費電力が下がります。 ファンを切っても CPU の温度が下のように余裕なので、現在はファンは使用していません。
$ cat /sys/class/thermal/thermal_zone0/temp 49388
Pi1B のころは下の写真のように、太いケーブルが色々な方向に刺さっていてケースを固定する必要がありましたが、設置が楽になりました。Raspberry Pi3 の Wifi と無線キーボードマウスセット が激安で入手できるようになったためですが。
電源を入れるだけで、デスクトップが表示されます。42インチの 4K (3840 x 2160) テレビですが、解像度は 1824 x 984 で表示されました(オーバースキャンON)。1m 以上離れても使えるので老眼には優しい環境です。
SDカードのパーティションも最初の起動に容量一杯まで自動的に拡張されます。 ターミナルから確認した結果です。10GB ほどの空きがあります。
pi@raspberrypi:~ $ sudo fdisk -l /dev/mmcblk0 Disk /dev/mmcblk0: 14.9 GiB, 16021192704 bytes, 31291392 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x01142531 Device Boot Start End Sectors Size Id Type /dev/mmcblk0p1 8192 93814 85623 41.8M c W95 FAT32 (LBA) /dev/mmcblk0p2 94208 31291391 31197184 14.9G 83 Linux pi@raspberrypi:~ $ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 15291056 4472468 10134576 31% / devtmpfs 470176 0 470176 0% /dev tmpfs 474784 0 474784 0% /dev/shm tmpfs 474784 18256 456528 4% /run tmpfs 5120 4 5116 1% /run/lock tmpfs 474784 0 474784 0% /sys/fs/cgroup /dev/mmcblk0p1 42137 21474 20663 51% /boot tmpfs 94956 0 94956 0% /run/user/1000
Wifiの設定
まず最初にネットワークを使えるようにします。 右上のアイコンをクリックするとアクセスポイントが表示されます。
アクセスポイントをクリックするとキーの入力が求められます。
キーを入力するとネットワークが有効になります。
いろいろな設定
その他の設定は、ターミナルを開いて「raspi-config」を実行しなくても、メニューから行うことができます。まず、「Raspberry Pi Configuration」を選択します。
「System」というタブが表示されますが、右端の「Localisation」を選択します。
一番上の「Set Locale」というボタンを押します。
ここで日本語と日本を下の図のように選択して「OK」ボタンを押します。このあと再起動すると後の設定は日本語でできるようになりますが、ここでは英語のまま続けます。
2番めの「Set Timezone」ボタンを押して、「Japan」を選択すると日本時間になります。
3番めの「Set Keyboard」ボタンはキーボードの配列を設定する重要な機能です。最初は英語キーボード配列になっているため、日本語キーボードでは記号のキーの位置が異なっています。「ODAG 109A」の設定に変更しましょう。
次は Wifi の国設定を変更します。
以上で、デスクトップとして普通に使うことができるようになります。別のマシンからネットワーク越しにターミナルアプリで操作する場合は次のように「SSH」を有効にします。
「SSH」を有効にした場合は、必ずパスワードを変更しましょう。
OpenGL と OpenGL ES2
2016年の2月頃から、Raspberry Pi ネイティブで動作する OpenGL ES2 ではない、デスクトップ上 (X11) で動作する普通のOpenGL のドライバーのベータ版が使えるようになっています。OpenGL ES2 は直接 Raspberry Pi の GPU を使い、デスクトップ(X11) とはハードウェア的に独立して、高速な3Dグラフィックスを表示する事ができます。 ここで、この Raspberry Pi ネイティブで動作する OpenGL ES2 用のライブラリが、 Raspbian Stretch で名称変更されてしまいました。
jessie
Raspbian jessie の /opt/vc/lib/ にある OpenGL ES2 用のライブラリです。libEGL.so と libGLESv2.so が確認できます。
$ uname -a Linux raspberrypi 4.9.20+ #985 Mon Apr 3 10:19:25 BST 2017 armv6l GNU/Linux $ ls -F /opt/vc/lib/*GL*.so /opt/vc/lib/libbrcmEGL.so /opt/vc/lib/libGLESv1_CM.so@ /opt/vc/lib/libbrcmGLESv2.so /opt/vc/lib/libGLESv2.so /opt/vc/lib/libEGL.so
stretch
Raspberry Pi メモ (13) の OpenGL ES2 のサンプルプログラムを実行すると次のようにエラーとなります。
$ ./triangle ./triangle: error while loading shared libraries: libGLESv2.so: cannot open shared object file: No such file or directory
Raspbian stretch の /opt/vc/lib/ にある OpenGL ES2 用のライブラリを調べてみます。
pi@raspberrypi:~ $ uname -a Linux raspberrypi 4.9.59-v7+ #1047 SMP Sun Oct 29 12:19:23 GMT 2017 armv7l GNU/Linux pi@raspberrypi:~ $ ls -F /opt/vc/lib/*GL*.so /opt/vc/lib/libbrcmEGL.so /opt/vc/lib/libbrcmGLESv2.so
Raspbian stretch の /opt/vc/lib/ には、/opt/vc/lib/libGLESv2.so と /opt/vc/lib/libEGL.so が存在しません。 かわりに libbrcmEGL.so と libbrcmGLESv2.so があります。したがって、次のように libbrcmEGL.so と libbrcmGLESv2.so をリンクするようにコンパイルし直せば動作するようになります。 または libbrcmEGL.so と libbrcmGLESv2.so へのシンボリックリンクとして libEGL.so と libGLESv2.so を作成する方法もありますが、先々のことを考えるとあまりいい方法ではありません。Stretch で Raspberry Pi ネイティブの OpenGL ES2 を使うプログラムは「コンパイルし直しましょう」ということですね。
INCS="-I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads" LIBS="-lbrcmGLESv2 -lbrcmEGL -lm -lbcm_host -L/opt/vc/lib" CFLAGS="-O2 -Wall" gcc ${CFLAGS} triangle.c -o triangle ${INCS} ${LIBS}
一方、普通の OpenGL を利用するソフトウェアはRaspberry Pi では動作しません。この普通の OpenGL 用のドライバーを使うためには、ターミナル(コンソール)から「raspi-config」コマンドを使って設定する必要があります。 ターミナルから「raspi-config」コマンドを実行して「7. Advanced Option」を選択します。
OpenGL のドライバーの設定には「A6. GL Driver」を選択します。
普通の OpenGL を使う場合は 「G1 GL (Full KMS)」を選択します。
デスクトップ上 (X11) で動作する普通の OpenGL のドライバーは 2016年の2月頃から2年近く経過しましたが、まだベータ版的な位置づけです。 OpenGL をフルに使う Blender を使ってみると、まだ色々不具合があります。
一方、これまでの Raspberry Pi ネイティブで動作する OpenGL ES2 を使う場合は 「G3 Legacy」を選択します。共存はできないようです。「G1 GL (Full KMS)」のままだと次のようなエラーとなります。
pi@raspberrypi:~/ljes-2.01/examples $ luajit demo_spheres.lua x-res:1600 y-res:1200 * failed to add service - already in use? pi@raspberrypi:~/triangle04 $ ./triangle * failed to add service - already in use?
Raspberry Pi で Electron
Raspbian Stretch に Electron がインストールされていることを見つけました。Electron は、JavaScript でプログラミングして、デスクトップアプリケーションが作成できるツールです。GitHub が作成した テキストエディター Atomから派生したものです。 内部で Node.js と Chromium (Google Chrome) が動作します。 Raspberry Pi は教育を目的としているだけあって、Raspbian は最初から非常に充実したプログラミング環境となっています。
Electron の起動は、コンソールから以下のコマンドを実行します。
$ /usr/lib/electron/electron
すると次のようなウィンドウが開いて、「Drag your app here to run it」と書いてある領域にスクリプトを含むファオルダをドラッグ・アンド・ドロップします。
または、スクリプトを含むファオルダを引数として electron コマンドに渡すとアプリケーションが起動します。
$ /usr/lib/electron/electron versionCheker
使ってみる
Electron が内部的に使っている Node.js や Chromium のバージョンを表示するだけの簡単なアプリケーションを作ってみます。
この例では versionChecker フォルダ内に次の3つのファイルを置きます。
versionChecker/ ├── package.json ├── main.js └── index.html
package.json
Electron は、実行時に引数として渡されたフォルダ内の package.json をみて起動するスクリプトを判断するため、最小限では「{"main":"main.js"} 」という内容でも大丈夫です。
{ "name" : "Electron version checker", "version" : "1.0.0", "main" : "main.js" }
main.js
最初に実行するメインプロセスのコード。Electron は Web サーバとブラウザが同時に動作するイメージで、メインプロセスは Web サーバ に相当します。この Web サーバは OS の資源(ファイルやOSのメニューなど)に自由にアクセス可能です。 メインプロセス (サーバ) は レンダラープロセス(ブラウザ) と呼ばれる BrowserWindow インスタンスを生成することで、Electron の画面を作ります。
各ページのレンダラープロセスから、OS 側の機能である GUI 関連の メニューなどの API を呼ぶことはできません。 もしページ内でGUI を操作したい場合には、そのレンダラープロセスはメインプロセスにそれらの操作するように伝える (remote) 必要があります。メニューの設定などはメインプロセス側の仕事です。
// electronモジュールを読み込み const electron = require('electron') const {app} = electron; const {BrowserWindow} = electron; // 新しいウィンドウ(Webページ)を生成 let mainWindow function createWindow () { // BrowserWindowインスタンスを生成 mainWindow = new BrowserWindow({width: 800, height: 600}) // index.htmlを表示 mainWindow.loadURL('file://' + __dirname + '/index.html') // デバッグするためのDevToolsを表示 // mainWindow.webContents.openDevTools() // ウィンドウを閉じたら参照を破棄 mainWindow.on('closed', function () { mainWindow = null }) } // アプリの準備が整ったらウィンドウを表示 app.on('ready', createWindow) // 全てのウィンドウを閉じたらアプリを終了 app.on('window-all-closed', function () { if (process.platform !== 'darwin') { app.quit() } })
index.html
レンダラープロセス側で動作するのは、ほとんど普通のWeb ページの HTML + CSS + JavaScript です。ブラウザが特定のバージョンの Chrome に決まっていますから、 ブラウザの種類や JavaScript のバージョンを気にすることはありません。 ほぼ最新の技術が使えます。 main.js で実行される win.loadURL で指定した HTML ファイルが、レンダラープロセスによって表示されるブラウザのページ内容を記述します。ここで普通のWebページのように JavaScript のコードが書かれていれば、レンダラープロセスがそのJavaScript のコードを実行します。 ブラウザに複数のページを表示する場合はページ毎に1つプロセスが生成されます。 レンダラープロセスで注意することは、普通のブラウザの JavaScript と同じように、ファイルにアクセスしたり、OSの機能を呼び出すことはできません。 その場合はプロセス間通信でメインプロセス側に依頼します。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Version Checker</title> </head> <body> <h1>Electron <script>document.write(process.versions.electron)</script></h1> <ul> <li>Node.js : <script>document.write(process.versions.node)</script></li> <li>V8 : <script>document.write(process.versions.v8)</script></li> <li>uv : <script>document.write(process.versions.uv)</script></li> <li>OpenSSL : <script>document.write(process.versions.openssl)</script></li> <li>Chromium : <script>document.write(process.versions.chrome)</script></li> </ul> </body> </html>
以上は非常に簡単な例ですが、下のスクリーンショットは Ace ( https://ace.c9.io/ ) という JavaScript で書かれた高機能なエディタを Electron に組み込んで実行したところです。多くのプログラミング言語の文法を認識できるエディタができてしまいます。Raspberry Pi 上でもサクサク動きます。