プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

伊勢ギーク・フェア2019 に出展しました

先日、三重県伊勢市で開催された伊勢ギーク・フェアに出展してきました。 私自身は数年ぶりの参加でした。

公式のFacebookページはこちら

https://www.facebook.com/igfaire/

会場の様子

当日、準備しながら撮った会場の様子はこんな感じでした。

f:id:junichim:20191126140657j:plain

f:id:junichim:20191126140716j:plain

実際に現場にいると写真で見るより、ずっと人が多い感じでした。 小さい子供も多くて、ゲームしたりロボット動かしたりと楽しそうです。私の子供も短い時間ですが、ご多分に漏れず、ロボットを動かしてご満悦のようでした。

出展内容

当日出展したのは、

blog.mori-soft.com

blog.mori-soft.com

で作った、LINEボットからラズパイカメラで撮影する、というものです。

ブースの様子はこんな感じです。

f:id:junichim:20191126143549j:plain

(写真中のQRコードでボットと友達になっても、現在はなにもできないです。悪しからず。)

ラズパイ zero は小さくて気に入ってるんですが、ブースに置くと・・・迫力ないですね。 ちなみに、後ろ向きのディスプレイは設定作業やトラブル対応のために持っていったものです。こっちのほうが目立ってますね。

あと、個人的に一番モノづくりしたのは、机の上においてある段ボールの看板だったりしました。

振り返り

がっつりモノづくりしている方が多数いるのでが、来場者もそういうものを求めてるんだろうと予想し、 こちらにはあんまり人来ないだろうなと思っていたのですが、思ったより興味を持ってみてくれていた方が いらっしゃいました。
ありがとうございます。

さて、今回は、LINEボットからラズパイカメラで撮影するというのを出しましたが、実際に会場で 使ってみるといくつか気づいた点がありました。

写真を1回リクエストしたにも関わらず、3~4枚まとめて写真が送られてくる

イベント会場で試すと、このような現象が発生していました。

もっとも、これは私の仕込んだバグでした。

ラメラサーバー側の処理(node.js)をsetIntervalを使った繰り返し処理として書いたのですが、 呼び出した関数が非同期で戻ってくるのに気づいておりませんでした。

また、呼び出した関数の処理(写真撮影と画像アップロードとLINEへの投稿)が完了したら、 撮影指示を削除するという流れとしていました。

このため、最初に呼び出した撮影指示が終わらないうちに、またsetintervalから関数が呼ばれてしまい、 この時点では撮影指示ファイルがまだ残っているので、もう一度写真撮影の処理が呼ばれて・・・ というのを何度か繰り返した結果、複数枚の画像が返送される、という現象になっていました。

仕事場のWiFi環境だと気づかなかったのですが、イベント会場では、テザリング経由で ネットワークにつないでいたので、処理に時間がかかり、 問題が発覚したという次第です。

古い撮影指示が実行される

これはイベント時の問題ではないのですが、気になったのでメモを残しておきます。

上記の問題をイベント会場で手直ししていたので、イベント翌日、リポジトリに 反映させようとして、ラズパイに電源をつなぎました。

そうすると、ラズパイ側のカメラサーバーが自動起動して、S3 上の撮影指示を読みにいってしまいました(これ自体は動作としては正しいです)。

どうもイベント後や夜中に撮影指示を送った方もいたようで、カメラサーバー起動により、 朝一番に私の事務所の壁や天井の写真が送られたようです。 いきなり変なタイミングで変な写真が送られてしまいすいませんでした。

まあ、こんな事故が起こらないように、撮影指示のタイムスタンプを見て、 一定以上の時間が経過している場合は無視するようなロジックをいれる必要があることに気づきました。

動かさないとわからないことですね。 おいおい組み込んでいこうと思います。

まとめ

やっぱり、イベントは見るのもいいけど参加するほうがおもしろいですね。
来年も頑張って何か出したいな。

Raspberry Pi Zero + カメラ で遊んでみました (2/2)

前回まででハードウェアのセットアップおよびOSのセットアップが終わったので、やっとここから、 Raspberry Pi で遊んでいきたいと思います。

node.js のインストール

NOOBSでインストールした Raspbian は、はじめから node.js v10.15.0 が入っていました。

pi@raspberrypi:~ $ dpkg --list | grep node
ii  libnode64:armhf                       10.15.2~dfsg-2+rpi1                   armhf        evented I/O for V8 javascript - runtime library
ii  node-normalize.css                    8.0.1-3                               all          Modern alternative to CSS resets
ii  nodejs                                10.15.2~dfsg-2+rpi1                   armhf        evented I/O for V8 javascript - runtime executable
ii  nodejs-doc                            10.15.2~dfsg-2+rpi1                   all          API documentation for Node.js, the javascript platform
ii  nodered                               0.20.5                                armhf        Node-RED flow editor for the Internet of Things
pi@raspberrypi:~ $

一方、npm は未インストールのようでした。
nodeはバージョンアップも激しいので、先々のことを考えて、nvmからインストールします。

まずは、既存のnodeをアンインストールしときます。

pi@raspberrypi:~ $ sudo apt autoremove nodejs
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージは「削除」されます:
  libc-ares2 libnode64 libuv1 nodejs nodejs-doc nodered
アップグレード: 0 個、新規インストール: 0 個、削除: 6 個、保留: 315 個。
この操作後に 87.2 MB のディスク容量が解放されます。
続行しますか? [Y/n] y
(データベースを読み込んでいます ... 現在 132805 個のファイルとディレクトリがインストールされています。)
nodered (0.20.5) を削除しています ...
nodejs (10.15.2~dfsg-2+rpi1) を削除しています ...
libnode64:armhf (10.15.2~dfsg-2+rpi1) を削除しています ...
libc-ares2:armhf (1.14.0-1) を削除しています ...
libuv1:armhf (1.24.1-1) を削除しています ...
nodejs-doc (10.15.2~dfsg-2+rpi1) を削除しています ...
mime-support (3.62) のトリガを処理しています ...
hicolor-icon-theme (0.17-2) のトリガを処理しています ...
gnome-menus (3.31.4-3) のトリガを処理しています ...
libc-bin (2.28-10+rpi1) のトリガを処理しています ...
man-db (2.8.5-2) のトリガを処理しています ...
desktop-file-utils (0.23-4) のトリガを処理しています ...
pi@raspberrypi:~ $ 

公式の説明や、下記の記事などを参考にNVMをインストールします。

Setup Guide: Raspberry Pi | Install Node.js via Node Version Manager (NVM) · cncjs/cncjs Wiki · GitHub

pi@raspberrypi:~ $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13527  100 13527    0     0  35135      0 --:--:-- --:--:-- --:--:-- 35135
=> Downloading nvm from git to '/home/pi/.config/nvm'
=> Cloning into '/home/pi/.config/nvm'...
remote: Enumerating objects: 286, done.
remote: Counting objects: 100% (286/286), done.
remote: Compressing objects: 100% (256/256), done.
remote: Total 286 (delta 34), reused 93 (delta 17), pack-reused 0
Receiving objects: 100% (286/286), 146.21 KiB | 176.00 KiB/s, done.
Resolving deltas: 100% (34/34), done.
=> Compressing and cleaning up git repository

=> Appending nvm source string to /home/pi/.bashrc
=> Appending bash_completion source string to /home/pi/.bashrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.config/nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
pi@raspberrypi:~ $ 

一度、ターミナルを閉じて、再度開いておきます。

NVMがインストール出来たら、nodeをインストールします。

pi@raspberrypi:~ $ nvm install v10.17.0

今回は最新の一つ前のLTS(v10.x)を選びました。

アプリの概要

さて、前の記事の冒頭で簡単に今回ラズパイを使って作るアプリについて触れましたが、改めて整理しておきます。

時々、家族みんなで外出した時に、『ガスコンロの火を消したっけ?』となる場合があります。幸い、消し忘れてたことはないのですが、 こうなると道中しばらくの間、出かける前の行動を振り返りながら、確かに消したよな?と確認する確認作業が続きます。 これ、テンションも下がるし、子供も暇そうでだんだん騒いでくるし、いいこと一つもないので、ここはラズパイの力を借りようと思います。

というわけで、今回作るのは、家のガスコンロのそばにカメラ付きのラズパイを置いて、LINEで要求するとその写真を撮って送り返してくれる、というものにします。

構成

最初は、ラズパイにWebサーバーを入れて、直接ボットサーバーとやり取りしてもいいかと思ったんですが、

  • 家のルータには穴を開けたくない
  • ラズパイ側に ngrok 入れて外からアクセス可能にする方法だと、再起動のたびに外から呼び出すURLを更新しないといけない

というのがあったので、今回は、

  • ボットサーバーは要求を受けたら、撮影指示をファイルにして、AWS S3 に書き込み
  • ラズパイは、S3 にファイルが書き込まれたかを一定間隔で監視し、ファイルを見つけたら、写真を撮って、S3 にアップし、LINEに画像を投げる

という動作とします(なお、以下では便宜上ラズパイ上の処理を行うものを『カメラサーバー』と呼ぶことにします)。図だとこんな感じになります。

f:id:junichim:20191220104134p:plain

(draw.io で描いています)

これなら、ネットワークさえつながっていれば、この機能を使うことができます。

早速、作っていきます。

LINE ボットの作成

LINEボットの作成については、あちこちで書かれているので割愛します。 Lambda (node.jsで書きました)でボットサーバーの処理を作って、API Gateway 経由でLINEから呼び出すというパターンにしています。

ボットサーバーの役割は

  • 呼び出されたメッセージの検証
  • 写真撮影のリクエストか否かの判定
  • 写真撮影の場合は、 S3 に所定のファイルを作成

写真撮影のリクエストか否かの判定は単に文字列を比較するだけです。将来、気が向いたら DialogFlow とつなげるのもありかもしれません。

最後の S3 へ撮影指示ファイルを作成するところだけ、説明しておきます。

この撮影指示ファイルは、

{
    "date": "2019-11-22T16:59:19.992+09:00",
    "replyToken": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "userId": "xxxxxxxxxxxxxxxxxxxxxx"
}

のようなJSONとしました。

JSON ファイル中に、replyToken と呼び出し元の lineId(JSON中では userId としてます)を含めています。
これは、ラズパイ側から画像メッセージを送る際に、もし可能であればLINEの応答メッセージで送るようにし、 ラズパイ側の処理やネットワークの問題でトークンの有効期限切れなどが発生して応答メッセージ送信が失敗した場合は、 lineId を使って、プッシュメッセージで送る、という方法を取るようにするためです。

また、この撮影指示ファイルを書き込む S3 のバケットは非公開とし、LINEボットサーバーおよびラズパイ上のカメラサーバーが awssdk 経由で直接操作する形としています。

GitHub のリポジトリにソース一式を載せておきましたので、気になる方はご覧ください。

ラズパイ上のカメラサーバー

ラズパイでのカメラサーバーも Lambda に合わせて、node.js で書くことにします。

node.js のメイン処理は、一定間隔で撮影処理(main関数としてまとめています)を呼び出すようなインターバル処理になります。 撮影処理が早く終わった場合は処理を一定時間待ち、撮影処理に時間がかかる場合は処理が終わるのを待ってから次の呼び出しに移ります。

main 関数の処理は、

  • 撮影指示ファイルの存在確認(複数も可)
  • 撮影指示ファイル分のループ

となり、ループ中では、

  • 撮影指示ファイルの取得
  • 写真撮影
  • LINEへ画像メッセージの送信
  • 後始末

という感じになります。

以下、ややこしそうなところだけ説明しておきます。

インターバル処理

最初は、

node.js のメイン処理は、

setInterval(main, PERIOD);

として、一定間隔でループを回すものとします。PERIOD は適当な時間間隔としておきます(現在は10秒)。

としていました。

この部分、思いっきり勘違いしていました。

伊勢ギークフェア当日の会場では、自分のスマホのテザリングでネットにつないでいたのですが、回線が遅いところで動かすと最初の撮影処理が終わる前に、 次のsetIntervalの呼び出し処理が呼ばれしまい、結果的に1回の写真リクエストに対して、3~4枚の写真が送られるということになりました。

setInterval は関数を(非同期で)呼び出したらすぐに戻るんですね。

そこで、メイン処理部分は下記の記事を参考にsleep処理を作成して対策しました。

ES2017 async/await で sleep 処理を書く - Qiita

上記の記事と同様に、sleep 関数を定義しておきます。

lib/utl.js

async function sleep (term) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, term);
    });
}
exports.sleep = sleep

このsleep関数を使い、interval処理を行う関数を定義します。

lib/utl.js

exports.interval = async function (callback, term) {
    while(true) {
        //const st_dt = Date.now();
        //console.log("start");
        await Promise.all([callback(), sleep(term)]);
        //console.log("end. elapsed is " + (Date.now() - st_dt));
    }
}

最後に、メイン関数は、このinterval関数を呼び出すようにします。

camera.js

// ループ開始
exec_main();

async function exec_main() {
    await util.interval(main, PERIOD);
}

一応、この形で処理に実行時間がかからなければ、インターバルで指定した間隔待ってから処理を呼び出し、呼び出し処理に時間がかかった場合は次の呼び出し処理を待つようにできました (PERIODは10秒です)。

node.js に慣れてるわけではないので、もし、node.js ならこうするのがベターだよ、みたいな方法があれば、ぜひ教えてください。

写真撮影

写真撮影は、

lib/photo.js より抜粋

exports.getPhoto = async function (imgFn, thumbFn) {
    return new Promise(function(resolve, reject) {
        let cwd = process.cwd();
        childProcess.exec(cwd + "/" + PHOTO_SCRIPT + " " + imgFn + " " + thumbFn, function(err, stdout, stderr) {
            if (err) {
                console.error("getPhoto:" + JSON.stringify(err));
                console.error("stderr: " + stderr);
                reject(err);
            } else {
                resolve(stdout);
            }
        });
    });
}

のようにして、シェルスクリプト(上記だと PHOTO_SCRIPT としてスクリプトファイル名を定義しています)を呼び出しています。

呼ばれたシェルスクリプトでは、

lib/photo.sh

#!/bin/bash
#
#

set -eu


function usage() {
    echo "photo.sh  output_filename  output_thumbnail_filename"
}

if [ $# -ne 2 ]
then
    usage
    exit 1
fi

IMG_FN=$1
THUMB_FN=$2

# 撮影
/usr/bin/raspistill -w 640 -h 480 -th none -n -t 10 -q 75 -o ${IMG_FN}

# サムネイル生成
/usr/bin/convert ${IMG_FN} -thumbnail 200x200 ${THUMB_FN}

のように、raspistill コマンドにより、写真を撮り、 convertコマンド(ImageMagick)により、サムネイルファイルを作成します。

サムネイルファイルを作成しているのは、LINEの画像メッセージの仕様で、 画像メッセージを送る場合は、URLで、 画像とそのサムネイルを指定する必要があるためです。

撮影した写真は、S3 のバケット(上記の撮影指示のバケットは別物です)へアップロードします。 こちらのバケットは、撮影指示のバケットとは異なり、公開しています。 また、LINEの画像メッセージの仕様で、httpsが求められるため、 S3 の静的ホスティングの上に、CloudFront をかまして、httpsアクセスを可能としておきます。

なお、CloudFront を利用して https でアクセスする方法については、独自ドメインでの例ですが、こちらの記事をご覧ください。 今回は独自ドメインを使っていないので、SSL証明書なども不要となるので、もっと簡単になります。

LINE へ画像メッセージの送信と後始末

画像のアップロードが成功したら、ボットサーバーの概要で書いたように、LINE API を利用して、

  1. 応答メッセージ
  2. プッシュメッセージ

の順番で画像メッセージが送れるか試行します。

また、両方の方法で画像メッセージを送るのが失敗した場合は、プッシュメッセージにて画像送信に失敗した旨のテキストメッセージを送るようにします。

最後に、メッセージ送信の成否にかかわらず、ラズパイ上に作成した画像ファイルと S3 上の撮影指示を削除しておきます。

その他

公開用のS3バケットにアップロードした画像ファイルは一定期間経過後、定期的に削除しようと思います。 CoudWatch Event を使えば、そんなに難しくなくできそうと思います。

どれぐらい残すかをしばらく使ってみてから決めようと思うので、今回はそこまで組んでません。

動作確認

ここまでできれば、動作確認です。

まずは、LINEボットと友達になります(ボットのQRコードは LINE Developer の画面か LINE 公式アカウントマネージャの画面に表示されています)。

f:id:junichim:20191123193140p:plain

f:id:junichim:20191123193207p:plain

次に、『写真』とか『撮影』とか送ると、しばし時間がたってから、

f:id:junichim:20191123193248p:plain

のように写真が送られてくれば、成功です。 画像をタップすると元の画像が表示されます。

f:id:junichim:20191123193309p:plain

いい感じですね。

ちなみに、この写真は部屋の天井付近にカメラを向けたものです。

カメラサーバーをデーモンとして起動

動作確認して問題なく動くことが確認出来たら、最後は、ラズパイの電源を入れれば、カメラサーバーが起動するようにします。

ちょっと調べると、ラズパイは systemd を使ってサービスを立ち上げるのが今どきの方法のようなので、 /etc/systemd/sytem 以下に camera-server.service ファイルを作成します。

/etc/systemd/system/camera-server.service

[Unit]
Description=camera server
After=syslog.target local-fs.target network-online.target nss-lookup.target

[Service]
Type=simple
WorkingDirectory=/home/pi/work/raspicamera
ExecStart=/home/pi/work/raspicamera/bin/camera_start
Restart=no
StandardOutput=append:/var/log/camera-server/camera-server.log
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

StandardOutput の記述がない場合は、標準出力がそのまま syslog に書き込まれるという非常に便利な動作になります。
ただ、ログの分量を多めに出しているとわかりにくいかと思い、別ファイルにログを出力するように設定を行っています。

また、ラズパイだと、ストレージの容量も限られているので、ログファイルはローテーションも必要だと思われるので、logrotate の設定も行っておきます。

/etc/logrotate.d/camera-server

/var/log/camera-server/camera-server.log {
    rotate 10
    daily
    missingok
    notifempty
    compress
    delaycompress
    postrotate
        /bin/systemctl restart camera-server > /dev/null 2> /dev/null || true
    endscript
}

設定が終わったら、一度ラズパイを再起動して問題なくカメラサーバーが立ち上がっていることを確認しておきます。

問題なく起動されていれば、OKです!

あとは、このラズパイをキッチンのコンロが見える場所に設置すれば完了です。 最後の難関は家族の許可を得ることですが、なんとか頑張ります!

変更履歴

  • 2019/11/25 ラズパイ側のメイン処理をasync/awaitを使ったインターバル処理に変更した点を追記
  • 2019/12/29 構成図を追加

Raspberry Pi Zero + カメラ で遊んでみました (1/2)

伊勢ギークフェアへの出展も兼ねて、Raspberry Pi Zero +カメラで遊んでみました。
LINEのボットに写真をお願いすると、Raspberry Pi (以下、ラズパイと呼びます)がカメラで撮って、 LINE に投げ返してくれるというものです。

ちょっと長いですが、自分用のメモとして書いておきます。

ラズパイの購入

今回、ラズパイを触るのが初めてになります。なので、まずはラズパイを買うところからになります。
一口にラズパイといっても、いろいろと種類があります。

Raspberry Pi - Wikipedia

なるべく安くてお手軽なもの、ということで、 Raspberry Pi Zero W という、小型の WiFi 付のモデルを選びました。 本体だけだと、1000円強とお安い!

とはいえ、初めて触るので、遊ぶのに必要なものなどをいろいろと買い揃えないといけません。そこで、KSY さんで下記のキットとカメラモジュールを購入しました。

本体はともかく、カメラモジュールがいい値段したりして、予想外に費用がかかりました。まあ、2台目からはいろいろと流用できそうなので、お安く遊べるかな?

セットアップ

さて、注文後しばらくすると、ラズパイが到着しました。

どこから手を付ければよいのか全然わからないので、ざっと、ネットを調べると、下記の記事などがありました。

http://www.feijoa.jp/laboratory/raspberrypi/firstMeetWithPi/

SDカードを指して、ディスプレ、キーボード、マウスをつなげて、電源入れればよいようです。
幸い、今回購入したキットは、SDカードにOS書き込み済みだったので、OSをSDカードに書き込む手間は不要でした。

カメラモジュールはいったん置いておいて、まずは本体を起動させてみます。
さっそくやってみます。

今回のキットのSDカードには、 NOOBS というOSインストーラが書き込まれています。 なので、最初の電源起動後、こんなOS選択画面が表示されます。

f:id:junichim:20191122221329j:plain

ここで、Raspbian を選択すると、

f:id:junichim:20191122221348j:plain

Raspbian のインストールが始まります。

f:id:junichim:20191122220906j:plain

こんな感じです。正確には覚えてませんが、それなりに時間がかかりました(10分~数10分ぐらいだったか?1時間はかかってなかったように思います)。

無事にセットアップが終わると、

f:id:junichim:20191122225836j:plain

Raspbianのデスクトップが立ち上がります。

f:id:junichim:20191122221007j:plain

画面の指示に従って、設定項目を入れていきます。 問題なく、すべての項目のセットアップが終わると、無事にOSが立ち上がる状態になります。

トラブル1:キーボードが使えない

実は、OS起動後のセットアップ中にいくつかトラブルがありました。

セットアップ中に、パスワードの変更を求められるのですが、USBハブ経由でキーボードを接続していたのに、なんとキーボードが認識されません。

状況を整理すると、

  • 家に落ちていた古いUSBハブを使った
  • これに、マウスとキーボードを接続
  • マウスは認識されるけど、キーボードは認識されない
  • USB ハブにキーボードのみにしても認識されないのは同じ
  • USB ハブを外して、キーボード直付けなら認識される

という状態でした。

慌ててネットを探すと、似たような話がありました。

Raspberry Pi Zero 関連 まとめ & 備忘録 | 日々のできごと

どうも、OTG がキーワードになりそうです。 とはいえ、購入したキットについていた、micro USB -> USB A の変換ケーブルはOTG対応になっています。なので、本当なら 普通の USBハブでも認識されて良さそうなものですが、ちょっと不思議です。

まあ、いつのかわからんぐらい古いUSBハブだったので、改めて新しいUSBハブを購入して試したところ、問題なく認識されるようになりました。

ちなみに買ったのはこれでした。

トラブル2:USBハブを指すと再起動する

上記のトラブル1を調べる際に、あるUSBハブを指すと、ラズパイが再起動するという現象がありました。

こちらも最初は原因がわからず困ったのですが、よくよく調べてみると理由は電源容量不足でした。

Zero WHにUSBハブを挿すと再起動されてしまいます - Raspberry Pi Forums

ハードウェアは難しいですね。

ちなみに、OSインストール後に自動でスタートするセットアップ中にこれらのトラブルは起きたのですが、途中で再起動しても 最初からセットアップがやり直されたので、大きな問題も起こりませんでした。

トラブル3:アップデートに失敗

セットアップ作業の最後でアップデートがかかるのですが、なぜかアップデートに失敗していました。

セットアップ完了後、改めて、

sudo raspi-config

を呼び出して、再度アップデートを試しても同じ結果でした。

これには、下記の記事を参考に、

Raspbianのsudo apt-get updateが失敗したら試したい解決方法

sudo apt-get update --allow-releaseinfo-change

とすればエラーを回避できました。

ちなみに、df -h でSDカードの空き容量を調べてみると、残りが約 800MB だったので、 このあといろいろとインストールすることも考え、一旦保留としました。

カメラ接続

OSのセットアップが終わったら、いったんシャットダウンして、カメラモジュールを接続します。

カメラモジュールをケースから出すとこんな感じです。

f:id:junichim:20191122231018j:plain

ちなみに、中央の白い真ん中に穴の開いたのは何だろうか?と思っていたのですが、後日、ピント調節用の治具だとわかりました。

ラズパイzeroの公式ケースには、カメラモジュール用のケーブルが付属しています。

f:id:junichim:20191122231912j:plain

上から2つ目の赤いケールに入っている短いフラットケーブルですね。

さて、これを実際どうやってカメラモジュールにつけるんだろうか?と少し考えてしまいました。
ま、困ったら調べようということで、下記の記事を見つけて、これを参考にケーブルを差し替えました。

第43回「Raspberry Pi Zero V1.3+カメラモジュールでミニ定点カメラを作ろう!」 | Device Plus - デバプラ

ケーブルはコネクタに刺さった状態で固定(というより抑えてるような感じ?)されているだけのようで、

f:id:junichim:20191122232256j:plain

黒いコネクタの両端を基盤側から外側に押し出すようにすると、コネクタが外れて、

f:id:junichim:20191122232335j:plain

ケーブルを簡単に抜くことができました。

f:id:junichim:20191122232546j:plain

そうしたら、先ほどの公式ケースに付属していた短いケーブルに差し替えて、

f:id:junichim:20191122232715j:plain

再度黒いコネクタを閉じれば終わりです。

f:id:junichim:20191122232741j:plain

ぶきっちょな私でも出来た!

続いて、同じ要領で本体側にもケーブルを接続します。 黒いコネクタを外して、

f:id:junichim:20191122232851j:plain

f:id:junichim:20191122233011j:plain

問題なくケーブルが接続できれば、ハード的な作業は完了です。

次は、ラズパイzeroの電源を入れて、カメラの設定をします。

カメラの有効化

ハードウェアの取り付け作業が終われば、OS側でカメラを有効にするのは簡単です。

下記の記事などを参考にして、

$ sudo raspi-config

を起動して、カメラを選択して有効化します。

試し撮り

Raspbianにはカメラでの撮影用のコマンドが用意されています。

$ raspisitll -o test.jpg

とコマンドをたたいて、問題なく画像が取得できれば、OKです。

ちなみに、何もパラメータを指定しないと、カメラの解像度(3280 × 2464 px)のサイズになります。

幅と高さを指定する場合は、

$ raspisitll -w 640 -h 480 -o test.png

とすると、指定したサイズになります。

詳しくは、公式ドキュメントなどを参照してください。

Raspberry Pi Camera Module - Raspberry Pi Documentation

その他の設定(と確認)

アプリの開発に取り組む前に、いくつかの設定と確認をやっておきます。

SSH と VNC を有効化

先ほどの raspi-config をもう一度呼び出して、SSHとVNCを有効にしておきます。

VNC は接続元のほうにも、VNC Viewer を入れておきます。

Download VNC Viewer | VNC® Connect

なお、下記記事のように、VNCで接続する際の解像度を指定することもできます。

Raspberry PiにVNCで接続して操作する - Qiita

スクリーンショット

ラズパイでスクリーンショットを撮るには、scrot コマンドを使えばよいようです。

Raspberry Piの環境を整える。 - colorful life generator

これで、OSとしてのセットアップが一通り終わったっぽいので、からはアプリケーション開発のための準備と実際の開発を行いたいと思います。