アイキャッチ1280x670

micro:bitとAzure Face APIで作る「入室管理システム」

こんにちは、遠藤です。
コピペテックマガジン第5回目は、第4回に引き続いてBBC micro:bitを使った電子工作です。

今回は、micro:bitと焦電赤外線センサー(人感センサー) EKMC1601111を繋いで、オフィスや家に入ってきた人をお知らせするシステムを作ってみたいと思います。
システムの全体像はこんな感じになります。

画像1

動作についてはまず、動画を見てみてください。

これは弊社のオフィスの入り口ですが、人が入室すると焦電赤外線センサーが検知してmicro:bitでそれを受け、micro:bitからPC (Surface)に対してBluetooth経由で人が来たことを通知します。

焦電赤外線センサーは、周辺と人や動物などが動く際に発する赤外線のゆらぎを検出するセンサーで、EKMC1601111は、データシートによると5mの距離、垂直方向に82度、水平方向に94度の指向性で人の動きを検出可能です。
また、EKMC1601111は集光レンズと信号増幅機も含めたセンサーモジュールとなっており、直接micro:bitの端子につなぎデジタル入力として値を読み取ることができます。

micro:bitは、人が来たことを検知するとBluetoothサービスを利用して、Bluetooth接続したPCのブラウザに対してUARTメッセージを通知します。
Bluetooth接続は、ブラウザで利用できるWeb Bluetoothという仕様を利用しますが、この記事を公開している現在ではPC版のChromeとAndroidのChromeのみ対応していています。記事ではPC版のChromeを利用します

Chromeが、micro:bitから人を検出したメッセージを受けつけるとPCのカメラで写真を撮ります。

撮った写真をサーバーに送信し、サーバー側でMicrosoft AzureのFace APIを呼び出し写真に写った人物を識別します。サーバー側のプログラムはPythonで動かします。

Face APIの結果を受けて、すでに登録されている人であった場合は名前をSlackに通知し、未登録だった場合は、写真と名前を登録するフォーム付きのメッセージをSlackに通知します。
名前の登録はSlackのチームメンバーから選択できるようにしています。メンバーを選択するとFace APIに新しい人物が登録され、次に入出したときに名前が通知できるようになります。

Slackでメンバーを選択した際にSlackからWebアプリが呼び出されますが、このときWebアプリはインターネットからアクセスできるようにする必要があります。
インターネットからアクセスできるように(トンネル)するためにngrokというサービスを利用します。

このように今回もmicro:bitは使いますが、電子工作部分はほんの一部で、人物を検出した後は、クラウドサービスとWebアプリを連携した作り込みといったソフトウェアがメインの内容になっています。


準備するもの

電子工作用買い物リスト

今回の電子工作に使用する部材は以下のとおりです。

画像2

• micro:bit (秋月電子通商)
• USBケーブル
• 焦電赤外線センサー EKMC1601111 (
秋月電子通商)
• ブレッドボード(
秋月電子通帳)
• ミノムシ(ワニ)口クリップ付きジャンパワイヤー x 3 (
秋月電子通商)

電子パーツについては、秋月電子通商のECサイトのリンクをつけてありますので、電子パーツを買えるお店が近くにない場合はこちらから購入してください。

その他、準備が必要なもの

• カメラ付きPC Windows または Mac

この記事ではWindows 10をベースに説明しています。
また、PCには以下をインストールしておいてください。

• Google Chrome
• テキストエディタ VisualStudio Code など (この記事ではVisual Studioを使用しました)

焦電赤外線センサーとmicro:bitのセットアップ

micro:bitで焦電赤外線センサーの入力を制御して写真を撮るプログラムを作成して、その後センサーとmicro:bitを繋いでいきます。

micro:bitのプログラム作成には、ブラウザで利用できるmakecode を利用します。

https://makecode.microbit.org を開くと、新しいプロジェクトが作成されプロジェクトが開きます。

完成版のmakecodeプロジェクトを以下のURLで公開していますので、必要に応じて参考にしてください。

https://makecode.microbit.org/_Vt4JkhcsM4dY

拡張機能Bluetoothを追加

ブロックを追加してプログラミングを始める前に、まずBluetoothパッケージを追加します。

右上の歯車アイコンをクリックして、メニューから[拡張機能]を選択します。

画像3

[bluetooth]を選択します。

画像4

[Remove extention(s) and add bluetooth]ボタンをクリックします。

画像5

ブロックリストの[無線]に替わって[Bluetooth]が追加されます。

画像6

Bluetoothのペアリング設定

次にmicro:bitのBluetoothの設定をしていきます。

[プロジェクトの設定]を開きます。

画像7

ここで、プロジェクト名も変更しておきます。
[名前]にプロジェクト名を設定し、[No Pairing Required: Anyone can connect via Bluetooth.]を選択します。

画像8

ペアリング設定を選択すると、プロジェクトの設定が閉じられます。

micro:bit用のプログラムを作成

必要なパッケージが追加できたら、以下のように人感センサーで入室を検知して、写真を取るプログラムを作成していきます。

画像9

1. [Bluetooth ...more]から[Bluetooth UARTサービス][最初だけ]に追加します。
2. [論理] から [もし <真▼> なら (+) ][ずっと]に追加し、<真▼>を[論理] > [(0) {=} (0)]に置き換え、左側の(0)を[高度なブロック] > [入出力端子] > [デジタルで読み取る 端子 {P0▼}]に置き換え、右側の(0)には「1」をセットします。
3. 2.のブロックに[Bluetooth ...more]から[Bluetooth UART 数値を文字で書き出す(0) ]を追加し、(0)を「1」に変更します。
4. 続けて、[基本] から [アイコンを表示 {アイコン}]を追加し、{アイコン}は「チェック」を選択します。
5. [基本] から [一時停止(ミリ秒) {100}]を追加して、停止時間を「5000」に設定します。 
6. [基本 ...more]から[表示を消す]を追加します。
7. [ずっと]ループの最後に[基本] から [一時停止(ミリ秒) {100}]を追加します。

micro:bitのBluetoothサービスには、Pin IOサービスという端子の値を直接Bluetooth接続機器から読み取れるサービスがあります。しかし、検証してみたところ有効な値を取得できませんでした。Pin IOサービスについては情報が少なく解決しそうになかったので、人を検出したらUARTサービスでメッセージを送信するようにしました。

micro:bit用のプログラミングは以上です。

[ダウンロード]をクリックして、hexファイルをダウンロードします。

micro:bitとPCをUSBケーブルで接続して、ダウンロードした「人が来たら通知する.hex」ファイルをmicro:bitに転送します。

画像10

micro:bitと焦電赤外線センサーをつなぐ

micro:bitに焦電赤外線センサーをつないで、センサーの動きを確認してみます。

焦電赤外線センサーEKMC1601111をブレッドボードに差します。
Source、Grand、Drainをそれぞれブレッドボードの以下の位置に差します。

画像11

ピンの向きを確認して、センサーを差し込みます。

画像12

Micro:bitのGND端子とGrand、3V端子とDrain、P0端子とSourceがつながるように、みのむしクリップ付きジャンパーワーイヤーでつなぎます。

画像13

ここまでの動作を確認してみます。
センサーに手をかざしたりすると、micro:bitにチェックマークが表示されます。

micro:bitからの通知を受けてPCで写真を撮る

Webアプリケーションのソースファイルを以下のURLからダウンロードしてください。

https://github.com/hrendoh/face-detection-with-microbit/archive/master.zip

ダウンロードしたファイル face-detection-with-microbit-master.zip を展開してPCのユーザのホームディレクトリ(Windowの場合は、「C\Users\<ユーザー名>」)に移動します。

展開したフォルダーからHTMLファイル face-detecttion-with-microbit-master/templates/index.html をChromeで直接開きます。

カメラの使用を許可するダイアログが表示されるので[許可]をクリックします。

画像14

次に[CONNECT]ボタンをクリックすると、Bluetoothペアリングの設定ダイアログが開きます。

「BBC micro:bit [pagit]」を選択して[ペア設定]をクリックします。

画像15

[試行中]に切り替わり[接続中]になったらペアリングとmicro:bitのBluetooth UARTサービスの準備に成功しています。

画像16

micro:bitと合わせて動作を確認してみます。
センサーで検知するとPCのカメラで写真が撮られることが確認できます。

確認用動画では、センサーの向き的に常に反応してしまっているので、5秒おきに写真が撮られるような動作になっています。

Webアプリケーション サーバーをセットアップ

先程はHTMLファイルを直接Chromeで開きましたが、次は撮った写真をサーバーに送信し、Face APIをたたいて写真の人物を識別するようにするために、PC上にWebサーバーを立てていきます。

アプリケーションの構成

今回のWebアプリケーションはPythonのflaskというWebアプリケーションフレームワークを使用して実装しています。
アプリケーションの構成は以下のようになっています。

- main.py
- templates/
    - index.html
- static/photos/

main.pyn には、Webアプリケーションのサーバーサイドのコードをすべて含んでいます。
templates ディレクトリは、flaskでテンプレートを配置するディレクトリです。先程使用したindex.htmlを含みます。
static ディレクトリは、cssやjs、画像など静的リソースを配置するディレクトリです。今回は撮影された写真を保存して、Slackからアクセスします。

Python環境 Anacondaのインストール

Pythonの環境はWindowsでもMacでもインストーラで簡単にセットアップできるAnacondaを使用します。
以下の手順でAnadondaをインストールしていきます。

1. Pythonのインストーラをダウンロードします。
https://www.anaconda.com/download/ にアクセスし下にスクロールするとダウンロードボタンがあります。
[Python 3.7 version]の[Download]ボタンをクリックします。

画像17

2. ダウンロードされたAnaconda3-5.3.0-Windows-x86_64.exeを実行します。
Anacondaのインストーラが開きます。[Next > ]をクリックして次に進みます。

画像18

2. [I Agree]をクリックします。

画像19

3. [Just Me]を選択して[Next >]をクリックします。

画像20

4. インストール先のフォルダを指定して[Next >]をクリックします。

画像21

5. オプションはデフォルトのまま[Install]をクリックしてインストールを開始します。

画像22

6. しばらく待ちます。インストールが完了したら[Next>]をクリックします。

画像23

7. テキストエディがVisualStudioCodeをインストールしますか?と聞かれます。テキストエディタがない場合は、ここでインストールしておいてください。
テキストエディタがすでにインストールされている場合は[Skip]をクリックします。

画像24

8. 以上でインストール完了です。[Finish]をクリックしてインストーラを閉じます。

画像25

PythonコンソールでWebアプリケーション サーバーを起動

Windowsメニューから[Anaconda3(64-bit)] > [Anaconda Prompt]を開きます。

(base) C:\Users\ユーザ名> のプロンプトが開きます。

ディレクトリ face-detection-with-microbit-master に移動し、「python main.py 」と打ち込みEnterを押して実行します。

画像26

Windowsの場合、Windowsファイアウォールの許可が求められます。(Macの場合はそのまま起動します)

画像27

[アクセスを許可する(A)]をクリックするとサーバーが起動します。

画像28

動作確認

http://localhost:3001 にアクセスすると以下のように、先程ファイルを直接開いたのと同じ画面が開きます。

画像29

今度は写真が撮られるとWebサーバーに写真が送られて、Webサーバー側でFace APIで検出しようとしています。
まだ、Azure Face APIの準備をしていないのでエラーになっています。

画像30

Microsoft Azure Face APIを使って顔を検出

次に、撮った写真に写っている人物をMicrosoftのFace APIを使って識別してみます。

Microsoft Azureのサブスクリプションを持っていない場合は、無料試使用版のサブスクリプションを取得できます。
以下のURLからAzureにサインナップしてください。

https://azure.microsoft.com/ja-jp/free/

画像31

サインナップするとAzure ポータルが開きます。
ポータルが開いたら、以下の手順でFaceリソースを追加していきます。

1. 画面の左のメニューから、[すべてのサービス] > [AI + MACHINE LEARNING]から[Cognitive Service]を選択します。

画像32

2. Cognitive Servicesのページに切り替わるので、左上の[+ 追加]ボタンまたは[Congnitive Serviesの作成]ボタンをクリックします。

画像33

3. AI + Machine Learningのページで、Cognitive Servicesの[さらに表示]をクリックします。

画像34

4. 右に開いたAPI一覧から[Face]を選択し、[作成]をクリックします。

画像35

5. 作成フォームが開きます。
[Name]には適当な名前「FaceDetection」を入れ、サブスクリプションは「Azure Free Trial」を選択します。
[場所]は「東日本」(japaneast)を選択し、価格レベルは「F0」、[Resource Group]は適当に作成したものを選択して[作成]をクリックします。

画像36

6. リソースの作成が完了すると、右上に以下のポップアップが表示されるので、[ダッシュボードにピン留めする]をクリックしてダッシュボードに登録しておきます。

画像37

7. 左のメニューから[ダッシュボード]を開き、作成した[FaceDetection]を選択します。

画像38

8. [FaceDetection]が開いたら、左から[Keys]を選択して、APIキーを表示します。

画像39

[KEY 1]をAPIの認証に使います。
[KEY 1]をコピーして、main.pyの「<Azure Face API Key>」の箇所を置き換えてください。

# <Azure Face API Key>をKEY 1の値に置き換え
FACE_API_SUBSCRIPTION_KEY = '<Azure Face API Key>'

main.pyを再起動します。
再起動は、main.pyを起動しているターミナルにフォーカスして[Ctrl + C]キーを入力すると停止します。再び「python main.py」を入力してEnterします。

写真が撮られると、Face APIで検出された顔に枠が表示されます。

画像40

WebアプリケーションのコンソールではSlackのWebhookを呼び出すところで、以下のようなエラーが表示されます。

画像41

引き続きngrok、Slackの設定をしていきます。

ngrokでWebアプリケーションをインターネットに公開

Slackの設定の前に、Webアプリケーションをインターネットに公開しておきます。

https://ngrok.com/ にアクセスしアカウントを作成します。
(アカウントを持っている方はサインアップの手順はスキップしてください。)

[Get start for free]か右上の[Sign up]ボタンをクリックします。

画像42

EmailまたはGithubアカウント、Googleアカウントいずれかで登録できますが、ここではEmailでサインナップしてみます。

画像43

登録フォームに名前、Eメールアドレス、パスワードを入力して[Create an account]ボタンをクリックします。

Eメールによるコンファームは無く、登録するとすぐに以下の[Setup & Install]のページが表示されます。

画像44

[Download for Windows]をクリックしてngrokコマンドを含むzipファイルをダウンロードします。

ダウンロードされた「ngrok-stable-windows-amd64.zip」ファイルを展開して、ngrokファイルをユーザのホームディレクトリ(C:\Users¥<ユーザ名>)に移動しておきます。

画像45

ページをスクロールして、[Connect your account]のコードをコピーします。

画像46

Anaconda navigatorからターミナルをもう一つ開き、コピーしたコードをペーストして実行します。

画像47

ngrokの認証情報が.ngrok2フォルダに保存されます。

続いて「ngrok http 3001 」を実行して、Webhookをngrokをつなぎます。

画像48

実行すると以下の画面に切り替わります。

画像49

ブラウザで、https://<xxxxx>.ngrok.io にアクセスすると、以下のように同じページが表示されます。

画像50

割り当てられるURLの値は起動毎に変わります。この記事が終わるまでは起動したままにしておいてください。

Slackチームに通知と人物を選択するWebhookを登録

次はSlackに、入室の通知と新しい人物の写真にラベル付けをするWebhookを登録します。

Slackワークスペースがない場合は、以下のURLより新しいチームをサインナップしてください。

https://slack.com/create#email

ワークスペースの準備ができたらSlackにサインインしているブラウザで、https://api.slack.com にアクセスしします。

画像51

このサイトで、Webhookを含むSlack用のアプリケーション Slack Appを作成し、発行されるWebhookのURLと、OAuthアクセストークンをmain.pyにセットします。

ところで、ただの通知のみのWebhookであればSlack Appを作成しなくても https://slack.com/services/new/incoming-webhook から簡単に設定が可能です。
この記事では、メンバーを選択するところでInteractive messagesという機能を使いますが、Interactive messagesはユーザの入力を受け付けるサーバーのEndpointを設定する必要があり、それはSlack Appの設定画面 Interactive Components で行います。
また、写真の人物を選択した際にSlackから送られてくる情報は、選択したユーザのSlackの内部Idのみなので、users.info APIをたたいてユーザ名を取得し、それをFace APIのPersonのnameにセットしています。Slack APIのアクセスにはOAuthアクセストークンが必要ですが、こちらもSlack Appの設定ページOAuth & Permissionsから取得することができます。

では、以下の手順でSlack Appを作成し設定してきましょう。

1. [Start Building]をクリックしてアプリケーションの作成を開始します。
以下の[Create a Slack App]フォームが表示されます。

画像52

[App Name]には「入室管理システム」と入力し、[Development Slack Workspace]では、アプリを利用するSlackのワークスペースを選択して、[Create App]ボタンをクリックします。

2. 新しくアプリケーションが作成され、以下の[Basic Information]のページが表示されます。
[Add features and functionality]から[Incoming Webhooks]をクリックして開きます。(左のメニューから[Incoming Webhooks]を開いても同じです)

画像53

3. Incoming Webhooksを有効にするために、右上のスイッチをクリックして「On」にして、[Add New Webhook to Workspace]をクリックします。

画像54

4. [Post to]で入室管理システムが投稿をするチャンネルを選択して[Authorize]をクリックします。

画像55

5. [Webhook URLs for Your workspace]の[Webhook URL]に、作成されたWebhoookのURLが追加されます。

画像56

追加されたURLをコピーして、main.pyの「<Slack Incoming Webhook URL>」を置き換えます。

# <Slack Incoming Webhook URL>をWebhook URLの値に置き換え
SLACK_INCOMING_WEBHOOK_URL = '<Slack Incoming Webhook URL>

6. 続いて、左の[Features]から[Interactive Components]を開き、Interactive messagesを有効にするために、右上のスイッチをクリックして「On」にします。

画像57

7. 設定が可能になるので[Request URL]に、ngrokのURLに「persons」を足した値「https://xxxxxx.ngrok.io/persons」を入力し、[Save Changes]をクリックして保存します。
「persons」はユーザーを選択した際にFace APIに人物 Personを登録するアクション名なります。

画像58

8. 次に、左のメニューより[OAuth & Permissions]を開きます。

画像59

9. 少しスクロールして、[Scopes]の[Select Permission Scopes]のプルダウンから「users.read」の権限を選択します。
「users.read」を付与することによって、users.info APIを使用してユーザ情報を取得できるようになります。

画像60

10. [Access your workspace's profile information users.read]が追加されたことを確認して、[Save Changes]をクリックします。

画像61

11. サイトの上部に、以下のメッセージが表示されるので[click here]をクリックします。

画像62

12. 再度、チャンネルにインストールします。

画像63

13. [OAuth & Permissions]のページに戻ります。

画像64

[OAuth Access Token]をコピーしてmain.pyの「<Slack OAuth Access Token>」を置き換えます。

# <Slack OAuth Access Token>をOAuth Access Tokenの値に置き換え
SLACK_OAUTH_ACCESS_TOKEN = '<Slack OAuth Access Token>'

main.pyを再起動します。

以上で、一通り実装完了です。

全体の動作確認

では、人の検出からSlackへの通知まで全体の動きを確認してみましょう。

冒頭の動画のように、センサーが反応して写真が撮られるとSlackに以下のような写メッセージが投稿されます。

画像65

[メンバーを選択]からメンバーを選択します。

画像66

メンバーを選択すると、main.pyのpersonsアクションが呼び出されて、選択した名前で写真がFace APIに登録されます。

Slackのinteractive messageのコールバックは3秒以内に応答を返さないとなりませんが、Azure Face APIを何度か叩くと3秒以上かかってしまうことがあるため、メンバーを選択したあとはエラーが表示されてしまうことがあります。
実際にはFace APIへの登録は非同期処理にする必要がありそうですが、この記事ではそのままにしてあります。

同じ人の写真が投稿される場合は、「<Slackのユーザ名>が入室しました。」というメッセージと共に写真が投稿されます。

画像67

他のメンバー、矢野さんが入室してきた場合も以下の通りちゃんと動くことが確認できました。

画像68

Slackのユーザ名「yanotaka」を選択後、再度検出すると正しく判定できています。

画像69

チューニングポイント

以上で、本編のアプリケーションは完成ですが、補足としていくつかチューニングポイントをまとめてみます。

写真を撮るタイミング

EKMC1601111は反応が良いので弊社オフィスのようにドアまでの距離が近いと部屋に入る前に写真が撮られてしまいあまりよいアングルで撮影できない場合があります。
解決策としては以下のような手段がありそうです。

1. 確実な方法は、反応したら一定時間連写しすべてサーバーに送信し、顔を検出できた一枚を採用するロジックにする。
2. 人を検知してから写真を撮るまでに間をおく。

写真単体での検出率アップ

顔が写っていても、解像度や明るさによっては検出率が下がります。
今回の記事では、Surface Pro 3のWebカメラを利用していますが、あまり明るさ調整の反応がよくないので、タイミングしだいでは暗く写ってしまったりします。
明るさについては解決策としては以下のような手段がありそうです。

1. カメラ性能の良いAndroid端末を利用する。
2. OpenCVなどを利用してソフトウェアで露出を上げる。

解像度については、幅640、高さ480にしてありますが、templates/index.html の以下のコードのwidthを変更して写真の解像を高くすることができます。

// 写真の横幅 (表示幅は320px、640だと表示されている大きさの倍の解像度になります)
var width = 640;
// 横幅、0のままであれば width の 3/4 の高さが使用されます
 var height = 0;


設置場所によってうまくいかない場合は参考に調整してみてください。


この記事が気に入ったらサポートをしてみませんか?