Raspberry Pi3 と Stretch と Electron (2017-12-10)

Raspberry Pi 3 Model B をいまさらながら購入しました。すでにPi1B(256MB)、Pi1B(512MB)、Pi1B+、Pi2Bと持っていて、DragonBoard410CHikeyOrange Pi PC2Orange Pi Zero と節操なく購入していたので、Pi 3 はパスと思っていました。しかし、独身の日(11/11)に安かった(Pi3、ケース、ファン、ヒートシンク、電源で5000円弱)ので、つい AliExpress でポチってしまいました。到着まで3週間ほどかかりましたが、無事入手できました。 5年前の初代 (Pi1B 256MB) と並べてみました。大きさ以外は別物ですね。

Pi1B_Pi3B.jpg

今回は 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.1buzz
1996/12/12 1.2rex
1997/07/05 1.3bo
1998/07/24 2.0hamm
1999/03/09 2.1slink
2000/08/15 2.2potato
2002/07/19 3.0woody
2005/06/06 3.1sarge
2007/04/08 4.0etch
2009/02/14 7.0lenny
2011/02/06 6.0squeeze
2013/05/04 7.0wheezy
2015/04/26 8.0jessie
2017/06/17 9.0stretch
20XX/00/00 10.0buster
20XX/00/00 11.0bullseye

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 版を起動すると次の画面が表示されます。使い方は、ファイルを選択、書き込み先を指定、書き込みと左から順番にクリックするだけと簡単です。

./Etcher12_0.png


ディスクイメージ (2017-11-29-raspbian-stretch.zip) を選択します。zip のままでも自動的に展開して書き込まれます。

./Etcher12_1.png


書き込み先は自動的に選択されますが、中央の「Change」を押して一応確認します。

./Etcher12_2.png


「Flash」を押すと書き込みが始まります。

./Etcher12_3.png


イメージを書き込んだ後に、元のファイルと書き込まれたイメージを比較する検証 (validation) も自動的に実行されます。

./Etcher12_4.png


終了すると、続けて同じイメージを書き込むか、別のイメージを使うかを聞かれます。 ここではメニューから「終了」するか、メニューから [x] して終了します。

./Etcher12_5.png


16GB のマイクロSDカードに書き込まれたイメージを確認します。 この時点では 5GB ほどが使われています。
SDC_partition.png


Raspbian Stretch の起動

4Kテレビと無線キーボードマウスセットを繋いで、テレビの裏に置きました。

Raspberry Pi 3 をケースに入れた写真が次です。小さいながらもCPUに付けたヒートシンクの上から結構な風量で冷却します。写真の電源ケーブルは安物で電圧降下が大きく稲妻マークが表示されるので、別に購入した太いものに交換しました。 ヒートシンクもセットに入っていたものとは交換しています。

Pi3Case.jpg

ケーブルがケースの1辺に2本 (電源と HDMI) 接続するだけなので、キレイに設置できます。 使っている CPU ファンの消費電力が 0.5W 程度ですが、Raspberry Pi3自身の消費電力が 2W ほどなので、ファンを切ると 20% 消費電力が下がります。 ファンを切っても CPU の温度が下のように余裕なので、現在はファンは使用していません。

$ cat /sys/class/thermal/thermal_zone0/temp
49388

Pi1B のころは下の写真のように、太いケーブルが色々な方向に刺さっていてケースを固定する必要がありましたが、設置が楽になりました。Raspberry Pi3 の Wifi と無線キーボードマウスセット が激安で入手できるようになったためですが。

Pi1B_cables.jpg

電源を入れるだけで、デスクトップが表示されます。42インチの 4K (3840 x 2160) テレビですが、解像度は 1824 x 984 で表示されました(オーバースキャンON)。1m 以上離れても使えるので老眼には優しい環境です。

Pi3Desktop.jpg

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の設定

まず最初にネットワークを使えるようにします。 右上のアイコンをクリックするとアクセスポイントが表示されます。

Pi3Wifi01.png


アクセスポイントをクリックするとキーの入力が求められます。

Pi3Wifi02.png


キーを入力するとネットワークが有効になります。

Pi3Wifi03.png


いろいろな設定

その他の設定は、ターミナルを開いて「raspi-config」を実行しなくても、メニューから行うことができます。まず、「Raspberry Pi Configuration」を選択します。

config00.jpg


「System」というタブが表示されますが、右端の「Localisation」を選択します。

config01.png


一番上の「Set Locale」というボタンを押します。

config02.png


ここで日本語と日本を下の図のように選択して「OK」ボタンを押します。このあと再起動すると後の設定は日本語でできるようになりますが、ここでは英語のまま続けます。

config03_locale.png


2番めの「Set Timezone」ボタンを押して、「Japan」を選択すると日本時間になります。

config04_timezone.png


3番めの「Set Keyboard」ボタンはキーボードの配列を設定する重要な機能です。最初は英語キーボード配列になっているため、日本語キーボードでは記号のキーの位置が異なっています。「ODAG 109A」の設定に変更しましょう。

config05_keyboard.png


次は Wifi の国設定を変更します。

config06_wifi.png


以上で、デスクトップとして普通に使うことができるようになります。別のマシンからネットワーク越しにターミナルアプリで操作する場合は次のように「SSH」を有効にします。

config07_ssh.png


「SSH」を有効にした場合は、必ずパスワードを変更しましょう。

config08_password.png

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」を選択します。

rpi51cfg00.png


OpenGL のドライバーの設定には「A6. GL Driver」を選択します。

rpi51cfg01.png


普通の OpenGL を使う場合は 「G1 GL (Full KMS)」を選択します。

rpi51cfg02.png


デスクトップ上 (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」と書いてある領域にスクリプトを含むファオルダをドラッグ・アンド・ドロップします。

rpi_electron.jpg

または、スクリプトを含むファオルダを引数として electron コマンドに渡すとアプリケーションが起動します。

$ /usr/lib/electron/electron versionCheker

使ってみる

Electron が内部的に使っている Node.js や Chromium のバージョンを表示するだけの簡単なアプリケーションを作ってみます。

electron_version.png

この例では 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 上でもサクサク動きます。

electron_ace.jpg





このページの目次