← 기사 목록
日本語https://zenn.dev/topics/ai/feed

猫2匹を見分けるカメラを作る (1) ── Raspberry Pi 4 + Coral 環境構築

추출된 키워드

52
Coral USB アクセラレーター·5環境構築·5Raspberry Pi 4·5picamera2·4tflite-runtime·4Python·4Raspberry Pi OS·4個体識別·4EdgeTPU·4Trixie·3venv·3libedgetpu1-std·3uv·3libcamera·3ImageNet·3mobilenet_v2_1.0_224_quant_edgetpu.tflite·3Fan SHIM·3Debian 13·3USB HDD·3Bookworm·3OV5647·3Debian 12·3Pi Camera Module·3flask·2vcgencmd·2numpy·2opencv-python-headless·2pillow·2Pimoroni·2gdown·2imagehash·2rpicam-hello·2psutil·2python3-rpi.gpio·2GPTパーティションテーブル·2Claude·2AI HAT+ 2·2Raspberry Pi 5·2Raspberry Pi AI Camera·2IMX500·2Raspberry Pi Imager·2SSH·2fdisk·2Google Inc.·2mkfs.ext4·2rsync·2fstab·2cmdline.txt·2systemd·2dphys-swapfile·2tmpfs·2Global Unichip Corp.·2

원문

16,816
猫2匹を見分けるカメラを作る (1) ── Raspberry Pi 4 + Coral 環境構築

猫2匹を見分けるカメラを作る (1) ── Raspberry Pi 4 + Coral 環境構築

はじめに

Coral USB アクセラレーターの使い道を考えていたところ、猫2匹のどちらがどのご飯を食べているかを判別して録画する、というシステムを思いつきました。猫の食事場所には人間の足も映り込むので、不要なフレームをスキップする処理も必要です。

最終的には以下のような構成になります。

Cat Monitor の Web UI

この記事は、Claudeとチャットでやり取りしながら手順を組み立てたものを記事化しています。AIが出力した手順をそのまま転載するのではなく、実機で動作確認しながらフィードバックを返して修正を重ね、最終的に動いた構成だけを整理しています。途中でハマった箇所も「試行錯誤メモ」として記載しているので、同じ道を通る人の参考になれば幸いです。

なお、Raspberry Pi公式のHAT型のAIアクセラレーター(AI HAT+ 2等)というのがありますが、PCIe接続のためRaspberry Pi 5専用です。Coral USB アクセラレーターであればUSB接続なのでRaspberry Pi 4でも利用できます。
また、Raspberry Pi AI Camera(IMX500搭載)も検討しましたが、Pi 5向けの設計らしくPi 4だとAI機能を活かしきれないという話があり、モデルの柔軟性を優先して Coral USB を選びました。

シリーズ構成:

完成イメージ

機能内容
個体識別カメラ映像から特定の猫を識別
不要フレームのスキップ人の足が映り込んだフレームは処理しない
自動録画対象の猫が映ったときだけ動画を保存
Web UI同一ネットワーク内のPCやタブレットから状態確認・録画ダウンロード

ハードウェア構成

パーツ用途補足
Raspberry Pi 4 (8GB)本体4GBでも動作可能
Pi Camera ModuleカメラV1(OV5647)以降。USBカメラも可
Coral USB アクセラレーターAI推論ラズパイ単体だと推論が遅いため
USB HDD + ケース録画・データ保存SDカード劣化対策。3.5インチACアダプター付きが安定
セルフパワーUSBハブUSB機器の安定動作エレコム・バッファロー製を推奨
USB-C 電源 5V/3A以上電源3A未満だと不安定
microSDカード 32GB以上OS後でHDDをrootに切り替える

Raspberry Pi OS のセットアップ

使用したOSバージョン

Raspberry Pi OS Lite (64-bit) の Trixie (Debian 13) ベース版を使用しました。執筆時点で公式から提供されている最新版です。

旧バージョン(Bookworm = Debian 12)を使う場合、システムPythonが3.11または3.12になるため、本記事の手順(システムPython 3.13でpicamera2を使う前提)と一部異なる可能性があります。

OSのインストール

Raspberry Pi Imager で Raspberry Pi OS (64-bit) を microSD に書き込みます。Lite版でもDesktop版でもOKですが、今回はLite版(コンソールのみ)で進めます。

書き込み前に歯車アイコンから以下を設定しておくと楽です。

  • ホスト名
  • ユーザー名・パスワード
  • Wi-Fi
  • SSH有効化

システム更新

sudo apt update && sudo apt upgrade -y

sudo パスワード省略

頻繁にsudoを叩くので、パスワード入力を省略します。

sudo visudo -f /etc/sudoers.d/pi-nopasswd
pi ALL=(ALL) NOPASSWD: ALL

pi
は実際のユーザー名に置き換えてください。

HDD をルートディスクにする

SDカードは書き込み回数が多いと劣化するので、録画ファイルなどを書き込む先はHDDにしたいところですが、今回はOSのルートディスクごとHDDに移してSDカードの劣化を最小限にします。

パーティション作成

lsblk                    # デバイス名確認(通常 /dev/sda)
sudo fdisk /dev/sda

fdisk内で以下を実行します。

g        # GPTパーティションテーブル作成
n        # 新規パーティション
1        # パーティション番号
[Enter]  # 開始セクター(デフォルト)
[Enter]  # 終了セクター(デフォルト=全容量)
w        # 書き込んで終了

フォーマットとUUID確認

sudo mkfs.ext4 /dev/sda1
sudo blkid /dev/sda1
# UUID="a1b2c3d4-..." をメモ

ルートファイルシステムのコピー

sudo mkdir /mnt/hdd
sudo mount /dev/sda1 /mnt/hdd
sudo rsync -axv / /mnt/hdd/

容量によりますが、それなりに時間がかかります。

fstab を編集

sudo nano /mnt/hdd/etc/fstab

/
の行のUUIDをHDDのものに書き換えます。他の行(
/boot/firmware
proc
)は変更不要です。
UUID=<HDDのUUID>     /              ext4  defaults,noatime  0  1
UUID=<元のbootUUID>  /boot/firmware vfat  defaults          0  2
proc                  /proc          proc  defaults          0  0

noatime
を付けるとアクセス時刻書き込みが省略されてHDDへの負荷が減ります。

cmdline.txt を編集(スピンアップ待ち対策)

sudo nano /boot/firmware/cmdline.txt

root=
の部分をHDDのUUIDに書き換え、
rootwait rootdelay=10
を追加します。
root=UUID=<HDDのUUID> rootwait rootdelay=10
オプション役割
rootwait
rootデバイスが現れるまで無期限に待つ
rootdelay=10
起動を10秒遅らせる(HDDのスピンアップ待ち)

systemd のタイムアウト調整

sudo nano /mnt/hdd/etc/systemd/system.conf
DefaultTimeoutStartSec=120s

再起動して確認

sudo umount /mnt/hdd
sudo reboot

# 再起動後
df -h /
# /dev/sda1 と表示されればOK

HDD化後の追加設定

rootをHDDに移したことで、SDカード前提のデフォルト設定を見直します。

swap の拡張

Raspberry Pi OSのデフォルトはswapが100MBです。rootがHDDに移っているのでswapもHDD上に作られます。SDカードと違い耐久性を気にする必要がないので、余裕を持たせておきます。

# 現在のswap状況確認
free -h
swapon --show

Lite版にはdphys-swapfileが入っていない場合があるのでインストールします。

sudo apt install -y dphys-swapfile
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=1024
sudo dphys-swapfile swapoff
sudo dphys-swapfile setup
sudo dphys-swapfile swapon

# 確認
free -h

8GBあれば通常は余裕がありますが、AI推論中はtflite-runtimeやOpenCVがメモリを使うのでswapがあると安全です。HDDはSDカードと違い書き込み耐久性を気にする必要がないので、余裕を持たせておきます。

tmpfs の確認

/tmp
/run
がRAM上(tmpfs)になっているかを確認します。
mount | grep tmpfs

/tmp
/run
がtmpfsとして表示されていればOKです。Raspberry Pi OSはデフォルトでtmpfsが設定されているので、通常は確認のみで問題ありません。

HDDのスピンダウンは設定しない

長時間アクセスがない場合にHDDを停止させるスピンダウン設定がありますが、今回は設定不要です。

catmonitorサービスがカメラループで常時動作しており録画ファイルもHDDに書き込むため、実質的にHDDへのアクセスが途切れません。スピンダウンが発生してもすぐスピンアップが必要になり、むしろモーターへの負荷が増えます。常時稼働のシステムではスピンダウンは逆効果です。

Coral USB アクセラレーターのセットアップ

EdgeTPU ランタイムのインストール

公式ドキュメントの手順は古く、Bookworm以降では

apt-key
が廃止されています。新しい署名形式で進めます。
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
  sudo gpg --dearmor -o /usr/share/keyrings/coral-edgetpu-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/coral-edgetpu-archive-keyring.gpg] \
  https://packages.cloud.google.com/apt coral-edgetpu-stable main" | \
  sudo tee /etc/apt/sources.list.d/coral-edgetpu.list

sudo apt update
sudo apt install libedgetpu1-std

認識確認

Coral USB をUSB 3.0ポート(できればセルフパワーUSBハブ経由)に接続して確認します。

lsusb
# "Global Unichip Corp." または "Google Inc." が表示されればOK

lsusbの出力例

末尾の

Global Unichip Corp.
の行が Coral USB アクセラレーターです。未初期化状態では
1a6e:089a
、推論を一度実行した後は
18d1:9302 Google Inc.
と表示が変わります。

Python 環境の構築

このシステムは2つのPython環境を使い分けます。

用途Python理由
カメラサーバー(catcamera)システム 3.13
picamera2
がシステムにのみインストール可能
推論・データ収集・各種Webアプリvenv 3.11
tflite-runtime
がPyPIに3.11向けwheelしかない

カメラと推論の処理を別プロセスに分離し、MJPEGストリーム経由でフレームを共有する設計です。

Python 3.11 のソースビルド

Raspberry Pi OS Trixieには

python3.11
パッケージがないので、ソースからビルドします。

ビルドツールをインストールします。

sudo apt install -y build-essential zlib1g-dev libncurses5-dev \
  libgdbm-dev libnss3-dev libssl-dev libreadline-dev \
  libffi-dev libsqlite3-dev libcap-dev

ソースをダウンロードしてビルドします。

wget https://www.python.org/ftp/python/3.11.9/Python-3.11.9.tgz
tar xzf Python-3.11.9.tgz
cd Python-3.11.9

./configure --enable-optimizations --enable-shared
sudo make altinstall

# 共有ライブラリのパスを通す
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/python311.conf
sudo ldconfig

ラズパイ4でのビルドは30〜60分かかります。

altinstall
を使うことでシステム標準のPythonを上書きしません。
python3.11 --version
# Python 3.11.9 と表示されればOK

# 共有ライブラリが見えるか確認
python3.11 -c "import sysconfig; print(sysconfig.get_config_var('Py_ENABLE_SHARED'))"
# → 1 と表示されればOK

システム Python 3.13 用パッケージのインストール

カメラサーバー(catcamera)はシステムPython 3.13で動かすので、picamera2を入れます。

sudo apt install -y python3-picamera2

確認します。

python3 -c "from picamera2 import Picamera2; print('ok')"
# → ok と表示されればOK

uv のインストール

3.11側の仮想環境とパッケージ管理にはuvを使います。pipより速く、依存関係の解決も賢いです。

curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env

プロジェクト構成と仮想環境

mkdir -p /home/pi/cat_project/{scripts,models,dataset,recordings,logs}
cd /home/pi/cat_project

uv venv --python python3.11
source .venv/bin/activate

systemdサービスは

User=pi
で動作しますが、
sudo
を使った操作でディレクトリが作られるとrootが所有者になる場合があります。サービス起動前にオーナーを確認しておくと安全です。
# オーナーがpiになっているか確認
ls -la /home/pi/cat_project/

# rootになっていた場合は修正
sudo chown -R pi:pi /home/pi/cat_project/

ライブラリのインストール

uv pip install "numpy<2" tflite-runtime opencv-python-headless pillow flask gdown imagehash

カメラの認識確認

V1(OV5647)を含む公式カメラはlibcameraで動作します。

# カメラの認識確認
rpicam-hello --list-cameras
# ov5647 [2592x1944] と表示されればOK

# OpenCVからカメラを使うために必要なパッケージ
sudo apt install -y libcamera-dev python3-libcamera

ImageNet 標準モデルのダウンロード

学習済みモデルが用意できるまでの動作確認用に、Coralの学習済みモデル(ImageNet)をダウンロードしておきます。EdgeTPU推論が動作することを確認する用途で使います。

cd /home/pi/cat_project/models

wget https://github.com/google-coral/edgetpu/raw/master/test_data/mobilenet_v2_1.0_224_quant_edgetpu.tflite
wget https://raw.githubusercontent.com/google-coral/edgetpu/master/test_data/imagenet_labels.txt

EdgeTPU推論の動作確認

tflite-runtime
から
libedgetpu
デリゲートを読み込んで、ダウンロードしたモデルで推論できるか確認します。
source /home/pi/cat_project/.venv/bin/activate

python -c "
import tflite_runtime.interpreter as tflite

interpreter = tflite.Interpreter(
    model_path='/home/pi/cat_project/models/mobilenet_v2_1.0_224_quant_edgetpu.tflite',
    experimental_delegates=[tflite.load_delegate('/usr/lib/aarch64-linux-gnu/libedgetpu.so.1')]
)
interpreter.allocate_tensors()
print('Coral via tflite-runtime: OK')
"

Coral via tflite-runtime: OK
と表示されれば、EdgeTPU推論が動作する状態です。

Fan SHIM のセットアップ

Pimoroni の Fan SHIM を使っている場合、ドライバを入れないとファンが常時全力回転します。CPUの温度に応じて自動でON/OFFするよう設定します。

ライブラリのインストール

Fan SHIMの制御にはGPIOアクセスが必要なため、システム全体(venv外)にインストールします。

sudo apt install -y python3-rpi.gpio python3-pip git
pip install fanshim psutil --break-system-packages

# automatic.py を使うためリポジトリをクローン
git clone https://github.com/pimoroni/fanshim-python /home/pi/fanshim-python

systemd サービスの作成

sudo nano /etc/systemd/system/fanshim.service
[Unit]
Description=Fan SHIM Controller
After=local-fs.target
Requires=local-fs.target

[Service]
Type=simple
User=pi
ExecStart=/usr/bin/python3 -u /home/pi/fanshim-python/examples/automatic.py \
  --on-threshold 65 \
  --off-threshold 55 \
  --delay 2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable fanshim
sudo systemctl start fanshim

# 動作確認
sudo systemctl status fanshim

温度の確認

# 現在のCPU温度
vcgencmd measure_temp

# 2秒ごとにモニタリング
watch -n 2 vcgencmd measure_temp

温度閾値の考え方

パラメーター理由
--on-threshold
65℃Pimoroni推奨値。AI推論中でも安全圏
--off-threshold
55℃65℃から10℃下がったら停止
--delay
22秒ごとに温度チェック

Coralが推論を肩代わりするのでCPU温度はそれほど上がりませんが、データ収集中やファイル転送中など負荷が上がる場面もあるので65/55℃が適切です。

まとめ

ここまでで環境構築は完了です。最終的なディレクトリ構成は以下のようになります。

cat_project/
├── .venv/              # uv の仮想環境(Python 3.11)
├── scripts/            # (次の記事で配置)
├── models/
│   ├── mobilenet_v2_1.0_224_quant_edgetpu.tflite
│   └── imagenet_labels.txt
├── dataset/            # (次の記事で各カテゴリの画像を保存)
├── recordings/
└── logs/

次回は、このベースの上に「データ収集 → 振り分け → 学習 → 本番運用」を実装していきます。