
ArduinoをJavaScriptで動かす「Johnny-five」。
魅力的ではあるものの、対応している電子部品に限りがあり、開発が行き詰ってしまいます。
Arduinoの開発言語はライブラリが充実しているC++を使った方が良さそうです。
でもNode.jsは使いたい
IoT実現のため、Arduinoの制御にJavaScriptを使うことは断念しましたが、ブラウザとの連携はNode.jsサーバーを使って、JavaScriptで行いたいです。
そうなるとArduinoとNode.jsサーバー間のデータ送受信で、Johnny-fiveに代わる仕組みが必要になります。
シリアル通信で何かしらの文字列を送受信できれば良いのですが・・・
node-serialportを使う
シリアル通信ができるNode.jsライブラリがありました!

ArduinoとNode.jsサーバー間で、文字列の送受信を行います。
例えば「LED=H」という文字列をNode.jsからArduinoにシリアル通信で送ると、Arduinoに接続されたLEDが光るというような想定です。
ちょこちょこハマる
結果的にはできましたが、ハマりどころが多かったです。
シリアル通信もあまり理解していないところから始めたので、簡単なところでつまずいています。
参考になるか分かりませんが、コードを掲載していきます。
開発環境は、この系統の情報が意外と少ない(?)、Windows 10です。
ディレクトリ構成
Cドライブ直下に「node-arduino」というディレクトリを作り、ここで開発を行います。

「node-serialport」インストール
すでにNode.jsとExpress、soket.ioはインストールされているとします。
Expressなどと同じ手順だと思いますが、コマンドプロントで
|
1 |
npm install serialport |
と入力すれば、インストールされます。
Node.jsプログラムの制作
続いてNode.jsサーバーのapp.jsを書きます。
以前書いたものに、飯谷健太さん、sifueさん、_shimizuさんの記事を参考に手を加えています。
var TCP_PORT = 3000,
DIRECTORY = 'htdocs',
SERIAL_PORT = 'COM20',
BAUD_RATE = 57600,
express = require('express'),
app = express(),
http = require('http').Server(app),
io = require('socket.io')(http),
serialPort = require('SerialPort'),
serial = new serialPort(SERIAL_PORT,{
parser: serialPort.parsers.readline('\n'),
baudrate: BAUD_RATE
});
var init = function () {
app.use(express.static(DIRECTORY));
http.listen(TCP_PORT, function(){
console.log(getIP() + ':' + TCP_PORT + ' でサーバーを起動');
});
serial.on('open',function(){
console.log('シリアルポート ' + SERIAL_PORT + ' と接続');
});
setIo();
},
//ローカルIPアドレス取得
getIP = function(){
var os = require('os'),
ip,
interfaces = os.networkInterfaces();
var getIPv4 = function(){
interfaces[dev].forEach(function(details){
if (details.family === 'IPv4' && details.address.indexOf('192.') > -1){
ip = details.address;
}
});
};
for (var dev in interfaces) {
getIPv4(dev);
}
return ip;
},
//ソケットIO設定
setIo = function(){
serial.on('data',function(data){
io.emit('recvmsg',data.toString());
});
io.on('connection',function(socket){
socket.on('led',function(msg){
serial.write(new Buffer(msg),function(err,results){
if(err) {
console.log('Err: ' + err);
console.log('Results: ' + results);
}
});
});
});
};
init();
ハマりどころとしては・・・
4行目 シリアルポートの指定
|
1 |
SERIAL_PORT = 'COM20', |
Macのサンプルコードだと「/dev/tty.usbmodemfd121」というような、Windowsユーザーの見慣れぬ文字列となっています。
Windowsの場合は、Arduinoと接続しているCOM番号を、コントロールパネルのデバイスマネージャーや、Arduino IDEで調べて指定します。
ただ、接続し直すとCOM番号が変わることがあるので、どうにかしたい・・・
11行目 改行パース
|
1 |
parser: serialPort.parsers.readline('\n'), |
シリアル通信でデータで「AAA」と文字列を送ると、「A\nA\nA\n」というような改行が入る仕様(?)につまづきました。
文字列は1文字ずつしか送れず、必ず改行が入るようです。
送信したバラバラの文字列を、Arduino上で組み立てるコードも、この後掲載します。
18行目 IPアドレス表示
|
1 2 |
console.log(getIP() + ':' + TCP_PORT + ' でサーバーを起動'); }); |
Wi-Fi接続の際、IPアドレスが変わっていることがあるので、コマンドプロントに出力することにしました。
実際の処理は、26行目以降のgetIP();です。
49行目 デバッグ用の受信コード
|
1 |
io.emit('recvmsg',data.toString()); |
Node.jsでシリアルポートを使っていると、Arduinoのシリアルモニタは使えません。
Arduinoのデバッグをする際は、確認したい値をブラウザに表示させます。
(コマンドプロントに表示でもよいのですが)
LED操作画面のindex.html
続いてNode.jsと連携するindex.htmlの制作です。

LED点灯ボタンがあるだけです。
index.htmlファイルに、HTML、CSS、JavaScriptをまとめて記述しています。
<!doctype html
<html>
<head>
<meta charset="utf-8">
<title>Node.jsでシリアル通信</title>
<script src="/socket.io/socket.io.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<style>
body {
padding-top: 500px;
background: #000;
text-align: center;
}
button {
padding: 20px 40px;
border-bottom: #999 solid 20px;
border-radius: 15px;
background: #EEE;
font-size: 100px;
}
button.on {
margin-top: 15px;
border-bottom: #095E13 solid 5px;
background: #3C9053;
color: #FFF;
}
</style>
</head>
<body>
<button id="ledBtn">LED点灯</button>
<script type="text/javascript">
var SWITCH_CLASS = "on",
socket = io(),
$ledBtn = $("#ledBtn"),
ledSwitch = 0;
var init = function(){
setBrowser();
setMicom();
}
//ブラウザ設定
var setBrowser = function(){
$ledBtn.on("click", function(){
if(ledSwitch === 0){
ledSwitch = 1; //true
$(this).addClass(SWITCH_CLASS);
}else{
ledSwitch = 0; //false
$(this).removeClass(SWITCH_CLASS);
}
socket.emit('led', 'l=' + ledSwitch);
});
},
//マイコン設定
setMicom = function(){
socket.on("buttonSwitch", function(buttonSwitch){
if(buttonSwitch === true){
ledSwitch = 1;
$ledBtn.addClass(SWITCH_CLASS);
}else{
ledSwitch = 0;
$ledBtn.removeClass(SWITCH_CLASS);
}
});
socket.on('recvmsg',function(data){
$ledBtn.text(data);
});
};
init();
</script>
</body>
</html>
52行目 Arduinoに送る文字列
|
1 |
socket.emit('led', 'l=' + ledSwitch); |
「LED点灯」ボタンを押したら、Node.jsを経由して、Arduinoにシリアル通信で文字列を送ります。
点灯の時は’l=1’、消灯の時は’l=0’としています。
また、逆にArduinoからNode.jsを経由して、文字列を受け取れるか確認するため、下記コードを一時的に追加していました。
|
1 2 3 |
socket.on('recvmsg',function(data){ $ledBtn.text(data); }); |
Arduinoからシリアル送信した文字を、LED点灯ボタンに表示させます。
前途したように、デバッグ用に使いました。
Arduinoのシリアル送受信プログラム
まだ終わりません。Arduinoにプログラムを書き込みます。
#define LED_PIN 13
int recieveByte = 0;
String instruction = "";
void setup(){
Serial.begin(57600);
pinMode(LED_PIN,OUTPUT);
}
void loop(){
instruction = "";
while (Serial.available() > 0){
recieveByte = Serial.read();
if(recieveByte == (int)'\n') break;
instruction.concat((char)recieveByte);
delay(1);//必要
}
if(instruction.length() > 0){
if(instruction == "l=1"){
digitalWrite(LED_PIN,HIGH);
}else if(instruction == "l=0"){
digitalWrite(LED_PIN,LOW);
}
}
}
17行目: 処理に余裕を持たせる
|
1 |
delay(1) |
シリアルポートから1文字ずつ送られてきたデータを、Arduino上で組み立てていますが、17行目にdelay(1)を入れないと、繰り返し処理が正しく動作しませんでした。
1m秒遅らせたら、シリアルで送られてきたデータを正常に受信できました。
回路は単純なLED接続
説明不要かもしれないくらい単純な、13番PINでのLED接続です。

最後に動作確認
コマンドプロントでサーバーを立ち上げます。
|
1 |
node app.js |
サーバー立ち上げに成功すると、「192.168.XXX.XXX:3000 でサーバーを起動」とコマンドプロントに表示されます。
そのアドレスを、同じWi-Fiに接続された端末のブラウザで表示させます。

ブラウザでページを読み込むと、LED点灯ボタンが表示されます。
クリックすると・・・

ボタンも緑色になり、Arduinoに接続された緑色のLEDが光ります。
うまく動作しました。
Johnny-fiveからnode-serialportに移行成功です。
Johnny-fiveほど手軽ではないですが、応用は利くでしょう。
















