ArduinoとXBeeとNode.jsを使用したらWeb画面からラジコンを操作できそう
最近はIoTにとても興味があるので、IoTを学ぶためにWeb経由でロボットを動かせたら面白いなと思って今回取り組んでみました。取り組んでみた結果、ArduinoとXBeeとNode.jsを使用したらWeb画面からラジコンを操作できたので、今回はその方法をご紹介したいと思います。
完成したらこんな感じに動きます。↓
以下の知識を使用しました!
今回、Web画面から操作できるラジコンを作成するにあたって以下の知識が必要になりました。
Node.js、Socket.IO、node-serialportなどは今回初めて使用したので、少し苦労しました。
ロボットは去年のGWに本を見ながら作成したものをそのまま流用したので、そのときの記憶を思い出しながら改良しました。1年も放置すると忘れるものですね。。。
・Arduino
・XBee
・電子回路
・HTML
・Node.js
・Socket.IO
・node-serialport
❏関連資料・記事
・ArduinoとGroveのセンサで部屋の温度・湿度を測定してみた!
・ArduinoとNode.jsで測定したセンサからの値をmongoDBに保存してみたよ!【#IoTっぽいこと】
・NodejsをWindowsにインストールする方法
Node.jsの環境構築を行う
まずはNode.jsを触ったことがなかったので、Node.jsの動かし方から学びました。
「ドットインストール」さんにNode.jsのレッスンもありましたので、そこで「こんな感じか~」ぐらいに学習しました。
まずは以下の通り「Node.js」のインストールから行っていきます。なお、私はWindows7の64bitのPCを使用しているのですが、それでは動かないモジュールが出てきたのでVMwareにWindows8.1をインストールして、その上に構築していきました。
①Node.jsをインストールする。
こちらの記事をご参照ください
→NodejsをWindowsにインストールする方法
②Nodistをインストールする。
こちらの記事をご参照ください
→NodistをWindowsにインストールする方法
Socket.IOのインストール
次に今回はSocket.IOを使用したいので、Socket.IOをインストールします。
Socket.IOをインストールする方法
→Socket.IOをWindowsにインストールする方法
node-serialportのインストールを行う
次にシリアルポート通信をNode.js⇔XBee⇔Arduino間で行いたいので、node-serialportをインストールします。
○node-serialportをインストールする
→node-serialportをWindowsにインストールする方法
ロボットを組み立てる
次にロボットのフレーム部分を組み立てます。今回は去年作成したロボットをそのまま流用しました。
○ロボットの機械部分を組み立てる
こちらの記事をご参照ください
→ArduinoとXBeeを使用してロボットを遠隔操作する!
受信回路を作成する
回路は、去年作成したロボットの回路を基本的に流用しました。そのままだと通信ノイズのようなものが発生し、うまく動作させることができなかったので、一部回路を改良しています。
ブレッドボードを2枚並べて配線しています。
※回路について専門的な知識はあまり持ち合わせていないため、動作は保証しかねます。
※単3電池を4本使用している電源は、電圧が低いのかロボットの動作が遅かったため、今回はアダプタから直接電源を供給しました。
Node.jsとhtmlのコードを書く
Node.jsとHtmlのソースは以下のようになっています。
ソースはGitHUBに公開していますので、こちらからダウンロードしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<body> <header class="container_24"></header> <div id="main" class = "grid_16"> <p> Direction <!-- ボタンFが押されたら前進 --> <button id="F">F</button> <br> <!-- ボタンLが押されたら左旋回 --> <button id="L">L</button> <!-- ボタンStopが押されたら停止 --> <button id="stop">Stop</button> <!-- ボタンRが押されたら右旋回 --> <button id="R">R</button> <br> <!-- ボタンBが押されたら前進 --> <button id="B">B</button> <br> <!-- ボタンUが押されたらアームを上げる --> <button id="U">U</button> <br> <!-- ボタンDが押されたらアームを上げる --> <button id="D">D</button> <br> </p> </div><!--main--> </body> |
次にクライアント側のNode.jsのソースは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
$(function(){ var socket = io.connect(); var lastCmd = "Stop"; //default //sending command to server function sendToServer( name ){ socket.json.emit('emit_from_client', name); } // id属性値が「F」である要素への参照を変数「$buttonF」に代入 var $buttonF = document.getElementById( "F" ); // マウスダウンイベント(ボタンを押した時のイベント)にイベントハンドラをバインド $buttonF.onmousedown = function ( $event ) { // 押したボタンが左ボタンの場合の処理 if( $event.button == 0 ){ // 100ミリ秒ごとに「countUpDown()」関数を呼び出す繰り返しタイマー $intervalID = setInterval( function(){ sendToServer($('#F').text(), $('#slideValue').val()); lastCmd = $('#F').text(); }, 100 ); } } // ここから以降は同じボタン処理を繰り返し // ~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~ // ここからストップボタンが押されたときの処理 $('#stop').click(function(){ sendToServer($('#stop').text(), $('#slideValue').val()); lastCmd = $('#stop').text(); // 繰り返しタイマーを中止 clearInterval( $intervalID ); }); }); |
次にサーバー側のNode.jsのコードは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
var app = require('http').createServer(handler), io = require('socket.io').listen(app), fs = require('fs'), path = require('path'), serialport = require('serialport'); io.set('log level', 1); // Serial Port var portName = 'COM2'; // WINDOWS環境(Macの場合は異なります) var sp = new serialport(portName, { //baudRate: 57600, baudRate: 9600, dataBits: 8, parity: 'none', stopBits: 1, flowControl: false, }); app.listen(3000); function handler(req, res){ var filePath = req.url; if (filePath == '/') { filePath = '/index.html'; } else { filePath = req.url; } //console.log(filePath); var extname = path.extname(filePath); //console.log("filePath: " + filePath); //console.log("ext: " + extname); //contentType切り分け var contentType = 'text/html'; switch (extname) { case '.js': contentType = 'text/javascript'; break; case '.css': contentType = 'text/css'; break; } console.log(contentType); //console.log(__dirname + filePath); fs.readFile(__dirname + filePath, function(err, data){ if(err){ res.writeHead(500); return res.end('Error'); } res.setHeader('Content-Type', contentType); res.writeHead(200); res.write(data); res.end(); }); } //click from client io.sockets.on('connection', function(socket){ //button pushed socket.on('emit_from_client', function(data){ //check the data // console.log(data); var receive = JSON.stringify(data); console.log("data: [" + receive + "]"); //write to serialport sp.write(receive , function(err, results) { // console.log('bytes written: ', results); }); }); }); sp.on('close', function(err) { console.log('port closed'); }); //serialport open sp.open(function () { console.log('port open'); }); |
Arduinoのコードを書く
次にArduinoに書き込むコードは以下のように記述しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#include<servo .h> Servo servo0; int val; void setup() { Serial.begin(9600); pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(8, OUTPUT); servo0.attach(8); } void loop() { if (Serial.available() > 0) { val = Serial.read(); if (val == 'F') { digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, HIGH); digitalWrite(2, LOW); delay(100); digitalWrite(5, LOW); digitalWrite(3, LOW); } else if (val == 'B') { digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, LOW); digitalWrite(2, HIGH); delay(100); digitalWrite(4, LOW); digitalWrite(2, LOW); } else if (val == 'R') { digitalWrite(5, HIGH); digitalWrite(4, LOW); digitalWrite(3, LOW); digitalWrite(2, HIGH); delay(100); digitalWrite(5, LOW); digitalWrite(2, LOW); } else if (val == 'L') { digitalWrite(5, LOW); digitalWrite(4, HIGH); digitalWrite(3, HIGH); digitalWrite(2, LOW); delay(100); digitalWrite(4, LOW); digitalWrite(3, LOW); } else if (val == 'U') { Serial.print('U'); servo0.write(50); delay(500); } else if (val == 'D') { Serial.print('D'); servo0.write(120); delay(500); } } } |
動くか検証してみる
では、いよいよ動かしてみたいと思います。
コマンドプロンプトを起動し、以下を入力します。すると、サーバーを起動できたことが確認できます。
ブラウザから以下を入力し、操作画面が表示されることを確認します。
画面が表示されたら、コマンドプロンプトには以下のように表示されます。
Fボタンを押すとブラウザから「F」が送信され、XBee経由でロボットが信号を受信して前進します。
Bボタンを押すとブラウザから「B」が送信され、XBee経由でロボットが信号を受信して後進します。
まとめ
今回は、ArduinoとXBeeとNode.jsを使用してWeb画面からラジコンを操作できるようにしてみました!
Nodejsの環境構築や、シリアル通信に手間取りましたがなんとか動かすことができました。
ここまでできたら、これをベースにしてもっとロボットに違う動きをさせたり、逆にロボットに取り付けたセンサーの情報を取得するといったこともできそうです。
これから他のことにも応用していきたいと思います!
コメントを残す