FirmataはホストマシンからUSBシリアル通信を経由してArduinoを操作できるプロトコルです。Cylon.jsのcylon-firmataアダプタを使い、Node.jsからArduino Uno R3を動かす環境を用意しようと思います。Cylon.jsのフレームワークが抽象化してくれるのでBeagleBone BlackにデプロイしたNode.jsのプログラムがPIN番号を変更するだけで動きます。
Ubuntu 14.04のXfceホストマシン
BeagleBone Blackと違いArduino Uno R3にはNode.jsをインストールしていないのでFirmataの場合Node.jsはホストマシン側にあります。ホストマシンにはChromebookにcroutonでインストールしたUbuntu 14.04のXfceデスクトップ環境を使います。
Arduino IDE
ホストマシンのUbuntuにArduino IDEをインストールします。apt-getでインストールするバージョンは1.0.5と古いのですが、最新版の1.6.0のdebパッケージはARMv7環境にインストールが失敗してしまいました。
$ sudo apt-get update && sudo apt-get install arduino arduino-core
ArduinoをUSBケーブルでChromebookと接続するとttyACM0
のデバイスファイルが作成されます。
$ ls -al /dev/ttyACM0
crw-rw---- 1 root serial 166, 0 Feb 23 13:34 /dev/ttyACM0
ログインユーザーでデバイスファイルを操作できるように権限設定をします。
$ sudo chmod a+rw /dev/ttyACM0
インストールしたarduino
コマンド実行してArduino IDEを起動します。
$ arduino
Arduinoのデバイスをシリアル接続で利用するためにdialogグループに追加するダイアログがでます。
ユーザをdialout グループに登録します。
$ sudo usermod -aG dialout mshimizu
ログインし直なおしてグループを確認します。
$ groups
mshimizu dialout video sudo plugdev audio
Firmata
FirmataファームウェアをホストマシンからArduinoにインストールする方法は、Gortを使う場合とArduino IDEからアップロードする場合と2種類あります。
Gortを使う場合
GortはGoで書かれたロボティクスのためのコマンドラインツールです。Arduino Firmataと互換性があるSparkCoreやDigisparkも操作できるようです。今回はavrdudeをインストールしてFirmataをArduinoにアップロードします。まずホストマシンにGortをインストールします。
$ cd ~/Downloads
$ wget https://s3.amazonaws.com/gort-io/0.3.0/gort_0.3.0_linux_arm.tar.gz
$ tar zxvf gort_0.3.0_linux_arm.tar.gz
gort_0.3.0_linux_arm/gort
gort_0.3.0_linux_arm/README.md
gort_0.3.0_linux_arm/LICENSE
$ sudo cp gort_0.3.0_linux_arm/gort /usr/local/bin
Gortのバージョンを確認します。
$ which gort
/usr/local/bin/gort
$ gort -v
gort version 0.3.0
シリアルポートをscanしてArduinoのデバイスファイルを確認します。
$ gort scan serial
1 serial port(s) found.
1. [/dev/ttyACM0] - [usb-Arduino__www.arduino.cc__0043_55431313338351E0F111-if00]
avrdudeをインストールしてsketchesアップロードの準備をします。
$ gort arduino install
Attempting to install avrdude with apt-get.
Reading package lists... Done
Building dependency tree
Reading state information... Done
avrdude is already the newest version.
avrdude set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 56 not upgraded.
FirmataファームウェアをArduinoにアップロードします。
$ gort arduino upload firmata /dev/ttyACM0
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude: Device signature = 0x1e950f
avrdude: reading input file "/tmp/555901447"
avrdude: writing flash (11452 bytes):
Writing | ################################################## | 100% 1.95s
avrdude: 11452 bytes of flash written
avrdude: verifying flash memory against /tmp/555901447:
avrdude: load data flash data from input file /tmp/555901447:
avrdude: input file /tmp/555901447 contains 11452 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 1.55s
avrdude: verifying ...
avrdude: 11452 bytes of flash verified
avrdude done. Thank you.
Arduino IDEを使う場合
Arduino IDEを使ってFirmataをアップロードする場合は通常のsketchesのアップロードと同じです。まずメニューからサンプルからStandardFirmataのソースファイルを開きます。
- File > Examples > Firmata > StandardFirmata
メニューからデバイスを選択します。
- Tools > Board > Arduino Uno
シリアルポートを選択します。
- Tools > Serial Port > /dev/ttyACM0
アップロードまたは右矢印ボタンをクリックしてArduinoにアップロードします。
- File > Upload
Node.js
ホストマシンからFirmataを通してしてArduinoを操作するためにUbuntuにNode.jsをインストールします。いつもはnvmを使いますがChromebookがARMv7なのでソースからビルドする必要があります。
$ nvm install -s v0.10
非力なChromebookなので今回は簡単にパッケージからインストールします。
$ sudo apt-get install nodejs npm
$ sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10
Node.jsのバージョン確認します。比較的新しいNode.jsがインストールされました。
$ node -v
v0.10.25
$ npm -v
1.3.10
cylon-firmata
ホストマシンのUbuntuにCylon.jsのArduino Firmataアダプタである、cylon-firmataをインストールします。package.jsonに必要なパッケージを定義します。MQTTでサンプルに使います。
{
"name": "mqtt-led",
"version": "0.0.1",
"private": true,
"dependencies": {
"cylon-firmata": "0.19.0",
"cylon-mqtt": "0.4.0"
},
"scripts": {"start": "node app.js"}
}
npm install
します。
$ cd ~/node_apps/
$ npm install
Lチカ
Lチカするサンプルアプリを用意しました。
var Cylon = require('cylon');
Cylon.robot({
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
led: { driver: 'led', pin: 13 }
},
work: function(my) {
every((1).second(), my.led.toggle);
}
}).start();
npm start
でプログラムを実行するとLチカが始まります。
$ npm start
> mqtt-led@0.0.1 start /home/mshimizu/node_apps
> node app.js
I, [2015-02-23T06:39:20.913Z] INFO -- : Initializing connections.
I, [2015-02-23T06:39:21.377Z] INFO -- : Initializing devices.
I, [2015-02-23T06:39:21.384Z] INFO -- : Starting connections.
I, [2015-02-23T06:39:26.465Z] INFO -- : Starting devices.
I, [2015-02-23T06:39:26.466Z] INFO -- : Working.
MQTTとLチカ
MQTTのpub/sub
workの中でMQTTのpub/subをすることでメッセージを送受信します。メッセージを受信するとLチカします。
var Cylon = require('cylon');
// Initialize the robot
Cylon.robot({
connections: {
mqtt: { adaptor: 'mqtt', host: 'mqtt://xxx.xxx.xxx.xxx:1883' },
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
toggle: { driver: 'mqtt', topic: 'toggle', connection: 'mqtt' },
led: { driver: 'led', pin: '13', connection: 'arduino' }
},
work: function(my) {
my.toggle.on('message',function(data) {
console.log("Message on 'toggle': " + data);
my.led.toggle();
});
every((1).second(), function() {
console.log("Toggling LED.");
my.toggle.publish('toggle');
});
}
}).start();
npm start
でプログラムを実行します。ArduinoからMQTTのpub/subを通してLチカが始まりました。
$ npm start
npm start
> mqtt-led@0.0.1 start /home/mshimizu/node_apps
> node app.js
I, [2015-02-23T06:55:24.462Z] INFO -- : Initializing connections.
I, [2015-02-23T06:55:25.031Z] INFO -- : Initializing devices.
I, [2015-02-23T06:55:25.039Z] INFO -- : Starting connections.
I, [2015-02-23T06:55:28.322Z] INFO -- : Starting devices.
I, [2015-02-23T06:55:28.327Z] INFO -- : Working.
Toggling LED.
Message on 'toggle': toggle
Toggling LED.
Message on 'toggle': toggle
Toggling LED.
Message on 'toggle': toggle
Toggling LED.
Message on 'toggle': toggle
Toggling LED.
Message on 'toggle': toggle
IFTTTとMQTTとLチカ
BeagleBone BlackにデプロイしたIFTTTのDo Buttonを使ったサンプルを使ってみます。MQTTでメッセージを受信すると標準出力とLチカを3秒間行います。BeagleBone Blackのコードから変更したのはconnection
とled
のPIN番号だけです。異なるコネクテッドデバイス間でもほぼ同じNode.jsのコードが実行できるのでCylon.jsは便利です。
var Cylon = require('cylon');
// Initialize the robot
Cylon.robot({
connections: {
mqtt: { adaptor: 'mqtt', host: 'mqtt://xxx.xxx.xxx.xxx:1883' },
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
ifttt: { driver: 'mqtt', topic: 'ifttt/bbb', connection: 'mqtt' },
led: { driver: 'led', pin: '13', connection: 'arduino' }
},
work: function(my) {
my.ifttt.on("message",function(data) {
console.log("Message on 'ifttt': " + data);
var timer = setInterval(my.led.toggle, 200);
setTimeout(function(){ clearInterval(timer)},3000);
});
}
}).start();
npm start
でプログラムを実行します。AndroidのDo ButtonアプリからWordPressボタンをタップするとMQTTブローカーを経由して、位置情報から生成したGoogleマップのURLがArduinoに通知されました。
$ npm start
> mqtt-led@0.0.1 start /home/mshimizu/node_apps
> node app.js
I, [2015-02-23T06:51:37.312Z] INFO -- : Initializing connections.
I, [2015-02-23T06:51:37.981Z] INFO -- : Initializing devices.
I, [2015-02-23T06:51:37.998Z] INFO -- : Starting connections.
I, [2015-02-23T06:51:41.334Z] INFO -- : Starting devices.
I, [2015-02-23T06:51:41.338Z] INFO -- : Working.
Message on 'ifttt': {"username":"username","password":"password","title":"","description":"<div><img src='http://maps.google.com/maps/api/staticmap?center=35.xxxxxxx,139.xxxxxxx&zoom=19&size=640x440&scale=1&maptype=roadmap&sensor=false&markers=color:red%7C35.xxxxxxx,139.xxxxxxx' style='max-width:600px;' /><br/><div>Do Button pressed on February 23, 2015 at 03:51PM http://ift.tt/1zBK1rg</div></div>","tags":{"string":"Do Button"},"post_status":"publish"}