Raspberry Pi を定点カメラとして使うために,電源 ON してからなるべく早く画像を撮影してアップロードする方法を探りましたので紹介します.
はじめに
電気二重層コンデンサで駆動する定点カメラを作ろうと思い立って考えた結果,Raspberry Pi Zero W を使うことにしました.Raspberry Pi には SONY の IMX219PQ を使ったカメラモジュールが公式に用意されおり,高品位な撮像が期待できます.
Raspberry Pi を使うにあたって気になるのが消費電力.電気二重層コンデンサを使うことを考えるとなるべく絞りたい.
このためには,素早く起動して撮影を行い,後は電源を切っておくことが重要です.
そこで,Raspberry Pi の起動時間の高速化に取り組むことにしました.
撮影スクリプト
撮影に使用するスクリプトは次のものです.PiCamera を使って撮影を行い,OpenSSH の scp でファイルをサーバにアップロードします.
ネットには無線 LAN で接続していることを想定しています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from datetime import datetime print('{} SCRIPT Start.'.format(datetime.now()), flush=True) import os import time import subprocess # print('{} Loading paramiko...'.format(datetime.now()), flush=True) # import paramiko print('{} Loading PiCamera...'.format(datetime.now()), flush=True) from picamera import PiCamera TMP_FILE_PATH = '/dev/shm/camera_uid_{}.jpg'.format(os.getuid()) IMAGE_NAME_FORMAT = 'camera-%Y%m%d_%H%M.jpg' SSH_HOST = '192.168.2.20' SSH_USER = 'guest' SSH_KEY = '/home/pi/.ssh/guest.id_rsa' SSH_CMD = 'ssh -i {key} -o IdentitiesOnly=yes -o StrictHostKeyChecking=no {user}@{host}' SCP_CMD = 'scp -i {key} -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -q {from_file_path} {user}@{host}:{to_file_path}' def upload(from_file_path): while True: try: proc = subprocess.run( [ *(SSH_CMD.format(host=SSH_HOST,user=SSH_USER,key=SSH_KEY).split(' ')), 'date "+%Y%m%d_%H%M"' ], stdout = subprocess.PIPE, check = True ) to_file_path = 'camera-{}.jpg'.format(proc.stdout.decode('utf-8').strip()) subprocess.run( SCP_CMD.format(host=SSH_HOST,user=SSH_USER,key=SSH_KEY, from_file_path=from_file_path,to_file_path=to_file_path).split(' '), check = True ) break except: pass time.sleep(1) def capture(): image_path = TMP_FILE_PATH camera = PiCamera() camera.resolution = (3280, 2464) camera.iso = 100 camera.capture(image_path, quality=100) return image_path print('{} START capture...'.format(datetime.now()), flush=True) image_path = capture() print('{} START upload...'.format(datetime.now()), flush=True) upload(image_path) print('{} FINISH.'.format(datetime.now()), flush=True) |
工夫したのは次の2点です.
- paramiko は使わない
- 最初,SSH を使ったアップロードのため,paramiko を使っていたのですが,import paramiko だけで 10 秒近くかかっていましたので,OpenSSH に切り替えました.
プロファイルも取ってみたのですが,純粋にモジュールのロードに時間がかかっているようです.
12345678ncalls tottime percall cumtime percall filename:lineno(function)209/1 0.184 0.001 12.212 12.212 {built-in method builtins.exec}1 0.001 0.001 12.212 12.212 capture.py:6(<module>)216/4 0.033 0.000 8.127 2.032 <frozen importlib._bootstrap>:966(_find_and_load)216/4 0.024 0.000 8.125 2.031 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)212/4 0.033 0.000 8.092 2.023 <frozen importlib._bootstrap>:659(_load_unlocked)181/4 0.016 0.000 8.087 2.022 <frozen importlib._bootstrap_external>:667(exec_module)274/4 0.006 0.000 8.063 2.016 <frozen importlib._bootstrap>:214(_call_with_frames_removed) - 時刻情報はサーバから取得
- Linux の起動の高速化を行うため,スクリプトは時刻合わせが行われる前に動作を開始します.そのため,ファイル名に時刻を埋め込むにあたっては,サーバから時刻情報を取得するようにしています.
Linux の起動高速化設定
Raspberry Pi の電源を ON してからなるべく早く先ほどのスクリプトを実行するため,Linux 起動の高速化を行いました.
実施内容は Ansible の Playbook にまとめ, fastboot として github においてあります.
やったこと大きく次の4点です.順に紹介します.
- 不要なサービスの削除
- 不要な動作の抑制
- クロック高速化
- 撮影の早期開始
不要なサービスの削除
次のコマンドを実行します.
割と色々止めてしまっていますが,無線 LAN でネットに接続した Raspberry Pi に SSH でログインする使い方であれば,特に制約は発生しません.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
sudo systemctl disable dphys-swapfile.service sudo systemctl disable keyboard-setup.service sudo systemctl disable apt-daily.service sudo systemctl disable wifi-country.service sudo systemctl disable hciuart.service sudo systemctl disable raspi-config.service sudo systemctl disable avahi-daemon.service sudo systemctl disable triggerhappy.service sudo systemctl disable ntp.service sudo apt-get purge -y --auto-remove exim4 "exim4-*" sudo apt-get purge -y --auto-remove dphys-swapfile sudo apt-get purge -y --auto-remove dbus sudo apt-get purge -y --auto-remove plymouth sudo apt-get purge -y --auto-remove alsa-utils |
不要な動作の抑制
起動時のコンソール出力を停止するため,/boot/cmdline.txt
を次のようにします,
1 |
dwc_otg.lpm_enable=0 root=PARTUUID=efaf36d8-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet |
Bluetooth 無効化し,不要な動作を停止するため,/boot/config.txt
の末尾に次の内容を追加します.
1 2 3 |
dtoverlay=pi3-disable-bt disable_splash=1 boot_delay=0 |
使用しないデバイスファイルを生成しないようにするため,/etc/udev/rules.d/99-com.rules
の最初の3行を次のように「#」でコメントアウトします.
1 2 3 |
# SUBSYSTEM=="input", GROUP="input", MODE="0660" # SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" # SUBSYSTEM=="spidev", GROUP="spi", MODE="0660" |
クロック高速化
SD カードアクセスを速め,CPU 速度を高速に保つため,/boot/config.txt
の末尾に次の内容を追加します.
1 2 3 4 5 6 |
# SD カードアクセスの高速化 dtoverlay=sdtweak,overclock_50=100 # クロックの常時高速化 arm_freq=1000 sdram_freq=500 force_turbo=1 |
撮影の早期開始
起動時にスクリプトを実行するには cron の @reboot や /etc/rc.local をする方法が一般的ですが,今回はなるべく早くスクリプトを実行したかったので,独自のサービスを定義します.
具体的には,下記の内容のファイルを /etc/systemd/system/capture.service
に作成します.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[Unit] Description=Capture Camera Image Service [Service] ExecStart=/home/pi/rasp-camera/client/capture.py Nice=-10 StandardOutput=syslog StandardError=syslog SyslogIdentifier=capture WorkingDirectory=/home/pi/ [Install] WantedBy=network.target |
その上で,次のコマンドを実行しておきます.
1 |
sudo systemctl enable capture.service |
効果確認
bootchart
bootchart で起動シーケンスの確認をしてみます.起動後,13秒ほどで撮影スクリプトが開始している様子が確認できます.なかなか早いです.
また,CPU の使用率が 100% に張り付いており,かつ,無駄なプロセスが見当たらないので,これ以上の高速化は難しそうです.
ちなみに,普通は見慣れない unionfs-fuse というのがありますが,これは SD カードを保護する目的で /etc と /var を読み取り専用にするために使っているものです.特に /var に対してはこれやっておかないと,常時稼働して 1 年程度で SD カードが壊れる可能性が高くなるので外せないです.
消費電力
Raspberry Pi Zero の電源を投入してから,ファイルのアップロードが完了するまでの 5V の消費電流の推移は次のようになります.アップロード完了までに必要な時間は 30 秒で,その間の平均消費電流は 213mA です.
SSH で伝送している最中が消費電流のピークとなり 500mA 近くいきますが,それが完了すれば 120mA 程度まで一気に低下します.低消費電力が売りの ESP32 でも無線 LAN 接続中は 3.3V 120mA を超えています。電圧差を考慮しても電力として倍もいっていないのはなかなか優秀.
参考文献
- Fast boot with Raspberry Pi
- 紹介した高速化テクニックは基本的にこのサイトを参考にしています.こちらのサイトの場合,ネットワークも無効化しているので,4秒ほどで起動が完了するようです.
- Raspberry Pi Zeroを10秒以内で高速起動する最も簡単な方法
- Raspberry Pi Zero の高速化の事例として参考にしました.この方もネットワークを無効化しており,起動時間としては 8.4 秒のようです.
まとめ
Raspberry Pi Zero W をカスタマイズすることで,電源 ON から 30 秒で撮影した画像のアップロードを完了させることができました.この間の消費電流は 213mA となり,必要なエネルギーは 5 * 0.213 * 30 = 32J となります.
これは 5V で充電された 90F の電気二重層コンデンサ(196 HVC ENYCAP)が蓄えられるエネルギー 460J の約7%となります.電気二重層コンデンサで動かすには十分な小ささです.
コメント