自動化厨のプログラミングメモブログ│CODE-LIFE

Python/ExcelVBA/JavaScript/Raspberry Piなどで色んなことを自動化

Raspberry PiのセットアップからPython実行環境構築とイメージファイルバックアップまで

Raspberry Piを購入してから10ヶ月ほど経ちましたが、分からないなりに色々いじくり回していると余計に訳がわからない事態に陥ることもしばしば。

仕方ないクリーンインストールするか・・・ということが何度もありました。

その手間をなるべく省くために大まかなセットアップ手順とリセットを楽にするためのimgバックアップの方法をメモしておきます。

Raspberry PiのRaspbianセットアップと設定後イメージファイルのバックアップ

NOOBSが書き込まれたSDカードが付属しているパターンならそれを使ってもいいと思います。

①OSのイメージファイルをダウンロード

RASPBIAN

www.raspberrypi.org

RASPBIANにはDESKTOP版とLITE版の2種類が用意されています。

DESKTOP LITE
容量 4.49GB 1.73GB
UI GUI / CLI CLIのみ

GUI・・・グラフィックユーザーインターフェース。Windowsのようにマウスを使って視覚的、直感的な操作。

CLI・・・コマンドラインインターフェース。マウスなどは使わずキーボードでのコマンド入力のみで操作。

どちらを選べばいいのか

CLIでの操作に慣れていない場合やSDカードの容量に余裕がある(8GB以上)場合はDESKTOP版。

とりあえず手持ちの古いSDカード(4GB)などで安く済ませたい、Raspberry Pi Zeroなのでスペックが低いという場合はLITE版。

※DESKTOP版も設定で後からCLIに切り替えることが可能です。

② EtcherでSDカードに書き込む

EtcherはRaspbian公式でも推奨されているツールです。使用方法は画像つきで見やすく以下の記事が大変参考になりました。

azriton.github.io

おおまかな流れとしては

  1. EtcherのSettingを開いてEject on successの チェックを外す
  2. OSイメージファイルを選択(zipのままでOK)
  3. 書き込むSDカードを選択
  4. Flash! を クリック

f:id:maru0014:20180924115637p:plain

Win32DiskImagerを利用する場合。例えば以下の記事の場合はSD FormatterでSDカードを予めフォーマットしておく必要があったり、zipファイルを7-zipで解凍する手間がかかりますが、その点Etcherなら一発で終わるので超簡単です。

③ 起動後すぐにSSH接続できるように設定しておく

SDカードに書き込み後そのまま起動した場合はWi-Fiの設定も何もされていませんが予め2つのファイルをルートフォルダ作成することでSSHをWi-Fiの設定が可能です。

Wi-Fi設定

書き込み完了後bootという名前のドライブが出現しているはずです。

f:id:maru0014:20180924115655p:plain

ここのルートフォルダに「wpa_supplicant.conf」を作成して中身にWi-FiのSSIDとパスワードを記載することで起動してすぐWi-Fiにつながるようにしておきます。

f:id:maru0014:20180924115706p:plain

テキストエディタで開いて以下のように入力して保存。Raspberry Piに搭載されたWi-Fiモジュールは2.4Gのみ対応です。

country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="ここにSSID"
        psk="ここにパスワード"
}

SSHの有効化

中身は空で「ssh」(拡張子なし)というファイルを置いておくだけです。

f:id:maru0014:20180924115908p:plain

④ Raspberry Piにセットして起動し、SSH接続

有線LANで直接接続する場合

こっちなら③の無線LAN設定は後からでもできますね。以下の記事がWindows/macそれぞれの接続方法が書かれていて分かりやすいです。

https://qiita.com/mascii/items/7d955395158d4231aef6

無線LANでする場合

ルーターの設定画面などからRaspberry PiのIPアドレスを確認してTeraTeamなどでSSH接続(デフォルトID「pi」、パスワード「raspberry」)

f:id:maru0014:20180924115934p:plain

⑤ raspi-configで各種設定

SSH接続できたら早速raspi-configを開いてパスワードの変更や日本用の設定をしていきます。

$ sudo raspi-config

f:id:maru0014:20180924120034p:plain

1 ChangeUser Password

念の為、初期パスワードは変更しておきましょう。

f:id:maru0014:20180924120100p:plain

3 Boot Options・・・起動方法

ここでGUIとCLIを選べます。今回はRaspberry Pi Zero WなのでCLIにしておきます。

B1 Desktop / CLI
- B1 Console を選択

f:id:maru0014:20180924120103p:plain

4 Localisation Options

f:id:maru0014:20180924120205p:plain

I1 Change Locale ・・・日本語環境にする 操作: スクロール(pageup/downキー)、チェック(Spaceキーでon/off) - en_GB.UTF-8 UTF-8のチェックを外す - ja_JP.EUC-JP EUC-JPja_JP.UTF-8 UTF-8 にチェック - Default localeをja_JP.UTF-8に設定(完了まで少し時間がかかります)

I2 Change Timezone ・・・日本時刻にする - Asia を選択 - Tokyo を選択

I4 Change Wi-fi Country ・・・Wi-Fiを日本に設定 - JP Japan を選択

5 Interfacing Options

各種インターフェースのON/OFFが可能。 VNC接続したい場合は有効化しておきます。

f:id:maru0014:20180924120143p:plain

7 Advanced Options

f:id:maru0014:20180924120508p:plain

A1 Expand Filesystem ・・・ファイルシステム拡張 SDカードの全容量を使用できるようになります(要再起動)

A3 Memory Split ・・・CLIで動作させる場合GPUパワーは最小限でOK GPUに割り当てるメモリを最小の16MBに設定

最後に「Finish」を選択→rebootの確認があった場合はrebootしておく。

⑥ IPアドレスを固定する

dhcpcd.confを編集して固定する

$ sudo nano /etc/dhcpcd.conf #nanoエディタで設定ファイルを編集

以下を追記

interface wlan0  #有線なら「eth0」無線なら「wlan0」
static ip_address=192.168.1.145 #Raspberry PiのIP
static routers=192.168.1.1 #ルーターのIP
static domain_name_servers=192.168.1.1 #ルーターのIP

Ctrl+X → Y → Enter で保存して閉じる

$ sudo service dhcpcd reload #設定を反映する
$ sudo reboot #無線LANの場合再起動が必要らしい

ifconfigでIPアドレスが指定したものになっているか確認

$ ifconfig
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.145  netmask 255.255.255.0  broadcast 192.168.1.255

ここまでの設定で基本的なところは終了。以下はこだわる人用

こだわり設定

ここから先の設定は慣れてきてからにしたほうが無難な気がします。

詳しい人以外は読み飛ばしてイメージファイルのバックアップへどうぞ

①「SDカード寿命対策」

1. Swap領域の無効化

$ free -h # メモリ確認
              total        used        free      shared  buff/cache   available
Mem:           433M         79M        160M        6.9M        194M        298M
Swap:           99M          0B         99M #<=99MSwapに割り当てられている
$ sudo swapoff --all #swapをOFF
$ sudo apt-get purge -y --auto-remove dphys-swapfile #package削除
$ sudo rm -fr /var/swap # フォルダ削除
$ free -h # メモリ再確認
              total        used        free      shared  buff/cache   available
Mem:           433M         81M         90M        6.9M        261M        293M
Swap:            0B          0B          0B #<=ここが0になっていれば成功

2. テンポラリ領域 を RAM へ

※これをやると一時ファイル用領域が足りなくなってpyenvが容量不足で動きませんでした。もしRAMへ移動してしまったなら/etc/fstabを再度編集し追記した行を削除しましょう。

$ sudo nano /etc/fstab # nanoエディタで設定ファイルを開く

以下の2行を追記

tmpfs           /tmp            tmpfs   defaults,size=32m,noatime,mode=1777  0       0  
tmpfs           /var/tmp        tmpfs   defaults,size=16m,noatime,mode=1777  0       0
$ sudo rm -fr /tmp # tmpフォルダ削除
$ sudo rm -fr /var/tmp # /var/tmpフォルダ削除
$ sudo reboot # 再起動

3. rsyslog の ログ出力を抑制

$ sudo nano /etc/rsyslog.conf # nanoエディタで設定ファイルを開く

以下のように不要なログを「#」でコメントアウトしていく

###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                         /var/log/cron.log
#daemon.*                       -/var/log/daemon.log
#kern.*                         -/var/log/kern.log
#lpr.*                          -/var/log/lpr.log
#mail.*                         -/var/log/mail.log
#user.*                         -/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
#mail.info                      -/var/log/mail.info
#mail.warn                      -/var/log/mail.warn
#mail.err                       /var/log/mail.err

#*.=debug;\  
#       auth,authpriv.none;\  
#       news.none;mail.none     -/var/log/debug

4. ログ出力ディレクトリ を RAM へ

$ sudo nano /etc/fstab

以下を追記

tmpfs           /var/log        tmpfs   defaults,size=32m,noatime,mode=0755  0       0
$ sudo nano /etc/rc.local # 起動時にディレクトリ構成を復元するスクリプト記述

exit 0の直前に以下のように追記

mkdir -p /var/log/apt
mkdir -p /var/log/fsck
mkdir -p /var/log/ntpstats
mkdir -p /var/log/samba

chmod 750 /var/log/samba
chown ntp:ntp /var/log/ntpstats
chown root:adm /var/log/samba

touch /var/log/btmp
touch /var/log/lastlog
touch /var/log/wtmp

chmod 600 /var/log/btmp
chmod 664 /var/log/lastlog
chmod 664 /var/log/wtmp

chown root:utmp /var/log/btmp
chown root:utmp /var/log/lastlog
chown root:utmp /var/log/wtmp
$ sudo rm -fr /var/log # ログフォルダ削除
$ sudo reboot # 再起動

参考 https://azriton.github.io/2017/03/16/Raspbian-Jessie-Lite%E3%81%AESD%E3%82%AB%E3%83%BC%E3%83%89%E5%BB%B6%E5%91%BD%E5%8C%96/

② 軽量化・高速化

1. カーネルのログを抑制

$ sudo nano /boot/cmdline.txt

以下を追記

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet

2. CPU の 動作クロック設定

$ sudo apt-get update
$ sudo apt-get install cpufrequtils -y --no-install-recommends

CPUの設定変更

$ sudo cpufreq-set -g performance #最大周波数で cpu を動作
$ sudo cpufreq-set -g powersave #最小周波数で cpu を動作
$ sudo cpufreq-set -g ondemand #cpu の負担が 95% の時に CPU を動的に切り替え
$ sudo cpufreq-set -g conservative #負担が 75% の時に CPU を動的に切り替え
$ sudo cpufreq-set -g userspace #ユーザーが指定した周波数で cpu を動作

再起動後も反映されるように設定ファイルを作成

$ sudo cp /usr/share/doc/cpufrequtils/examples/cpufrequtils.sample /etc/default/cpufrequtils # Sampleをコピーして作成
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies # CPUの最大・最小スピードを確認
700000 1000000 #<ーこちらはRaspberry Pi Zero Wのものです
$ sudo nano /etc/default/cpufrequtils # nanoエディタで編集

以下のように記述

ENABLE="true"  
GOVERNOR="performance"  
MAX_SPEED=1000000
MIN_SPEED=700000

3. アップデートやらクリーンアップやらをshファイルで一括実行

「create_minumum_raspbian.sh」を作成・編集

$ nano create_minumum_raspbian.sh

以下を貼り付け

#! /bin/sh

# Update repos
sudo apt update

# Packages to remove
DOCS="man manpages libraspberrypi-doc debian-reference-en debian-reference-common"
GCC="gcc-4.5-base:armhf gcc-4.6-base:armhf gcc-4.7-base:armhf"
DEV=`sudo dpkg --get-selections | grep "\-dev" | grep -v "deinstall" | sed s/install//`
SOUND="omxplayer "`sudo dpkg --get-selections | grep -v "deinstall" | grep sound | sed s/install//`
PYTHON=`sudo dpkg --get-selections | grep -v "deinstall" | grep python | sed s/install//`
JAVA="java-common oracle-java7-jdk oracle-java8-jdk"
LEARNING="scratch squeak-vm squeak-plugins-scratch supercollider sonic-pi wolfram-engine"

# Purge packages
sudo apt purge -y $DOCS $GCC $DEV $SOUND $PYTHON $JAVA $LEARNING
sudo rm -rf /usr/local/games/
sudo rm -rf /usr/games/

# Autoremove
sudo apt autoremove -y
# Upgrade packages and distribution
sudo apt upgrade -y
sudo apt dist-upgrade -y
# Clean archive files
sudo apt clean -y

# Update firmwares
sudo apt install -y rpi-update
sudo rpi-update

# Clear logs
cd /var/log/
sudo rm `find . -type f`
history -c

# Reboot
sudo reboot

実行

$ sh create_minumum_raspbian.sh

色々アップデートも行っているので多分30分以上かかる。

参考

https://azriton.github.io/2017/03/19/Raspbian-Jessie-Lite%E3%81%9D%E3%81%AE%E4%BB%96%E8%A8%AD%E5%AE%9A/

https://qiita.com/shinsumicco/items/c48cb9457a49a03f453e

イメージファイルのバックアップ

Raspberry Piの設定がいい感じになったら、再インストール・再セットアップの手間を省くためにSDカードイメージをメインPCでバックアップを取っておきます。

利用するのはWin32 Disk Imager。結局使うんかいってやつですよね。 Etcherは書き込みは出来ても読み込みの機能がないので仕方ないです。

①shutdownコマンドでRaspberry Piの電源を切ります。

$ sudo shutdown -h now

②SDカードをメインPCに入れてWin32 Disk Imagerでimgを抽出

バックアップ先とファイル名を指定→SDカードのドライブレターを選択→Readを押す

f:id:maru0014:20180924120239p:plain

f:id:maru0014:20180924120313p:plain

これで初期設定後のRaspbianがバックアップできました。再インストールのときはこのイメージファイルを再びEtcherで書き込めばスピーディです。

Pythonでの利用がメインの場合は以下が終わったあとのバックアップでも良い気がします。

Python実行環境を整える

Raspbianには最初からPythonがインストールされています。 ただし、バージョンはPython 2.7と3.5。 ※今後のアップデートで変わって行くかもしれませんが。

python -Vで2.x系、python3 -Vで3.x系のバージョンを確認できます。

ここで問題なのが3.6以降に追加された文法機能。

参考 https://qiita.com/shirakiya/items/2767b30fd4f9c05d930b

メインPCで3.6.6や3.7.0の環境で快適にスクリプトを書いたは良いものの、いざRaspberry Piに実行環境を移すときに困ります。

わざわざ3.5以前の構文に書き直すなんて面倒くさいのでRaspberry Pi側を3.6以降に対応させます。

複数バージョンのインタプリタとプロジェクトごとの環境構築のためにpyenvとpipenvを利用します。

pyenvとは

複数バージョンのPythonを切り替えて使えるようにするもの。

pipenvとは

プロジェクト単位で利用するインタプリタやライブラリを指定して仮想環境を構築できるようにするもの。

git経由でpyenvをインストール

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install git
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.shrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.shrc
$ echo 'eval "$(pyenv init -)"' >> ~/.shrc
$ source ~/.shrc
$ pyenv

依存関係のあるライブラリをインストール

sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev
sudo apt-get install libffi-dev

pyenvでPython3.7.0をインストール

pyenv install 3.7.0

Python 3.7.0をデフォルトのインタプリタとして設定

$ pyenv global 3.7.0
$ python3 -V
Python 3.7.0

pipenvをインストール

$ pip install --upgrade pip
$ pip install pipenv

suで使いたい場合

$ sudo pip install --upgrade pip
$ sudo pip install pipenv

pipenvでプロジェクト単位の仮想環境構築

プロジェクト用フォルダを作成して、pipenvコマンドでPythonのバージョンを指定して環境構築。

以下のいずれかで実行。

$ pipenv install --three  # Python 3
$ pipenv install --two  # Python 2
$ pipenv --python 3.7.0  # バージョンを厳密に指定する

これでようやく・・・、と思いきやエラー発生。

Traceback (most recent call last):
  File "/home/pi/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pipenv/vendor/pexpect/expect.py", line 109, in expect_loop
    return self.timeout()
  File "/home/pi/.pyenv/versions/3.7.0/lib/python3.7/site-packages/pipenv/vendor/pexpect/expect.py", line 82, in timeout
    raise TIMEOUT(msg)
pexpect.exceptions.TIMEOUT: <pexpect.popen_spawn.PopenSpawn object at 0xb5556a70>
searcher: searcher_re:
    0: EOF

timeoutとあるのでどういうことかと検索したらstackoverflowが出てきた。

https://stackoverflow.com/questions/50382837/pipenv-install-timing-out-on-rpi

TL;DR: the fix is to extend the timeout Solved it. Because the RPi Zero is slow, it was timing out. Taking a clue from the discussion on github, I noticed that its now possible to extend the default timeout with environment variables. So this solved the problem:

つまりRaspberry Pi Zeroは処理速度が遅いため時間切れになっているので時間制限を伸ばしてやればいいらしい。

$ export PIPENV_TIMEOUT=500

これで再挑戦!

Virtualenv location: /home/pi/.local/share/virtualenvs/PyProjects-2hoSbewb

うまくいきました!

suで実行する必要がある環境は-Eで環境変数を引き継いで実行

$ sudo -E pipenv --python 3.7.0

参考 http://a4dosanddos.hatenablog.com/entry/2016/09/30/001007

仮想環境でHello World!

pipenv shellでvirtualenvを起動する。

pi@raspberrypi:~/PyProjects $ pipenv shell # 仮想環境立ち上げ
(PyProjects-2hoSbewb) $
(PyProjects-2hoSbewb) $ python
Python 3.7.0 (default, Sep 21 2018, 17:19:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello World!")
Hello World!

これにてPythonの仮想環境構築完了です。

pipでパッケージをインストールするには

これもpipenv installとする必要があります。

$ pipenv install requests
$ python
>>> import requests
>>>

別の仮想環境に切り替える

exitがpyenvで言うところのdeactivate

(PyProjects-2hoSbewb) $ exit
$ 

参考

https://qiita.com/sl2/items/1e503952b9506a0539ea

https://qiita.com/sl2/items/1e503952b9506a0539ea

https://qiita.com/Nimimal/items/72c2e2a6a566d1f5d2a2

https://www.lifewithpython.com/2018/02/python-pipenv.html

あとがき

ここ数日、QiitaでPythonの環境構築に関する記事を色々読んでpyenvを利用せずに直にインストールする方法もあったんですが、途中でよくわからなくなり結局事例の多いpyenvを利用することにしました。

まぁどんなふうに使うかによって要不要の意見は分かれるのでしょうが、右も左も分からない身としては情報が多いやり方が安心・・・。

Raspberry Pi Zero W Starter Kit

Raspberry Pi Zero W Starter Kit