ArduinoとProcessingで遊ぶ!

前回の記録 - ArduinoとCdSセルで遊ぶ。

What's Processing?

Processingとは、PCアートやビジュアルデザインをしたい人に最適な、オープンソースのプログラミング言語とその開発環境を提供しているプロジェクトのことです。
Processingの良い点はそのコーディングが簡単にできることです。高度な知識や複雑なプログラミングなしでも、ある程度のイメージ(画像)やその動きを作成・実現できるのです。これなら、お手軽につかえるArduinoと相性抜群! ちなみに、Processingのプログラミング言語はJavaをベースとしています。グラフィックに特化したJavaと捉えることもできるでしょう。

IDEのインターフェース
こんなに興味深いプロジェクトを使わない手はありません。さっそく、IDEをダウンロードしましょう。下のリンクからダウンロード出来ます。 processing.org / Download 寄付をしない場合は"No Donation"にチェックを付けてから"Download"ボタンをクリックしましょう。OSを選択するとダウンロードが始まります。インストールが完了したら、processing.app(または.exe)を起動します。初期設定は特に必要ありません。

手順

前回のArduinoは環境光に応じた数値を出力するだけでした。今回はProcessingとタッグを組みます。これで、数値をグラフ化したり、もっと面白いことができるようになるのです!
-手順-
  1. Arduinoは環境光の変化に応じた値を出力。
  2. Arduinoの出力する値をProcessingが受け取る。
  3. Processingは受け取った値に応じたバーチャートを描画。
注釈: 1.は前回までの話になります。2.の出力された値の受け渡しにはシリアルポートを使用します。そして3.が今回の記録の目玉になります。

1,接続図

ハードウェアは前回紹介した、
を、そのまま使用します。前回、Arduinoから出力された値はUSBケーブルを伝ってPCへと(具体的に言うとArduinoIDEのシリアルモニターへと)届けられていました。今回はこの値を、Processingで受信したいと思います。これを実現するにあたってハードウェアの変更は特に必要なく、ソフトウェアの変更だけで十分です。つまり、ハードウェアの準備は完了です。

2,Arduinoのアプローチ

ArduinoからProcessingへデータを送信するため、Arduinoのスケッチに改良を加えます。前回のスケッチは次のようなものでした。
Before... (前回まではこんなかんじ)

int val = 0; int iPin = A0; int oPin = 13; void setup() { Serial.begin(9600); pinMode(oPin, OUTPUT); } void loop() { val = analogRead(iPin); Serial.println(val); if(val<920){ digitalWrite(oPin, LOW); }else{ digitalWrite(oPin, HIGH); } delay(200); }
これに改良を加えたものが下のスケッチです。
...After (今回使うスケッチはこんなかんじ)

int val = 0; int iPin = A0; int oPin = 13; boolean i; void setup() { Serial.begin(9600); pinMode(oPin, OUTPUT); } void loop() { val = analogRead(iPin)/4; Serial.write(val); i = (val<100) ? LOW : HIGH; digitalWrite(oPin, i); delay(1000/600); }
変わった点はProcessingが受け取りやすい値になるよういくつかの処理を追加したことです。簡単に言うと、
  • print()は人が読みやすい値を出力する。
  • write()はソフトウェアが読みやすい値を出力する。
  • valの値を4で割りwrite()に最適化した。
  • おまけ,ifではなく?を使いスケッチを短くした。
もっと詳しく知りたいという方は下の文章を読んでみましょう。

printとwrite

Arduinoの出力に使っていたprintln()を、write()へ変更しました。print()系の関数たちは人が読みやすい文字を出力することに力を入れており、可読性の高いASCIIと呼ばれる文字コードに変換してから出力してくれます(要は英数字を表示してくれるということ!)。一方のwrite()はソフトウェアが読み取りやすい値を出力することに力を入れており、print()のように文字コードへ変換せずに、値をそのままバイナリデータとして出力します。ArduinoからProcessingへ円滑に値を送信することを考えると、print()よりもwrite()のほうが適切だとわかります。

analogReadを4で割る意味

val = analogRead(iPin)の末尾に"/4"を付け加えました。"/"は"割る"という意味です。この場合、analogRead(iPin)を4で割っています。なぜか? analogRead()は0~1023のうちのどれかの値を返します。今回Processingへ送信することを考え、write()関数を使用することにした、ということは先に説明した通りですが、ここに4で割る理由があります。write()は出力する値をバイナリデータで出力します。バイナリデータとは2進数化されたデータのことですが、ArduinoとProcessing間でやり取りできるバイナリデータの値は0~255まででなければなりません。最大値が4分の1なのです。今回は目を瞑って4で割るという荒業に出ましたが、本来はmap()関数などを利用して数値を割り当て/変換をするのが良いのでしょう。

三項演算子 ? :

loop()内の"if文"を"?"をつかった分岐処理に変更したため、ほんのちょっとだけスケッチが短くなりました(ifや?の使い方を見る)。意味は、valの値が100未満ならLOWを、100以上ならHIGHを変数iに格納します。この変数iはすぐ下のdigitalWrite()で使用しています。

寄り道: プロトコル


コンピュータ間もしくは1つのコンピュータ内のソフトウェア間で通信をするとき、これを守らないと上手く送受信できないよ、という決まりごとがあります。この決まりごとのことを”プロトコル”と呼びます。たとえば、送信のタイミングと受信のタイミングの合わせ方であったり、送受信できるデータの型はどういったものなのか、データを転送する速度はどの程度にするか、といった事前の決め事です。ArduinoからProcessingへ値を送信する場合も同じことが言えます。Arduinoの送信とProcessingの受信のタイミングを合わせるため、また送受信できるデータ型を合わせるため、両方に準備が必要なのです。人間界で言うところの”お互いに話を合わせる”段階です。

3,Processingの出番

いよいよProcessingの出番です。さっそくProcessingのIDEに次のスケッチを描きましょう!
import processing.serial.*;
Serial ardPort;

int p, value;
int portIndex = -1; //Default : -1

void setup() {
  size(140, 180);
  if(portIndex==-1){
    for(int i=0, l=Serial.list().length; i<l; i++){
      println(i+" : "+Serial.list()[i]);
    }
    exit();
  }else{
    ardPort = new Serial(this, Serial.list()[portIndex], 9600);
  }
}

void draw(){
  println(value);
  p = value*100/255;
  background(255-value);
  fill(0, 102, 173);
  text(value*100/255+"%", 58, 150);
  fill(200, 150, 60);
  rect(55, 130-p, 30, p);
}

void serialEvent(Serial p){
  value = ardPort.read();
}
上のスケッチをIDEへ書き込んだら、このページで設定したシリアルポートの名前(Arduinoが通信に使っているポートの名前: 紹介ページではMacは"/dev/tty.usbmodem1a21"、Windowsは"COM3")を覚えましょう。覚えたらIDE左上のRunをクリックして実行!するとIDEのログに次のような出力が現れるはずです。

Macのログ出力

Windowsだとこんな感じ

もし...このコンソール上に、

WARNING: RXTX Version mismatch
  Jar version = RXTX-2.2pre1
  native lib version = RXTX-2.2pre2
という警告ログが出力され、さらにフリーズや動作の不具合がありましたら、このページ下部に解決案があります。参考までにどうぞ。
それらは、Processingが見つけたPCにあるポートの一覧表です。この中からArduinoが通信に使っているポートの名前を見つけます。見つかったら、今度は図のportIndexという数字を覚えましょう(上図で言うと、/dev/tty.usbmodem1a21は"0"、COM3ならば"1"です)。その番号を、スケッチ先頭付近のint portIndexに代入します。-1になっている部分がそれです。-1を消してその番号を入力しましょう。
自分の環境では0でした。

… int p, value; int portIndex = 0; //Default : -1 …
再度Runをクリック。間違いがなければちっちゃなウィンドウが現れるはずです。もしエラーが発生した場合で、かつportIndexがハイライトされている場合は、ポートの選択が間違っています。

ちっちゃなウィンドウとは私のことです
このウィンドウのバーチャート(棒グラフ)。それこそが、環境光の量をリアルタイムで表すバーであり、今回の記録の目玉となる部分であります! 携帯端末(とくにスマホ)で観察できる、”環境光の明るさで液晶画面のバックライトの明るさが変化する仕組み”を垣間見ることができました。
めでたし、めでたし
スケッチについてもっとくわしく知りたいかたは下の文章を読んでみましょう。

宣言について

import processing.serial.*;は、Processingでシリアルポートを扱うのに必要な関数の集まり(その名前がprocessing.serial)をすべて("*"は"全て"という意味)取り込む、という意味のコードです。これら関数には、SerialやserialEventといったものが含まれます。これらは今回のスケッチにも登場しています。

シリアル通信

Serialはシリアル通信の接続、初期設定をするためのオブジェクトです(シリアル通信に必要な"機能のまとまり" = "オブジェクト",と考えて良いでしょう)。よく見ると見覚えのある数字があると思います。9600というやつです。ボーレートのことです。ArduinoのボーレートとProcessingのボーレートを同じ数値にしたことがポイントです。プロトコルってやつですね。

Arduinoからのデータを読む

serialEvent()とは、指定したポートにデータが届くと、勝手に自分の中にあるコードの処理を実行してくれる関数です。 今回はそのserialEvent()の中にvalue = ardPort.read();と書きました。これは、Serialオブジェクトに設定したポート(portIndexで指定したポート)にデータが届いたら、そのデータを読み取り(read)、valueという変数にそのデータを代入するように、とプログラムしたというわけです。

バーチャートの表示

draw()という関数の中が、目に見える形で現れる部分です。バーチャートはrect()という関数で描かれています。rect(x, y, 幅, 高さ);と書くことで,座標x,yの位置に指定した幅と高さを持つ長方形を描いてくれます. 高さにArduinoから送られてきた値、つまりvalueを設定することで、長方形の高さが明るさに応じて変わるということです。ちなみにfill()という関数を使うことで、色をつけることができるようになります。色の指定方法は赤、緑、青の割合を0~255の間で指定します。たとえば真っ赤を表示したいなら、赤の割合だけを最高値の255にすればよいので、fill(255, 0, 0);と書けば良いのです。白はfill(255, 255, 255);と書けます。では反対の黒はどうすれば良いか?考えてみましょう。

背景と%

background()は背景色です。CdSセルを暗くすると背景色も暗くなり、明るいところに持って行けば明るくなります。直感的ですね。background(255-value)という部分の話です。Arduinoのスケッチの、valを4で割ったもうひとつの意味が見えますね。text()はバーチャートの下に表示されるパーセンテージの値を描画します。

ウィンドウサイズ

もし、ウィンドウのサイズを変更したいならば、void setup()のすぐ下にあるsize()の中の2つの値を変更しましょう。size(幅, 高さ);と入力します。幅300px、高さ500pxのウィンドウを表示したいならば、size(300, 500);と指定するだけです。簡単ですね。

警告ログについて(Windows)

この警告ログと対処法はprocessing1.5.1で確認済です。
WARNING: RXTX Version mismatch
  Jar version = RXTX-2.2pre1
  native lib version = RXTX-2.2pre2
これはRXTXというシリアルポートを簡単に扱うためのJavaライブラリの問題を警告するログです。このログを見るかぎり、どうやらProcessingは"2.2pre1というバージョンを使いたかったのに、手元には2.2pre2というバージョンしかなかったよ"ということを訴えたいようです。解決案として、Processingの手元に2.2pre1を置いておく、という案が考えられます。案なのでダメもとですが次の手順を踏むと良いでしょう。
まずはここから2.2pre1をダウンロード。

赤枠内のBinary版をダウンロード
続いてダウンロードしたZipを解凍し、RXTXcomm.jarというファイルをコピー。それをprocessing.exeがあるフォルダ内(processing-1.5.1)の "/modes/java/libraries/serial/library/" に貼付け・上書き保存。

ここに貼付け・上書き保存
ダウンロードしたRXTXフォルダに戻り"/Windows/i368-mingw32/"内の"rxtxParallel.dll"と"rxtxSerial.dll"の2つをコピー。ふたたびprocessing-1.5.1フォルダ内に戻り、"/modes/java/libraries/serial/library/windows32/"内に貼付け・上書き保存。これでもう一度Processingを起動しなおして、スケッチを実行してみます。運が良ければ警告は出力されないはずです。

参考元:Processing Forum
ここで蛇足をひとつふたつみっつ。Arduinoは、iPhone用の電源アダプタが供給してくれる電気でも、もちろん動いてくれます。そういえば、USBは5Vで動作するものの1つでしたね。また、Arduinoは+5Vだけでなく+3.3Vも出力してくれます。+5Vと+3.3Vの出力があればいろいろな物を動かすことができそうです。
予告:
そろそろArduinoは、我が家のLANを散歩したくなってきたようです。
つづく…
次回の記録 - Ethernetシールドの登場!!
8597964275523467318 http://www.storange.jp/2012/03/arduinoprocessing.html http://www.storange.jp/2012/03/arduinoprocessing.html ArduinoとProcessingで遊ぶ! 2012-03-31T15:51:00+09:00 http://www.storange.jp/2012/03/arduinoprocessing.html Hideyuki Tabata 200 200 72 72