ラズベリーパイ(Raspberry Pi Zero WH)とフォトリフレクタでハムスターの回転計

赤いケースのRaspberry Pi Zero WHとフォトリフレクタを使い、ハムスターの回し車の回転数を計測してスマホ画面にグラフ表示するアイキャッチ

ラズベリーパイ(Raspberry Pi Zero WH)と、これまで紹介したフォトリフレクタ、WebIOPiを使って、ハムスターの回し車の回転計を作ります。

フォトリフレクタで回し車の回転を検出し、DHT11で温度・湿度も読み取ります。

測定したデータはCSVファイルに保存し、JavaScriptのチャートライブラリ Chart.js を使ってグラフ表示します。

パソコンやスマホのブラウザから確認できるようにすると、ハムスターが夜にどれくらい回し車を回しているのか、あとから見返しやすくなります。

うさたん

回し車の回転数がグラフで見えるの、楽しそう!

まある

フォトリフレクタで回転を数えて、ブラウザで見られるようにしていきます。

関連する前回までの記事はこちらです。

目次

今回の制作内容

今回は、ハムスターの回し車に赤い反射テープを貼り、ケージの外側に置いたフォトリフレクタでその通過を検出します。

赤い反射テープがセンサーの前を1回通るたびに、回転数を1回として数えます。

さらに、温湿度センサー DHT11 で温度と湿度も読み取り、回転数とあわせてブラウザに表示します。

ハムスターの回し車、フォトリフレクタ、Raspberry Pi Zero WH、WebIOPi、スマホやPCでのグラフ確認までの流れを5ステップで説明した図

大まかな流れは、次の通りです。

  1. 回し車の裏側に赤い反射テープを貼る
  2. ケージの外側にフォトリフレクタを設置する
  3. Raspberry Pi Zero WHで回転数をカウントする
  4. DHT11で温度・湿度も読み取る
  5. WebIOPiでブラウザから確認できるページを作る
  6. Chart.jsで回転数・温度・湿度をグラフ表示する

ポイントは、センサーや配線をハムスターの生活エリアに入れないことです。

今回の作例では、フォトリフレクタとブレッドボードをケージの外側に置き、回し車の外側から赤い反射テープを読み取る形にしています。

ハムスターの紹介

こちらが我が家のジャンガリアンハムスター「ハムハム」です。

人なつっこいジャンガリアンハムスターで、ケージに手を入れると近づいてきます。今、生後8カ月くらいの女の子です。

ケージの前でこちらを見ているジャンガリアンハムスターの写真

夜になると、回し車をよく回しているようです。

回し車の中で走っているジャンガリアンハムスターの写真

実際にどれくらい回しているのかを測ってみたいと思ったので、Raspberry Pi Zero WHとフォトリフレクタを使って回転計を作ってみます。

回転計の作成にあたって、こちらのブログも参考にさせていただきました。ありがとうございました!

ハムスターの回転計(回し車 カウンター) [光学]

準備するもの

今回使うものは、次の通りです。

  • Raspberry Pi Zero WH
  • microSDカード
  • microUSB電源ケーブル
  • パソコン
  • ブレッドボード
  • ジャンパーワイヤー
  • 抵抗
  • フォトリフレクタ(反射型フォトセンサ)
  • 8ビットシフトレジスタ 74HC595
  • 温湿度センサ DHT11
  • ハムスターの回し車
  • ブレッドボードを固定する台

Raspberry Pi Zero WH

Raspberry pi zero WH は、初期設定と環境設定が済んだものを使います。

Raspberry Pi Zero WH本体の写真

microSDカード

Raspberry PiのOSやプログラムを保存するために、microSDカード を使います。

Team製32GB microSDHCカードの写真

microUSB電源ケーブル

Raspberry Pi Zero WHの電源用に、microUSB電源ケーブルを使います。

Raspberry Pi Zero WHの電源に使うmicroUSB電源ケーブルの写真

パソコン

プログラム作成やブラウザでの動作確認に使います。

Windowsパソコンの写真

ブレッドボード

ブレッドボード は、はんだ付けをしなくても電子部品を差し込んで配線できるボードです。

白いブレッドボードの写真

ジャンパーワイヤー

ジャンパーワイヤー は、Raspberry Piとブレッドボード、電子部品同士をつなぐために使います。

赤と黒のジャンパーワイヤーの写真

抵抗

抵抗は、フォトリフレクタやDHT11の回路で使います。

抵抗の写真

フォトリフレクタ(RPR-220)

フォトリフレクタ(反射型フォトセンサ)は、回し車の反射テープを検出するために使います。

RPR-220フォトリフレクタ本体の写真

フォトリフレクタの基本的な使い方は、こちらの記事で紹介しています。

8ビットシフトレジスタ 74HC595

8ビットシフトレジスタは、出力の制御に使います。

GPIOの使用数を減らすために使う8ビットシフトレジスタ74HC595の写真

温湿度センサ DHT11

温湿度センサ DHT11 は、温度と湿度を測るために使います。

温度と湿度を測定するDHT11温湿度センサーの写真

ハムスターの回し車

回し車の裏側に、赤い反射テープを貼ります。

ハムスターの回し車の裏側に赤い反射テープを貼った写真

回し車が回転すると、この赤い反射テープがフォトリフレクタの前を通過します。

フォトリフレクタで回転を数えるしくみ

フォトリフレクタは、赤外線を出して、反射して戻ってきた光を検出するセンサーです。

今回の回し車では、通常の面よりも赤い反射テープのほうが強く反射します。

そのため、赤い反射テープがフォトリフレクタの前を通過したときに「検出」として扱い、カウントを1増やします。

ケージの外側に置いたフォトリフレクタが、回し車の裏側に貼った赤い反射テープを検出し、通過するたびに回転数を1ずつ増やす仕組みを説明した図

大事なのは、フォトリフレクタや配線をケージの中に入れないことです。

センサー台はケージの外側に置き、回し車の裏側に貼った赤い反射テープを外側から読み取ります。

センサー台を作る

フォトリフレクタの高さを調整して、ブレッドボードを固定する台を作ります。

今回は、手元にあったレゴブロックを使って、ブレッドボードとフォトリフレクタを固定しました。

ハムスターのケージの外側に置くセンサー台を作り、ブレッドボードとフォトリフレクタを回し車の高さに合わせて設置する方法を説明した図

センサー台の正面は、このような形です。

レゴブロックで作ったセンサー台の正面写真。ブレッドボードとフォトリフレクタを固定している

後ろ側は、ジャンパーワイヤーを通せるように少し隙間を作っています。

レゴブロックで作ったセンサー台の後ろ側の写真。配線を通すための隙間がある

横にRaspberry Pi Zero WHを置いて、ケーブルも固定しやすいようにしています。

レゴブロックの横にRaspberry Pi Zero WHを置き、ケーブルを固定している写真

この台を、ハムスターのケージの外側、回し車の横に置きます。

ハムスターのケージの外側にセンサー台を設置した全体写真

横から見ると、フォトリフレクタが回し車の赤い反射テープに向くように設置されています。

ケージの外側に置いたフォトリフレクタが、回し車の裏側の赤い反射テープを向いている横からの写真

配線方法

回路図

回路図はこのようにしました。

温湿度センサーのDHT11は、4.7kΩのプルアップ抵抗が必要ということで、手元にあった10kΩの抵抗を使用しました。

Raspberry Pi Zero WH、フォトリフレクタ、DHT11、74HC595を接続したハムスター回転計の回路図

配線図

配線の方法を、簡単な図で示します。

Raspberry Pi Zero WH、フォトリフレクタ、DHT11、74HC595をブレッドボードに接続する配線図

配線の写真

写真で見ると、このような感じです。

ハムスター回転計のRaspberry Pi Zero WHとブレッドボード全体の配線写真

ブレッドボード部分をアップにすると、このようになります。

フォトリフレクタ、DHT11、74HC595を配線したブレッドボードのアップ写真

Chart.jsでグラフを表示する

次は、Raspberry Pi Zero WHで取得したデータを、ブラウザで見やすく表示する準備をします。

まず、回転数・温度・湿度をグラフにする流れを確認します。

回転数を棒グラフ、温度と湿度を折れ線グラフで表示した計測結果のイメージ図

ブラウザでグラフを描画するために、Chart.jsを用意します。

回転数や温度・湿度をグラフで表示するために、JavaScriptのチャートライブラリ Chart.js を使います。

Chart.jsは、HTML5のcanvasを使って、JavaScriptでグラフを表示できるライブラリです。

設定方法は、次の2つがあります。

設定方法1:ライブラリにアクセスする

外部ライブラリにアクセスして使う場合は、HTMLファイルのheadタグ内に次のように記述します。

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js"></script>

設定方法2:ダウンロードして使う

外部ライブラリにアクセスせず、ダウンロードしたファイルを使うこともできます。

ローカルに置いたChart.jsを使う場合は、次のように準備します。

Chart.jsの公式サイトにアクセスし、「Git Started」ボタンをクリックします。

Chart.js公式サイトの画面

InstallationのGitHub releasesリンクをクリックします。

Chart.jsのInstallation画面

ページの一番下のChart.jsファイルをクリックしてダウンロードします。

Chart.jsファイルのダウンロード画面

/home/pi/webiopi/test/jsフォルダを作成し、ダウンロードしたChart.jsを保存します。

HTMLファイルの head タグでChart.jsを読み込みます。

<!-- グラフ描画用のチャートライブラリファイル読み込み -->
<script src="js/Chart.js"></script>

グラフのデータ・オプションを設定する

JavaScriptで、描画するグラフのデータやオプションを設定します。

回転数は棒グラフ、温度と湿度は折れ線グラフとして表示します。

// グラフのデータ・オプションを設定
var ctx = $('#canvas').get(0);
var myChart = new Chart(ctx, {
  type: 'bar', // 棒グラフを指定
  data: {
    labels: array_lavels, // 横軸のラベル
    datasets: [{
      data: array_data, // グラフのデータ
      backgroundColor: 'rgba(153, 102, 255, 0.2)', // 棒グラフの背景色
      borderColor: 'rgba(153, 102, 255, 1)', // 棒グラフの縁取りの色
      borderWidth: 1  // 棒グラフの縁取りの太さ
             ……

キャンバスでグラフ描画する

bodyタグ内のグラフを描画したい場所に、canvas タグを置きます。

<!-- HTML5のcanvasで、グラフを描画 -->
<canvas id="canvas"></canvas>

Pythonのスケジューラーモジュール

Python側では、一定時間ごとにCSVファイルへデータを書き込みます。

そのために、スケジューラーモジュールをインストールします。

インストール

まずは、現在インストール済みのパッケージを一覧で確認します。

> pip3 list

pip3は、Python3のパッケージを管理するコマンドです。

インストール済みのパッケージがずらっと表示されます。

schedule」がなければpip3でインストールします。

> sudo pip3 install schedule

使い方

スケジューラを使う流れは、次の3段階です。

  1. プログラム内でインポートする
  2. 実行したいスケジュールと関数を登録する
  3. 登録した関数を実行する
import schedule              # スケジューラライブラリ
……
# 5分毎にseveCSVを実行するようスケジュールを登録
schedule.every(5).minutes.do(seveCSV)
……
# 設定したスケジュール通り、5分毎にseveCSV関数を実行
schedule.run_pending()

PythonのDHT11モジュール

温湿度センサー DHT11 を簡単に使用するために、Pythonのモジュールを使います。

インストール

Adafruit社がGitHubで公開しているPythonモジュールをインストールします。

> git clone https://github.com/adafruit/Adafruit_Python_DHT.git
> cd Adafruit_Python_DHT
> sudo python3 setup.py install

使い方

このモジュールを使う流れは、次の通りです。

  1. プログラム内でインポートする
  2. 使用するGPIOを指定する
  3. 温度・湿度を読み取る
import Adafruit_DHT as DHT # DHT11用ライブラリ
……
DHT_PIN = 15 # 温湿度入力ピン GPIO15(ピン番号10)
……
humi, temp = DHT.read_retry(DHT.DHT11, DHT_PIN)

プログラム

プログラムは、大きく2つの流れで処理しています。

  1. 回転数をCSVファイルに保存
  2. CSVファイルを読み込んでグラフ描画

長いコードは、本文内で読みやすいようにアコーディオン形式にしています。

回転数をCSVファイルに保存

フォトリフレクタからの信号をカウントした回転数と、DHT11で測定した温度・湿度を一定時間ごとにCSVファイルに保存します。

ハムスターは夜行性なので、夜20時くらいから、翌朝の6時くらいまでの回転数を測定します。

夜間の回転数を続けて見たいので、昼間の12時から24時間の単位で区切って保存することにしました。

CSVファイルを読み込んでグラフ描画

保存してあるCSVファイルのうち最新のファイルを読み込み、グラフを描画します。

保存されているCSVファイルから、日付選択のセレクトボックスを生成します。

セレクトボックスで日付を選択すると、グラフのデータを切り替えて再表示します。

ファイル構成

ファイルの構成は、こちらです。

WebIOPiで使うファイル構成図

index.html

index.html は、ブラウザに回転数グラフ、日付選択、回転中の状態、現在の回転数を表示するためのファイルです。

WebIOPiのマクロを呼び出して、Python側で保存したCSVデータを受け取り、Chart.jsでグラフ化します。

index.html のコードを見る
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Raspberry Pi Zero WH | ハムスターの回転数</title>
<!-- WebIOPiのJavascriptライブラリファイル読み込み -->
<script type="text/javascript" src="/webiopi.js"></script>
<!-- グラフ描画用のチャートライブラリファイル読み込み -->
<script src="js/Chart.js"></script>
<script type="text/javascript">
// WebIOPiの準備が整ったときに呼び出す関数
webiopi().ready(function() {

  // 表示データ設定関数の定義
  var setDispData = function(macro, args, response){

    // getDispDataマクロからの戻り値を取得
    var getData = response.split(";");

    // グラフ横軸のラベル(時間)
    var array_lavels = getData[0].split(',');

    // グラフのデータ(回転数)
    var array_data   = getData[1].split(',');

    // グラフのデータ(温度)
    var array_temp   = getData[2].split(',');

    // グラフのデータ(湿度)
    var array_humi   = getData[3].split(',');

    // セレクトボックスにoption要素がなければ生成
    if( !($('#filelist').children().length) ){

      // ファイルリスト取得
      var array_files  = getData[4].split(',');
  
      // ファイルリストをセレクトボックスに設定
      for(let i = 0; i < array_files.length; i++){
        $('#filelist').append('<option value="'+i+'">'+array_files[i]+'</option>');     
      }
    }

    // 合計数を#totalに設定
    $("#total").text(getData[5]);

    // グラフのデータ・オプションを設定
    var ctx = $('#canvas').get(0);
    var myChart = new Chart(ctx, {
      type: 'bar',                                      // 棒グラフを指定
      data: {
        labels: array_lavels,                           // 横軸のラベル
        datasets: [
        {
          label:'回転数',
          data:            array_data,                  // グラフのデータ
          backgroundColor: 'rgba(153, 102, 255, 0.2)',  // 棒グラフの背景の色
          borderColor:     'rgba(153, 102, 255, 1)',    // 棒グラフの縁取りの色
          borderWidth:     1,                          // 棒グラフの縁取りの太さ
          yAxisID:'y-left'
        },
        {
          type:'line',
          label:'温度',
          data:            array_temp,                  // グラフのデータ
          backgroundColor: 'rgba(255, 99, 132, 0.2)',   // 棒グラフの背景の色
          borderColor:     'rgba(255,99,132,1)',        // 棒グラフの縁取りの色
          borderWidth:     1,                          // 棒グラフの縁取りの太さ
          fill: false,                                  // 折れ線グラフを中抜きに
          yAxisID:'y-right'
        },
        {
          type:'line',
          label:'湿度',
          data:            array_humi,                  // グラフのデータ
          backgroundColor: 'rgba(54, 162, 235, 0.2)',   // 棒グラフの背景の色
          borderColor:     'rgba(54, 162, 235, 1)',     // 棒グラフの縁取りの色
          borderWidth:     1,                          // 棒グラフの縁取りの太さ
          fill: false,                                  // 折れ線グラフを中抜きに
          yAxisID:'y-right'
        }
        ]
      },
      options:{
        title: {                       // グラフタイトル
          display:  true,
          fontSize: 18,
          text:     '回し車の回転数'
        },
        scales: { 
          yAxes: [{
            id: "y-left",               // Y軸のID
            type: "linear",             // linear固定 
            position: "left",           // 表示位置
            ticks: {
              beginAtZero: true         // 縦軸の座標を0から始める
            }
          },
          {
            id: "y-right",              // Y軸のID
            type: "linear",             // linear固定 
            position: "right",          // 表示位置
            ticks: {
              max: 90,
              min: 0
            },
            gridLines: {                 // 横グリッド線を非表示
              drawOnChartArea: false, 
            }
          }
          ]
        }
      }
    });
  }


  // データ表示関数の定義
  var dispData = function(drawData){

    // getDispDataマクロを呼び出した後、setDispData関数を実行
    webiopi().callMacro("getDispData", [drawData], setDispData);

  }

  // カウンター更新関数の定義
  var updateCounter = function(macro, args, response) {

    // getCounterマクロで取得したカウント数が0より大きかったら
    if ( response  ){

      // getCounterマクロで取得したカウント数を#counterに設定
      $("#counter").text(response);

    }
  }

  // カウンターチェック関数の定義
  var checkCount = function(){

    // getCounterマクロを呼び出した後、updateCounter関数を実行
    webiopi().callMacro("getCounter", [], updateCounter);

    // 1秒後にcheckCount関数を実行
    setTimeout(checkCount, 1000);

  }

  // グラフとデータを表示
  dispData(0);

  // GPIOボタンを作成
  var button = webiopi().createGPIOButton(17, "回転中");

  // #controlsにGPIOボタンを追加
  $("#controls").append(button);

  // カウンターチェック関数を実行
  checkCount();

  // Refresh GPIO buttons
  webiopi().refreshGPIO(true);

  // セレクトボックス変更時、選択された値を取得する
  $('[name=files]').change(function() {

    // グラフとデータを表示
    dispData($('[name=files]').val());

  });

});

</script>

<style type="text/css">
    button {
        display: inline-block;
        margin: 5px 5px 5px 5px;
        width: 80px;
        height: 35px;
        font-size: 12pt;
        color: white;
    }
                
    #gpio17.HIGH {
        background-color: Pink;
    }
                
    #gpio17.LOW {
        background-color: Red;
    }
</style>
</head>
<body>
<!-- HTML5のcanvasで、グラフを描画 -->
<canvas id="canvas"></canvas>

<!-- 日付選択 セレクトボックスと回転数合計 -->
<p><b>表示日</b>: <select id="filelist" name='files'></select>  <b>合計</b>: <span id="total">0</span>回</p>

<!-- GPIOボタンと現在の回転数 -->
<p><span id="controls"></span> <b>回転数</b>: <span id="counter">0</span>回</p>

</body>
</html>

getDispData マクロから返ってきた文字列を、セミコロンとカンマで分割して、グラフ表示用の配列に変換しています。

回転数は左側の縦軸、温度と湿度は右側の縦軸を使うようにして、1つのグラフでまとめて見られるようにしています。

また、getCounter マクロを1秒ごとに呼び出して、回し車が回っているときに画面上の回転数も更新されるようにしています。

JavascriptやCSS(スタイルシート)などは、別のファイルにした方がいいのですが、ここでは内容を追いやすいように1つのファイルにまとめています。

script.py

script.py は、フォトリフレクタの入力を読み取り、回転数をカウントするPythonファイルです。

カウントした回転数と、DHT11で読み取った温度・湿度を、決まった間隔でCSVファイルへ保存します。

script.py のコードを見る
import webiopi              # WebIOPiライブラリ
import datetime             # 日付時刻ライブラリ
import schedule             # スケジューラライブラリ
import csv                  # csvファイルライブラリ
from pathlib import Path    # ファイル関連のライブラリ
import Adafruit_DHT as DHT  # DHT11用ライブラリ

#debug
#webiopi.setDebug()
#webiopi.debug("デバッグメッセージ")

GPIO = webiopi.GPIO

LOOP_TIME = 0.1       # LOOPする時間の間隔(0.1秒)

IN_GPIO = 17          # GPIO pin using BCM numbering
                      # GPIO17(ピン番号11)

DHT_PIN = 15          # 温湿度入力ピン GPIO15(ピン番号10) 

PREV_GPIO = GPIO.LOW  # 前回のGPIO値

COUNTER = 0           # カウンター

PREV_COUNTER = 0      # 前回のカウンター値

                      # CSVファイルのPath
DATA_DIR = '/home/pi/webiopi/test/data/'

CSV_SAVE_TIME = 10    # CSVファイルに保存する間隔(10分)


# setup function is automatically called at WebIOPi startup
def setup():
    # set the GPIO used by the light to output
    GPIO.setFunction(IN_GPIO, GPIO.IN)

    #指定した時間ごとに、CSVファイルに回転数を保存するよう設定
    schedule.every(CSV_SAVE_TIME).minutes.do(seveCSV)

# loop function is repeatedly called by WebIOPi 
def loop():

    # 変更するグローバル変数を宣言
    global COUNTER, PREV_COUNTER, PREV_GPIO

    # GPIOの入力が、HIGHからLOWに変わったら
    if ( GPIO.digitalRead(IN_GPIO) == GPIO.LOW
     and PREV_GPIO == GPIO.HIGH ):
        COUNTER += 1
        PREV_GPIO = GPIO.LOW
    # GPIOの入力が、LOWからHIGHに変わったら
    elif ( GPIO.digitalRead(IN_GPIO) == GPIO.HIGH
     and   PREV_GPIO == GPIO.LOW ):
        PREV_GPIO = GPIO.HIGH

    # setup()で設定したスケジュール通りに処理を実行(CSV保存)
    schedule.run_pending()

    # LOOP_TIME時間 スリープしたあと、ループを繰り返す
    webiopi.sleep(LOOP_TIME)


# destroy function is called at WebIOPi shutdown
#def destroy():
#    GPIO.digitalWrite(IN_GPIO1, GPIO.LOW)



# CSVファイルにデータを保存する
# お昼の12時から24時間で1ファイルにする
def seveCSV():

    # 変更するグローバル変数を宣言
    global COUNTER

    # 現在時刻を取得
    now = datetime.datetime.now()

    # お昼の12時以降だったら
    if ( now.hour >= 12 ) :
        # 次の日の日付を織り込んだファイル名を生成
        file_name = DATA_DIR+"cnt_{0:%Y%m}{1}.csv".format(now,now.day+1) 
    else:
        # 日付を織り込んだファイル名を生成
        file_name = DATA_DIR+"cnt_{0:%Y%m%d}.csv".format(now)

    # 温度・湿度を取得
    for i in range(3):
        humi, temp = DHT.read_retry(DHT.DHT11, DHT_PIN)

        # 値が異常ならリトライ
        if (humi > 90) or (temp > 50):
            sleep(0.1)
            continue
        break

    # 書き込みデータ生成 HH:MM,回転数,温度,湿度 ex.10:25,120,22,66
    write_data = ["{0:%H:%M}".format(now), COUNTER,round(temp),round(humi)]
  
    # カウンターをリセット
    COUNTER = 0

    # データをCSVファイルに書き込み
    with open(file_name, 'a') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(write_data)


# グラフデータを取得するマクロ
@webiopi.macro
def getDispData(disp_data):

    # ファイル名を取得(PosixPathオブジェクト)
    file_list = sorted(Path(DATA_DIR).glob('*.csv'), reverse=True)

    # CSVファイルを読み込む
    with open(str(file_list[int(disp_data)])) as fp:
        reader = list(csv.reader(fp))
  
    # ファイルの日付部分のみの文字列のlist(配列)に変換(セレクトボックス用))
    str_files = []
    for row in file_list:
        str_files.append((str(row))[31:39])

    # 二次元配列の行と列を入れ替える
    reader = list(map(list, zip(*reader)))

    # 回転数の合計を計算する
    total = sum(int(i) for i in reader[1])

    # list(配列)を文字列に変換(前後の[]をカット)
    str_time = ','.join(reader[0])
    str_cnt  = ','.join(reader[1])
    str_temp = ','.join(reader[2])
    str_humi = ','.join(reader[3])
    str_file = ','.join(str_files)

    return  "%s;%s;%s;%s;%s;%d" % (str_time, str_cnt, str_temp, str_humi, str_file, total)


# カウントアップしていたら、カウンター値を、前回と同じなら0を返すマクロ
@webiopi.macro
def getCounter():

    # 変更するグローバル変数を宣言
    global PREV_COUNTER

    if ( PREV_COUNTER != COUNTER):
        PREV_COUNTER = COUNTER
        return "%d" % (COUNTER)
    return 0

処理の流れ

センサー側の処理は、次のように進みます。

  1. GPIO17を入力として設定する
  2. フォトリフレクタの値が変化したタイミングでカウントを増やす
  3. 指定した間隔で seveCSV を実行する
  4. DHT11から温度・湿度を読み取る
  5. 時刻・回転数・温度・湿度をCSVファイルに保存する
  6. ブラウザから呼び出されたら、表示用のデータを返す

データファイル

プログラム内で作成し、データを保存するCSVファイルです。

ファイル名は、cnt_日付.csv の形式になります。

フォーマットは、時間,回転数,温度,湿度 です。

20:10,281,25,51
20:20,678,25,54
20:30,687,25,52
20:40,407,25,51
20:50,313,25,52
21:00,458,26,53
21:10,581,26,54

動作確認

WebIOPiを起動して、http://raspberrypi.local:8000/test/にアクセスします。

ハムハムが回し車を回すと……。

回し車を回しているハムスターの写真

回転数グラフの下の「回転中」ボタンが赤くなり、回転数が増えていきます。

保存されたデータは、ブラウザ上でグラフとして表示されます。

回転数は紫の棒グラフ、温度は赤、湿度は青の折れ線グラフです。

回転数・温度・湿度のグラフ画面

終了するときは、WebIOPiを停止し、Raspberry Piも停止します。

まとめ

Raspberry Pi Zero WH、フォトリフレクタ、DHT11、WebIOPi、Chart.jsを組み合わせて、ハムスターの回し車の回転数を測定しました。

回し車の裏側に貼った赤い反射テープを、ケージの外側からフォトリフレクタで読み取り、回転数としてカウントします。

さらに、DHT11で温度・湿度も取得し、CSVに保存したデータをブラウザでグラフ表示できるようにしています。

気になっていたハムハムの回し車の回転数を、実際に測定してグラフ化したことで、運動量が一目で分かるようになりました。

測り始めて数日でも、日によって回転数に差があることが分かります。多い日には2万回以上、休みが多い日は1万回くらいという変化も見えます。

年齢や季節、温度にもよるようですし、運動量で体調が分かって、エサの量を調節することもできそうです。

次の記事では、Raspberry PiとScratchを使って動かすロボット制作に進みます。

関連するラズベリーパイ記事や制作記録はこちらです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次