Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

赤外線アレイセンサの結果をWeb上で表示

先日、javascriptでヒートマップを表示する方法をまとめました。
elsammit-beginnerblg.hatenablog.com

今回は以前から用いている赤外線アレイセンサ値をヒートマップで表示してみたいと思います!!



■構成

今回もこちらの赤外線アレイセンサをラズパイに接続して動作させていきます。
用いている赤外線アレイセンサはいつも通りこちら。

AMG8833 IR 8 * 8サーマルイメージャーアレイ温度センサーモジュール8x8赤外線カメラセンサー

構成はこちら。
f:id:Elsammit:20201031171813p:plain

また、ラズパイ側はgo言語を用いて赤外線アレイセンサの受信とpost responseを行っていきます。

■サーバサイド実装

ではラズパイ側での実装を進めていきます。
先ほど記載した通り、go言語で実装いたします。
PCからのpost requestを受け取り、赤外線アレイセンサのセンサ値をjsonでresponseさせるため、
go言語ライブラリのGinを用います。

コードはこちら。

package main

import (
	"time"
	"github.com/gin-gonic/gin"
	"github.com/jweissig/amg8833"
)

func Do_Post() {
	r := gin.Default()
	r.POST("/post/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": gridpost,
		})
	})
	r.Run()
}

var gridpost []float64

func main() {
	amg, err := amg8833.NewAMG8833(&amg8833.Opts{
		Device: "/dev/i2c-1",
		Mode:   amg8833.AMG88xxNormalMode,
		Reset:  amg8833.AMG88xxInitialReset,
		FPS:    amg8833.AMG88xxFPS10,
	})
	if err != nil {
		panic(err)
	}

	ticker := time.NewTicker(1 * time.Second)
	go Do_Post()
	for {
		gridpost = amg.ReadPixels()
		<-ticker.C
	}
}

実施していることですが、
Ginでpost受信するためのサーバをスレッドで立ち上げ、
そのままメイン関数で赤外線アレイセンサ値を1秒ごとに取得しています。
サーバ立ち上げ時の関数はDo_Post()です。
赤外線アレイセンサ値は

{
      "message": gridpost,
}

というようにjsonデータ化してresponseとして返しております。

■フロントエンド実装

次にWeb上でヒートマップを表示するための実装をしていきます!!
post送信にはjQueryを用います。
ではコードです。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Test</title>
        <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.css'>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    </head>
    <body>
        <div style="height:800px; width:800px">
            <canvas id="heatMap" style="height:800px; width:800px"></canvas>
        </div>
        <script type="text/javascript">
            'use strict'

            const mapHeight = 8;
            const mapWidth = 8;

            var datalist = [];


            // データセットの生成
            const generateDatasets = function(){
                const datasets = []
                for(let i=0; i<mapHeight; i++){
                    datasets.push({
                        data: new Array(mapWidth).fill(1),
                        borderWidth: 0.2,
                        borderColor: "#FFFFFF",
                        backgroundColor: generateColor(i)   // 変更
                    })
                }
                return datasets    
            }

            // 定期的に赤外線アレイセンサ値を取得.
            const interval = function(){
                $.post("パス")
                .always(function(data){
                    datalist = data.message
                })
                heatMap.data = {
                    datasets: generateDatasets(),
                    labels: generateLabels()
                }
                Chart.defaults.global.animation.duration = 0
                heatMap.update();
            }
            setInterval(interval, 1000);

            const generateColor = function(y){
                const datasetColors = []
                for(let x=0; x<mapWidth;x++){
                    const opa = ((datalist[x + (mapHeight-y-1) * mapWidth] - 16)*0.08).toFixed(2);
                    datasetColors.push("rgb(235,10,10,"+opa+")")
                }
                return datasetColors;
            }

            // データラベルの生成
            const generateLabels = function(){
                let labels = []
                for (var i=1; i<mapWidth+1; i++){
                    labels.push(i)
                }
                return labels
            }

            const ctx = document.getElementById('heatMap').getContext('2d')
            const heatMap = new Chart(ctx, {
                type: 'bar',
                data: {
                    datasets: generateDatasets(),
                    labels: generateLabels()
                },
                options: {
                    title: {
                    display: true,
                    text: 'Heat Map Sample',
                    fontSize: 18,
                },
                animation: false,
                animation: {
                    duration: 0
                },
                legend: {
                    display: false
                },
                scales: {
                    xAxes: [{
                        gridLines: {
                            color: '#FFFFFF',
                        },
                        barPercentage: 0.99,
                        categoryPercentage: 0.99,
                        stacked: true,
                        ticks: {
                            min: 0,
                            display: false,
                        }
                    }],
                    yAxes: [{
                        gridLines: {
                            color: '#FFFFFF',
                            zeroLineWidth: 0
                        },
                        stacked: true,
                        ticks: {
                            min: 0,
                            stepSize: 1,
                            display: false
                        }
                    }]
                },
            }
        });
        </script>
    </body>
</html>

ちょっと長いですが、、、
先日のヒートマップをランダムに表示するコードと異なる点は2つ。
1つ目は、
赤外線センサ値取得のための定期的なjQueryでpost送信部。
post responseで得られたjsonのmessageに赤外線アレイセンサ値が格納されているので、
datalist変数に値を格納し、heatmapとして表示するためにgenerateDatasets()実行+heatMap.update()を行っています。

const interval = function(){
    $.post("パス")
    .always(function(data){
        datalist = data.message
    })
    heatMap.data = {
        datasets: generateDatasets(),
        labels: generateLabels()
    }
    heatMap.update();
}
setInterval(interval, 1000);

2つ目はヒートマップ表示のためのRGBAの値の調整。

const generateColor = function(y){
    const datasetColors = []
    for(let x=0; x<mapWidth;x++){
        const opa = ((datalist[x + (mapHeight-y-1) * mapWidth] - 16)*0.08).toFixed(2);
        datasetColors.push("rgb(235,10,10,"+opa+")")
    }
    return datasetColors;
}

■実行してみる part1

では先ほどのコードを実行してみます!!
真ん中あたりに人を配置して実行させてみました!!
実行結果はこちら。
f:id:Elsammit:20210221180658g:plain

あまり濃淡がはっきりせず人がどこにいるのか分かりにくいですね😅
よく見ると濃淡があって分かりますが。。。
こちらの計算により濃淡を変化させているのですが、、、
こちらのような、センサ値に対して濃淡を連続値にしてしまうときれいな濃淡を出すのが難しそう。。。

const opa = ((datalist[x + (mapHeight-y-1) * mapWidth] - 16)*0.08).toFixed(2);

■濃淡表現式の変更

ということで、先ほどの式を変更し、非連続で濃淡(というかRGB値)を変更してみました!!
コードはこちら。

const generateColor = function(y){
    const datasetColors = []
    for(let x=0; x<mapWidth;x++){
        if(datalist[x + (mapHeight-y-1)*mapWidth] >= 30){
            datasetColors.push("rgb(235,10,10,"+1.0+")")
        }else if(datalist[x + (mapHeight-y-1)*mapWidth] >= 23){
            datasetColors.push("rgb(235,10,10,"+0.5+")")
        }else{
            datasetColors.push("rgb(5,10,235,"+0.8+")")
        }
    }
    return datasetColors;
}

レイセンサの各画素毎に、
 ・28以上:RGB値(235,10,10,1.0)
 ・28より小さく18以上:RGB値(235,10,10,10,0.5)
 ・18より小さい:RGB値(5,10,235,0.8)
としました。

■実行してみる part2

では変更したコードで実行してみます。
先ほどと同様に真ん中あたりに人を配置して実行。
結果はこちら。
f:id:Elsammit:20210221181836g:plain

うん!!人がいる部分といない部分ではっきりしていますね。
見やすくなりました!!

■最後に

まだとりあえず表示出来ただけですが、、、
赤外線アレイセンサ値を取得し、ヒートマップとしてWeb上に表示させることが出来ました。

ただしこちらのコードはまだまだで、、
 ・最初の1秒はヒートマップに赤外線アレイセンサ値が表示されない(真っ黒なヒートマップが表示される)
 ・1秒前の赤外線アレイセンサ値がWeb上のヒートマップに表示される
等々、まだまだな部分があるので、修正していきたいと思います!!
とりあえず今回は表示出来たよ。という報告で