6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Arduinoの測定値をNode.jsで受けてSocket.ioとchart.jsでリアルタイムにグラフ表示

Last updated at Posted at 2020-05-17

#概要
Arduinoの測定値をリアルタイムにグラフ表示してみたかったので、Node.js諸々を用いてブラウザ上にグラフ表示してみました。
今回はひとまず光センサーを測定対象にしました。光センサーの抵抗値の変化を電圧としてArduinoのアナログ入力で測定しています。

普段コーディングしない人間のコードなので変な箇所が多々あるかもしれません。その辺はご了承ください。

##構成
ハードウェアとソフトウェアの構成を示します。Arduino周りの回路はDEVICE PLUSの記事を参考にしてください。
###ハードウェア

  • PC (Mac)
  • Arduino UNO (PCとUSB接続)
  • 光センサー回路
    • ブレッドボード
    • 光センサー
    • 抵抗(1kΩくらい)
    • ジャンパー線

###ソフトウェア

  • Node.jsのフレームワークであるExpress
  • Arduinoとシリアル通信するためのserialportライブラリ
  • リアルタイム通信するためのSocket.ioライブラリ
  • グラフ表示するためのchart.jsライブラリ

#ソースコード
ソースコードは以下の4つです。

  • Arduino
    • serialCom.ino
  • サーバ側
    • app.js
  • クライアント(ブラウザ)側
    • index.html
    • index.js
ディレクトリ構造
.
├── app.js
├── index.html
├── node_modules
│   ├── @serialport
│  :
│   └── yeast
├── package-lock.json
├── package.json
└── public
   └── index.js

##Arduino

serialCom.ino
int analogPin=A3;
double aval=0;
double val=0;

void setup() {
    Serial.begin(9600);
}

void loop() {
    aval = analogRead(analogPin);
    val = 5 * aval / 1024;
    Serial.println(val);
    delay(100);
}

アナログ入力のA3ピンと5V出力を使用しています。(使用する端子は回路によって変わります。)
analogReadで得られる数値は10bitのA/Dコンバータの出力コードなので、電圧に変換しています。測定間隔は100msにしました。

##サーバ側

app.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
const SerialPort = require('serialport');
const Readline = require('@serialport/parser-readline');
const port = new SerialPort('/dev/cu.usbmodem141101', {
  baudRate: 9600
});
const parser = new Readline();
port.pipe(parser);

app.use(express.static('public'));

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

// ブラウザ側とのコネクション確立
io.on('connection', (socket) => {
  console.log('a user connected');
  socket.on('disconnect', () => {
    console.log('user disconnected');
  });
});

//サーバ起動
http.listen(3000, function(){
  console.log('listening on *:3000');
});

//Arduinoからデータを受信したらクライアントへ送信
parser.on('data', (data) => {
  io.emit('graph update', (data));
});

必要なモジュールをインポートしてそれぞれ設定します。
Arduinoからのデータをシリアルポートで待ち受けます。(ポート名は環境によって変わります。)
httpサーバのポート3000で待ち受けます。
socket.ioでクライアントのブラウザと接続します。
Ardionoからシリアルポート経由でデータを受信したらブラウザへデータを送信します。

##クライアント側

index.html
<!doctype html>
<html>
  <head>
    <title>グラフテスト</title>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js'></script>
    <script src='//code.jquery.com/jquery-3.2.1.min.js'></script>
    <script src='http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.2/moment.min.js'></script>
    <script src='//cdn.socket.io/socket.io-1.4.5.js'></script>
  </head>
  <body>
    <canvas id="canvas" width="500" height="500"></canvas>
    <script src='index.js'></script>
  </body>
</html>

jquery, chart.js, moment.js, socket.ioを読み込んでいます。
(moment.jsをバンドルしたchart.jsもあるみたいですが、今回はそのまま。)
canvasタグ内にchart.jsでグラフが描画されます。
script部分は別ファイルにしています。

index.js
const socket = io.connect();
var ctx = document.getElementById('canvas').getContext('2d');

// グラフの作成
var myChart = new Chart(ctx, {
  type: 'line',
  data: {
      labels: [],
      datasets: [{
          label: 'data-label1',
          data: [],
          backgroundColor: 'rgba(0,0,225,1)',
          borderColor: 'rgba(0,0,225,1)',
          borderWidth: 1,
          lineTension: 0,
          fill: false
      }]
  },
  options: {
      title: {
        display: true,
        text: 'CHART TITLE'
      },
      scales: {
          xAxes: [{
              ticks: {
                //autoSkip: true,
                maxTicksLimit: 10
              }
          }],
          yAxes: [{
              ticks: {
                  // beginAtZero:true,
                  // autoSkip: true,
                  // maxTicksLimit: 10,
                  min:0,
                  max:5,
                  stepSize:1
              }
          }]
      },
      // グラフサイズ固定
      responsive: false,
      //maintainAspectRatio: false
  }
});

$(() => {
  // サーバから値を受け取った時の処理
  socket.on('graph update', (recievedData) => {
    // 現在時刻の取得
    const time = moment();
    const outputTime = time.format('HH:mm:ss');
    // 追加するデータのラベルに時間を追加
    myChart.data.labels.push(outputTime);
    // グラフにデータを追加
    myChart.data.datasets[0].data.push(recievedData);
    // データ数が100以上なら一番古い要素を削除
    if (myChart.data.datasets[0].data.length > 100) {
      myChart.data.labels.shift();
      myChart.data.datasets[0].data.shift();
    };
    // グラフの表示を更新
    myChart.update();
  })
});

myChartがグラフの設定です。
その後に続くのがサーバからデータを受け取った時の処理です。
moment.jsでラベルに現在時刻を追加しています。
無限にデータが増え続けるので、データ数100を上限にしています。

#結果
ArduinoをUSBで接続してから、ターミナルでnode app.jsと叩いてサーバを起動、ブラウザで127.0.0.1:3000へアクセスするとこんな感じのグラフが表示されます。
ダウンロード.png
光センサーの上で手で光を遮ったりしたグラフになります。光を遮ると光センサーの抵抗値が上がるので電圧も上がります。
横軸がなぜか均等にならないのですが、気が向いたら改善します。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?