ラズパイ4デジカメ計画③〜Nodejsでlibcameraを使ったカメラ機能を実装する


※ 当ページには【広告/PR】を含む場合があります。
2024/02/15
ラズパイ4デジカメ計画②〜NodejsとGPIOでラズパイの起動・シャットダウンを操作する
蛸壺の中の工作室|Nodejsでlibcameraを使ったカメラ機能を実装する

ラズパイ4Bでなんちゃってデジタルトイカメラに仕立てる話の3回目です。

前回までで、液晶タッチパネルをセットアップしたり、GPIOピンから電源のオン・オフに関して細かくみていきました。

本回でようやくラズパイ用カメラと本体を接続し、GPIOに接続したスイッチからカメラによる撮影ができるまでの手順を解説します。


ラズベリーパイ4B 4GB 技適対応品

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

ラズパイ専用3.5インチ液晶タッチスクリーン

ラズパイ用カメラモジュールを接続する

過去にこのブログでも、ラズパイゼロにカメラモジュールを接続する方法を解説したことがあります。

合同会社タコスキングダム|タコツボの中の工作室
【ラズパイDIY講座】ラズパイゼロで作る監視カメラ① 〜 ラズパイ側から画像配信してみる

ラズパイゼロに接続したカメラのセットアップと、WebRTC配信のための環境構築の方法、簡単な画像の転送までをテストしてみます。

この記事はおおよそ3年前に認めた内容になっていますが、当時のカメラユーティリティソフトであった
『raspistill』は現役引退し、その後継である『libcamera』がラズパイ製品に標準採用されている状況です。

参考|Camera software - Raspberry Pi Documentation

libcameraベースのソフトウェアの正式採用と前後し、カメラモジュールV1やV2などの古いカメラモジュール製品は、
『レガシーカメラ』として区別されています。

レガシーとはいってもとりあえずは現行のOSで動作するようですが、そう遠くない将来で最新のラズパイ製品群で動作できなくなる恐れもあることは頭に入れておかないといけません。

今回利用するのはレガシーカメラの中でも、正規のラズパイ用カメラモジュールではなく、その互換性商品の一つ・「
ラズパイ互換カメラモジュール
」を使います。

合同会社タコスキングダム|蛸壺の中の工作室

価格は1000円弱で、正規品のラズパイカメラモジュールと比較しても非常に安い分、カメラの性能としては劣るものの、決して怪しい商品ではなく、中身は組込みで良く利用されているOmniVision製CMOSイメージセンサ・
「OV5647」です。

基本的にカメラモジュールは最新のものほど高価な部品になっている傾向にあります。

最近の高性能なカメラモジュールを、いきなり開発途中で動作させていて壊すとショックも大きいです。

ラズパイでカメラを利用した開発を行うのであれば、最初のうちは廉価版のカメラモジュールを使って進めていくとなにかあった際に少し気持ちが安心します。

カメラモジュールの取り付け

能書きはともかく、早速これをそのままカメラポートに取り付けてみましょう。

合同会社タコスキングダム|蛸壺の中の工作室

ここでは、カメラモジュールの取り付け方向にだけ注意しましょう。

基板にシルクプリントで印字してある
「CAMERA」のある方向側に、リボンコネクタの端子がある方を向けて挿入します。

端子の挿入方向が反対になっていると、当然デバイスとして認識されないので注意が必要です。

レガシーカメラのセットアップ・動作テスト

先程も述べたように既にV1相当のカメラモジュールは
レガシーカメラ扱いになっており、製品の利用は非推奨として、公式としては動作サポートされなくなっています。

レガシーカメラ製品はその設定を有効にしないと利用できないため、まずはその設定を有効化していきます。

まずは先程接続したカメラモジュールを
「raspi-config」コマンドで設定します。

            $ sudo raspi-config
        
として設定画面を呼び出し、以下の手順でカメラモジュールを有効化しましょう。

合同会社タコスキングダム|蛸壺の中の工作室

設定できたらラズパイを再起動します。

この時点ではまだ、カメラモジュールは認識されません。

ヘルパーコマンドから、カメラの利用ステータスを表示させてみると、

            $ vcgencmd get_camera
supported=0 detected=0, libcamera interfaces=0
        
となり、すべてのフラグがなし(0)の状態で、このままでは利用できません。

ちなみに、Raspberry Pi OS Bullseyeから従来のカメラモジュール製品で利用してきたユーティリティソフト群も非推奨になっているため、当時からある
vcgencmdコマンドからカメラの互換性を調べるのもあまり意味をなさないようになっています。

参考|Camera software - Introducing the Raspberry Pi cameras

それで、どうすればデバイスとして認識してくれるかというと、
/boot/config.txtにカメラセンサーのメーカー型式を明示に指定する必要があります。

            $ sudo nano /boot/config.txt
        
で、このファイルの最後の行らへんに以下を追加します。

            #...省略

dtoverlay=ov5647

#...
        
変更を保存したら、ラズパイを再起動して、デバイスとして認識されているかを確認しましょう。

            $ ls /dev/ | grep video
video0
#...
        
カメラデイズであるvideo0が増えていたらOKです。

また参考までに、
vcgencmdコマンドを叩いてみると、

            $ vcgencmd get_camera
supported=1 detected=0, libcamera interfaces=1
        
というレスポンスが返ってくるようになります。

libcamera以降では、
「libcamera-hello」というコマンドで動作確認するのが作法のようです。

ラズパイの実機やSSH越しでも良いので、以下のコマンドをターミナルから叩いてみます。

            $ libcamera-hello
Preview window unavailable
[0:00:49.368615839] [1674]  INFO Camera camera_manager.cpp:297 libcamera v0.0.5+83-bde9b04f
[0:00:49.427213820] [1675]  INFO RPI vc4.cpp:437 Registered camera /base/soc/i2c0mux/i2c@1/ov5647@36 to Unicam device /dev/media4 and ISP device /dev/media0
[0:00:49.427555432] [1675]  INFO RPI pipeline_base.cpp:1101 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[0:00:49.429376080] [1674]  INFO Camera camera.cpp:1033 configuring streams: (0) 1296x972-YUV420
[0:00:49.429980469] [1675]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1296x972-SGBRG10_1X10 - Selected unicam format: 1296x972-pGAA
#0 (0.00 fps) exp 33222.00 ag 8.00 dg 1.00
#...
#140 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
#141 (30.02 fps) exp 33222.00 ag 8.00 dg 1.00
        
エラーもなくきちんと動作していれば一安心です。

実際に一枚写真を試し撮りしてみましょう。

シンプルな静止画を撮るコマンドは、
「libcamera-jpeg」です。

            $ libcamera-jpeg -n -o test.jpg
[0:01:00.920428999] [1681]  INFO Camera camera_manager.cpp:297 libcamera v0.0.5+83-bde9b04f
[0:01:00.966632314] [1682]  INFO RPI vc4.cpp:437 Registered camera /base/soc/i2c0mux/i2c@1/ov5647@36 to Unicam device /dev/media4 and ISP device /dev/media0
[0:01:00.966773925] [1682]  INFO RPI pipeline_base.cpp:1101 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[0:01:00.968313777] [1681]  INFO Camera camera.cpp:1033 configuring streams: (0) 1296x972-YUV420
[0:01:00.968866702] [1682]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1296x972-SGBRG10_1X10 - Selected unicam format: 1296x972-pGAA
[0:01:06.120863607] [1681]  INFO Camera camera.cpp:1033 configuring streams: (0) 2592x1944-YUV420 (1) 2592x1944-SGBRG10_CSI2P
[0:01:06.125998310] [1682]  INFO RPI vc4.cpp:565 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 2592x1944-SGBRG10_1X10 - Selected unicam format: 2592x1944-pGAA
Still capture image received
        
これでカメラモジュールから画像が問題なく取り込めれば、レガシーカメラの動作試験完了です。

余談〜レガシーカメラはどこまでサポートされる?

前々回の記事でも述べたように、現行の最新版である
Raspberry Pi OS Bookworm(Debian12ベース)ではレガシーカメラのみならず、従来の接続デバイスの互換性サポートを終了しているため、過去に動作していたものが動かないなど、各所でシビアな問題が火を噴き始めています。

合同会社タコスキングダム|タコツボの中の工作室
ラズパイ4デジカメ計画①〜格安の(サポートの終了したWiringPI系)液晶タッチパネルを使えるようにする

WiringPiベースのラズパイ用液晶タッチパネルをRPiOS Bookwormでも動かすコツ

過去のカメラで動作していたアプリケーションを動かし続けようとすると、唯一できる対応策として、現時点でのレガシー版である
Raspberry Pi OS Bullseye(Debian11ベース)を使い続ける必要があります。

ただし、この
Bullseyeも永遠ではなく、サポート終了予定が2024年6月までとなっています。

それ以降では、公式のイメージからは消えてゆく運命ですので、OSイメージがどこかにアーカイブされたものを使い続けるしかなくなりそうです。

さらに悪いことに、レガシーカメラ機能を用いて市販されていた製品のサポートという点では、
BullseyeのlinuxカーネルであるKernel 5.10のサポートも2026年12月で終了とされています。

つまり、今後レガシー製品を動かそうとすると、逆に最新のモジュールデバイスが使えないので、新旧織り交ぜながらラズパイを利用することがかなり困難になることが予測されます。

レガシーカメラ製品を多用されていたユーザーからすると、ラズパイでまともにレガシー品を動かせるのも2026年までかな、と頭の隅におかれて利用を継続しておいたほうがよいでしょう。


ラズベリーパイ4B 4GB 技適対応品

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

ラズパイ専用3.5インチ液晶タッチスクリーン

Nodejsによるカメラ撮影アプリケーションを実装する

ここからは、nodejsでデジカメアプリを実装していきます。

なお、前回セットアップ済である
「node16」をそのまま使っていきます。

参考|ラズパイへNode.js(v16)環境を準備する

ラズパイのどこかに適当な作業フォルダを作成し、以下の構成で最低限必要な以下のファイルを準備します。

            $ tree
.
├── main.js
├── src
│   ├── camera_ctrl.js
│   └── switch_ctrl.js
└── package.json
        

npmパッケージのインストール

まずは、
package.jsonから作成していきます。

            $ nano package.json
        
で以下の内容で編集します。

            {
    "name": "rpi-legacy-camera-app",
    "version": "0.0.1",
    "description": "RPi legacy camera app for armhf",
    "main": "main.js",
    "private": true,
    "dependencies": {
        "pigpio": "^3.3.1"
    }
}
        
大したことはなく、前回に引き続きpigpioを使うだけのプロジェクトになります。

内容を追加したら、保存して、npmパッケージをインストールします。

            $ yarn install
        
で、node_modulesyarn.lockが作成されるはずです。

nodejsでカメラ撮影プログラムの実装

最初に
main.jsから実装していきます。

この
main.jsは一定の時間間隔で処理ループを行うことを担当します。

            $ nano main.js
        
ここでは以下のような内容で編集しましょう。

            const fs = require('node:fs');
const path = require('node:path');
const sw = require('./src/switch_ctrl');

//👇Ctrl&Cキーでプロセスを終了させる場合
process.on('SIGINT', () => {
    process.exit(0);
});

const sleep = (_ms) => {
    return new Promise(resolve => { setTimeout(() => resolve(), _ms)});
}

(async () => {
    //👇静止画の保存先としてtmpフォルダを作成
    const _dir = path.resolve(__dirname, 'tmp');
    if (!fs.existsSync(_dir)) {
        console.log('tmpフォルダを作成します。');
        fs.mkdirSync(_dir);
    }
    console.log(`An app is getting started!`);
    while(true) {
        //👇シャッタースイッチが押されたかを確認
        await sw.push();
        //👇100msほど時間間隔を空ける
        await sleep(100);
    }
})();
        
次にGPIOの機能を盛り込むためにswitch_ctrl.jsの実装します。

            $ nano src/switch_ctrl.js
        
このコードは以下のように実装します。

            const { execSync } = require('node:child_process');
const camera = require('./camera_ctrl');

const Gpio = require('pigpio').Gpio;
//👇38番ピン(GPIO20)をシャッタースイッチに設定
const button = new Gpio(20, {
    mode: Gpio.INPUT,
    pullUpDown: Gpio.PUD_UP,
});

const sleep = (_ms) => {
    return new Promise(resolve => { setTimeout(() => resolve(), _ms)});
}

const callShutdown = async () => {
    execSync(`/sbin/shutdown -h now 'Turn off by GPIO'`);
};

const push = async () => {
    const _start = Date.now();
    //👇ボタンが押された状態(0)が開始する
    if (button.digitalRead() === 0) {
        console.log("Button has been pushed!");
        while(true) {
            //👇ボタンが離された状態(1)に戻るまで待機
            if (button.digitalRead() === 1) {
                break;
            }
            await sleep(50);
        }
        //👇ボタンが押されてから離されるまでの時間[ms]を取得
        const _end = Date.now() - _start;
        if (_end > 5000) {
            //👇ボタンが5秒長押しで電源オフ
            console.log("SHUTDONW signal detected! Bye-bye!!");
            await callShutdown();
        }
        else if (_end < 50) {
            //まれに入力シグナルのノイズ電圧を誤検出する際の対策
            return;
        }
        else {
            //👇ボタン押し5秒未満ならカメラ撮影処理を開始
            console.log(`Let me take a picture!`);
            await camera.shutter();
        }
    }
    return;
};

exports.push = push;
        
ここでは前回の記事で説明した方法で、GPIOに接続したスイッチからラズパイの電源をOFFにしています。

前回からの修正点として、シャッタースイッチを長押し(5秒間)したら"電源OFF"、それより短い時間なら"写真撮影"と、1つのボタンに2つの機能を実装している点です。

最後にカメラコントロールの機能をまとめた
camera_ctrl.jsの実装します。

            $ nano src/camera_ctrl.js
        
このファイルの中身は以下です。

            const { execSync } = require('node:child_process');
const path = require('node:path');

let shutter_numb = 0;

const sleep = (_ms) => {
    return new Promise(resolve => { setTimeout(() => resolve(), _ms)});
}

const shutter = async () => {
    shutter_numb += 1;

    //👇保存先はtmpフォルダを指定
    const pwd = path.resolve(__dirname, '../tmp');

    const output = `${pwd}/${shutter_numb}-${(new Date()).toISOString()}.jpg`;
    const disp = 'DISPLAY=:0.0';
    const width = 640;
    const height = 480;
    const timeout = 2000
    const cmd = `libcamera-jpeg -o ${output} -f -t ${timeout} --width ${width} --height ${height}`;

    await execSync(`${disp} ${cmd}`);
    console.log('A picture has been saved.');
};

exports.shutter = shutter;
        
ここではexecSync関数から、libcamera-jpegを内部コマンドとして呼んでいます。

libcamera-jpegのより詳しいオプションはlibcamera-jpeg --helpで確認してください。


ラズベリーパイ4B 4GB 技適対応品

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

ラズパイ専用3.5インチ液晶タッチスクリーン

カメラアプリを起動・常駐させる

まずは早速先程のnodejsアプリをラズパイ実機のターミナルから動くことを確認してみましょう。

            $ sudo $(which node) main.js
        
ただしく動いた場合、カメラアプリが以下のような状態でシャッター待ちになります。

合同会社タコスキングダム|蛸壺の中の工作室

あとは、
前回と同じボタン配置で、スイッチを押すたびにtmpフォルダに写真が保存されるようになっていると思います。

なお、スイッチ5秒押しで電源もOFFになります。

デスクトップメニューに登録して起動する

このままだと、ラズパイを立ち上げ後にわざわざターミナルを起動してコマンドを打たないと使えないのはとても不便です。

せめてデスクトップのスタートメニューからクリックして起動するようにしてみましょう。

まずプロジェクトフォルダに、
start-camera-app.shというスクリプトを作成します。

            $ nano start-camera-app.sh
        
でこのスクリプトに以下の内容で編集して保存します。

なお、リソースやコマンドは絶対パスを基本として使います。

ここでは一例として、ユーザー名を
user、nodejsプロジェクトの場所を/home/user/camera-workerと与えます。

試されたい場合には、ご自分の環境設定に合わせて修正してください。

            #!/bin/bash

export DISPLAY=:0.0

WORK_DIR=/home/user/camera-worker
MY_NODE=/home/user/.nvm/versions/node/v16.20.2/bin/node

sudo $MY_NODE $WORK_DIR/main.js
        
このスクリプトに実行権を与えておきましょう。

            $ sudo chmod +x start-camera-app.sh
        
スタートメニューに登録するには、「/usr/share/applications/」以下にデスクトップ定義ファイル(.desktopファイル)を保存するだけです。

このカメラアプリ用に
node-camera-app.desktopを準備します。

            $ sudo nano /usr/share/applications/node-camera-app.desktop
        
このファイルは以下のような内容にします。

            [Desktop Entry]
Name=node-camera-app
Type=Application
Version=1.0
Comment=libcamera app hosted by nodejs
Exec=/home/user/camera-worker/start-camera-app.sh
Terminal=true
Categories=Utility;
        
これを保存して、一旦再起動し、デスクトップのスタートメニューを覗いてみましょう。

合同会社タコスキングダム|蛸壺の中の工作室

すると、
node-camera-appが登録されているので、これをクリックしたらカメラアプリが起動するようになります。

systemdで常駐デーモン化する

少し高度な設定になりますが、ラズパイが起動したら自動でアプリが立ち上がるようにすると、よりデジカメ感が出ます。

かつてはラズパイの起動時にGUIアプリを登録するやり方は何通りかありましたが、よく利用されきた
「autostart」は現在非推奨になって、利用には向いていません。

代わりにすべてのアプリ自動起動に推奨されるのは、
「systemdによるサービス化」です。

systemdサービスにすることで、常時バックグラウンドの別プロセスとして管理され、適切なタイミングで起動できるようにすることができる反面、GUIアプリを立ち上げるにはXsesstionやXauthorityなどのLinux特有のディスプレイ機能を理解している必要もあります。

ともかく、早速systemdへサービスとして登録していきます。

systemdサービスの作り方も簡単で、
「/etc/systemd/system/」以下にサービスファイル(.service)を置くだけです。

            $ sudo nano /etc/systemd/system/camera.service
        
このファイルの中身を以下のようにします。

            [Unit]
Description=Camera Launcher
After=multi-user.target

[Service]
User=user
Environment=DISPLAY=:0.0
Environment=XAUTHORITY=/home/user/.Xauthority
ExecStart=lxterminal -e /home/user/camera-worker/start-camera-app.sh
Restart=always

[Install]
WantedBy=multi-user.target
        
こちらも試される場合には、ユーザー名やリソースの絶対パスが正しいか確認して利用してください。

サービスファイルを保存したら、systemサービスをリロードさせます。

            $ sudo systemctl daemon-reload
        
これでサービス化は完了ですが、一旦手動でカメラアプリが動くかをチェックします。

            $ sudo systemctl start camera.service
$ sudo systemctl status camera.service
● camera.service - Camera Launcher
     Loaded: loaded (/etc/systemd/system/camera.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-02-15 15:02:03 JST; 25min ago
   Main PID: 768 (lxterminal)
      Tasks: 14 (limit: 1539)
        CPU: 1min 49.635s
     CGroup: /system.slice/camera.service
             ├─ 768 lxterminal -e /home/user/camera-worker/start-camera-app.sh
             ├─1311 /bin/bash /home/user/camera-worker/start-camera-app.sh
             ├─1317 sudo /home/user/.nvm/versions/node/v16.20.2/bin/node /home/user/camera-worker/main.js
             └─1324 /home/user/.nvm/versions/node/v16.20.2/bin/node /home/user/camera-worker/main.js

Feb 15 15:02:03 raspberrypi systemd[1]: Started Camera Launcher.
Feb 15 15:02:05 raspberrypi lxterminal[768]: error: XDG_RUNTIME_DIR not set in the environment.
Feb 15 15:02:09 raspberrypi sudo[1317]: user : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/home/user/.nvm/versions/node/v16.2>
Feb 15 15:02:09 raspberrypi sudo[1317]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=1000)
        
エラーが発生していないことを確認して、サービスを止めます。

            $ sudo systemctl stop camera.service
        
では、ラズパイ起動時に自動で立ち上がるようにこのサービスを有効化します。

            $ sudo systemctl enable camera.service
        
これで、ラズパイを再起動して、無事カメラアプリが自動で起動したらラズパイのソフト面での「デジカメ化」が完了です。

残った課題〜撮りためた画像を取り込む方法

撮った写真を移動する方法はいくつか考えられます。

一番手っ取り早いのが、ラズパイの入ったSDカードをそのまま他のPCのUSBなどに挿して、画像データを移す方法はいかにも「デジカメ」です。

個人的には、せっかくラズパイでSSH接続もできるので、
「rsync」コマンドでフォルダごと同期させるスクリプトを使っています。

            #!/bin/bash

echo '======= APP DOWNLOADER FROM RPI TO LOCAL MACHINE ======='

source .env
###☆.envファイルの例:
#TARGET_SSH_CLIENT=user
#TARGET_SSH_CIP=192.168.1.10
#WORKER_DIR=camera-worker

echo "TARGET_SSH_CLIENT=$TARGET_SSH_CLIENT"
echo "TARGET_SSH_CIP=$TARGET_SSH_CIP"
echo "WORKER_DIR=$WORKER_DIR"

rsync -avP --delete \
    --include="*.jp*g" \
    --include="*.png" \
    --exclude="*.*" \
    --exclude="node_modules/" \
    --exclude="src/" \
    -e ssh $TARGET_SSH_CLIENT@$TARGET_SSH_CIP:/home/$TARGET_SSH_CLIENT/$WORKER_DIR/tmp/ ./tmp
        
他にはオンライン接続している環境なら、直接クラウドストレージにも保存できるようなAPIもnodejsで簡単に機能拡張も可能です。

そこらへんはご自身の好みでいろいろと模索してみてください。

蛇足〜サービスの起動時間をちょっと短縮

ラズパイの起動でどのくらい遅いか少し気になるので、アプリ立ち上げまでの時間をチェックしてみます。

            $ systemd-analyze time
Startup finished in 3.706s (kernel) + 14.376s (userspace) = 18.082s
graphical.target reached after 14.277s in userspace
        
おおよそ18秒かかっています。

どこらへんのサービスが重いか内訳も見てみます。

            $ systemd-analyze blame
7.972s hciuart.service
7.304s rc-local.service
2.117s e2scrub_reap.service
2.090s dev-mmcblk0p2.device
1.744s raspi-config.service
1.704s rpi-eeprom-update.service
1.501s udisks2.service
1.233s systemd-logind.service
1.157s dhcpcd.service
1.110s ModemManager.service
#...
  12ms plymouth-quit-wait.service
        
一見、ワシャワシャと重要であろうサービスが並んでいて、重いものほど勝手にサービスを無効化しては困るかに見えます。

こちらの記事を参考にしますと、hciuart.serviceはBluetoothに関連するサービスで、Bluetoothを利用しない限りは余分なサービスとのこと。

ということで、以下の2つのサービスを無効化します。

            $ sudo systemctl disable bluetooth.service
$ sudo systemctl disable hciuart.service
        
再起動後、どのくらい早くなったか確認してみます。

            $ systemd-analyze time
Startup finished in 4.109s (kernel) + 14.586s (userspace) = 18.696s
graphical.target reached after 14.497s in userspace
        
まぁ良いか...どれだけ頑張ってもSDカードの物理特性に因るものが大きく、安いSDカードで起動10秒は切れないようですので、高速化を極めたい方は以下の記事を参考にしてみてください。

参考|Raspberry Pi Zero W で電源 ON 後,最速で撮影画像をアップロード


ラズベリーパイ4B 4GB 技適対応品

ラズパイマガジン 2019年12月号 カメラ&センサー工作入門

ラズパイ専用3.5インチ液晶タッチスクリーン

まとめ

以上、今回はnodejsでカメラ機能の実装を具体的に解説していきました。

デジカメにしてはアプリの起動までに20秒ほど時間がかかるものの、中身はラズパイですので仕方ありません。

専用のデジカメとは違い、あくまでもなんちゃってデジカメですので、機能性の出来はさほど期待せずにここらへんでソフト面の話は打ち止めさせていただきます。

次回は、カメラの筐体などハード面でいろいろと作成していく予定です。