知的好奇心 for IoT

IoT関連の知的好奇心を探求するブログです

昔作ったガイガーカウンターをESP8266とBlynkでIoT化する

4年前たまたま書店で見つけた「よくわかる最新線量計の基本と作り方」という本に、ガイガーカウンターの自作方法が解説されていたので当時作ってみました。

f:id:IntellectualCuriosity:20170827175150j:plain

自作筆箱版ガイガーカウンター

ソビエト製のSBM-20というガイガーミュラー管を使っていて、カッコイイですよね。でも、歩数計を改造したカウンターでは使い勝手が悪かったので、どうにかできないかと思いつつ放置していたんです。

先日書いた「ESP8266とDHT11とBlynkでスマホとWebにリアルタイムで温度と湿度を表示する」で使ったBlynkがかなりいい感じだったので、4年越しでガイガーカウンターをBlynkに対応させて使い勝手を向上させることにしました。

f:id:IntellectualCuriosity:20170827182137j:plain

ブレッドボード版IoTガイガーカウンター

スマホアプリのBlynkではこんな風に表示します。

f:id:IntellectualCuriosity:20170828022233p:plain

単位のcpmはcounts per minuteのことで、ガイガーミュラー管が1分間に検出した放射線の回数を表します。上の図でもわかる通り、1分間ではかなり検出数にムラがでるので1時間平均も載せるようにしています。

 

ハードウェア

使ったもの

筆箱版で使用していた部品

(抵抗・コンデンサ・ヒューズクリップはブレッドボードへの転用ができない状態になっていたため、新しいものを使っています。)

乾電池置き換え用電源部品

改造歩数計カウンター置き換え用IoT化部品

その他

回路図

f:id:IntellectualCuriosity:20170828193714p:plain

写ルンです改造高電圧発生ボードを表現できなかったため、実際とは少し違う回路図になっています。LDOレギュレータの出力1.5Vがボードへの入力となり、出力を400V電池として表現しました。

ブレッドボード版IoTガイガーカウンターでESP8266用とLDOレギュレーター用にそれぞれ電源を二つ取っているのには理由があります。

ESP8266のVCC(3.3V出力)をLDOレギュレーターの入力に使うためにVCCとグランドを繋ぐと、高電圧出力が得られなくなってしまうんです。テスターで計ったら1.5Vになっていました...。ガイガーミュラー管の検出信号をフォトカプラーを使ってESP8266に伝えることで、高電圧出力側とESP8266のグランドを分けて電源を1つにしようといろいろと頑張ったのですがうまく動作させることができませんでした。

グランドを分けるためにUSB電源を2つ取っているので、USB電源の取り先のグランドが繋がっていると高電圧を発生させることができません。同じPCのUSBから電源を取ってしまうとグランドが繋がってしまうので注意が必要です。

 

ソフトウェア

Blynk設定

少し改良して、1分間の検出数、1分間の検出数(1時間平均)、2つの検出数のグラフの他に、閾値を超えたときの通知を追加しました。

f:id:IntellectualCuriosity:20170902015805p:plain

1分間の検出数と1分間の検出数(1時間平均)はValue Displayを使いました。

f:id:IntellectualCuriosity:20170902021847p:plain

グラフはHistory Graphを、通知はNotificationを使いました。通知のタイミングや通知内容はArduinoのプログラムで制御します。

f:id:IntellectualCuriosity:20170902022900p:plain

 

Arduinoプログラム

お待ちかね?のプログラムです。今回は結構シンプルになってます。

※2017/10/1更新 ヘッダーファイル名が全て小文字になっていました

/*
 * Geiger Counter
 * September 1, 2017
 * By Hiroyuki ITO
 * http://intellectualcuriosity.hatenablog.com/ 
 * MIT Licensed.
 */

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

#define BLYNK_AUTH    "YourAuthToken"
#define WIFI_SSID     "YourWiFiSSID"
#define WIFI_PASSWORD "YourWiFiPassword"

#define SIGNAL_PIN 5
#define NOTIFY_LIMIT 100 // 100cpm
#define NOTIFY_TEXT "WARNINIG! The device detected more than 100cpm."

/*
 * Global Variable
 */
volatile int min_count;
volatile int hour_count;
int before_hour_count;
int times;

BlynkTimer timer;

/*
 * Interrupt Function
 */
void interrupted() {
  min_count++;
  hour_count++;
}

/*
 * Send Data to Blynk
 */
void sendData() {
  Blynk.virtualWrite(V5, min_count);
  if (before_hour_count > 0) {
    Blynk.virtualWrite(V6, before_hour_count / 60);
  }
  BLYNK_LOG("Minutes: %04d  Hours: %04d", min_count, before_hour_count / 60);

  // Push Notification
  if (min_count > NOTIFY_LIMIT-1) {
    Blynk.notify(NOTIFY_TEXT);
  }
  
  min_count = 0;
  times++;

  // 1 hour
  if (times > 60) {
    before_hour_count = hour_count;
    hour_count = 0;
    times = 1;
  }
}

/*
 * Setup
 */
void setup() {
  Serial.begin(74880);
  BLYNK_LOG2("Reset Reason: ", ESP.getResetReason());
  pinMode(SIGNAL_PIN, INPUT);
  attachInterrupt(SIGNAL_PIN, interrupted, FALLING);
  Blynk.begin(BLYNK_AUTH, WIFI_SSID, WIFI_PASSWORD);

  // Setup a function to be called every minute
  timer.setInterval(60000L, sendData);

  times = 1;
  min_count = 0;
  hour_count = 0;
  before_hour_count = 0;
}

/*
 * Loop
 */
void loop() {
  Blynk.run();
  timer.run();
}

今回の1番の目玉は、ガイガーミュラー管の検出パルスを割り込みを使ってカウントすることで、カウント漏れを防ぐようにしたところです。

attachInterrupt(SIGNAL_PIN, interrupted, FALLING);が割り込み設定で、interrupted()が割り込み処理関数です。割り込み処理関数で変更される変数にはvoliteを付けるようなので気を付けましょう。

 

サイドバーのGeiger counterのソース

Blynk HTTP RESTful APIを用いてサイドバーに機器のステータス、1分間の検出数、1時間平均の1分間の検出数を表示しています。
ガイガーカウンターのデータは1分毎に送るようにしているので、setInterval()の間隔も1分毎にしています。
しかし、そのままではページを表示してから1分経つまでの間データが表示されないため、ページ読み込み時にもデータを表示する関数を実行しています。

<div id="blynk_geiger_status">ステータス取得中...</div>
<div id="blynk_geiger_min">カウント取得中...</div>
<div id="blynk_geiger_hour">毎時平均カウント取得中...</div>

<script type="text/javascript">// <![CDATA[
// 読み込み時にデータを表示
window.onload = function() {
  getDHT11byBlynk();
}

// 1分毎にデータを更新
setInterval(getDHT11byBlynk,60000);

function getDHT11byBlynk() {
  var authToken = "YourAuthToken";  // Blynkの認証トークン
  var minPin = "V5";                // カウント(分)仮想ピン
  var hourPin = "V6";               // カウント(毎時平均)仮想ピン

  // ステータス取得
  var xhrStatus = new XMLHttpRequest();
  xhrStatus.onreadystatechange = function() {
    if (this.readyState == 4) {
      var status = JSON.parse(this.responseText);
      if (status) {
          statusHTML = "<font color ='blue'>Online</font>";
      } else {
          statusHTML = "<font color ='red'>Offline</font>";
      }
      document.getElementById("blynk_geiger_status").innerHTML = statusHTML;
    }
  };
  xhrStatus.open("GET", "http://blynk-cloud.com/" + authToken + "/isHardwareConnected", true);
  xhrStatus.send();

  // カウント(分)
  var xhrTemp = new XMLHttpRequest();
  xhrTemp.onreadystatechange = function() {
    if (this.readyState == 4) {
      var minCount = JSON.parse(this.responseText);
      if (minCount > 99) {
        var minColor = "<font color ='red'>";
      } else {
        var minColor = "<font color ='green'>";
      }
      document.getElementById("blynk_geiger_min").innerHTML = minColor + minCount + "cpm (minute)</font>";
    }
  };
  xhrTemp.open("GET", "http://blynk-cloud.com/" + authToken + "/get/" + minPin, true);
  xhrTemp.send();

  // カウント(毎時平均)
  var xhrHum = new XMLHttpRequest();
  xhrHum.onreadystatechange = function() {
    if (this.readyState == 4) {
      var hourCount = JSON.parse(this.responseText);
      if (hourCount > 29) {
        var hourColor = "<font color ='red'>";
      } else {
        var hourColor = "<font color ='green'>";
      }
      document.getElementById("blynk_geiger_hour").innerHTML = hourColor + hourCount + "cpm (hour avg.)</font>";
    }
  };
  xhrHum.open("GET", "http://blynk-cloud.com/" + authToken + "/get/" + hourPin, true);
  xhrHum.send();
}
// ]]></script>

 

おわり