🚦

光センサを使用して、設備機器の赤ランプが点灯したら、担当者へ通知する実験

2023/08/14に公開
3

概要

設備機器に装備されている信号灯や警告灯の赤ランプ(やその他の色のランプ)が点灯したら、それを光センサで検出して、メール送信やSNS(Slack)投稿により、メッセージや写真を担当者へ通知する実験を行いました。これにより、IoT未対応の設備がIoT化でき、担当者の負担軽減が期待できます。

実験したシステムの構成
実験したシステムの構成

以下に、送信されたメールの例を示します(ほぼモザイクとなっています(汗)。

送信されたメールの例
送信されたメールの例

これは、ある大型の加工設備にて、加工中の異常停止により赤ランプが点灯したときに送信されたメールです。この加工設備には進捗などを示す状態表示器がありましたので、その写真をメールに添付しています。

この加工設備は、IoT機能やネットワーク機能がありませんが、本実験のシステムを後付けしてIoT化することで、担当者への通知機能が付加できました。

このようなシステムでは、たとえば以下のようなメリットが考えられます。

  • 設備機器の改造が不要(光センサを貼り付けるだけなので)
  • IoT機能やネットワーク機能がなくても使用可能(マイコンが担当するので)
  • 単なる光センサなので、パイロットランプやインジケータ等でも使用可能(明暗の差が検出できれば、どこでも)
  • ランプ点灯だけでなく、別のトリガでメール送信等が可能(例えば、温度センサを取り付け、筐体温度が上限値を超えた時、など)
  • データベースなどを併用することで、過去の履歴等も閲覧可能(過去の何時何分にどのような通知をしたか、など)

なお、本実験は、令和3年度(2021年度)に行ったもので、メール送信やSlack投稿も当時の方法となります。インターネット上のサービスは、セキュリティ等の理由で頻繁に仕様変更が行われますので、ここに記載した方法では既に実行できない可能性もあります。ご了承ください。

使用したもの

機器

項目 内容 型番等
マイコン ラズベリーパイ RaspberryPi 3B+
光センサ CdSセンサ (不明)
A/Dコンバータ 10bit、2ch、SPI接続 Microchip MCP3002
カメラ USB接続のWebカメラ Logicool C615n

サービス

分類 サービス 運営会社
メール Gmail Google社
SNS Slack Slack Technologies社

実際の機材

ラズベリーパイと光センサ

今回の実験は、2つの現場で行っています。1番目に行った実験機材の写真を以下に示します。ラズベリーパイは、専用ケース(写真の赤いもの)に入れ、ケース底面にブレッドボードを貼り付けました(つまり、写真の状態でラズベリーパイは逆さまになっています)。

そして、ブレッドボード上に光センサの回路を構成しました。使用した光センサは、CdSセルと呼ばれるもので、明るさに反比例して抵抗値が増減するものです。

ラズベリーパイとブレッドボード
ラズベリーパイとブレッドボード (大きい写真

光センサ
光センサ

明るさ調整ボリュームとオン検出確認LED

現場毎に赤ランプの明るさや周囲の明るさが異なります。これを考慮して、明るさ調整用のボリュームを付けました。ボリュームの抵抗値をしきい値として、光センサの抵抗値がしきい値を下回った(あるいは上回った)ときに、オンを検出するようにしました。これにより、現場毎の環境の違いに対応できます。

実際の調整は、現場の赤ランプに光センサを貼り付けたあと、赤ランプを強制点灯させ、ボリュームを上下させて調整します。調整時のオン検出が分かるようにボリュームの横にLEDを配置しました(下の写真の緑LED)。具体的には、次のように調整します。

  • 赤ランプを強制点灯
  • ボリュームを上下させ、確認LEDが点灯する位置で固定
  • 赤ランプを消灯し、確認LEDも消灯することを確認

明るさ調整ボリュームとオン検出確認LED
明るさ調整ボリュームとオン検出確認LED

実験

取り付け

1番目の実験にて、実際に加工設備に取り付けた様子を以下に示します。ラズベリーパイは、赤ランプのすぐ近くに設置しました。ネットワーク接続は、有線LANを使用しました。また、光センサの取り付けは、透明な粘着テープで貼り付けました。

設置(左上:赤ランプ、右下:ラズベリーパイ)
設置(左上:赤ランプ、右下:ラズベリーパイ)

光センサを赤ランプへ取り付け(透明な粘着テープで貼り付け)
光センサを赤ランプへ取り付け(透明な粘着テープで貼り付け)

プログラム概要

プログラムは、Python3で作成しました。使用した主なモジュールは以下の通りです。

種別 モジュール
GPIO入出力 RPi.GPIO
Slack投稿 requests、json等
メール送信 smtplib、email.mime(MIMEMultipart、MIMEText、MIMEApplication)等

プログラムの大まかな流れは、次のとおりです。

  1. 異常検出(赤ランプ点灯)待ち
  2. 異常検出(赤ランプ点灯)したら、写真撮影
  3. さらに、Slackへ投稿、あるいは、メール送信

異常検出(赤ランプ点灯)待ち

赤ランプが点灯したかどうかは、上記「明るさ調整ボリュームとオン検出確認LED」にも書いたとおり、ボリュームの抵抗値をしきい値として、光センサの抵抗値がしきい値を下回った(あるいは上回った)かどうかを定期的に見るようにしています。

今回使用したラズベリーパイは、アナログ値の入力ができませんので、抵抗値(抵抗の電圧値)は、外付けのA/Dコンバータにより入力しました。

なお、異常検出してメール送信等を行った後は、異常が解消されるまで(赤ランプが消灯するまで)、異常が継続中とみなし、メール送信等を行いません。つまり、異常検出~異常解消の間に最初の1回だけメール送信等が行われます。

点滅への対応

2番目の実験では、異常停止時の赤ランプは点灯ではなく、点滅でした。約0.5秒間隔で、点灯と消灯を繰り返します。人間が見れば、点滅で異常を知らせている、と簡単に認識できますが、プログラムでこれを検出するには、工夫する必要があります。

なぜなら、従来の方式の「赤ランプ点灯で異常検出」で判定すると、以下のようにメール送信が繰り返される事態となります。

  • 最初の点灯:異常検出なのでメール送信
  • 0.5秒後に消灯:異常解消
  • 0.5秒後に点灯:異常検出なのでメール送信
  • 0.5秒後に消灯:異常解消

一度異常検出したら、それ以降、異常検出をロックする、などの機能で対処できますが、折角なので、プログラムによる点滅の検出に挑戦してみました。

結論のみ書くと、今回は、点灯と消灯の累積時間を一定時間計測して、その割合から点滅判定する方式としました。たとえば、0.5秒間隔で点滅する赤ランプにて、3秒~5秒間計測し、点灯の割合が50%程度になっていれば異常検出と判定するプログラムとしました。(誤差もあるため30%~70%等かなり広く許容範囲をとりました。)

この方式は、
 赤ランプ点灯 → 即、異常検出
とはならず、
 赤ランプ点灯 → 3秒~5秒計測 → 異常検出
と少し遅れが生じます。計測時間を長くすれば精度は高まりますが、異常検出の遅れとのトレードオフとなりますので、今回は計測時間を3秒~5秒程度としました。

写真撮影

写真撮影は、当初OpenCVを使用し、Pythonプログラムで行いましたが、カメラとの相性なのか(別のカメラでは問題なかった)、画像の乱れが発生したので、外部の写真撮影コマンドを使用しました。外部コマンドで撮影した写真は、特定のディレクトリに保存させ、それをPythonプログラム側でファイルとして受け取る方法としました。使用した写真撮影コマンドは「fswebcam」です。

「怪我の功名」でしょうか。外部コマンドによるファイルの受け渡し方式にしたことで、実行する外部コマンドを変更するだけで、写真撮影以外にも使用できました。たとえば、スクリーンキャプチャした画像を使用するなどです。極端な話、画像でなくても、表計算ファイルやプレゼンテーションファイルなどを使用することも可能です。

Slack投稿

1番目の実験でSlack投稿を試しました。

事前にSlack側で、アプリケーションを登録し、トークンと投稿先のチャンネルIDを取得しておきます。

そして、以下のような関数により、メッセージを投稿しました。引数messが送信するメッセージです。

def slack_post_mess(mess):
    global token_full, chan_id, slack_url

    headers = {'Authorization': token_full}
    param = {
        'channel': chan_id,
        'text': mess,
    }

    #送信
    res = requests.post(url=slack_url, params=param, headers=headers)

    #結果
    res_d = json.loads(res.text)
    return res_d['ok']

また、以下の関数により、写真の投稿を行いました。引数のimg_fileが画像ファイルのパスです。

def slack_post_img(img_file, header_mess=''):
    global token_full, chan_id, slack_url

    files = {'file': open(img_file, 'rb')}
    headers = {'Authorization': token_full}
    param = {
        'channels': chan_id,  #チャンネルID(必須)
        #'filename': 'new-filename',  #アップロード後のファイル名
        #'title': '画像のタイトル',   #画像の上に表示されるタイトル
        #'initial_comment': '投稿者', #投稿者部分に表示される
    }
    if header_mess: param['initial_comment'] = header_mess

    #送信
    res = requests.post(url=slack_url, params=param, files=files, headers=headers)

    #結果
    res_d = json.loads(res.text)
    return res_d['ok']

なお、実験した装置の担当者から、「異常が発生していなくても、任意のタイミングで写真が欲しい」との要望があり、Slackのボットも作成しました。担当者がSlackに'photo'と投稿すると、その時点で写真撮影し投稿する単純なボットです。構築方法等は省略します。

任意のタイミングで写真を上げるボット
任意のタイミングで写真を上げるボット

メール送信

2番目の実験でメール送信を行いました。

メールサービスは、GoogleのGmailを使用しました。事前にアプリパスワードの取得等を行っておく必要があります。

メール送信は、以下のような関数により行いました。関数の引数は、img_fileが画像ファイルのパス、img_titleが画像ファイルの題名です。これにより、記事冒頭で示したメール例が送信されます。

def send_mail(img_file, img_title=''):
    if not conf_data['header']['to']:
        return False

    msg = MIMEMultipart()
    msg["Subject"] = conf_data['header']['sub']
    msg["From"] = conf_data['header']['from']
    msg["To"] = conf_data['header']['to']

    msg.attach(MIMEText(conf_data['header']['body'], "plain", "utf-8"))

    if os.path.isfile(img_file):
        #添付ファイル
        with open(img_file, "rb") as f:
            mb = MIMEApplication(f.read())
        if not img_title: img_title = os.path.basename(img_file)
        mb.add_header("Content-Disposition", "attachment", filename=img_title)
        msg.attach(mb)

    try:
        #メール送信
        sendToList = conf_data['header']['to'].split(',')
        s = smtplib.SMTP(conf_data['server']['addr'], conf_data['server']['port'])
        s.starttls()
        s.login(conf_data['server']['user'], conf_data['server']['pass'])
        s.sendmail(conf_data['header']['from'], sendToList, msg.as_string())
        s.quit()
    except Exception as e:
        return False

    return True

メール送信に関する情報は、ほぼ固定されていますので、変数conf_dataに様々なデータを集約しています(実際には、設定ファイルから読み込んでいます)。メール送信で使用してるメンバを以下に示します。

1次元目 2次元目 意味
header to 送信先メールアドレス
sub 送信メールの題名
from 送信元メールアドレス
body メール本文
server addr メールサーバのアドレス
port メールサーバのポート番号
user メールサーバのユーザ名
pass メールサーバのパスワード

設定等

今回の実験ではラズベリーパイを使用したため、モニタやキーボードは接続せず、設定等のUIをWebとしました。ラズベリーパイ上でWebサーバを動かし、PHPにて以下の機能を実装しました。

  • カメラの画角調整(一定間隔(1秒間隔)で現在のカメラ画像を表示、これを見ながら画角調整)
  • 送信先メールアドレス等の設定(メール送信時のみ)
  • 過去送信したカメラ画像の閲覧
  • ラズベリーパイのシャットダウン
  • など

Web UI(カメラの画角調整)
Web UI(カメラの画角調整)

Web UI(送信先メールアドレス)
Web UI(送信先メールアドレス)

Web UI(過去送信したカメラ画像)
Web UI(過去送信したカメラ画像)

その他のデータ

2番目の実験では、温湿度センサと電流センサ2個にて、常時データ取得を行いました。電流センサは設備機器のモータの配線に接続し、稼働状況を見るために使用しました。

これらのデータは、ラズベリーパイ上で InfluxDB、Grafana、telegraf 等を動作させ、グラフで確認できるようにしました。

その他のデータのグラフ表示(Grafana)
その他のデータのグラフ表示(Grafana)

参考:
IoT実験:ラズパイで温度取得しグラフ表示 (1)ラズパイで温度取得
IoT実験:ラズパイで温度取得しグラフ表示 (2)サーバでデータベース
IoT実験:ラズパイで温度取得しグラフ表示 (3)ラズパイでデータ送信、サーバで可視化

まとめ

今回は、設備機器の信号灯の赤ランプが点灯したタイミングで、何らかのアクション(メール送信やSNS投稿で担当作業者へ通知)を行う実験をしました。

元々IoT機能が装備されていない設備機器において、後付けでIoT機能を付加することができ、ほんの少しですが、作業者の負担軽減が図れました。

Discussion

YutaYuta

コメント失礼します、
配線の写真をもっと見やすい状態で投稿して欲しいのですが、お願い出来ますでしょうか。

YutaYuta

写真ありがとうございます。
ちなみになのですが、通知だけのシステムでteamsにメールが来るシステムの作り方などわかったりしますでしょうか、