Raspberry Pi Zero WHをヘッドレスでセットアップ

 Raspberry Pi Zero WHはminiHDMIやmicroUSBが備わっているため、モニタやキーボードを繋げば一般のPCと同じようにセットアップをすることができます。
 が、私はRaspberry Pi Zero WHにモニタやキーボードを繋いで利用することは考えていないため、ヘッドレスでセットアップしようと思います。
 そのために行ったことを以下に記載します。
 

Raspbianをダウンロード

 私事ですが、シングルボードコンピュータは使ったことがありますが、Raspberry Piシリーズは初めてです。
 Raspberry Piシリーズ用のOSであるRaspbianはRaspberryシリーズは搭載SoCが各モデルで異なりますが、全モデル共通のダウンロードイメージとなるようです。
 "RASPBIAN STRETCH WITH DESKTOP"、"RASPBIAN STRETCH LITE"の2種類が公式のダウンロードページから提供されていますが、前述の通りヘッドレスでセットアップ及び運用するため、"RASPBIAN STRETCH LITE"の方をダウンロードします。
Download Raspbian for Raspberry Pi
 本投稿記載時点では、2018-04-18-raspbian-stretch-lite.zipというファイルがダウンロードされます。
 

microSDにRaspbianを書き込む

 2018-04-18-raspbian-stretch-lite.zipを展開すると、2018-04-18-raspbian-stretch-lite.imgというファイルが現れます。
 これはRaspbianのディスクイメージが記録されたファイルですので、ディスクイメージをmicroSDに書き込める何らかのツールを使用します。
 私はWindows10環境で作業していますので、Rufusを使用しました*1

 なお、Raspbianを書き込んだ後のmicroSDはWindows10から認識されませんが(ファイルシステムが違うため)それで正常です。
 

 ここまでは特に変わったことのないごく普通の手順です。
 ヘッドレスでセットアップするために行う固有の手順は以下の通り。
 

公式のヘッドレスセットアップガイド

 RaspberryPi財団公式では以下の説明があります。

If you do not use a monitor or keyboard to run your Pi (known as headless), but you still need to do some wireless setup, there is a facility to enable wireless networking and SSH when creating a image.

Once an image is created on an SD card, by inserting it into a card reader on a Linux or Windows machines the boot folder can be accessed. Adding certain files to this folder will activate certain setup features on the first boot of the Pi itself.

Setting up wireless networking
You will need to define a wpa_supplicant.conf file for your particular wireless network. Put this file in the boot folder, and when the Pi first boots, it will copy that file into the correct location in the Linux root file system and use those settings to start up wireless networking.

More information on the wpa_supplicant.conf file can be found here.

Enabling SSH
SSH can be enabled by placing a file called ssh in to the boot folder. This flags the Pi to enable the SSH system on the next boot.

See here for more details.

Setting up a Raspberry Pi headless - Raspberry Pi Documentation

 適当に意訳すると、以下のような感じとなります。

モニタやキーボードを使わずに(すなわちヘッドレスで)Piを動かす場合、イメージ作成時にいくつか設定が必要ながら無線LANSSHを有効化する仕組みがあります。
SDカードにイメージを作成して、LinuxWindowsマシンのカードリーダに挿入すればbootフォルダがアクセスできるはずです。このフォルダにとあるファイルを追加すれば、Piの初回起動時に特定の機能をPi自身で有効化します。

無線LANの設定
特定の無線LANに接続するために、wpa_supplicant.confを定義する必要があります。このファイルをbootフォルダに配置すれば、Piの初回起動時にLinuxファイルシステムの適切な場所にコピーされ、無線LANの設定に使われます。
wpa_supplicant.confの詳細はこちら

SSHの有効化
SSHsshファイルをbootフォルダに配置すれば有効化されます。これは次回起動時にSSHを有効化するようPiに示すものです。
この詳細はこちら

 ということで、所定のファイルを予めmicroSDカードに配置しておくことで、無線LANSSHを有効化できればヘッドレスでセットアップ及び運用が可能になるわけです。
 (ところで、bootフォルダがWindowsからでもアクセスできるような文言が書かれていますが、私の環境では前述の通りアクセスできません。)
 

起動後sshを自動で有効化

 前掲のヘッドレスセットアップガイドとは別の公式のドキュメントには以下の記載があります。

3. Enable SSH on a headless Raspberry Pi (add file to SD card on another machine)
For headless setup, SSH can be enabled by placing a file named ssh, without any extension, onto the boot partition of the SD card from another computer. When the Pi boots, it looks for the ssh file. If it is found, SSH is enabled and the file is deleted. The content of the file does not matter; it could contain text, or nothing at all.

If you have loaded Raspbian onto a blank SD card, you will have two partitions. The first one, which is the smaller one, is the boot partition. Place the file into this one.

SSH (Secure Shell) - Raspberry Pi Documentation
 ヘッドレスセットアップガイドでは"boot folder"と表現されていたものが、こちらでは"boot partition"に変わっています。
 単なる表記揺れだと思ってスルーしていたら、後で嵌りました(後述)。結果的に"partition"の方が正解で、"folder"は誤記のようです。

 適当に意訳すると以下のような感じになります。

3. ヘッドレスのRaspberry PiSSHを有効化(他のマシンでSDカードにファイルを追加)
ヘッドレスセットアップのために、他のコンピュータでsshという名前のファイルを(拡張子を付けずに)SDカードのブートパーティションに配置することでSSHを有効化することができます。
Piがブートする際、sshファイルを探します。それが見つかればSSHは有効化され、sshファイルは削除されます。
ファイルの中身は何でも構わず、何らかの文字列を含んでもいいし、空っぽでもいいです。

Raspbianを空のSDカードに書き込んだなら、2つのパーティションがあるはずです。
最初のパーティション(小さい方のパーティション)がブートパーティションなので、そこにこのファイルを配置してください。

 
 ちょっと困りました。前述の通り、私のWindows環境からはRaspbianを書き込んだSDカードにアクセスできません。
 WSL(Windows Subsystem for Linux)を使えばLinuxファイルシステムにアクセスできるのではと考えましたが、WSLの仕組み上Windows側で認識できていないドライブを、WSLでマウントすることはできないようです。

 Macを使うという手段もありますが、私の手元にあるMacbookはbootcampでWindows環境で運用しておりOSXはもう何年も起動していないためアップデートの手間などを考えると使いたくありませんでした。
 そこで、既に運用中のOrangePiOneというRaspberryPiと同様のシングルボードコンピュータを使って作業することにしました(OS環境としては、ARMBIAN 5.38 stable / Ubuntu 16.04.4 LTSですので、所謂Linux端末です)。
 

microSDをマウント

 OrangePiOneにRaspbianを書き込んだmicroSDカードを挿入したUSBカードリーダを接続し、dmesgを確認すると以下の出力が得られました。

ehci_irq: highspeed device connect
usb 2-1: new high-speed USB device number 2 using sunxi-ehci
usb 2-1: New USB device found, idVendor=8564, idProduct=4000
usb 2-1: New USB device strings: Mfr=3, Product=4, SerialNumber=5
usb 2-1: Product: Transcend
usb 2-1: Manufacturer: TS-RDF5
usb 2-1: SerialNumber: 000000000039
scsi0 : usb-storage 2-1:1.0
scsi 0:0:0:0: Direct-Access     TS-RDF5  SD  Transcend    TS37 PQ: 0 ANSI: 6
sd 0:0:0:0: [sda] 62535680 512-byte logical blocks: (32.0 GB/29.8 GiB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Mode Sense: 23 00 00 00
sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
 sda: sda1 sda2
sd 0:0:0:0: [sda] Attached SCSI removable disk

 ストレージデバイスsdaにsda1、sda2の2つのパーティションが確認できます。
 これが先のドキュメントに"you will have two partitions"と記載されていたものの実体のようですので、とりあえずマウントします。

sudo mkdir /mnt/usb_sda1 && sudo mount /dev/sda1 /mnt/usb_sda1/
sudo mkdir /mnt/usb_sda2 && sudo mount /dev/sda2 /mnt/usb_sda2/

 

microSDの中身を確認

 sda1、sda2のそれぞれのルートディレクトリを確認すると以下の通りでした。

ls -ltr /mnt/usb_sda1/
total 21776
-rwxr-xr-x 1 root root   22264 Mar 28 21:08 bcm2708-rpi-0-w.dtb
-rwxr-xr-x 1 root root   21761 Mar 28 21:08 bcm2708-rpi-b.dtb
-rwxr-xr-x 1 root root   22020 Mar 28 21:08 bcm2708-rpi-b-plus.dtb
-rwxr-xr-x 1 root root   21474 Mar 28 21:08 bcm2708-rpi-cm.dtb
-rwxr-xr-x 1 root root   23044 Mar 28 21:08 bcm2709-rpi-2-b.dtb
-rwxr-xr-x 1 root root   24240 Mar 28 21:08 bcm2710-rpi-3-b.dtb
-rwxr-xr-x 1 root root   24503 Mar 28 21:08 bcm2710-rpi-3-b-plus.dtb
-rwxr-xr-x 1 root root   22952 Mar 28 21:08 bcm2710-rpi-cm3.dtb
-rwxr-xr-x 1 root root   52064 Mar 28 21:07 bootcode.bin
-rwxr-xr-x 1 root root     190 Apr 18 10:08 cmdline.txt
-rwxr-xr-x 1 root root    1590 Apr 18 09:25 config.txt
-rwxr-xr-x 1 root root   18693 Mar 10 03:28 COPYING.linux
-rwxr-xr-x 1 root root    2599 Apr 17 20:50 fixup_cd.dat
-rwxr-xr-x 1 root root    6575 Apr 17 20:50 fixup.dat
-rwxr-xr-x 1 root root    9726 Apr 17 20:50 fixup_db.dat
-rwxr-xr-x 1 root root    9730 Apr 17 20:50 fixup_x.dat
-rwxr-xr-x 1 root root     145 Apr 18 10:08 issue.txt
-rwxr-xr-x 1 root root 4922144 Apr 17 20:50 kernel7.img
-rwxr-xr-x 1 root root 4676016 Apr 17 20:50 kernel.img
-rwxr-xr-x 1 root root    1494 Mar 10 03:28 LICENCE.broadcom
-rwxr-xr-x 1 root root   18974 Apr 18 10:08 LICENSE.oracle
drwxr-xr-x 2 root root   11264 Apr 18 09:15 overlays
-rwxr-xr-x 1 root root  673444 Apr 17 20:50 start_cd.elf
-rwxr-xr-x 1 root root 4968292 Apr 17 20:50 start_db.elf
-rwxr-xr-x 1 root root 2825124 Apr 17 20:50 start.elf
-rwxr-xr-x 1 root root 3912164 Apr 17 20:50 start_x.elf
ls -ltr /mnt/usb_sda2/
total 88
drwxr-xr-x  2 root root  4096 Apr 18 09:20 bin
drwxr-xr-x  2 root root  4096 Apr 18 10:07 boot
drwxr-xr-x  4 root root  4096 Apr 18 09:05 dev
drwxr-xr-x 84 root root  4096 Apr 18 10:08 etc
drwxr-xr-x  3 root root  4096 Apr 18 09:16 home
drwxr-xr-x 16 root root  4096 Apr 18 09:28 lib
drwx------  2 root root 16384 Apr 18 10:07 lost+found
drwxr-xr-x  2 root root  4096 Apr 18 09:03 media
drwxr-xr-x  2 root root  4096 Apr 18 09:03 mnt
drwxr-xr-x  3 root root  4096 Apr 18 09:16 opt
drwxr-xr-x  2 root root  4096 Mar 12 23:03 proc
drwx------  2 root root  4096 Apr 18 09:03 root
drwxr-xr-x  5 root root  4096 Apr 18 09:17 run
drwxr-xr-x  2 root root  4096 Apr 18 09:28 sbin
drwxr-xr-x  2 root root  4096 Apr 18 09:03 srv
drwxr-xr-x  2 root root  4096 Mar 12 23:03 sys
drwxrwxrwt  2 root root  4096 Apr 18 10:08 tmp
drwxr-xr-x 10 root root  4096 Apr 18 09:03 usr
drwxr-xr-x 11 root root  4096 Apr 18 09:03 var

 sda2の方に/bootディレクトリがあります(ちなみに、中身は空のディレクトリです)。
 これがヘッドレスセットアップガイドの言うところの、"boot folder"のことであろうと判断し、ここにsshファイルをtouchしました(そして後述のwpa_supplicant.confもここに配置した状態のmicroSDRaspberry Pi Zero WHに挿入して起動させてもSSHは有効化されませんでした)。

 一方、ヘッドレスセットアップガイドでは無い方のドキュメントには"boot partition"に配置せよと書かれており、それは"first one(注:ここでのoneはpartition)"だと書かれてもいます。
 2つの公式ドキュメント間で齟齬がありますが、結果的には、sda1の方(すなわちboot partiton)のルート直下にsshファイル(後述のwpa_supplicant.confも)を配置するのが正解でした。

sudo touch /mnt/usb_sda1/ssh

 

起動後WiFiに自動接続

 sshが有効化されても、Raspberry Pi Zero WHには有線LANはありませんので、ネットワークからアクセスするためには無線LANの設定が必要です。
 そこで、WiFiに自動で接続されるようにします。そのためには、アクセスポイントのSSIDとパスワードを何らかの方法で事前に与えておく必要があります。
 その手段がヘッドレスセットアップガイドに記載のあるwpa_supplicant.confで、実体は設定情報が記録されたテキストファイルです。

 SSIDが"島原のLAN"、パスワードが"16371211"だった場合、wpa_supplicant.confに記述すべき内容は最低限以下の通りとなります。

country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
	ssid="島原のLAN"
	psk=1b83cb27b1aaf43875882a8d7399f7546c4380346ad9c48334a1079d7c7b2be6
}

 1行目は日本国内で使用する場合は必須(無線LANで使用可能な周波数帯域は国によって異なるため、この設定が無いと国内では電波法違反となる周波数の電波を出してしまう可能性が有る)。
 2,3行目は変更する必要が無いので、そのまま。
 4-7行目が接続する無線LANネットワークに応じて設定値を記述する必要があります。ここには他にもkey_mgmt, pairwise, group等の認証方式に係る情報を定義できるのですが、その設定値が定かではなく*2、私が調べた限り何が正しいのか判断付かないため私は最低限必要な情報以外は記述しないことにしました。
 ssidSSIDそのものの文字列です。pskがsha1で暗号化されたパスワードです。
 暗号化されたパスワードを生成するにはLinux環境でwpa_passphraseコマンドを使うのが簡単です。以下のように、wpa_passphraseコマンドの引数にSSIDを与えて実行すると、パスワード入力を求められるので入力します。するとwpa_supplicant.confのテンプレートとして使える文字列が標準出力に得られます。

$ wpa_passphrase 島原のLAN
# reading passphrase from stdin
16371211
network={
        ssid="島原のLAN"
        #psk="16371211"
        psk=1b83cb27b1aaf43875882a8d7399f7546c4380346ad9c48334a1079d7c7b2be6
}

 wpa_passphraseコマンドが使えない場合は、node.js*3を使っても同様の暗号化が可能です。

> node -e "console.log(require('crypto').pbkdf2Sync('16371211', '島原のLAN', 4096, 32, 'sha1').toString('hex'))"
1b83cb27b1aaf43875882a8d7399f7546c4380346ad9c48334a1079d7c7b2be6

 こうして準備したwpa_supplicant.confをヘッドレスセットアップガイドによれば、"boot folder"に置けということになっていますが誤りで、先のsshの時と同様に、"boot partition"に配置するのが正解です。
 

 これでようやくRaspberry Pi Zero WHの初回起動準備ができました。
 

sshファイルとwpa_supplicant.confをbootパーティションに配置したRaspbianイメージが書き込まれたmicroSDRaspberry Pi Zero WHに挿入して起動

 ここまでの作業に問題が無ければ、電源接続後Raspberry Pi Zero WH本体のLEDがしばらく点滅した後、常時点灯状態となり起動完了しているはずです。
 デフォルトの"raspberrypi"という名称のホストに、デフォルトの"pi"という名称のユーザで、デフォルトの"raspberry"というパスワードでSSH接続が可能なはずです。
1st login to headless Rapberry Pi Zero WH

 接続できなければまずは使用中の無線ルータの管理画面などで、Raspberry Pi Zero WHが接続されているか確認してみてください。
 それらしき端末が見つかれば、単に名前解決の問題ですし、そうでなければこれまでの準備作業に問題があったということになります。
 

対話型設定ツールを実行

 raspi-configを実行すると、各種設定のための対話型ツールが開きます。

$ sudo raspi-config

 多くの場合、piユーザのパスワード変更、ロケール設定、文字コード設定、ツールのアップデート辺りを実行することになるのではないかと思います。
 

ソフトウェアの更新や任意の設定等を実行

 あとは、普通のLinuxマシンとしてカスタマイズすればよいと思います。
 apt upgradeした後、新規ユーザを追加しデフォルトのpiユーザをロックアウトするとかそんな感じでしょうか。
 

その他

技適

 私がマルツで購入した個体には技適マーク及び認証番号は基板裏面に表示されていました。
f:id:kachine:20180523012902j:plain
 

アンテナ

 無線LAN/Bluetoothを搭載していますが外部アンテナ端子は無く、基板上にアンテナパターンが形成された所謂PCBアンテナを搭載しています。
 同様にPCBアンテナを搭載したESP-WROOM-02やWROOM-32では基板を見ればそれらしいアンテナパターンが解りますが、Raspberry Pi Zero WHではどこがアンテナなのか判りませんでした。
 調べてみると、基板上に"Uses antenna technology licensed from Proant AB"とプリントされていますが、丁度その印字位置にPCBアンテナが形成されているようです。
 ライセンス元のProant ABの以下のニュースからリンクされている以下の記事のFigure1に画像付きで説明されています。
Glowing review - Antenna news - Proant AB
A lesson in wireless engineering from the Raspberry Pi
 

CPU

 CPU情報を確認してみると以下の通りで、当然ですがスペック通りBCM2835を搭載し、シングルコア機です。
 重い処理(例えば初回apt upgrade実行)中に、別セッションでssh接続しようとするだけでもログインプロンプト表示まで数秒待たされるパフォーマンスです。

$ cat /proc/cpuinfo | grep -v Serial
processor       : 0
model name      : ARMv6-compatible processor rev 7 (v6l)
BogoMIPS        : 697.95
Features        : half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xb76
CPU revision    : 7

Hardware        : BCM2835
Revision        : 9000c1

 技適の通った無線が使えて、速くなくていいからLinuxも使いたいという用途には適していると思います。
 ヘッドレス運用を前提としつつもLinuxが必須でないなら、そもそもビデオ出力のないESP32(ESP-WROOM-32)搭載ボードの方が半額程度で調達可能なので用途の見極めが難しいかもしれません。
 例えば、GPIO経由でセンサ情報を拾って無線LAN経由でどっかのサーバに投げるだけの用途ならESP32で十分でしょうし、サーバーに投げる前にデータの蓄積・加工が必要な用途ならRaspberry Pi Zero WHにsqliteなどのDBを導入して実装するのが容易に実現できるでしょうし。
 



以上。

*1:Rufusの使い方は以下の投稿内に記載していますので、本投稿では省略します。
Orange Pi OneにArmbianを導入した - 記憶は人なり

*2:例えばWPA2の場合、WPA2-PSKと定義していたり、WPA2でもWPA-PSKと定義していたり。

*3:わざわざ個別にインストールしなくても、Adobe Createve Cloud (CC)を使っていれば、node.jsはC:\Program Files (x86)\Adobe\Adobe Creative Cloud Experience\libsにインストールされています。