道路監視システム
はじめに
以下の前回記事で難所であり要所はクリアしたので、いよいよ道路監視システムとしてのシステム化を行う。
全体的な処理の流れ
1、10分に一度撮像して保存、後続処理に渡す
2、画像をもとに物体検知、数をカウント
2-1、(デバッグ用)検知した物体を四角形で囲っている画像を最長辺を指定して表示
3、2-1の画像を保存
4、1日単位のcsvファイルに検知した物体ごとの数を追記して保存
制限事項
・現時点でローカル保存のみで、NAS等の外部ストレージ保存は手動
今後自動NASバックアップを検討
・自動削除機能は未実装
現時点で1回10分当たり1MB弱、1日で140MB程度要してローカルのストレージが32GB(実際22GB)なので削除機能が別途
・夜間輝度調整
夜間は撮影しても真っ暗で、輝度調整しても限界なので諦める。
・タイムラプス動画作成
制限というよりも削除前に動画化して残すと面白いかも
ハードウェア系
・ラズパイ4B 4GB
・中華カメラモジュール 5M pixel(¥1000)
・配置環境
カメラモジュールが基盤剥き出しなので養生(見た目悪い)

撮像対象のイメージ(イラスト

ソースコード
・画像から分析、結果を出力
・分析結果からデータを可視化してWebサイト上に動的に掲載
実行結果


csvファイルに追記した結果は気が向いたタイミングでグラフ化予定。
遠いところにある車などは検知ができていないので、このモデルの限界と思われ。
中華カメラでも問題なく動作しているので地味にすごい。
しばらく運用して気になるところは随時改良予定。
画像からオブジェクトを検出する(Darknet YOLOv4-tiny model)
はじめに
ラズパイ4とカメラモジュールが転がっていたので何かobject検知系で何か作ろうと思いつく。
その前段で必要前提条件である画像からのオブジェクト検知について使えそうな技術を検証したのが本記事。
全体システムの最終的なゴール
簡易的な交通量監視システムの構築
(趣味の範疇なので精度や速度は無視する。)
本記事の検証項目
静止画像からオブジェクトを検知できて、raspi4bでも動作する軽量な方法を調査・検証
検証実施内容
GPT4-Vision
OpenAI社のVisionモデルでサクッとやろうとしたが、結果的には不適合で検証終了。

メリット
◎APIに画像を載せるだけなので導入が超手軽
⚪︎費用も512x512pixの画像なら約0.002ドル/1リクエスト(0.3円くらい)とお手頃。
デメリット
❌オブジェクトのカウントをしてくれない
CAPTHA対策なのかオブジェクトの数を数えるように指示してもNGの旨が返ってくる。
△JSON形式でレスポンスを固定できない
システムプロンプトで指示はできるが、完全固定ではない模様(95%くらい守ってくれる?)
△安いとはいえリクエストの都度費用がかかるため大量のリクエストに不向き
1時間に1回リクエストで月220円くらいかかる。
TensorFlow LiteのMobileNet+SSDモデル
お手頃順にtensorFlowを検証したが、こちらはそもそもうまく動作しなかったため、不採用。
Colab上で動作検証をしたが、オブジェクト検知部分がおかしく色々調査してみたが、時間がかかりそうであったためスキップ。
・利用したモデル
lite-model_ssd_mobilenet_v1_1_metadata_2.tflite
YOLOv4-tinyモデル
本記事で紹介するモデル。特に問題なく動作したためこちらを採用。
こんなお手頃に動作するなんて驚きですね。
・簡単な説明(by gpt4)
特徴: YOLO(you only look once)は非常に高速であり、多くの一般物体を検出するための学習済みモデルが豊富に用意されています。
使用方法: YOLOの学習済みモデル(例えばYOLOv3-tinyやYOLOv4-tiny)をダウンロードし、YOLOフレームワークを使用して画像から車両を検出します。
メリット
⚪︎ローカルで動作するのでAPI費用が不要
⚪︎実行に要する時間も数秒程度(対象画像の解像度に比例するがHD画質程度であればこのくらい)
デメリット
△導入や閾値調整が必要
・利用した学習済みモデル(各種外部ファイルはここからダウンロード)
・ソースコード(Colab)
概ねあってます。
今流行りでのLLMではないですが、これくらいの精度でるなら交通量調査人の代替もすぐではないでしょうか。
*1:input_shape[1], input_shape[2]
AWS: コンテナをECRにpushしてECSタスクで起動する
概要
cloud9でイメージを作成→ECR へpush→ECSのタスクとして起動する
dockerfile作成(git参照)
0.ECRの認証を行う
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/m2p8a3y8
docker push public.ecr.aws/m2p8a3y8/tweet-something:latest
1.image build
凡例:docker build -t [image_name]:[tag] [Dockerfile_target]
ex) docker build -t python3_cont:1.0 ./
1a.container run
ローカルでコンテナを起動したい場合。
-d でバックグラウンド起動(他と組み合わせて-idt と指定)
docker run -itd [python3_cont]:[1.0]
1b.container exec
ローカルでコンテナの中へ入ってデバッグしたい場合。
sudo docker exec -it <<1a2dfe4802bc>> bash
<<*>>の部分は任意のコンテナID
2.container tag
ECRへ登録するためにECRのタグをイメージに付与する。
docker tag python3_cont:1.0 public.ecr.aws/m2p8a3y8/tweet-something:latest
3.container push
ECRへイメージを登録。
docker push public.ecr.aws/m2p8a3y8/tweet-something:latest
参考文献
Dockerコンテナをずっと起動しておく - WEB開発ノート
AWS EC2のストレージ(EBS)料金を大幅に抑える
EBSの料金を安くする方法
cloud9でたまにしかEC2を起動しないのにEBSで地味に料金がかかっているので、snapshotを作成して料金を抑える。
現状:12ヶ月の無料期間が終了後はgp2の50GBで月に5ドル料金が発生している。
作成手順
1.ボリュームのsnapshotを作成する
EC2 → サイドメニューのボリューム → 対象のボリューム → スナップショットの作成
1分程度で作成完了。

2.EBSボリュームの削除
ボリュームのデタッチを選択

ボリュームの削除

これで課金されなくなりました。課金の単位は毎秒(内部的には毎分)で発生するので、削除後にすぐに効力が出ます。
snapshotの料金は見落としているかもですが、請求書上は発生しておらず課金形態が謎。
以下の金額が計上されてました。どうやらEBS料金の4割程度になるみたいです。
$0.05 per GB-Month of snapshot data stored - Asia Pacific (Tokyo)
復元手順
1.スナップショットからボリュームの作成
サイドバー スナップショット→対象のボリュームを選択→スナップショットからボリュームの作成

ボリューム設定は以下を除きデフォルトのまま。
アベイラビリティゾーン(AZ)は作成手順1に記載のAZを選択すること

作成ボタンを押すとすぐにボリュームができる。
2.ボリュームのアタッチ

1、紐づけるインスタンスを選択
2、デバイス名は作成手順1で確認したデバイス名にする(画像は途切れていますが)
/dev/sda1 と入力

これで復元完了。
待ち時間はほとんどありませんでした。
ラズパイ起動時にサービスを自動立ち上げする
はじめに
宅急便自動受け取りシステムver2のpythonプログラムをOS起動時に自動起動させたい。
以前はcronでやってたがsystemdでやるのがいい感じらしいのでこの手法でやる。
設定
全体的な流れ
・サービスを登録
・サービス有効化
これだけ
サービス内容
好きなエディタで編集
sudo nano /etc/systemd/system/start_app.service
[Unit]
Description=door open program
After=multi-user.target
[Service]
ExecStart=/usr/bin/python3 main.py
WorkingDirectory=/home/<user_name>/Desktop/doorOpen
Restart=always
[Install]
WantedBy=multi-user.target
Restart=always
で異常終了しても自動でアプリを再起動してくれる
有効化
sudo systemctl enable start_app.service
無効化する際は
sudo systemctl disable start_app.service
sudo reboot now
で自動起動
その他
以上の設定を行うとLINE通知が届かなくなるが、パスや権限の問題の可能性が大。。。
・参考
https://monomonotech.jp/kurage/raspberrypi/systemd_autostart.html
マンションのオートロックを自動で解錠するVer2
前回作ったもの(下記事)から引っ越しにより改修を加えたので改修箇所を中心に記事にします。
主な改修点
ラズパイが話せるようになった
LINE通知できるようになった
イベント検知で駆動できるようにコードを書き換えた
GPIOからシャットダウン・起動できるようになった
全体像
全体像



動画Ver
ソースコード(GitHub)
GitHub - tech0x86/raspi3B-doorOpen: auto lock unlocker
ラズパイが話せるようになった
OpenJtalkを利用して任意の音声を話せるようになりました。
jtalk.shのシェルスクリプトをpythonからコールしてます。
jtalk.sh
#!/bin/bash
tempfile=`tempfile`
option="-m /usr/share/hts-voice/mei/mei_happy.htsvoice \
-x /var/lib/mecab/dic/open-jtalk/naist-jdic \
-ow $tempfile"
echo "$1" | open_jtalk $option
aplay -q $tempfile
rm $tempfile
main.py
import subprocess
def jtalk_script(message):
subprocess.run([PATH_JTALK +" "+message],shell=True)
・参考
Raspberry Pi(ラズパイ)を音声合成で日本語をしゃべらせてみた!(OpenJTalk) | りけろぐ
・
LINE通知できるようになった
LINE Notifyで来訪等を通知できるようになりました。
TOKENは下記コマンドでOSの環境変数化しています。
export LINE_TOKEN=XXXX
main.py
import requests
LINE_NOTIFY_TOKEN = os.environ.get("LINE_TOKEN")
LINE_NOTIFY_API = "https://notify-api.line.me/api/notify"# line に通知する
def send_line_message(notification_message):
headers = {"Authorization": f"Bearer {LINE_NOTIFY_TOKEN}"}
data = {"message": f" {notification_message}"}
r = requests.post(LINE_NOTIFY_API, headers = headers, data = data)
print(r)
time.sleep(1)

・参考
Pythonで、LINEにメッセージを通知する方法【LINE NOTIFY】 | ラズパイの実
イベント検知で駆動できるようにコードを書き換えた
前作の無限ループで状態をチェックするのもあまりスマートではないため、割り込み関数的な処理に変更。(以下の関数)
GPIO.add_event_detect(PIN_CDS, GPIO.RISING, callback=light_detected, bouncetime=5000) # 割り込み関数
ただ、誤作動が結構ある。。
GPIOからシャットダウン・起動できるようになった
プログラムがフリーズ等してもタクトスイッチを押すことでOSを安全にシャットダウン・起動できるようになった
下記ファイルの最終行に追記
/boot/config.txt
dtoverlay=gpio-shutdown
回路上でGPIO 3 (ピン番号 5) と GND (ピン番号 6)を短絡する
・参考
ラズパイをディスプレイ無しでSSH接続までセットアップする
環境を新規構築もしくは引越しした際に環境が変わった時に、わざわざディスプレイとキーボードを繋いでセットアップするのが面倒だったので、SSH接続までの手順を記録。
前提条件
ルータにDHCP機能があること(有線、無線)
クライアント端末はMac OS(他のOSの場合は適宜読み替えてください)
新規環境構築
Raspberry Pi Imager を利用してOSをSDカードへ書き込み
一番上のOSを選択。

オプションを設定する(重要)
画像の通り自身の環境に合わせて設定
SSHログインする際に必要なのでメモしておく。

OS書き込み
10分程度で書き込み完了。SDカードをラズパイに差して電源をいれて起動。
SSH接続
上の設定で間違いがなければ自宅のLANに接続されているはず。
ルータのDHCP機能でIPが自動割り振られているが、IPアドレスは分からないので、ホストネームとユーザ名を指定してssh ログインする(下記コマンド)。
ssh <username>@<hostname>.local
上の例だと
ssh pi3b1@pi3b1.local
※ログインパスワードは↑の画像で設定したユーザログインのものと同じ。
IPアドレスでログインする場合は
ssh pi3b1@192.168.0.10 とか
IPアドレス固定
DHCPだと勝手にIPアドレスが変わってしまうため、静的IPアドレスを設定。
以下は無線LANの設定例(有線LANの場合はwlan0ではなく、eh0)
下記ファイルを編集
nano /etc/dhcpcd.conf
<ファイル末尾に追記>
interface wlan0
static ip_address=192.168.0.10
static routers=192.168.0.1
static domain_name_servers=8.8.8.8 192.168.0.1
ラズパイを再起動して設定を反映
sudo reboot now
上記操作後にクライアント端末(macとか)で同じようにSSH接続しようとすると
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
のエラーが出る場合があります。
もし出たらクライアント端末で、該当のラズパイのアドレス箇所を削除しましょう。
nano /Users/<user_name>/.ssh/known_hosts
パッケージ更新
下記コマンドでパッケージを更新する。apt-getから変わったみたい。
sudo apt update
sudo apt full-upgrade
既存の環境修正
引越しなどでルータが変わった場合に接続先を更新する対応です。
必要なのはLANケーブル1本だけ。
無線LANには勝手に繋がらないので、ルータ/ハブに有線で繋いでDHCPでアドレスを自動割り当てされるようにしましょう。
そしたら下の書き方で接続されるはず。
ssh pi3b1@pi3b1.local
無線LANの設定の更新
下記ファイルに接続情報があるみたいです。
nano 等で開いて各自の環境に合わせて編集。
/etc/wpa_supplicant/wpa_supplicant.conf
編集
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP
network={
ssid="ssid" #接続する予定のWi-FiのSSID"で括る
psk="password" #パスワード
key_mgmt=WPA-PSK
}
あとは再起動しましょう。
