0%

Arduino UnoをUbuntuホストマシンからCylon.jsとFirmataを使って操作する

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-ide.png

Arduinoのデバイスをシリアル接続で利用するためにdialogグループに追加するダイアログがでます。

dialout-group.png

ユーザを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

standardfirmata-upload.png

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でサンプルに使います。

~/node_apps/package.json
{
"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チカするサンプルアプリを用意しました。

~/node_apps/app.js
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チカします。

~/node_apps/app.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: {
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のコードから変更したのはconnectionledのPIN番号だけです。異なるコネクテッドデバイス間でもほぼ同じNode.jsのコードが実行できるのでCylon.jsは便利です。

~/node_apps/app.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"}