猫2匹を見分けるカメラを作る (1) ── Raspberry Pi 4 + Coral 環境構築
はじめに
Coral USB アクセラレーターの使い道を考えていたところ、猫2匹のどちらがどのご飯を食べているかを判別して録画する、というシステムを思いつきました。猫の食事場所には人間の足も映り込むので、不要なフレームをスキップする処理も必要です。
最終的には以下のような構成になります。

この記事は、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 を選びました。
シリーズ構成:
- 本記事 (1):環境構築(ハードウェア、OS、Coral、Python環境)
- (2) データ収集と最初のモデル:実装、データ収集、Colabでの学習、本番運用
- (3) 誤判定を直して精度を上げる:(後日公開)
- 番外編 Webアプリのコード詳解
完成イメージ
| 機能 | 内容 |
|---|---|
| 個体識別 | カメラ映像から特定の猫を識別 |
| 不要フレームのスキップ | 人の足が映り込んだフレームは処理しない |
| 自動録画 | 対象の猫が映ったときだけ動画を保存 |
| 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

末尾の
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 |
2 | 2秒ごとに温度チェック |
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/
次回は、このベースの上に「データ収集 → 振り分け → 学習 → 本番運用」を実装していきます。
- 次の記事 (2) データ収集と最初のモデル
- (3) 誤判定を直して精度を上げる:(後日公開)
- 番外編 Webアプリのコード詳解