2023年01月25日 更新

ラズパイとAminoMEで顕微観察IoTシステム!

どうも、クラゲです。
今回はRaspberry Pi(ラズパイ)とUSBスティック型顕微鏡のAminoME(アミノメ)を使って、いつでもどこでも経過観察できるIoTシステムを作ります!



[TOC]

概要

AminoMEとはUSBスティックサイズの顕微鏡で、PCのUSB端子に挿入してお手軽に顕微観察できるデバイスです。MID(Micro Imaging Device)技術により、チップの上に見たいものを載せるだけで顕微観察が可能になっています。詳しくはこちらのページを参照してください。

AminoMEはWindows、Android、Raspberry Piの環境で動かすことが可能です。クラゲは今回Raspberry Piで動かし、検討した結果を皆さんに共有します!

今回最終的に作るシステムは、AminoMEで定期的に観察した画像をチャットアプリに送信する自動システムです。Slackというチャットアプリを使いますが、タイムラインに観察記録が残るため、変化が分かりやすいです。また、スマホ側にもSlackアプリを入れておけば、遠く離れた場所からもリアルタイムで確認することができます。

夜寝ている間にプログラムを実行しておいて朝起きた時に一気に結果を見たり、ちょっと外出する際に出先からスマホで結果を確認したりするなど可能です。

ラズパイを使うメリット

今回のシステムはPCでも作成可能ですが、ラズパイを使うメリットは以下の2点です。

  1. 長時間1つのタスクだけのために割り当てられる
  2. ハードウェアが小型で邪魔にならず、メインPCから無線で閲覧・操作できる

メインPCの場合、インターネットを閲覧したり、ウェブ会議を行ったり、メールやチャットなどを行うと思いますが、今回の手法だと、自動画像保存のタイミングで影響を受けてしまう可能性があります。一方でラズパイはこれらの用途で使うことはほぼ無いと思いますので、1つのプログラム実行に集中することができます。

また、VNCという機能を使うことにより無線でラズパイ画面を閲覧・操作できることから、邪魔にならない場所や人がいない場所にも置いておけます。例えば、エアコンが効いてない部屋にラズパイを置き、エアコンが効いている部屋でメインPCから閲覧・操作できるということです。

AminoMEの入手

以下のサイトから購入できます。2種類ありますが、外観が異なるだけでどちらでも機能に違いはありません。

AminoME | iddkshop powered by BASE

ラズパイへインストール

Aminomeを購入した方はこちらのページにアクセスし、パスワードを入力すると実行に必要なファイルを入手することができます。

Rasberry_Pi_GUAISCap.zipをダウンロードして展開し、ラズパイの/home/piの下に以下の3つのファイルを置きます。

  • guais-cap-0.0.1-armhf.deb
  • guais-tools-0.0.1-armhf.deb
  • libguais-0.0.1-armhf.deb

LXTerminal を開いて以下のコマンドを打ち込みます。

sudo dpkg -i libguais-0.0.1-armhf.deb
sudo dpkg -i guais-cap-0.0.1-armhf.deb
sudo dpkg -i guais-tools-0.0.1-armhf.deb

これでインストール完了です! 簡単!

0.0.1はバージョンを示しており、ファイル名は今後変わる可能性がありますので、入手したファイルのバージョンに適宜修正してください。

ビューアの実行と観測

AminoMEデバイスをラズパイのUSB端子に挿入後、以下のコマンドを打ち込むことでビューアが立ち上がります

GUAISCap



今回はどこの家庭にもあると思われる調味料「食卓塩」をざっくりを置いてみました。AminoMEに直接置いています。



ウィンドウの左下に/dev/video0などと表示されていることを確認します。表示されていない場合は、ウィンドウを閉じたり、デバイスを挿入し直したりしてから、もう一度コマンドを打ち込んでください。
メニューからOptions > Camera Settings...を選択します。

ここでExpoure TimeAnalog Gainを調整しますが、ポイントとして、マウスのドラッグではなく、キーボードの カーソルキーを使って行います。というのもほぼ0に近い値で調整するためです。マウスを使うと一気に通り過ぎてしまいます。

クラゲは以下で設定しましたが、これは周囲の明るさや対象物によって異なりますので、各自の環境で調整してください。

  • Expoure Time:0x01C9
  • Analog Gain:0x004F

調整が終わったらOKを押してください。この調整値はウィンドウを閉じても保持されます。ただし、ラズパイを再起動したり、AminoMEデバイスをラズパイに挿入し直すとリセットされます。

もし、真っ黒い画面のまま表示されていない場合は、一度ウィンドウを閉じてもう一度GUAISCapコマンドを実行してみて下さい。真っ白で「塩」が確認できない場合は、Expoure Timeをほぼ0に近いところで調整してみてください。

自動観察IoTシステム

手動での観察はできましたので、ここからは自動観察IoTシステムを作ってゆきます。主に以下の4つのステップに分かれています。

  • Pythonプログラムからビューア実行
  • スクリーンショットで画像保存
  • Slackへ画像投稿
  • 定期的にプログラム実行

Pythonプログラムを使ってシステムを実行します。
Raspberry Pi OSに最初からインストールされているGeanyなどを使って以降のコードを実行してください。

今回、クラゲはトマトの果肉を置いてみました。

ステップ1:Pythonプログラムからビューア実行

/home/piに以下のコードを作成して実行します。GUAISCapビューアが既に開いている場合は閉じてから実行してください。

import subprocess
import time

#GUAISCap実行
proc = subprocess.Popen(['GUAISCap'])

#5秒待つ
time.sleep(5)

#GUAISCapを強制終了
proc.kill()

subprocessを使うことにより、Pythonプログラム上でコマンドが扱えるようになります。ビューアが5秒表示された後、自動的に終了します。

subprocessに関しての詳しい内容はこちらのページを参照してください。

ステップ2:スクリーンショットで画像保存

スクリーンショットアプリspectacleを使うとアクティブなウィンドウの画像が保存できます。

まず、spectacleをラズパイにインストールします。

sudo apt -y install kde-spectacle

インストール完了まで数分かかります。
GUIでも実行できますが、今回はPythonを使った自動システムですので、コマンドを活用します。Pythonコードは以下の通りです。

import subprocess
import time

#GUAISCap実行
proc = subprocess.Popen(['GUAISCap'])

#5秒待つ
time.sleep(5)

#spectacleでスクリーンショット保存
subprocess.run(['spectacle', '-a', '-b', '-n', '-o', 'image.png'])

#GUAISCapを強制終了
proc.kill()

これを実行すると/home/piimage.pngというファイルができていることを確認してください。

なお、実行時に以下のようなメッセージが表示されますが、特に問題はありません。

QDBusConnection: name 'org.kde.kglobalaccel' had owner '' but we thought it was ':1.59' QXcbClipboard: Unable to receive an event from the clipboard manager in a reasonable time

spectacleに関しての詳しい内容はこちらのページを参照してください。

ステップ3:Slackへ画像投稿

はじめに、こちらのページを参考にSlack APIのトークンとチャンネルIDを取得してください。以下コードのtokenchannnelsに追記してPythonコードを完成させ、実行してください。

import subprocess
import time
import requests

#slackの設定
url = "https://slack.com/api/files.upload"
data = {
   "token": "", #★要入力
   "channels": "", #★要入力
   "initial_comment": "ラズパイで顕微観察しました!"
}

#GUAISCap実行
proc = subprocess.Popen(['GUAISCap'])

#5秒待つ
time.sleep(5)

#spectacleでスクリーンショット保存
subprocess.run(['spectacle', '-a', '-b', '-n', '-o', 'image.png'])

#GUAISCapを強制終了
proc.kill()

#5秒待つ
time.sleep(5)

#画像ファイル読み込み
files = {'file': open('image.png', 'rb')}

#Slackへ送信
requests.post(url, data=data, files=files)

Slackアプリに表示されます。

ステップ4:定期的にプログラム実行

datetimeを活用して、指定した時間間隔でGUAISCap実行・スクリーンショット保存・Slackへ送信を行います。コメントに日付・時刻も含めました。
以下コードのtokenchannnelsに追記してPythonコードを完成させ、実行してください。

import datetime
import subprocess
import time
import requests

#slackの設定
url = "https://slack.com/api/files.upload"
data = {
   "token": "", #★要入力
   "channels": "", #★要入力
   "initial_comment": "ラズパイで顕微観察しました!"
}

#実行間隔の設定時間[sec]
TIME_SETTING = 5 * 60 #5min

#最後に送信した時刻の初期化
last_time = datetime.datetime(1, 1, 1) #最古の年月日(時刻は省略)

#メインループ
while True:
    try:
        #現在時刻の取得
        current_time = datetime.datetime.now()

        #経過時間を計算
        elapsed_time = current_time - last_time

        #設定時間を経過したら実行
        if elapsed_time.seconds >= TIME_SETTING:
            #時刻を取得し文字列化
            message = current_time.strftime('%Y年%m月%d日 %H時%M分%S秒 の顕微観察です!')

            #表示
            print(message)

            #最後に送信した時刻の更新
            last_time = current_time        

            #GUAISCap実行
            proc = subprocess.Popen(['GUAISCap'])

            #10秒待つ
            time.sleep(10)

            #spectacleでスクリーンショット保存
            subprocess.run(['spectacle', '-a', '-b', '-n', '-o', 'image.png'])

            #GUAISCapを強制終了
            proc.kill()

            #5秒待つ
            time.sleep(5)

            #画像ファイル読み込み
            files = {'file': open('image.png', 'rb')}

            #Slackのコメント
            data["initial_comment"] = message

            #Slackへ送信
            requests.post(url, data=data, files=files)

    except Exception as e:
        #エラー内容出力
        print(e)

        #10秒待つ
        time.sleep(10)

このコードの例では、5分毎にスクリーンショット画像と時刻メッセージをSlack送信します。TIME_SETTINGの値を変更することで、時間間隔を変更できます。

確実に画像を取得できるようにスクリーンショットを保存したらGUAISCapビューアを閉じ、次回スクリーンショットを撮る直前にGUAISCapビューアを起動しています。

また、安定動作のために、最初のsleepを5秒から10秒に変更し、何らかのエラーで実行が停止してしまわないようにtry...exceptも加えました。

以下は、実行してからしばらく経った後のSlackアプリ画面の様子です。タイムラインをスクロールすることで変化の様子が分かりやすく観測できます。

高解像度で画像取得

これまでは、全体画像を縮小表示して画像サイズを軽くしていました。実際にはもっと大きなサイズで高解像度の画像を取得できます。
v4l2コマンドOpenCV を活用することにより、このような画像を得ることができます。こちらも「食卓塩」の画像ですが、最初にお見せした画像に比べて高解像度になっているのがわかると思います。

以下にコード例を参考に載せておきます。

import numpy as np
import cv2
import os #v4l2コマンドを使用するため

#カメラデータ取得
os.system('v4l2-ctl  --stream-count=1 --stream-mmap=3 --stream-to=testpg.raw')
# testpg.raw は任意の名前で指定

#RAW画像ファイルをOpenCVに入れるための再配列
width=4208
height=3120

fd = open("/home/pi/testpg.raw",mode='rb')
f = np.fromfile(fd, dtype=np.uint16, count=height*width)
img = f.reshape((height,width))

#OpenCVで再配列の読み込み及びファイルフォーマット変更処理
cv2.imwrite('/home/pi/testpg.jpg', img)

#RAW画像の再配列処理終了
fd.close()

#RAW画像の削除
os.remove('/home/pi/testpg.raw')

実行して処理をを行うとプログラムが終了し、/home/pi/testpg.jpgというファイルが生成されます。ダブルクリックしてラズパイの画像ビューアで確認することが可能です。Ctrlキーを押しながらマウスホイールを回転させると拡大・縮小ができます。

ModuleNotFoundError: No module named 'cv2'というエラーが出ている場合は、OpenCVのインストールが必要です。OpenCVに関しての詳しい内容はこちらのページを参照してください。

このプログラムの場合、GUAISCapビューアで見ている状態よりも明るく撮影されるようです。画像が真っ白になっていたら、GUAISCapビューアにてCamera Settings...からExpoure Timeをやや小さめに設定してみて下さい。

最後に

AminoMEの詳細についてはこちらのAminoME特設ページをご参照ください。

今回は家にあった食材を対象物としましたが、身近に採取できる微生物で観察すると面白い発見ができるかもしれません。また、OpenCVは画像処理や機械学習、ディープラーニングとも簡単に連携ができますので、様々な応用が可能です。ぜひ、皆さんも挑戦してみてください!

以上、ラズパイとAminoMEで顕微観察IoTシステムでした!