はじめに
いろいろなサイトを参考にさせていただきながらセットアップをしました。
参考にしたサイトは末尾に一覧にしました。
各種コマンド、スクリプトファイルなどは見やすさのために転記していますが、
参考にしたサイトがオリジナルであるものがほとんどです。
ありがたや...
3部作
本「ラズパイ3で会議室の利用人数を監視する」は3部作となっております。
- サーバー構築編
- Azureセットアップ編
- ラズパイセットアップ編 (これです)
用意するもの
以下のものを用意しました。
USBメモリーはSWAPにします。ヒートシンクは念のため。広角レンズは広い画角が欲しい場合に。
- Raspberry Pi メインボード Bluetooth(R) Wi-Fi対応モデル Raspberry Pi 3 model B
- カメラモジュール
- microSDHCカード(16GB)
- 電源アダプター (5V 2.5A)
- USBメモリー(16GB)
- ヒートシンク
- セリア(100円ショップ)の広角レンズ
セットアップ
基本的な環境設定
OSイメージのダウンロード
https://www.raspberrypi.org/downloads/raspbian/
から最小構成である Raspbian Buster Lite をダウンロードします。
PKG (as of 2020/01/20) SIZE
---------------------------------------------------- -------
Raspbian Buster with desktop and recommended software 2541 MB
Raspbian Buster with desktop 1123 MB
Raspbian Buster Lite 435 MB
---------------------------------------------------- -------
OSイメージをmicroSDHCカードに焼く (PCを使って)
Etcherを使いました。
色々考えずにすんで便利!
ラズパイに色々接続する
- microSDHCカード(基板裏にスロットがあります)
- カメラ (フレキの向きを間違えないよう。繊細なので慎重に)
- USBメモリ
- USBキーボード ※セットアップ時のみ
- HDMIケーブル + ディスプレイ ※セットアップ時のみ
- ネットワークケーブル
- CPUにヒートシンクを貼る
- 電源(USB-Micro端子)
電源を接続するのは必ず最後にしましょう
初期パスワードでログイン
login : pi
password : raspberry
$ passwd
でパスワードは変更しておきましょう。
proxy設定 (プロキシ内にいる場合)
プロキシ内にいる場合、いろいろ設定が必要なので、ここでまとめて書いておきます。
プロキシサーバが http://proxy.xxxx:10080
であることを前提に書いています。
$ sudo vi /etc/apt/apt.conf
Acquire::http::proxy "http://proxy.xxxx:10080/";
Acquire::https::proxy "http://proxy.xxxx:10080/";
※行末のセミコロン(;)を忘れないように!
$ vi ~/.curlrc
proxy = "http://proxy.xxxx:10080"
$ sudo vi /etc/wgetrc
http_proxy=http://proxy.xxxx:10080/
https_proxy=http://proxy.xxxx:10080/
あとは、gitのproxyもあるのですが、gitをインストールした後に設定します。
SSH有効化など、sudo raspi-config でやっておく事
$ sudo raspi-config
で設定画面を立ち上げます
1. SSH有効化
5 Interfacing Options --> P2 SSH --> Would you like enable? ==> YES
2. TimeZoneを東京(Tokyo)に変更
4 Localisation Options --> I2 Change Timezone --> Asia --> Tokyo
3. Localeに ja_JP.EUC-JP と ja_JP.UTF-8 を追加
4 Localisation Options --> I1 Change Locale --> ja_JP.EUC-JP EUC-JP/UTF-8にチェック --> default en_GB.UTF-8
※ロケールの生成にすこし時間がかかります
4. キーボードレイアウトの変更 (JPキーボード)
4 Localisation Options --> I3 Change Keyboard Layout --> Generic 105-key PC (intl.) --> other
--> Japanese --> Japanese (OADG 109A) --> The default for... --> No Compose Key
SSH接続テスト
$ ifconfig -a
でIPアドレスを調べましょう。Windows/Linuxなどの別端末から
$ ssh -l pi xxx.xxx.xxx.xxx
で接続できればOK
WindowsであればTera Termを使うのも便利です
時刻合わせ (apt-getなどが正常に動作するように)
以下のコマンドで google様から現在時刻をいただきます
$ sudo date -s "$(curl -s --head http://www.google.co.jp | grep ^Date | cut -b 7-)"
.bashrc
にも設定してログインのたびに時刻を合わせるようにします
$ echo 'sudo date -s "$(curl -s --head http://www.google.co.jp | grep ^Date | cut -b 7-)"' >> .bashrc
ソフトウェアアップデート
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade
upgradeは時間がかかります
各種インストール
プロキシサーバが http://proxy.xxxx:10080
であることを前提に書いています。
プロキシ環境ではない場合は、git configのproxy設定と、pipの --proxy http://proxy.xxxx:10080
は不要です
$ sudo apt-get install git
$ sudo apt-get install samba
$ sudo apt-get install vim
$ sudo apt-get install python-dev
$ sudo apt-get install python-pip
$ sudo apt-get install libffi-dev
$ sudo apt-get install watchdog
$ sudo apt-get install imagemagick
(以下、gitの設定)
$ git config --global http.proxy http://proxy.xxxx:10080
$ git config --global https.proxy http://proxy.xxxx:10080
$ git config --global user.email "(your mail address)"
$ git config --global user.name "(your name)"
$ git config --list
(以下、Azureライブラリのインストール)
$ pip install --upgrade pip --proxy http://proxy.xxxx:10080
$ pip install --upgrade setuptools --proxy http://proxy.xxxx:10080
$ pip install cffi --proxy http://proxy.xxxx:10080
$ pip freeze
$ pip uninstall azure
$ pip install azure --proxy http://proxy.xxxx:10080
$ pip install azure-cosmosdb-table --proxy http://proxy.xxxx:10080
samba設定
$ sudo vim /etc/samba/smb.conf
# pi home sharing
[pi]
path = /home/pi
read only = no
guest ok = no
force user = pi
# tmp directory sharing
[tmp]
path = /tmp
read only = yes
guest ok = no
force user = pi_guest
以下のコマンドで必要なユーザを作ります。
パスワードは適宜決めてください
$ sudo adduser pi_guest
$ sudo smbpasswd -a pi
$ sudo smbpasswd -a pi_guest
$ sudo systemctl enable smbd
$ sudo systemctl restart smbd
watchdogを有効にする
$ sudo vi /lib/systemd/system/watchdog.service
[Install]
WantedBy=multi-user.target <----- 追加する
$ sudo update-rc.d watchdog enable
$ sudo modprobe bcm2835_wdt
$ sudo vi /etc/watchdog.conf
max-load-1 = 24 <----- コメント(行頭の#)を外す
watchdog-device = /dev/watchdog <----- コメント(行頭の#)を外す
watchdog-timeout = 10 <----- 追加する
カメラを有効にする
$ sudo raspi-config
から
5 Interfacing Options > P1 Camera > enabled? ==> YES
設定後リブートが必要です。
darknet + YoloV2のセットアップ
darknetのインストール
darknet本体をgithubから取得しビルドします。
$ cd
$ mkdir git
$ cd /home/pi/git
$ git clone https://github.com/pjreddie/darknet
$ cd darknet
$ make
重みファイルを持ってきます。
$ wget http://pjreddie.com/media/files/yolov2.weights
[テスト] 写真撮影
$ raspistill -w 600 -h 400 -o /tmp/test.jpg
[テスト] 物体認識
$ cd /home/pi/git/darknet
$ ./darknet detect cfg/yolov2.cfg yolov2.weights /tmp/test.jpg -o /tmp/res
結果が /tmp/res.jpg に出力されます
ラズパイのSDカードを守る(延命措置)
SDカードに繰り返し書き込みを行うと、意外に早くSDカードが死んでしまいます。
以下の4つの作業を行ってSDカードを延命します。
サーバなど常時電源ONでラズパイを運用する場合は必須だとおもいます。
(1) テンポラリ領域をtmpfs(Ramdisk上)にする
(2) ログ出力を減らす
(3) ログファイルの一次作成場所をtmpfs(Ramdisk上)にする
(4) swapを外付けUSBメモリに逃がす
(1) テンポラリ領域をtmpfs(Ramdisk上)に設定する
$ sudo vim /etc/fstab
でfstab
をひらき、以下の2行を追加
tmpfs /tmp tmpfs defaults,size=32m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=16m,noatime,mode=1777 0 0
ディスク上の /tmp, /var/tmp を消して再起動
$ sudo rm -rf /tmp
$ sudo rm -rf /var/tmp
$ sudo shutdown -r now
(2) ログ出力を減らす
$ sudo vim /etc/rsyslog.conf
で rsyslog.conf
を編集して
不要そうなログを # でコメントアウトしたのち、リスタート。
$ sudo systemctl restart rsyslog
以下のサービスは既知の問題でエラーログを大量に出すので無効にする
$ sudo systemctl stop avahi-daemon
$ sudo systemctl disable avahi-daemon
(3) ログファイルの一次作成場所をtmpfs(Ramdisk上)にする
必要なスクリプト4つ
(i) セットアップ・スクリプト・ジェネレータ
(ii) セットアップ・スクリプト (1による自動生成)
(iii) バックアップ・スクリプト
(iv) init.d用スクリプト (2と3を呼び出す)
(i) セットアップ・スクリプト・ジェネレータ
$ vi /home/pi/scripts/make-init-logfiles.sh
#!/bin/sh
# 出力するスクリプトファイル
fScr="${HOME}/scripts/setup-logs.sh"
#ログファイル
stat --format='%a %U:%G %n' `find /var/log/ -maxdepth 1 -mindepth 1 -type f` | grep -v '.gz\|.log$\|1$\|.old' > ~/logFiles
cp -i ~/logFiles ~/logFiles.bak
#ログディレクトリ
stat --format='%a %U:%G %n' `find /var/log/ -maxdepth 1 -mindepth 1 -type d` > ~/logDirs
cp -i ~/logFiles ~/logDirs.bak
echo "#!/bin/sh" > $fScr
echo "\n### Make directories ###" >> $fScr
cat ~/logDirs | while read line
do
echo "##" >> $fScr
echo $line | awk '{print "mkdir -p " $3}' >> $fScr
echo $line | awk '{print "chmod " $1 " " $3}' >> $fScr
echo $line | awk '{print "chown " $2 " " $3}' >> $fScr
done
echo "\n### Make files ###" >> $fScr
cat ~/logFiles | while read line
do
echo "##" >> $fScr
echo $line | awk '{print "touch " $3}' >> $fScr
echo $line | awk '{print "chmod " $1 " " $3}' >> $fScr
echo $line | awk '{print "chown " $2 " " $3}' >> $fScr
done
# 実行権をつけておく
$ chmod +x $fScr
(ii) セットアップ・スクリプト
上記スクリプトを実行することで生成します。
後に手順を説明します。
(iii) バックアップ・スクリプト
$ vi /home/pi/scripts/backup-logs.sh
#!/bin/sh
LOG_DIR="/back/logs/"
LOG_FILE="${LOG_DIR}backup-history.txt"
sudo sh -c "date > $LOG_FILE"
sudo sh -c "rsync -av /var/log/* $LOG_DIR >> $LOG_FILE"
(iv) init.d用スクリプト
$ vi /etc/init.d/setup-tempfs-logs
#!/bin/sh
### BEGIN INIT INFO
# Provides: setup-tempfs-logs
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Setup tempfs log files
### END INIT INFO
case "$1" in
start|"")
sh /home/pi/scripts/setup-logs.sh 2>&1 >/dev/null
;;
stop)
sh /home/pi/scripts/backup-logs.sh 2>&1 >/dev/null
;;
*)
echo "Usage: /etc/init.d/setup-tempfs-logs [start|stop]" >&2
exit 3
;;
esac
手順
Step 1) セットアップスクリプトを除く各種スクリプトを作成する
Step 2)セットアップ・スクリプト・ジェネレータの実行
$ sh /home/pi/scripts/make-init-logfiles.sh
Step 3) バックアップ・スクリプトを実行してバックアップ作成
$ sudo mkdir -p /back/logs
$ sh /home/pi/scripts/backup-logs.sh
$ ls /back/logs
step 4) init.d登録
古いコマンド (insserv
があればこちらを利用)
$ sudo insserv -d setup-tempfs-logs
$ sudo ls -la /etc/rc*.d/*setup-tempfs-logs
新しいコマンド (insserv
がなければこちらを利用)
$ sudo /lib/systemd/systemd-sysv-install enable setup-tempfs-logs
step 5) cron登録
$ sudo crontab -e
0 * * * * /home/pi/scripts/backup-logs.sh
step 6) fstab更新
$ sudo vim /etc/fstab
tmpfs /var/log tmpfs defaults,size=32m,noatime,mode=0755 0 0
step 7) リブート
$ sudo rm -rf /var/log
$ sudo shutdown -r now
step 8) いろいろ確認
$ df /var/log
$ ls /back/logs
(4) swapを外付けUSBメモリに逃がす
step 1) USBメモリをswap用にする
-->
以降は分かりやすさのためのコメントです。(なので実際には打たない)
$ lsblk --> マウントポイントを知る ex) /dev/sda1
$ umount /dev/sda1 --> 念のためアンマウントする
$ sudo mkfs.ext4 /dev/sda1 --> USBメモリをフォーマット
$ sudo mkswap -c -v1 -L usbswap /dev/sda1 --> USBメモリをスワップに
$ lsblk -f --> 確認
$ sudo fdisk /dev/sda --> パーティションタイプを82に変更(注:"sda1"ではなく"sda")
p --> パーティション一覧表示
t --> タイプ変更
82 --> linux swap(82)を指定
p --> 表示(確認)
w --> 書き込み
step 2) fstabでファイルシステムに追加
$ sudo vim /etc/fstab
LABEL=usbswap swap swap default 0 0
step 3) リブート
$ sudo shutdown -r now
step 4) 既存のSWAPの解放と、USBメモリのSWAP指定
$ sudo swapoff --all
$ sudo swapon -L usbswap
$ swapon -s
step 5) SWAPの利用状況を確認する
$ top
で KiB Swap: に全体の容量、使用容量、空き容量 が表示されます
top - 12:11:01 up 12 min, 2 users, load average: 1.00, 0.88, 0.52
Tasks: 134 total, 2 running, 132 sleeping, 0 stopped, 0 zombie
%Cpu(s): 25.3 us, 0.0 sy, 0.0 ni, 74.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 880552 total, 848320 used, 32232 free, 4524 buffers
KiB Swap: 3949092 total, 17180 used, 3931912 free. 32944 cached Mem ★これ!★
監視システム起動
各種スクリプト
Azure Table Storage にデータを投げるための補助スクリプト
import os
import sys
from azure.cosmosdb.table.tableservice import TableService
from azure.cosmosdb.table.models import Entity
# args[1] = pi_id
# args[2] = number (of persons)
# args[3] = time stamp (short format)
# args[4] = time stamp (long format)
# args[5] = source (last 2 octed of IP address)
# RowKey = timestamp (long format) + ':' + pi_id
args = sys.argv
# proxy
os.environ["https_proxy"] = "http://proxy.xxxx:10080"
# connect to Azure Table Service
table_service = TableService(account_name='(my storage service)', account_key='(my account key)')
table_service.create_table('(my table)')
# creat entity
task = { 'PartitionKey': 'log',
'RowKey': args[4] + ':' + args[1],
'pi_id': args[1],
'count': args[2],
'timestamp_short': args[3],
'timestamp_long': args[4],
'source': args[5] }
# insert the entity
table_service.insert_entity('(my table)', task)
監視システム本体
#!/bin/sh
# unique id for each Raspberry PI
pi_id=3
# swap
sudo swapoff --all
sudo swapon -L usbswap
# initialize loop flag
echo "1" > /home/pi/scripts/flag.txt
flag=`cat /home/pi/scripts/flag.txt`
# loop
while [ $flag -eq "1" ]
do
# capture and person detection
raspistill -w 608 -h 456 -o /tmp/cam.jpg
cd /home/pi/git/darknet
./darknet detect cfg/yolov2.cfg yolov2.weights /tmp/cam.jpg -out /tmp/res > /tmp/result0.txt
cat /tmp/result0.txt | grep person > /tmp/result1.txt
res=`cat /tmp/result1.txt | wc -l`
# timestamp
long_ts=`stat /tmp/cam.jpg | grep Modify | sed -r "s/^Modify:\s*([0-9 :\-]+).*$/\1/"`
short_ts=`stat /tmp/cam.jpg | grep Modify | sed -r "s/^Modify:\s*[0-9]{4}\-([0-9]{2})\-([0-9]{2})\s([0-9]{2}):([0-9]{2}).*$/\1\/\2 \3:\4/"`
# source
src=`ip a | grep "xx.xx" | sed -r "s/^\s*inet\s*[0-9]+\.[0-9]+\.([0-9]+\.[0-9]+).*$/\1/"`
# call WebAPI
curl -F "pi_id=${pi_id}" -F "number=$res" -F "short_timestamp=$short_ts" -F "long_timestamp=$long_ts" -F "source=$src" https://xxxx.herokuapp.com/faces/create
# call Azure
python /home/pi/scripts/azure_test.py ${pi_id} $res "$short_ts" "$long_ts" "$src"
# jpg rotation (for debug)
for cnt in 9 8 7 6 5 4 3 2 1
do
src=`expr ${cnt} - 1`
mv -f /tmp/cam${src}.jpg /tmp/cam${cnt}.jpg
mv -f /tmp/res${src}.jpg /tmp/res${cnt}.jpg
done
cp /tmp/cam.jpg /tmp/cam0.jpg
cp /tmp/res.jpg /tmp/res0.jpg
# check flag
flag=`cat /home/pi/scripts/flag.txt`
done
定時起動、定時終了するように設定する
Step 1) serviceスクリプトを書く
$vi /etc/systemd/system/person_detection.service
[Unit]
#just what it does
Description= person detection service
[Service]
#not run by root, but by me
User=pi
#we assume the full service as active one the script was started
Type=simple
#where to find the executable
ExecStart=/home/pi/scripts/person_detection.sh
#what you want: make sure it always is running
Restart=always
[Install]
#which service wants this to run - default.target is just it is loaded by default
WantedBy=default.target
念のためモード変更
$ sudo chmod 777 person_detection.service
Step 2) serviceに登録し起動する
$ sudo systemctl enable person_detection.service
$ sudo systemctl start person_detection.service
Step 3) 確認
$ sudo systemctl status person_detection.service
● person_detection.service - person detection service
Loaded: loaded (/etc/systemd/system/person_detection.service; enabled)
Active: active (running) since Thu 2020-01-16 18:54:48 JST; 6min ago
Main PID: 17989 (person_detectio)
CGroup: /system.slice/person_detection.service
tq17989 /bin/sh /home/pi/scripts/person_detection.sh
tq18380 /bin/sh /home/pi/scripts/person_detection.sh
tq18381 ./darknet detect cfg/yolov2.cfg yolov2.weights /tmp/cam.jpg -out /tmp/res
tq18382 grep person
mq18383 wc -l
(ログは略)
Step 4) crontab で定時起動、定時終了
$ sudo crontabl -e
0 8 * * 1-5 systemctl start person_detection.service
0 21 * * 1-5 systemctl stop person_detection.service
以上で完了です
お疲れ様でした!!
参考にさせていただいたサイト(大感謝)
【構築編】RaspberryPi + 物体検出 で室内の人数を slack へ可視化
https://qiita.com/ryhoh/items/a9191d65214f42fb94d4
RaspberryPiにtiny-Yolov2を実装してリアルタイム画像検出を行ってみた
https://qiita.com/daiarg/items/2ef986732632af5a5133
Raspberry PiでDarknetを使う
https://qiita.com/Brutus/items/b898a4b0e28303f3edfa
Raspberry Pi 3を買ってみた、必要な物やOSのインストールなど
https://jyn.jp/raspberrypi3-getting-started/
Raspberry PiのSDカードが壊れた!寿命を延ばす方法 5+1選!【運用編を追加】
https://iot-plus.net/make/raspi/extend-sdcard-lifetime-5plus1/
【STEP-27】swap領域を別デバイスに移動してSSD最適化
https://www.fabshop.jp/%E3%80%90step-27%E3%80%91swap%E9%A0%98%E5%9F%9F%E3%82%92%E5%88%A5%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%AB%E7%A7%BB%E5%8B%95%E3%81%97%E3%81%A6ssd%E6%9C%80%E9%81%A9%E5%8C%96/
avahi-daemon constantly reporting "Invalid response packet from host"
https://bugs.launchpad.net/ubuntu/+source/avahi/+bug/1342400
永久ループのあるcronコマンドを実行するにはどうすればよいですか?
https://tutorialmore.com/questions-58529.htm
crontabの書き方
https://www.server-memo.net/tips/crontab.html
ラズパイにpipをインストールする
http://poohkids.com/raspberrypi/raspi_pipinstall/
ゼロからはじめるAzure 第2回 ストレージの種類と概要
https://news.mynavi.jp/article/zeroazure-2/
テーブルストレージを用いたWebアプリケーション
https://news.mynavi.jp/article/zeroazure-3/
テーブルストレージによる更新、削除、複雑な検索処理
https://news.mynavi.jp/article/zeroazure-4/
【Microsoft公式】
Python を使用して Azure Table Storage と Azure Cosmos DB Table API を使用する
https://docs.microsoft.com/ja-jp/azure/cosmos-db/table-storage-how-to-use-python
[GitHub] Azure/azure-cosmos-table-python
https://github.com/Azure/azure-cosmos-table-python/tree/master/azure-cosmosdb-table
YOLOを使って認識した結果のバウンディングボックスを構成する座標値とそれに対応したクラス名を取得したいです
https://teratail.com/questions/106933
ルーターもアップグレード完了
https://seasky.blue/weblog/index.php?e=2268
ubuntu18.04 - Ubuntu 18にinsservがありません
https://tutorialmore.com/questions-293762.htm
mkswap - システム管理コマンドの説明 - Linux コマンド集 一覧表
https://kazmax.zpp.jp/cmd/m/mkswap.8.html
Darknetのサンプルのソースを覗いてみた。(I looked into the sample source of Darknet.)
https://iwaki2009.blogspot.com/2017/06/darkneti-looked-into-sample-source-of.html
curlコマンドから HTTP POST する方法
https://qiita.com/letsspeak/items/8c7266742371699ab45e
ラズパイ2/3のスペック差
https://ja.wikipedia.org/wiki/Raspberry_Pi
Raspberry Pi 3B+のウオッチドッグタイマー(Watch Dog Timer:WDT)を有効化して自動再起動する方法
https://atooshi-note.com/raspberry-pi-watchdog/
[EOF]