#概要
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
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にしました。
##サーバ側
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からシリアルポート経由でデータを受信したらブラウザへデータを送信します。
##クライアント側
<!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部分は別ファイルにしています。
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
へアクセスするとこんな感じのグラフが表示されます。
光センサーの上で手で光を遮ったりしたグラフになります。光を遮ると光センサーの抵抗値が上がるので電圧も上がります。
横軸がなぜか均等にならないのですが、気が向いたら改善します。