INDEX(各項目ごとの目次)

[HOME]  [Processing関係]  [Arduino関係]  [マテリアル関係]  [秋葉原工作マップ]

2008年用ですが、部分的に内容を更新しています(2010/06/14)。
また、[建築農業工作ゼミ2009-2010]とも連動していますので、そちらにも幾つかサンプルがあります。
:

検索キーワード「processing」に一致する投稿を関連性の高い順に表示しています。 日付順 すべての投稿を表示
検索キーワード「processing」に一致する投稿を関連性の高い順に表示しています。 日付順 すべての投稿を表示

1/30/2009

目次:Processing

*以下のサンプルは、Processing1.5バージョンを前提としたプログラムです。現行(2013年時点)のProcessing2.0では変更点がいくつかあるので、そのままでは動作しないプログラムもあります(videoライブラリなど)。近日中に記載内容をProcessing2.0にあわせて変更していきたいと思います。もうしばらくお待ち下さい。

書籍:Books
Built with Processing[Ver. 1.x対応版] -デザイン/アートのためのプログラミング入門
ビジュアライジング・データ ―Processingによる情報視覚化手法
Getting Started With Processing
Processing: A Programming Handbook for Visual Designers and Artists
Processing: Creative Coding and Computational Art (Foundation)
Learning Processing: A Beginner's Guide to Programming Images, Animation, and Interaction
Programming Interactivity: Unlock the Power of Arduino, Processing, and Openframeworks

基本操作:Basics
Processingのダウンロードとインストール」--Processingのセッティング。
Processingの基本操作 その1」--プログラムの仕方。
Processingの基本操作 その2」--図形の描画。
Processingの基本操作 その3」--図形を動かす。
Processingの描画サンプル」--図形を動かすサンプル。
Processing マウス入力1」--マウスボタン/クリック。
Processing マウス入力2」--マウスに合わせて図形を動かす/図形をドラッグする。
Processing マウス入力3」--図形の上にマウスが重なると色が変わる/ロールオーバー。
Processing マウス入力4」--トグルボタン/フラグ/3回押すとオンになるスイッチ。
Processing 文字と画像」--文字(フォント)の表示方法、画像の取り込みと表示方法。
Processing 手描きの線の表現」--手描きで自由に線を描く。
Processing ドラッグしながら図形を描く」--描画ソフトのように矩形をドラッグして描く。
Processing:デジタル時計のプログラム」--時間に合わせて文字列を表示する。
Processing:アナログ時計のプログラム」--時間に合わせて図形を回転させる。

サウンド:Sound
Processing サウンド/Sonia JSynプラグイン」--MacOSX(Intel)は、JSynプラグイン再インストールが必要。
Processing サウンド1/Sonia」--Soniaライブラリで音源の再生/停止/ポーズする。
Processing サウンド2/逆再生」--Soniaライブラリで逆再生の音源をつくる。
Processing サウンド3/テンポ」--Soniaライブラリで音源再生のテンポ変換をする。
Processing サウンド4/スクラッチ」--Soniaライブラリを使って曲をスクラッチ演奏する。
スピーカ/音出力について」--通常のコーンスピーカ以外の特殊なスピーカなどについて

ファイル選択/読み込み/書き出し:File chooser/File loading/File output
Processing FileChooser/ファイル選択画面の表示」--Java Swingファイルチューザー(画像/音源ファイル読み込み)。
Processing FileChooser2」--ファイルチューザーで画像を選択表示、ドラッグ可能にする。
Processing ドラッグした図形の動きを記録/保存/再生する」--データのセーブ/ロードを使ったサンプル。

Webカメラ:Web camera
Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。

シリアル通信:(センサ/アクチュエータ+Arduino基板との通信)Serial communication
Arduino-Processing シリアル通信1」--ひとつの値を送信する(非同期通信)。
Arduino-Processing シリアル通信2」--複数の値を送信する(同期通信)。
Arduino-Processing シリアル通信3」--大きな値を複数送信する(ビット演算の説明)。
Processing-Arduino シリアル通信4」--Processingの図形をマウスで動かしてArduinoを制御。
Arduino-Processing シリアル通信5」--大きな値、複数の値を文字列で一括送信する。
Arduino-Processing シリアル通信6」--複数のArduinoをProcessingとシリアル通信する。

ネットワーク/ワイヤレス通信:Network/Wireless communication
Processing-Arduino ネットワーク制御」ネットワークを通してサーボ、LEDを制御する。
Processing HTTPサーバ/Webページ表示」--Networkライブラリを使ってWebサーバとして機能させる。
Arduino+Xbee Shield/Processing+XBee Explorer USB」--Xbee、XBee Explorer USBを用いて無線通信する。
Arduino-Processing BlueTooth通信+曲げセンサ」--曲げセンサの入力値をBluetoothで送信する。

その他:Others:3D models/Sudden Motion Sensor(Mac)/QR code/Firmata library
Processing 3Dモデル/OBJ Loader」--外部制作した3Dモデルを読み込む。
Processing 緊急モーションセンサー(Mac)」--緊急モーションセンサーで3Dモデルを動かす。
Processing QRコード/2次元コード」--QRコードを生成/読み込み/解読する。
Processing-Arduino Firmataライブラリ」--ProcessingでArduino基板の各設定をし制御する。
Processing ライブラリのインストール先(v149以降)」バージョン149以降のライブラリインストール変更点。
ProcessingプログラムをApplet表示する方法」--プログラムをWeb上でAppletを使って表示する。

5/26/2008

Arduino-Processing シリアル通信1

【変更】以下はArduino1.0までのシリアル通信に対応したプログラム内容です。
Arduino2.0使用の際は、バイト送信する場合は、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。

今回はシリアル通信を用いて、Arduino基盤に接続した入力装置(可変抵抗器)で、Processingで描かれた図形を動かしてみます。
Arduino側のシリアル通信は、前回のモニタリングで使用したときのような感じです。Processingにおいても、シリアル通信の設定が必要になります。

通信の流れとして:
Arduino基盤に接続した入力装置からの値をanalogRead()で読み取る。
その値をSerial.print()でProcessing側に送る。
Processing側で、その値をSerial.read()で読み取る。
Processing上の図形の座標値に入れる。
という感じです。

まずは、Arduino側からプログラムしていきます。今回入力装置となる可変抵抗器を基盤に接続します。


Arduino側のプログラム:
int val; //読み取り値の変数を用意

void setup(){
  Serial.begin(9600);
}
void loop(){
  //アナログ入力0番ピンの値を読み取り(0~1023)
  //4で割った値を変数valに入れる(0~255)
  val=analogRead(0)/4;
  //シリアルでvalを送信
  Serial.write(val);
  //1秒間に20回ループ(0.05sec)とする
  delay(50);
}

上記プログラムの説明:
Processingと通信する場合、Serial.write()で一度に送ることができる値は、0〜255までの数値になるので、analogRead()で読み取った値(0〜1023)を4で割って、最大値が255になるようにスケーリングした値をvalに代入し送信します。delay(50)程度にし、一秒間に20回送信することにします。Arduino側から一方的にデータを送り続けるので、あまりにも多くのデータを送りすぎると、Processing側での受取処理が追いつかなくなり、反応に時差がでることがあります。

Processingのプログラムについて:
Processing側のプログラムでは、シリアル通信(Serial)はライブラリに含まれており、必要に応じてその機能を取り込む(import)必要があります。
Processingのsketchを開いたら、メニューバーのSketch>Import Library>serialを選択します。そうすると、プログラムを書く欄に自動的に「import processing.serial.*;」という一文が追加されます。これによって、シリアル機能が導入されます。そして以下のようにmyPort(名前は任意)というシリアルのためのインスタンスを用意し、シリアルポート、通信速度を設定します。Processingのシリアル通信についての説明は、Processing画面のメニューバーでHelp>Referenceへ行き、そのページ内の上部のLibrariesをクリックし、さらにページ内のCore Librariesの欄にSerialという項目があるので、そこをクリックします(Processingのサイトにも同じSerialのページがあります)。

Processing側のプログラム:
//シリアルライブラリを取り入れる
import processing.serial.*;
//myPort(任意名)というインスタンスを用意
Serial myPort;

int x; //図形のX座標の変数を用意

void setup(){
  //画面サイズ
  size(256,256);
  //シリアルポートの設定
  myPort=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
}

void draw(){
  //背景色を白に設定
  background(255);
  //XY座標を(x,100)に設定し、
  //幅50、高さ50の円を描画
  ellipse(x,100,50,50);
}

void serialEvent(Serial p){
  //変数xにシリアル通信で読み込んだ値を代入
  x=myPort.read();
}

上記プログラムの説明:
初期設定のsetup()内の「myPort=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);」の設定において、MacOSXの場合は「/dev/tty.usbserial-********」の箇所の********の部分は使用しているArduino基盤によって異なります。Arduino画面のメニューバーのTools>Serial Portのなかから使用している基盤のシリアルポートと同じものを書いて、両端を「"」マークで括ってください。Windowsの場合は、「COM*」(*は番号)のようにポートが表示されるので、同様に「COM*」を「"」マークで括ってください。
通信速度の「9600」は、通常この設定で構いません。

シリアル通信が行われるたびに、serialEvent()内のx=myPort.read()によってArduino基盤から送られて来た値を読み込み、変数xに代入され、最終的にellipse()のX座標に代入されます。Arduinoから送られてくる値は0〜255であるため、Processing上のellipse()のX座標の移動範囲も0〜255(256段階)となります。それに合わせて、Processingの画面幅を256に設定しました。つまり、ellipse()を1ピクセルずつ左右に動かすことができます。


関連:
Arduino-Processing シリアル通信2」(複数の値をバイトで送る/同期通信)
Arduino-Processing シリアル通信3」(大きな値を複数送る)
Processing-Arduino シリアル通信4」(ProcessingからArduinoを制御する)
Arduino-Processing シリアル通信5」(複数の値を文字列で送信する)
Arduino-Processing シリアル通信6」(2台のArduinoとProcessingを通信させる)

5/27/2008

Arduino-Processing シリアル通信2


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


前回のシリアル通信では、ひとつの値をArduinoからProcessingへ一方的に送り続ける内容でした。今回は、Arduino側から三つの可変抵抗器を使って、三つの異なる値をProcessingへ送りたいと思います。

例えば、Processing上の3DモデルのX座標、Y座標、Z座標の値を送り、それぞれのツマミで三次元的に立体を動かすことができるプログラムになるということです。
Arduinoから3つの値を送るには、
Serial.write(x);
Serial.write(y);
Serial.write(z);

となります。
3つの値がXYZの順番で送られる場合、XYZ XYZ XYZ・・・と繰り返されますが、Processing側の読み取りを開始するタイミングがずれると、最初の幾つかの値をスキップしてしまい、YZX YZX YZX・・・、あるいはZXY ZXY ZXY・・・となってしまいます。このように、順番がずれないようにするためには通信上の工夫が必要となります。今回の方法では、3つの値を一方的に送るのではなく、受取確認をしながらお互いに通信します。以下にプログラムを書きます。

Arduino側のプログラム:
//x,y,zの3つの変数を用意し、初期値を0とする
int x=0;
int y=0;
int z=0;

void setup(){
  //シリアル通信開始
  Serial.begin(9600);
}

void loop(){
  //アナログ入力ピン0,1,2を
  //それぞれx,y,zに対応させる
  //値を4で割って最大値255にする
  x=analogRead(0)/4;
  y=analogRead(1)/4;
  z=analogRead(2)/4;

  //Processingから合図のデータが
  //一つ送られてきたらという条件
  if(Serial.available()>0){
    //x,y,zの順番で値を送る
    Serial.write(x);
    Serial.write(y);
    Serial.write(z);
    //先ほどのProcessingからの
    //合図のデータを読み込む
    Serial.read();
  }
}

Arduinoプログラム上のSerial.available()は、外部(この場合Processing)から1バイト分のデータが何個送られてきているかを数えてくれます。送られてくるデータは、Arduinoであれ、Processingであれ、それぞれのメモリ上(バッファ領域)に一旦貯められます。その後、Serial.read()によって、貯められているデータから順番にひとつずつ読み込む処理をします。もし、読み込む処理をしなければ、送られたデータは次々とバッファ領域に溜まり続けます(設定した限界をこえるとそれ以上貯めることはできなくなります)。if(Serial.available()>0){...}という条件は、データが1個以上貯まったら(0個より多い場合)、{...}内の処理をするという意味です。

このプログラムの場合の手順は以下のようになります。

(1)まず、Processingから合図用のデータが送られてくる。
(2)合図用のデータが、一旦Arduinoのバッファ領域に貯められる。
(3)Serial.available()で、現在何個データが貯まっているか数える。
(4)合図用のデータが1個以上あれば、(5)以下を実行する。
(5)Serial.write(x)で、新たなxの値を送信する。
(6)Serial.write(y)で、新たなyの値を送信する。
(7)Serial.write(z)で、新たなzの値を送信する。
(8)Serial.read()で、バッファ領域内の合図用のデータを読み込む。
(9)結果、バッファ領域が空になる(データの個数が0個になる)。
(10)Processingからの合図用のデータを待つ。

その後は(1)に戻り、同様の処理を繰り返します。要するに、Processingからの合図のデータが毎回1個送られて、それを確認後、Arduinoはx、y、zの値を送り返すという手順を踏みます。

次にProcessing側のプログラムを書きます。Arduinoのプログラムで書いたように、Processingからは、合図用のデータを1個送る必要があります。そうすれば、Arduinoから3個のデータが送られてくるので、Processingのバッファ領域にデータが3個貯まったときに、読み込む処理をさせればいいということになります。今回はx、y、zの3個の値なので3Dの図形を動かすプログラムにします。

Processing側のプログラム:
//シリアルライブラリを取り込む
import processing.serial.*;
//シリアルのオブジェクトmyPortを用意
Serial myPort;

//x,y,zの3個の変数を用意
int x=0;
int y=0;
int z=0;

void setup(){
  //3D用の画面サイズとして設定
  size(255,255,P3D);
  //シリアルポートの設定(「A4001Kjl」は基盤により異なる)
  //Windowsの場合は、"COM5"などとなる(前回ブログを参照)
  myPort=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
  //3D図形の塗りは無し(ワイヤーフレーム描画)
  noFill();
}

void draw(){
  //背景色を白に設定
  background(255);
  //3Dの位置座標にx,y,z入れる
  translate(x,y,z);
  //一辺50のボックス(立方体)を描画
  box(50);
}

//シリアル通信処理
void serialEvent(Serial p){
  //Arduinoから送られてきたデータが
  //3個(2より多い)の場合
  if(myPort.available()>2){
    //x,y,zの順番でデータを読み込む
    x=myPort.read();
    y=myPort.read();
    z=myPort.read();
    //読み込み後、合図データ送信
    myPort.write(65);
  }
}

//マウスが押されたら通信開始とする
void mousePressed(){
  //念のためバッファ領域を空にする
  myPort.clear();
  //とりあえず65という合図用データを送る
  myPort.write(65);
}

以上が、Processing側のプログラムです。3Dの場合は、size()の括弧内に画面幅、高さ以外に「P3D」を書き足します。ワイヤーフレームで描画した方が、今回の場合分かりやすいと思うので、noFill()をつかって塗り面を無しにしました。
void draw(){...}内のtranslate()は、その後に描画される3D図形の座標値をいれます。translate()に含まれる値が変化することで、3D図形は移動します。box()は、3Dの直方体を描画します。box(50,100,80)というように3つ値を入れれば、幅、高さ、奥行きをそれぞれ定義できます。box(50)の場合は、各辺が50の立方体になります。
シリアル通信の部分は、まずmousePressed()でマウスを押したときに、myPort.clear()でProcessingのバッファ領域内に貯まっているデータをとりあえず空にします(初期化)。そして通信を開始するきっかけとなる合図のデータをmyPort.write(65)で送ります。65という値を送っていますが、0〜255の値であれば何でも構いません。Arduino側は送られてくるデータの個数を数えるのであって、データの中身の値については、何でもいいことになります。つまり、合図用に何らかのデータを1個送ればいいということです。一旦合図用のデータがProcessingから送られれば、次にArduinoがそのデータを受取り、そして3個のデータを送り返してきます。void serialEvent(Serial p){...}内のif(myPort.available()>2){...}内では、Arduinoから送られて来たデータがProcessingのバッファ領域に3個貯まったら(2個より多くなったら)myPort.read()で3回読み込み、x,y,zの3個の変数にそれぞれ値を入れていき、それらのデータは、box()の3D座標になるtranslate()に代入され、box()が動きます。



もう一度、手順をはじめから書くと、

(1)Arduinoの電源がオンになり、Arduinoのプログラムが開始。
(2)Processingのプログラムを立ち上げる。
(3)Arduinoは、Processingからの合図用データを待つ。
(4)Processing側でマウスを押す(通信開始)。
(5)Processingのバッファ領域を一旦空にする(初期化)。
(6)Processingから合図用データが1個送られる。
 *以下、Arduino上での処理
(7)Arduinoのバッファ領域に合図用データが一旦貯められる。
(8)Arduinoのバッファ領域内のデータの個数を数える。
(9)データの個数が1個以上のとき、以下の処理を実行。
(10)Arduinoから、新たなxの値を送信する。
(11)Arduinoから、新たなyの値を送信する。
(12)Arduinoから、新たなzの値を送信する。
(13)バッファ領域内の合図用のデータを読み込む。
(14)読み込んだ結果、Arduinoのバッファ領域が空になる。
(15)次の合図用データがバッファ領域に貯まるまで待機。
 *以下、Processing上での処理
(16)Processingのバッファ領域にデータが貯められる。
(17)Processingのバッファ領域内のデータの個数を数える。
(18)データの個数が3個になったら、以下の処理を実行。
(19)xの値として1番目のデータを読み込む。
(20)yの値として2番目のデータを読み込む。
(21)zの値として3番目のデータを読み込む。
(22)その結果、Processingのバッファ領域が空になる。
(23)Processingから合図用データが1個送られる。
(24)次の3個のデータがバッファ領域に貯まるまで待機。
 *その後は(7)へ戻り処理を繰り返します。

Serial.available()
myPort.available()を使うことで、バッファ領域内に貯められているデータの個数を数え、その個数をもとにデータを送受信するタイミングを制御することができます。これ以外にも、送られる複数のデータの先頭部分や最後の部分に「.」(ピリオド)などの特定のデータを付け加えて送ることで、読み込み開始地点や読み込み終了地点を知らせる方法もあります。
シリアル通信を使うことで、コンピュータの内側と外側の世界をつなぐことができます。今後も様々な表現に応じて「シリアル通信」の技術は、繰り返し登場してきます。今回一気に理解できなくても、徐々に使いこなしていくことで、身についていくと思います。


関連:
Arduino-Processing シリアル通信1」(一つの値を送る/非同期通信)
Arduino-Processing シリアル通信3」(大きな値を複数送る)
Processing-Arduino シリアル通信4」(ProcessingからArduinoを制御する)
Arduino-Processing シリアル通信5」(複数の値を文字列で送信する)
Arduino-Processing シリアル通信6」 (2台のArduinoとProcessingを通信させる)

6/01/2008

Processing-Arduino シリアル通信4


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


前回までは、Arduino基盤に接続したセンサなどからProcessingの画像を動かしていましたが、今回はその逆で、Processingで制作した画像からArduinoを制御したいと思います。前回同様合図用のデータを送り、確認し合いながら通信します。Processingでマウスで動かすことができるスライダをつくり、256段階の値をArduino側に送り、PWM出力を用いてLEDの明るさを調節できる内容とします。Processing側から操作するので、まずProcessing側のプログラムから書きます。

Processingのプログラム:
//シリアルライブラリの取り込み
import processing.serial.*;
Serial port;

//X座標の変数
int x=0;

void setup(){
  size(255,100);
  //シリアルポートの設定
  port=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
}

void draw(){
  background(100);
  line(x,0,x,height);
}

void serialEvent(Serial p){
  //データ数が0個より多いとき
  if(port.available()>0){
    //X座標を送信
    port.write(x);
    //Arduinoからの合図用データを
    //読み込んでバッファを空にする
    port.read();
  }
}

void mouseDragged(){
  //ドラッグ中のX座標にマウスX座標を
  //最小値0,最大値255で入れる
  x=constrain(mouseX,0,255);
}

void keyPressed(){
  //sキーを押したら
  if(key=='s'){
    //通信開始用データ送信
    port.write(0);
  }
}


今回は、キーボードの「s」キーを押すことでシリアル通信を開始することにしました。「s」キーを押さなければ、Processing、Arduinoの両方のプログラムは、どちらも待機中となります。そのため、Processing側から「s」キーを押して、通信開始のきっかけとなるデータを1個(1バイト分)送ります。
Arduino側では、11番ピン(PWMピン)にLEDのプラス側を、GNDにマイナス側をつなぎます。必要に応じてその間に抵抗(220Ω)を直列つなぎします。

Arduinoのプログラム:
//読み取り値の変数
int val=0;

void setup(){
  //シリアル通信開始
  Serial.begin(9600);
}

void loop(){
  //データが0個より多いときの時
  if(Serial.available()>0){
    //データの読み込み
    val=Serial.read();
    //合図用データ送信(1バイト)
    Serial.write(65);
  }
  //アナログ出力(11番ピン)に読み込み値を入れる
  analogWrite(11,val);
}

手順としては、
(1)両方のプログラムが開始される。
(2)合図用データの待機中。
(3)Processingから「s」キーで通信開始用データを送信。
(4)Arduinoのバッファ内データを数える。
(5)Arduinoバッファ内データが1個以上ならデータ読み込み。
(6)その結果、Arduinoバッファ内データが空になる。
(7)Arduinoから合図用データ送信。
(8)Proccessingバッファ内データを数える。
(9)Processingバッファ内データが1個以上ならX座標データ送信。
(10)合図用データを読み込み、バッファを空にする。
 *以後は、(4)へ戻り通信を繰り返す。

追記:
上記プログラムで通信が途切れてしまう場合、ArduinoよりProcessingの処理速度が速すぎるのかもしれません。Processingのvoid setup(){...}内でframeRate(30)程度にするか、draw(){...}内にdelay(20)程度を挿入し少しスピードダウンすると安定するかもしれません。
あるいは、ProcessingからArduinoへ一方向的にデータを送る内容なので非同期通信にしてもいいかもしれません。その場合もProcessingのvoid setup(){...}内でframeRate(30)程度にスピードダウンし、void draw(){...}内にport.write(x)を入れて(serialEvent()は使わず)30fpsで定期的に送信し、Arduino側でそのデータを受け取るようにします(合図用データは送る必要はありません)。


関連:
Arduino-Processing シリアル通信1」(一つの値を送る/非同期通信)
Arduino-Processing シリアル通信2」(複数の値をバイトで送る/同期通信)
Arduino-Processing シリアル通信3」(大きな値を複数送る)
Arduino-Processing シリアル通信5」(複数の値を文字列で送信する)
Arduino-Processing シリアル通信6」 (2台のArduinoとProcessingを通信させる)

10/18/2008

Arduino-Processing シリアル通信6


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


これまでのシリアル通信では、ProcessingとArduinoの一対一の通信を行ってきましたが、今回はProcessingで二つのシリアルポートを使い、二つのArduinoとシリアル通信を行う実験をしてみます。それぞれのArduino基盤には可変抵抗器をとりつけて入力値をProcessingへ別々に送信することにします。Processingの画面では、二つの入力信号を個別に読み取ってそれぞれの状態を描画することにします。

具体的なサンプルとして、「Pong」(下画像)のように二つのコントローラによって対戦するプログラムにします。それぞれのArduino基盤がコントローラとしてコンピュータに接続され、画面上でそれぞれのラケットを動かすことになります(得点のプログラムは含まれていません)。


(上画像:Processingの画面「Pong」)

Arduino基盤と可変抵抗器の接続は以下のようになります(二つ必要です)。



Arduinoのプログラム:
void setup(){
  Serial.begin(9600);
}

void loop(){
  //可変抵抗器の読み取り
  int val=analogRead(0);
  //シリアル通信処理
  if(Serial.available()>0){//合図用データが一つ来たら
    //合図用データを読み込んでバッファを空にする
    Serial.read();
    //読取値を4で割り、バイトで送信
    Serial.print(val/4,BYTE);
  }
}

Arduino側のプログラムでは、可変抵抗器からの読取り値を4で割ってスケールダウンした値(0~255)をシリアル通信でProcessing側へ送信しています(同期通信させるために合図用データを用いるシリアル通信の方法については「Arduino-Processing シリアル通信2」を参照して下さい)。二つのArduino基盤とも同じ内容になります。

Processingのプログラム:
//シリアル通信ライブラリを取り込む
import processing.serial.*;
//二つのポートのインスタンス
Serial portA;
Serial portB;
//二つの読取値の変数
int valA=100,valB=100;
//ボ−ル座標用変数
int x=100,y=100;
//ボールの動きの向きの変数(1:正の向き、-1:負の向き)
int dirX=1,dirY=1;

void setup(){
  //画面サイズ設定
  size(300,256);
  //二つのシリアルポート設定
  portA = new Serial(this, "/dev/tty.usbserial-A50019vD", 9600);
  portB = new Serial(this, "/dev/tty.usbserial-A40014iU", 9600);
  //図形外形線なし
  noStroke();
  //塗り色(白)
  fill(255);
  //矩形描画位置を中央に設定
  rectMode(CENTER);
}

void draw(){
  //背景(黒)
  background(0);
  //左ラケット描画(valAをY座標に代入)
  rect(20,valA,10,30);
  //右ラケット描画(valBをY座標に代入)
  rect(280,valB,10,30);
  //ボール描画
  rect(x,y,10,10);

  //ボールX座標の動き
  x+=dirX;//X軸方向に+1または-1ずつ進める

  //ラケットAに当たった時のはね返り
  if(x==30 && y>valA-15 && y<valA+15){
    dirX*=-1;//向きを反転する
  }
  //ラケットBに当たった時のはね返り
  if(x==270 && y>valB-15 && y<valB+15){
    dirX*=-1;//向きを反転する
  }
  //画面左端からはみ出た場合
  if(x<0){
    x=270;//右側に戻る
  }
  //画面右端からはみ出た場合
  if(x>width){
    x=30;//画面左側に戻る
  }

  //ボールY座標の動き
  y+=dirY;//Y軸方向に+1または-1ずつ進める

  //画面上下位置でのはね返り
  if(y<5 || y>251){
    dirY*=-1;//向きを反転する
  }  
}

//キーを押した場合
void keyPressed(){
  //「s」キーでシリアル通信開始
  if(key=='s'){
    //二つのポートへ開始用データ送信
    portA.write(65);
    portB.write(65);
  }
}

//シリアル通信処理
void serialEvent(Serial p){
  //portAの場合
  if(p==portA){
    if(p.available()>0){
      //値を読み込みvalAに代入
      valA=p.read();
      //合図用データ送信
      portA.write(65);
    }
  }
  //portBの場合
  if(p==portB){
    if(p.available()>0){
      //値を読み込みvalBに代入
      valB=p.read();
      //合図用データ送信
      portB.write(65);
    }
  }
}

Processing側のプログラムでは、二つのシリアルポートを用意し、それぞれportA、portB(名前は任意)にしておきます。serialEvent(Serial p){...}の括弧内のpは、ポート名に対応しています(今回の場合は、pはportAまたはportBに対応します)。serialEvent()は、Processingがデータを受信した際に作動するので、if()文を使ってどちらのポートなのかを条件分けして判別し、ポートに応じてそれぞれの読込み値を変数に代入します。同期通信させるために、Arduinoから送信されたデータをp.available()で確認しデータを読み込んだ後に、合図用データ(0~255の数値あるいは'A'や'a'などの一つの文字/1バイト分のデータ)を送信しています。
Processingのプログラムを開始したら、「s」キーを押すことでシリアル通信を開始することにしました(プログラム開始から数秒経った後に「s」キーを押さないと、シリアル通信が開始されないことがあります)。

関連:
Arduino-Processing シリアル通信1」(一つの値を送る/非同期通信)
Arduino-Processing シリアル通信2」(複数の値をバイトで送る/同期通信)
Arduino-Processing シリアル通信3」(大きな値を複数送る)
Processing-Arduino シリアル通信4」(ProcessingからArduinoを制御する)
Arduino-Processing シリアル通信5」(複数の値を文字列で送信する)

12/21/2008

Processing-Arduino Firmataライブラリ

今回は、「Firmataライブラリ」のテストを行いたいと思います。
通常Processing-Arduinoの間を通信させるときにはシリアル通信を使い、Processing側のプログラムとArduino側のプログラムをそれぞれ別々に書いていましたが、「Firmataライブラリ」を使うことで、Processing側から直接Arduinoをプログラムし制御することが可能になります(パソコンにUSB接続したArduino基板をProcessing側からのプログラムだけで操作できるので便利です)。

Firmataライブラリを使うための準備:
・まずFirmataライブラリをダウンロードし、Processingのlibrariesフォルダ内にインストールします。
・Arduino-0012であればArduino用Firmataライブラリは含まれているので、メニューバーのSketchBook>Examples>Library-Firmata>StandardFirmataを開き、Arduino基板にアップロードしておきます。Arduinoのセッティングは以上です。

今回はProcessing用のFirmataライブラリに含まれているサンプルを用いたいと思います。
Processingを開いて、File>Sketchbook>libraries>arduino>examples>arduino_outputを選択します。
以下のようなプログラムが表示されるはずです。

import processing.serial.*;

import cc.arduino.*;

Arduino arduino;

color off = color(4, 79, 111);
color on = color(84, 145, 158);

int[] values = { Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW,
Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW, Arduino.LOW };

void setup() {
size(470, 200);

println(Arduino.list());
arduino = new Arduino(this, Arduino.list()[0], 115200);

for (int i = 0; i <= 13; i++)
arduino.pinMode(i, Arduino.OUTPUT);
}

void draw() {
background(off);
stroke(on);

for (int i = 0; i <= 13; i++) {
if (values[i] == Arduino.HIGH)
fill(on);
else
fill(off);

rect(420 - i * 30, 30, 20, 20);
}
}

void mousePressed()
{
int pin = (450 - mouseX) / 30;

if (values[pin] == Arduino.LOW) {
arduino.digitalWrite(pin, Arduino.HIGH);
values[pin] = Arduino.HIGH;
} else {
arduino.digitalWrite(pin, Arduino.LOW);
values[pin] = Arduino.LOW;
}
}


Processing上でこのプログラムをランさせます。この時点でProcessingから、Arduino基板の各ピンの入出力設定がなされます。Processingでは以下のような画面が現れます。



14個ならんでいる正方形をそれぞれクリックすれば(クリックするとその正方形は塗りつぶされる)、Arduinoの0番ピンから13番ピンの合計14個のピンに対応してデジタル出力されます(Processing画面上の左端の正方形がArduinoの13番ピンに対応)。試しにProcessing画面上左端の正方形をクリックすると、13番ピンに接続されたLED(基板内蔵LED)が点灯します。同様に他の正方形をクリックすれば、それに対応したピンからデジタル出力されることが確認できます(各ピンにLED+抵抗:220Ωを接続して下さい)。
ただし、0番ピンと1番ピンに関しては、Processing-Arduino間でのシリアル通信で使用されているため、クリックしても反応しないので、2番ピンから13番ピンでのデジタル出力制御となります。

Processingのプログラム上で、

arduino.pinMode(ピン番号, 入出力設定);

とすれば、Arduinoの任意のピンの入出力設定(Arduino.INPUT または Arduino.OUTPUT)を行うことができます。
出力をHIGHかLOWにするには、

arduino.digitalWrite(ピン番号, 出力値);

で、出力値をarduino.LOWかarduino.HIGHで設定します。
そのほか、

デジタル入力:arduino.digitalRead(ピン番号)
アナログ入力:arduino.analogRead(ピン番号)
アナログ出力:arduino.analogWrite(ピン番号,出力値)

という感じになるので、arduino.を頭につければ、Arduino上でのプログラムとほぼ同じです。

1/30/2009

目次:Arduino


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


・Arduinoボード購入先については、ページ右下のショップリストに掲載(秋葉原のマップはこちら)。
Arduino 日本語リファレンス

書籍:Books
Arduinoをはじめよう
Making Things Talk -Arduinoで作る「会話」するモノたち
Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ
CQ ham radio (ハムラジオ)増刊 マイコンと電子工作No.1 電脳Arduinoでちょっと未来を作る 2010年 01月号 [雑誌]
アーデュイーノ互換マイコン・ボードを作る (プリント基板付き電子工作解説書シリーズ)
Physical Computing: Sensing and Controlling the Physical World with Computers
Programming Interactivity: Unlock the Power of Arduino, Processing, and Openframeworks
Practical Arduino: Cool Projects for Open Source Hardware (Technology in Action)
Arduino Cookbook (Oreilly Cookbooks)

基本操作:Basics
Arduinoのセッティング」--Arduino 0018のダウンロード/インストールの仕方
Arduino基盤の概要」--Arduino基盤の機能や端子の説明
Arduino LEDの点滅」--プログラム、アップロードの仕方、LEDを点滅させる
Arduino 7セグLEDの点灯」--7セグLEDの接続/表示方法
Arduino アナログ入出力」--LEDの明暗をコントロールする

入出力部品の種類:Input/Output Parts and Materials
センサについて」--赤外線距離センサ、光センサ、タクトスイッチの接続と入力方法
センサについて2」--各ショップにおけるセンサの種類(秋月、千石、共立、Sparkfun)
出力方法について」--表示、アクチュエータ、熱、音などの出力部品の種類について
Arduino モータドライバ+モータ」--モータドライバやDCモータの種類/選び方
スピーカ/音出力について」--通常のコーンスピーカ以外の特殊なスピーカなどについて
導電性素材/材料について」--電気を通すことができる様々な材料について
素材実験/鉛筆の描画線」--紙の上に鉛筆で描いた線を可変抵抗として使う
素材実験/小型・薄型の材料」--チップLEDやペーパーバッテリなどの小型部品について

センサ(入力系)各種:Sensors/Inputs
センサについて」--赤外線距離センサ、光センサ、タクトスイッチの接続と入力方法
Arduino 圧電スピーカ」--ブザー、センサとして圧電スピーカを使う/シリアルモニターの仕方
Arduino 加速度センサ」--加速度センサで物体の傾斜角を計測する
Arduino デジタルコンパス/HMC6352」--方位センサ「HMC6352」の使い方
Arduino 距離センサ/超音波レンジファインダー」--Parallax「Ping)))」の使い方
Arduino-Processing BlueTooth通信+曲げセンサ 」--曲げセンサの入力値をBluetoothで送信する
Arduino タッチパネル(4線式)」--4線式タッチパネルの接続方法/使い方
Arduino タッチセンサ」--抵抗だけでタッチセンサをつくる
Arduino デジタルカラーセンサ S9706」--RGB同時測光カラーセンサの実験
光センサ フォトICダイオード S9648-100」(建築農業工作ゼミ2009より)
温・湿度センサ SHT-71」(建築農業工作ゼミ2009より)
温度センサ LM35DZ」(建築農業工作ゼミ2009より)
温度センサ LM60BIZ」(建築農業工作ゼミ2009より)
Arduino:7セグ+照度センサNJL7502L」--照度センサで得た値を7セグを用いて表示する

マトリクスLED:Matrix LED
Arduino マトリクスLED1」--マトリクスLEDをArduinoに直結して表示する
Arduino マトリクスLED2/MAX7219」--LEDドライバMAX7219でマトリクスLED表示する
Arduino+Processing マトリクスLED+Webカメラ」--Webカメラの映像をマトリクスLEDに映す

サーボ/モータ/モータドライバ:Servos/Motors/Motor drivers
Arduino サーボ制御」--PWM、ライブラリ、パルスによるサーボ制御
Arduino 小型DCモータ/TA7291P」--モータドライバTA7291Pでモータを制御する。
Arduino モータドライバ+モータ」--モータドライバやDCモータの種類/選び方

シリアル通信:(パソコン上のProcessingプログラムとの通信)Serial communication
Arduino-Processing シリアル通信1」--ひとつの値を送信する(非同期通信)
Arduino-Processing シリアル通信2」--複数の値を送信する(同期通信)
Arduino-Processing シリアル通信3」--大きな値を複数送信する(ビット演算の説明)
Processing-Arduino シリアル通信4」--Processingの図形をマウスで動かしてArduinoを制御
Arduino-Processing シリアル通信5」--大きな値、複数の値を文字列で一括送信する
Arduino-Processing シリアル通信6」--複数のArduinoをProcessingを通してシリアル通信する

ワイヤレス/ネットワーク通信:Wireless/Network comminication
Arduino+Xbee Shield/Processing+XBee Explorer USB」--Xbee、XBee Explorer USBを用いて無線通信する
Arduino-Processing BlueTooth通信+曲げセンサ 」--曲げセンサの入力値をBluetoothで送信する
Processing-Arduino ネットワーク制御」--ネットワークを通してサーボ、LEDを制御する
Arduino Ethernet Shield」--イーサネットシールドを使って、ArduinoをWebサーバとして機能させる
Arduino Mega + Ethernet Shield」--未対応のArduino Megaにイーサネットシールドを重ねて使う方法
Arduinoで計測した値を指定のwebサーバに送信/保存する」(建築農業工作ゼミ2009より)

ビデオ信号/TV:Video signal/TV
Arduino ビデオ信号/テレビ画面に出力」--Arduinoを使ってテレビ画面に模様や矩形を表示する
Arduino ビデオ信号/バウンドするドット」--Arduinoを使ってテレビ画面に動く映像を表示する

ライブラリ:Libraries
Processing-Arduino Firmataライブラリ」--ProcessingでArduino基板の各設定をし制御する。
Arduino PID制御ライブラリ」--PID制御用の専用ライブラリ

シールド/ハードウェア:Shield/Hardware
Arduino TouchShield Slide」--Liquidwireが販売しているArduino用OLEDタッチパネルスクリーン
Arduino Li-ionバッテリ Litium Backpack Stealth」--Arduino基板用リチウムイオン充電電池パック
Arduino AC Power Shield」--交流電源を制御するArduinoシールド
Arduino Mega+Arduino IDE version 0015」--54個のデジタル入出力ピンがある大型のArduino基板
Arduino Mega:ピンマッピング」--Arduino MegaボードとATmage1280のピン配置関係
Arduino Mega:analogRead 8~15番ピンのバグ」--Arduino0017におけるバグの解決方法
Arduino Quad Core Quadruino」--ATmega328を4個搭載したArduino基板:Quidruino
DSbrut」--LilyPad ArduinoでプログラムできるニンテンドーDS用のカートリッジ基板

5/28/2008

Arduino-Processing シリアル通信3


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


前回までのサンプルでは、ArduinoのSerial.write()を用いて、0〜255までの256段階の値を扱っていました。analogRead()からは、0〜1023までの1024段階の値を読み取ることができるのに、わざわざ4で割って256段階にスケーリングして解像度を落としていました。
今回はanalogRead()から読み取った1024段階の値を解像度を落とさずProcessingへ送信したいと思います。1024段階の値を二つの値に分解して送信する方法を用いることにします。大きな画面上で図形などを滑らかに動かすときや、センサなどから読み取った値を精度高く計算したいときは、解像度を低くできない場合があります。そのような時に、今回の方法を用いるといいでしょう。
今回もまた3個の可変抵抗器を基盤につなぎ(配線については前回ブログ参照)、それぞれをanalogRead()で1024段階で読み取り、Processing上でも1024段階で表現したいと思います。

Arduinoのプログラム:
//3つの変数を用意
int x, y, z;

void setup(){
  //シリアル通信開始
  Serial.begin(9600);
}

void loop(){
  //x,y,zの変数へ読み込んだ値を入れる
  x = analogRead(0);
  y = analogRead(1);
  z = analogRead(2);

  //Processingからの合図用データが
  //バッファ領域内に一つ以上になったら
  if(Serial.available() > 0){
    //それぞれの値を2つの値に
    //分解するための変数を用意し
    //計算結果を入れる
    int x_high = x / 256;
    int x_low = x % 256;
    int y_high = y / 256;
    int y_low = y % 256;
    int z_high = z / 256;
    int z_low= z % 256;
    //分解した値を送る
    Serial.write(x_high);
    Serial.write(x_low);
    Serial.write(y_high);
    Serial.write(y_low);
    Serial.write(z_high);
    Serial.write(z_low);
    
    //合図用データを読み込んで、
    //バッファ領域を空にする
    Serial.read(); 
  }
}

以上のプログラムで、x,y,zは整数型の変数です。整数型の計算では、例えば10/3=3、3/10=0であり、小数点以下の部分は無視されます(四捨五入もされません)。ちなみに、小数点まで求める場合は、float型の変数を用います。
それから「%」(Modulo)という割り算の余りを求める計算式があります。10%3=1、3/10=3、10%4=2、10%5=0となります。
今回はこの二つの計算方法を使って、0〜1023の1024段階の値をx_highとx_lowという二つの値に分解して、二つのデータとしてArduinoから送ります。送られたデータはProcessing上で再び合成されて、一つの値として扱われるようにします。
例えばArduinoのanalogRead()から950という読み取り値があったら、
x_high = 950 / 256;
x_low = 950 % 256;

として、
x_high = 3;
x_low = 182;

となります。
この二つの値3と182をそれぞれProcessingへ送信し、Processing上で、
x_high * 256 + x_low = 950

つまり、
3 * 256 + 182 = 950

と計算し直して、もとの値950を得ることになります。実は、分解された値は前回同様最大値が255(256段階)であり、大きな値に対して256が幾つ分あり、そしてその余りが幾つかということを計算して送信しています。
同様にyとzについても分解して送信し、Processing上で合成します。
今回は3つの値があり、それぞれを二つに分解して送信するので、合計6回送信します。

Processingの方では、円のXY座標と大きさをそれぞれ調節可能にするプログラムとします。解像度が1024段階あるので、画面サイズは大きめにしておきます。前回同様、マウスで画面をクリックしたら、通信開始するプログラムにします。

Processingのプログラム:
//シリアルライブラリを取り込む
import processing.serial.*;

Serial myPort;
int x,y,z;

void setup(){
  //大きめの画面サイズに設定
  size(1000,700);
  //滑らかな描画にする
  smooth();
  //シリアルポート設定
  myPort=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
  //バッファ領域を空にしておく
  myPort.clear();
  //図形の塗りを200に設定
  fill(200);
}

void draw(){
  //背景を白に設定
  background(255);
  //円の描画
  //XY座標と幅、高さに変数を入れる
  ellipse(x,y,z,z);
}

void serialEvent(Serial p) {
  //バッファ領域に6個のデータがあるとき
  if(myPort.available()>5){
    //分解された値を読み込む変数を用意し
    //各変数に読み込み値を入れる
    int x_high = myPort.read();
    int x_low = myPort.read();
    int y_high = myPort.read();
    int y_low = myPort.read();
    int z_high = myPort.read();
    int z_low = myPort.read();
    
    //読み込んだ値をそれぞれ合成し、
    //1024段階の値としてx,y,zに代入
    x = x_high * 256 + x_low;
    y = y_high * 256 + y_low;
    z = z_high * 256 + z_low;
    
    //合図用のデータを送る
    myPort.write(65);
  } 
}

//マウスが押されたら通信開始
void mousePressed(){
  myPort.write(65);
}

0〜255というのは、1バイト分のデータであり、二進数の
00000000〜11111111

の値ということになります。00000000は0であり、11111111は255です。0か1が8桁あり8ビット(=1バイト)となります。
16ビットなら16桁あり
0000000000000000〜1111111111111111

となり、0〜65535となります。16ビットなので2バイトあります。
今回値を二つに分けて送信した方法というのは、16ビットを
00000000|00000000

というように上位8桁と下位8桁に分けて送信したことと同じです。
もし、256という値なら、
00000001|00000000

となり、上位8桁だけをみれば00000001なので、8ビットの1と等しいことになります。下位8桁は00000000なので、8ビットの0になります。つまり、256の場合は、1(上位)と0(下位)が送信されるということになります。
950を16ビットの二進数であらわすと、
0000001110110110

であり、同様に上位8ビット、下位8ビットで分けると、
00000011|10110110

になり、
上位8ビット00000011は10進数の3であり、下位10110110は182になり、3と182を送信することになります。
ArduinoやProcessingにも二進数/ビット演算の数式や関数があります。
>>」という記号を用いて、
950 >> 8

と書けば、この値は3となります。つまり、950/256=3と同じ結果が得られます。
>>」というのは「右にシフトする」という意味で、「950 >> 8」においては「950を8桁右にシフトする」ということになります。二進数で言えば、
0000001110110110

という16桁を8桁右にずらす(シフト)ので、
0000000000000011

となり、十進数の3になります。
950 >> 1

なら、1桁右にずらすので、
0000000111011011

となります。ずらされて右端からあふれてしまった0や1は消えてしまいます。
そのほか「&」というのもあります。
950 & 255

と書けば、
182となり、950 % 256と同じ結果が得られます。以下のようにそれぞれを上下に重ね合わせて、950を255でマスキングするような感じです(ビットマスク)。
00000011|10110110  950
00000000|11111111  255
00000000|10110110  182

255の0のある桁(上位8桁)の真上の950の桁00000011はすべて消されて0となり、255の1のある桁(下位8桁)の真上の950の桁10110110だけ残ります。255は16桁のうち上位8桁はすべて0が並んでおり、下位8桁はすべて1が並んでいるので、255というマスキングを950に施すということは、950の上位8桁を消して(0にする)、下位8桁だけを取り出すということになります。つまり、
950 >> 8 = 3
950 & 255 = 182

という計算でも、950/256=3、950%256=182と同じ値が得られるということになるので、Arduino上のxの値に関しては、
x = analogRead(0);
byte mask = B11111111;
Serial.write(x >> 8);
Serial.write(x & mask);

と書くことができます。「byte mask = B11111111」というのは、maskというバイト型の変数を用意し、その値が11111111であるということで、xの値の下位8桁だけを取り出すために使っています。Arduinoにおいてバイトの場合は、8桁の二進数の頭の部分に「B」(二進数/バイナリーのフォーマット)を付けます。Processing上では、
(3 << 8) + 182 = 950

というように、逆に「3を左に8桁シフト」してから「182を足す」と「950」になるので、Processingでは、
x = (x_high << 8) + x_low;

と書けば同じ値を得ることができます。

二進数の表記やビット演算はサンプルプログラムやデータシートの中にも出てくることがあります。ビットやバイトを使わなくてもプログラムできますが、覚えておくと便利なときもあり、考え方や計算もよりシンプルになる場合があります。


関連:
Arduino-Processing シリアル通信1」(一つの値を送る/非同期通信)
Arduino-Processing シリアル通信2」(複数の値をバイトで送る/同期通信)
Processing-Arduino シリアル通信4」(ProcessingからArduinoを制御する)
Arduino-Processing シリアル通信5」(複数の値を文字列で送信する)
Arduino-Processing シリアル通信6」(2台のArduinoとProcessingを通信させる)

6/12/2008

Arduino-Processing シリアル通信5


【変更】以下はArduino1.0まで対応したプログラム内容です。
特にシリアル通信においては、Arduino2.0使用の際、バイト送信する場合、
Serial.print(value,BYTE);
のかわりに、
Serial.write(value);
を使用してください。


以前行ったシリアル通信では、ArduinoのanalogRead()で読み取った値(0〜1023までの値)を0〜255(8ビット)にスケールダウン(4で割る)して送信するか、256以上の大きな値を、二つの0〜255(8ビット)の数値に分解して送っていました。今回は、たとえば「1023」という255より大きい値を、そのままの「1023」という値で送信したいと思います。そのためには、読み取った整数値(int型)を文字列として送信します。
今回は3つの可変抵抗器を読み取って(接続方法は「Arduino-Processing シリアル通信2」を参照)、Arduinoから3つの値をまとめて送信します。複数の値を送る際には数値と数値の間にデリミターという区切りの記号(今回の場合「,」コンマ)を挿入して送信します。そうすることによって、Processingでデータを受け取る際に、データ内容を混同せず読み取ることができます。最初の二つの読み取り値は、Serial.print()を使ってDEC(十進数文字列)のフォーマットで送信し、区切り記号のコンマもSerial.print()で文字列として送信します。最後の読み取り値を送る時に、DECフォーマットでSerial.println()を用い「改行」して送信します。改行することで、Processing側でデータを受け取る際に、送られて来たデータのどの部分が最後であるのかを確認することが可能になります。それでは、Arduinoのプログラムから始めます。

Arduinoのプログラム:
void setup(){
  //シリアル通信開始
  Serial.begin(9600);
}

void loop(){
  //3つのセンサの値を読み取り、変数に代入
  int x=analogRead(0);
  int y=analogRead(1);
  int z=analogRead(2);

  //合図用データが一個きたら
  if(Serial.available()>0){
    //xの値を十進数文字列で送信
    Serial.print(x,DEC);
    //区切り記号コンマを送信
    Serial.print(",");
    //yの値を十進数文字列で送信
    Serial.print(y,DEC);
    //区切り記号コンマを送信
    Serial.print(",");
    //zの値を十進数文字列かつ改行して送信
    Serial.println(z,DEC);
    //合図用データを読み込みバッファを空にする
    Serial.read();
  }
}


「xの値 コンマ yの値 コンマ zの値 改行」というデータが一度に送られることになります。Serial.print(value,DEC)の「DECフォーマット」の数値は文字列であり、以前使ったSerial.print(value,BYTE)の「BYTEフォーマット」の数値と異なる値になります。文字列の「1」は、BYTEフォーマットでは、「49」に相当します。十進数文字列とバイトの数値の対応は以下のようになります(ちなみに、BYTEフォーマットの「65」は文字列の「A」になります)。

DEC: BYTE:
 0  48
 1  49
 2  50
 3  51
 4  52
 5  53
 6  54
 7  55
 8  56
 9  57

アスキーコード表」にこれらの対応関係が掲載されています。
たとえば、「120」という値の場合、BYTEフォーマットならそのまま「120」となりますが、DECフォーマットでは「49 50 48」というように「1」「2」「0」という3つの文字を送ることになります。DECフォーマットでは、1桁の数値なら1バイト分のデータであり、2桁なら文字二つを送るので2バイト、3桁なら3バイト必要になります。BYTEフォーマットは、255までの数値であれば1バイトで済みますが、それ以上の数値は「Arduino-Processing シリアル通信3」で行ったように、分解して送るなどの工夫が必要となります。
DECフォーマットで、そのままの値を文字列として送信した方が分かりやすいのですが、その分バイト数が増えてしまうことにもつながります。BYTEフォーマットであれば少ないバイト数で送ることができますが、大きな数値を分解して計算し直さなければいけないので、十進数の数値として扱いづらくなります。状況に応じて使い分けるのがいいと思います。

次に、Processing側のプログラムに入る前に、どのようなかたちでデータを受け取るかということについて説明します。

例えば、3つの可変抵抗器から読み取られる値が、

x=120
y=284
z=1015

の場合、Arduinoからは、

「120 コンマ 284 コンマ 1015 改行」

というデータが送られてきます。
「コンマ」は「アスキーコード表」では「44」であり、「改行」記号は「アスキーコード表」の「13」と「10」がデータの最後に付け加えられることになります。
「13」は「キャリッジリターン(行頭に戻る)」ということであり、文字列では「\r」になります。
「10」は 「ラインフィード(次の行へ移る)」ということであり、文字列では「\n」になります。
Windowsでは、キャリッジリターンとラインフィードで改行となり、Macintoshでは、キャリッジリターンのみで改行されるので、この二つがあることで、いずれにせよ改行されることになります。

先ほどの、

「120 コンマ 284 コンマ 1015 改行」

というデータは、

"120" + "," + "284" + "," + "1015" + "\r" + "\n" 

という文字列データになります。
コンマや改行記号を手掛かりにすれば、データの順番や終わりの部分をProcessing側で判別して読み込むことができます。それでは、このようなことを踏まえてProcessingのプログラムをしてみたいと思います。PFontを用いて、数値を文字で画面に表示することにします。マウスを押したら通信開始することにします(プログラムが開始して数秒たってからマウスを押さないと反応しないときがあります)。

Processingのプログラム:
//シリアルライブラリを取り込む
import processing.serial.*;
//シリアル通信用変数portを用意
Serial port;

//フォント用変数fontを用意
PFont font;

//読み込み値の変数を用意
int x,y,z;

void setup(){
  //画面サイズ設定
  size(400,200);

  //フォントをロードする
  font = loadFont("Monaco-10.vlw");
  //フォント使用開始:サイズ10
  textFont(font, 10);
  //文字を右寄りに配置する
  textAlign(RIGHT);

  //シリアルポート設定
  port = new Serial(this,"/dev/tty.usbserial-A50019vD",9600);
  //念のためバッファを空にする
  port.clear();
  //「10」(ラインフィード)が来る度に
  //serialEvent()を発動させる
  port.bufferUntil(10);  
}

void draw(){
  //背景を白で塗りつぶす
  background(255);
  //3つの値を文字で表示する
  text(x,100,50);
  text(y,200,50);
  text(z,300,50);
}

//シリアル通信
void serialEvent(Serial p){
  //文字列の変数stringDataを用意し、
  //「10」(ラインフィード)が来るまで読み込む
  String stringData=port.readStringUntil(10);

  //文字列データが空ではないとき
  if(stringData!=null){
    //文字列データに含まれる改行記号を取り除く
    stringData=trim(stringData);

    //整数型の配列data[]を用意し、
    //コンマ記号をもとに文字列データを区切って
    //配列data[]に整数化して入れておく
    int data[]=int(split(stringData,','));

    //配列data[]内のデータが3つなら、
    if(data.length==3){
      //最初のデータをxに代入
      x=data[0];
      //次のデータをyに代入
      y=data[1];
      //その次のデータをzに代入
      z=data[2];

      //合図用データ送信
      port.write(65);
    }
  }  
}

//マウスが押されたら通信開始
void mousePressed(){
  //開始用データ送信
  port.write(65);
}

Processing上のシリアル通信では、まず初期設定setup(){...}内で、bufferUntil()を使って、指定した文字がArduinoから送られて来るたびにserialEvent()が作動するように設定しておきます。Arduinoから最後に送られてくるSerial.println()によって、データの末尾が改行記号の「\n」であることから、今回はbufferUntil()の括弧内には「10」を入れておきます。整数値「10」は文字列の改行記号の「\n」(ラインフィード)に相当します。
そして、serialEvent(){...}内では、readStringUntil()を用いて、同様に「10」つまり「\n」が来るまでデータを読み込む設定にします。読み込まれたデータは、3つの値以外にも「コンマ」や「改行」記号が含まれた連続した文字列なので、その文字列の内容を整理し直す必要があります。
「stringData!=null」は、読み込まれたデータが空(null)ではないとき、つまり何かしらのデータがあるときという条件です。データがあれば、その文字列データに含まれている余分な空白記号や改行記号をtrim()によって取り除きます。
その後、それぞれの値の区切り記号(デリミター)として用いた「,」コンマをもとに、連続したひとつのデータをsplit()で分解します。split()によって分解されたデータは、複数のデータを内包する配列に変換されます。さらに、分解されたデータは、まだ文字列なので、int()を用いて整数値へ変換します。そのためにdata[]という配列を用意し、「int data[]=int(split(stringData,','))」の中で、この一連の変換作業を行っています。配列については、「Arduino 7セグLEDの点灯」の後半でも触れていますので、参照してください。
if(data.length==3){...}は、配列data[]内のデータ数が3つあるときにという条件です。length配列の大きさ(データを何個含んでいるか)を数えます。データ数が3つあることを確認してから、配列data[]に含まれる一つ目の値「data[0]」をxに代入します(配列では、最初のデータは0番目となります)。同様にyとzについても代入します。最後に合図用データを一つ送信します(65以外の数値でも大丈夫です)。合図用データをArduinoへ送信すれば、Arduinoは再び新たなデータを送り返してきます。

連続した文字列データを個別の数値に変換する手続きを以下にもう一度書きます。
Arduinoで読み取った3つの値を、

x=120
y=284
z=1015

とすれば、
Arduinoからは、

"120" + "," + "284" + "," + "1015" + "\r" + "\n" 

という順番で文字列として送信されます。
Processingでは、port.readStringUntil(10)で括弧内の「10」つまり「\n」までを、

"120,284,1015\r\n" 

という連続したデータとして読み込みます(「\r\n」は改行記号)。合計14個の文字があるので14バイトになります。「\r」と「\n」はそれぞれ1バイトずつとなります。 
trim()で「改行」記号を削除すると、

"120,284,1015"

になります。
split()で「,」をもとに分解すると、

{"120","284","1015"}

という、3つの文字列を含んだ配列のデータに変換されます。
さらに、これら3つの文字列をint()で整数の数値に変換すると、

{120,284,1015}

になり、予め用意しておいた整数型の配列data[]に入れます。

int data[]={120,284,1015}

そして、「data.length」によって配列data[]のデータ数が3個であるかを確認し、これらの値(整数値)を順にx、y、zへ入れます。

x=data[0]
y=data[1]
z=data[2]

この手順を踏んで、連続した文字データを個別の数値として扱うことができます。


関連:
Arduino-Processing シリアル通信1」(一つの値を送る/非同期通信)
Arduino-Processing シリアル通信2」(複数の値をバイトで送る/同期通信)
Arduino-Processing シリアル通信3」(大きな値を複数送る)
Processing-Arduino シリアル通信4」(ProcessingからArduinoを制御する)
Arduino-Processing シリアル通信6」 (2台のArduinoとProcessingを通信させる)

9/26/2008

Processing Webカメラを光センサとして使う

今回は、パソコンに接続したWebカメラを光センサとして使う応用実験を行います。点光源(LEDなど)を空間内で動かし、その軌跡をProcessingの画面上に描画してみたいと思います(身体にLEDなどの点光源をつけて、腕を動かしたり歩いたりすれば、身体の動きを連続的に描画/記録することができます)。
Processingでは、videoライブラリを用いてWebカメラを通してキャプチャし、キャプチャした画面のピクセルをひとつずつ読み込んで、設定した明るさ以上のピクセルを選択します。選択したピクセルのみを別の色で表示するプログラムになります。
以下のプログラムでは、カメラからキャプチャした画像の各ピクセルの明るさ(0~255)を調べ、そのピクセルの明るさが254以上であれば、画面上に赤で表示する内容になります。クリックすれば、黒で塗りつぶして画面をリセットすることにします。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。

*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。

//ライブラリを取り込む
import processing.video.*;

//オブジェクトの用意
Capture video;

//画面サイズの変数と値
int w=320;
int h=240;

void setup() {
  size(w, h);
  video = new Capture(this, w, h, 30);
  //背景を黒にしておく
  background(0);
  video.start();//Processing2.0以上の場合はこの行が必要
}

void draw() {
  //画面のピクセルをロードしておく
  loadPixels();

  //カメラ画像のピクセルをひとつずつ調べる
  for(int i=0;i<w*h;i++){
    //ピクセルが254以上の明るさの場合
    if(brightness(video.pixels[i])>=254){
      //選択されたピクセルを赤にする
      pixels[i]=color(255,0,0);
    }   
  }

  //ピクセル表示更新
  updatePixels();
}

//キャプチャ画面の読み込み
void captureEvent(Capture video) {
  video.read();
}

//マウスボタンを押したら
void mousePressed(){
  //背景を黒にする
  background(0);
}


LEDなどの点光源をカメラに対して動かせば、以下のような画像ができあがります。赤いピクセル部分が、動かした点光源の軌跡です。




webカメラからの映像と合成(オーバーレイ)するには、以下のようになります。ここでは、webカメラからの映像を左右鏡像反転しています(カメラによっては、セッティング画面で鏡像にできるものもあります)。カメラからの映像を鏡像にすることで、点光源を右に動かせば画面内の点光源も右に動くようになります。マウスボタンを押せば画面を黒にリセット、「s」キーを押すと画面内の映像をjpeg画像で保存、「t」キーを押すとカメラセッティング画面になります。
import processing.video.*;
Capture video;
int w=320;
int h=240;

//軌跡用の配列を用意しておく
int[] pix=new int[w*h];

void setup() {
  size(w, h);
  video = new Capture(this, w, h, 30);
  //軌跡用配列の値をすべてゼロにしておく
  for(int i=0;i<w*h;i++){
    pix[i]=0;
  }
  video.start();//Processing2.0以上の場合はこの行が必要
}

void draw() {
  loadPixels();
  for(int i=0;i<w*h;i++){
    if(brightness(video.pixels[i])>=254){
      //ピクセルを鏡像反転するための計算
      //配列に値を記憶しておく
      int a=i/w;
      pix[w-i%w+a*w-1]=255;//選択されたピクセルだけを255にする
    }
    //配列からの値を画面ピクセルへ代入
    //選択されたピクセルを緑で画面表示    
    pixels[i]=color(0,pix[i],0);
  }
  updatePixels();

  //合成するカメラ映像の処理
  tint(255,128);//透明度128(50%)
  scale(-1.0, 1.0);//左右反転(鏡像)
  image(video, -w, 0);//映像出力
}

//カメラ映像読み込み
void captureEvent(Capture video) {
  video.read();
}

//マウスボタンを押すとリセット(黒へ)
void mousePressed(){
  for(int i=0;i<w*h;i++){
    pix[i]=0;
  }
}

int num=0;//保存画像インデックスの変数

void keyPressed(){
  //sキーを押すと(jpeg画像で保存)
  if(key=='s'){
    String s="image_" + num + ".jpg";//保存ファイル名
    save(s);//画像保存
    num++;//保存画像インデックスを+1しておく
  }
  //tキーを押すと
  if(key=='t'){
    video.settings();//カメラセッティング画面表示
  }
}

「s」キーを押すことで画面をjpegフォーマットで保存できるようにsave()を用います。画像は、save()の括弧内の指定したファイル名でスケッチフォルダ内に保存されます。インデックス用の変数numを用意し、image_0.jpg、image_1.jpg、image_2.jpg...というように、保存名にはインデックス番号がつくようにします。
「t」キーを押せばsettings()によって、カメラのセッティング画面が現れます。カメラの露出やコントラストなどの設定が「オート/自動」になっている場合があるので、できれば「マニュアル/手動」に切り替えて、それぞれを固定値にしたほうが、選択するピクセルの明るさが変化せずに済むのでいいでしょう。


上画像:合成/重ね合わせられた映像
映像内の手にはボタン電池に接続されたLEDが点灯しています。
この画像は、プログラム中にある「s」キーを押して画像保存したものです。


ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
      

関連:
Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。

7/24/2008

Processing サウンド1/Sonia

今回は、Processingを使ってサウンド制御をしてみます。「Sonia」という音のライブラリを使用します。音に関してはこの他に「Minim」や「Ess」というライブラリもあります。

Sonia」を利用するには、
・「Sonia」サイトへ行く。
・「download」をクリック。
・Sonia 2_9 for Processing V90 [ZIP]の[ZIP]部分をクリック。
・ダウンロードが開始され、デスクトップなどに展開する。
・展開したファイル(sonia_v2_9)をMacosXなら/Application/Processing0135/libraries内に入れる。
 WindowsならC:¥Program File¥processing-0135-expert¥libraries内に入れる。
JSynプラグインをインストールする(画面の指示に従って自動インストール)。

・インストール完了
*Processingを開いたままインストールした場合は、Processingを再起動すれば使うことができます。

「Sonia」では、wavまたはaiffのフォーマットを読み込むことができます。まず、これらのフォーマットの音源を用意します。今回はwavフォーマットを使用することにします。

wavフォーマットの音源がない場合は、既にiTunesに登録してある曲(音源)をwavフォーマットに変換し直して使用することができます。

iTuneで音源をwavフォーマットに変換する方法:

・iTunesを起動し、「iTunes/環境設定」を開く。
・環境設定ウィンドウ内の「詳細」をクリック。
・「詳細」設定の「読み込み」をクリック。
・「読み込み方法:」を「WAVエンコーダ」にする。
・「設定」は「自動」でも構いません。
・「OK」ボタンをクリック。
・iTunesのもとの画面に戻り、曲(音源)を選択する。
・メニューバー/詳細から「選択項目をWAVに変換」を選ぶ。

以上で選択した音源はwavフォーマットに変換され、iTunes内に保存されます。
iTunes外の音源も、一旦iTunesに取り込んで変換すれば使うことができます。

用意した音源は、プログラムを書いたファイルのsketchフォルダ内のdataフォルダ内(ない場合は新規作成)に入れておきます。(dataフォルダについては、以前の「Processing 文字と画像」を参照)。
新規sketchを開いたら、一旦保存して、そのsketch名が「sketch_08724a」なら、MacosXの場合/User/username/Documents/Processing/sketch_08724a内にdataフォルダを作成し音源を入れておく必要があります。Windowsの場合、C:¥Documents and Setting¥username¥My Documents¥Processing¥sketch_08724a内となります。

音源は各自用意するか、無料音源サイトなどからダウンロードして下さい。
無料音源サイト:音の杜 http://mmworks.info/otonomori/

まずは、単純に音源を再生するプログラムです。プログラムをランさせれば、音源が再生されます。
尚、プログラムをランさせた時に「Exception in thread "Thread-2" java.lang.OutOfMemoryError:...」のような赤文字のエラーが出たら、メモリーが足りないということなので、MacosXの場合はメニューバーのProcessing>環境設定を選択し(ウィンドウが現れる)、「Set maximum available memory to ... MB」の欄に256MBなど充分なメモリー(曲や音源のサイズ)を記入し、チェック欄にチェックを入れて下さい。Windowsの場合は、File>Preferencesを選択し、同様に充分なメモリー数を記入しチェックを入れて下さい。


//ライブラリを取り込む
import pitaru.sonia_v2_9.*;
//音源tune(名前は任意)を用意
Sample tune;

void setup() {
//とりあえず画面を200角に設定
size(200,200);
//Sonia開始
Sonia.start(this);
//括弧内に音源名を指定し設定する
tune = new Sample("music.wav");
//音源の再生
tune.play();
}

void draw(){
//特になし
}

//Soniaの使用停止
public void stop(){
Sonia.stop();
super.stop();
}


まず、ライブラリを取り込んで、音源のオブジェクト名tune(名前は任意)を設定します。setup(){...}内で、Soniaの使用開始をしたら、tune = new Sample("music.wav");で、予め用意しておいたdataフォルダ内の音源を指定します。Sample()の括弧内に音源名を「"」マークで両端を括っていれておきます。tune.play()で音源の再生をします。今回の場合はsetup(){...}内にtune.play()が書かれているので、プログラムをランさせると同時に再生が開始されます。画面表示は特に使わないので、とりあえず200ピクセル角に設定してあります。最後のpublic void stop(){...}は、ウィンドウを閉じたときにSoniaの使用を停止するプログラムです。これを書いておかなければ、ウィンドウを閉じてもSonia自体のプログラムはランし続けてしまうことがあるので、忘れずに書いておいてください。

次に、クリックしたら再生し、もう一度クリックしたら停止するプログラムを書いてみます。


//ライブラリを取り込む
import pitaru.sonia_v2_9.*;
//音源tune(名前は任意)を用意
Sample tune;

//再生/停止の切替フラグを用意
//falseの時停止、trueの時再生とする
boolean start=false;

void setup() {
//とりあえず画面を200角に設定
size(200,200);
//Sonia開始
Sonia.start(this);
//音源名を指定し設定する
tune = new Sample("music.wav");
}

void draw(){
//特になし
}

//クリックした場合
void mousePressed(){
if(start==false){//フラグが停止の時
start=true; //フラグを再生にする
tune.play(); //音源再生

}else{ //フラグが再生に時
start=false; //フラグを停止にする
tune.stop(); //音源停止
}
}

//Soniaの使用停止
public void stop(){
Sonia.stop();
super.stop();
}


再生と停止を切り替えるためにboolean型の変数(フラグ)start(名前は任意)を用意し、falseなら停止、trueなら再生という状態をクリックするごとに記憶させておきます。同時にそれに応じて停止/再生をtune.stop()とtune.play()で設定します。
ただ、このままでは再生する度に音源の冒頭部分に戻ってしまいます。効果音のような短い音源の場合なら、この設定でもいいのですが、曲にようにもう少し長い音源の場合は、ポーズ(一時停止)させたほうがいいかもしれません。
以下では、クリックして停止したときに、曲の停止箇所を記憶させておき、もう一度クリックした時に、その続きから再生されるようにしてみます。


//ライブラリを取り込む
import pitaru.sonia_v2_9.*;
//音源tune(名前は任意)を用意
Sample tune;

//再生/停止の切替フラグを用意
//falseの時停止、trueの時再生とする
boolean start=false;

//音源全体の長さの変数
int totalFrames;
//再生箇所(停止箇所)の変数
int playHead;

void setup() {
//とりあえず画面を200角に設定
size(200,200);
//Sonia開始
Sonia.start(this);
//音源名を指定し設定する
tune = new Sample("music.wav");
//音源の長さを取得する
totalFrames=tune.getNumFrames();
}

void draw(){
//特になし
}

//クリックした場合
void mousePressed(){
if(start==false){//フラグが停止の時
start=true; //フラグを再生にする

//再生箇所指定で音源再生
tune.play(playHead,totalFrames);

}else{ //フラグが再生に時
start=false; //フラグを停止にする

//停止箇所を記憶させる
playHead=tune.getCurrentFrame();
tune.stop(); //音源停止
}
}

//Soniaの使用停止
public void stop(){
Sonia.stop();
super.stop();
}


音の場合、通常サンプルレートと呼ばれる数値でデータ量が扱われます。CDなどの場合44100Hzであり、1秒間に44100個の信号が扱われます。2秒ならその倍の88200個の信号になるので、基準のサンプルレートが44100Hzであれば、その数値を数えれば、再生時間(サンプル数)が計算できます。上のプログラムでは、まずtotalFramesという変数を用意して、getNumFrames()という関数で音源全体の時間の長さ(サンプル数)を取得しておきます。10秒間の音源であれば、44100×10=441000となります。そして、playHeadという一時停止させる箇所を記憶させておく変数を用意し、getCurrentFrame()によって、現在の再生箇所を取得します。つまり、マウスをクリックして停止するときに、その停止箇所を記憶させることになります。つぎに、tune.play(playHead,totalFrames)というように括弧内に再生開始箇所と終了箇所を指定して再生させます。こうすることで、クリックで停止させるごとに、停止箇所を記憶しておき、もう一度再生させるときに、前回の停止箇所から再生させることが可能になります。

関連:
Processing サウンド4/スクラッチ」--曲をスクラッチ演奏する
Processing サウンド3/テンポ」--音源再生のテンポ変換をする
Processing サウンド2/逆再生」--逆再生の音源をつくる

*MacOSX(Intel)の場合、新たにJSynプラグインをインストールする必要があります。ここをクリックすると、インストール画面に移動します。移動先のページ上の「Click Here to Install JSyn Plugin」のボタンを押してインストールしてください。

 iTunes Music Store(Japan)

10/11/2008

Processing Webカメラ/定点記録画像

身体の動作などを連続写真として記録するために、Webカメラを用いインデックス番号をつけて画像保存する方法です。設定したフレームレートで撮影画像を順番に保存していきます。以下は、フレームレート2の速度(0.5秒/フレーム)で処理するサンプルです。sキーで連続写真の画像を0.5秒おきに保存し、eキーで保存を終了、cキーでカメラセッティング画面に切り替わります。
videoライブラリの基本的な使い方は「Processing Video(Webカメラ)」を参照して下さい。

*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。


//ライブラリの取り込み
import processing.video.*;
Capture myCapture;

//記録開始用のフラグ
boolean start=false;
//記録画像インデックス用変数
int num=0;

void setup() {
//画面サイズ設定
size(320, 240);
//キャプチャする映像の設定(2フレーム/秒)
myCapture = new Capture(this, width, height, 2);
//ループのフレームレート(2フレーム/秒)
frameRate(2);
}

void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
if(start){
//記録中の目印表示
rect(0,0,10,10);
//記録画像インデックス名(jpgで保存)
String s="image_"+num+".jpg";
//画像を保存
save(s);
//インデックス番号を更新
num++;
}
}

//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}

void keyPressed(){
//sキーで画像記録開始
if(key=='s'){
start=true;
}
//eキーで記録終了
if(key=='e'){
start=false;
}
//cキーでカメラセッティング
if(key=='c'){
myCapture.settings();
}
}


連続写真の画像は、撮影された数だけスケッチフォルダのなかに保存されます。

(スケッチフォルダの中にインデックス番号を含んだ保存名で保存される/MacOSXの場合)

上図の場合、「image_0.jpg」から「image_10.jpg」までの合計11枚の画像が保存されています。フレームレートは2なので、約5.5秒間撮影(連続保存)したことになります。

関連:
Processing Video (Webカメラ)」--Webカメラの使い方/映像にフィルタをかけて表示。
Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。

8/11/2008

Arduino+Processing マトリクスLED+Webカメラ

今回は、Webカメラから取り込んだ映像をArduinoに接続した8×8マトリクスLEDに映す実験を行います。まず、ProcessingでWebカメラからの映像を8×8ピクセルで取り込み、合計64個のピクセルの明るさの値(0〜255)を調べてから、その個々の値をシリアル通信でArduinoに送ります。Arduino側では、受け取った64個分の値をマトリクスLEDの個々の明るさに反映させます。Arduino基盤とマトリクスLEDとは、ICを使わず直結することにします(接続方法は「Arduino マトリクスLED1」を参照)。
Processingの画面では、マトリクスLEDの表示シミュレーション(モニタリング)を同時に行うことにします(前回行ったモザイク処理のような方法で赤い円を64個映し出すことにします)。


「Processingの画面(モニタリング)」

Processingのプログラム:

//ビデオライブラリを取り込む
import processing.video.*;
//キャプチャ用オブジェクトを用意
Capture video;

//シリアル通信ライブラリを取り込む
import processing.serial.*;
//シリアル通信オブジェクトを用意
Serial port;

//64個分のピクセル色の配列を用意
int[] pixelValue=new int[64];

//シリアル通信開始用フラグ
boolean start=false;

void setup(){
//画面を160角に設定
size(160,160);
//描画を滑らかにする
smooth();

//映像キャプチャの設定(幅8,高さ8ピクセル,フレームレート30)
video = new Capture(this, 8, 8, 30);

//ポートの設定
port=new Serial(this,"/dev/tty.usbserial-A40014iU",9600);

//外形線なし
noStroke();
}

void draw(){
//背景を黒で塗る
background(0);

//64個分のピクセルの処理
for(int i=0;i<64;i++){
//映像の各ピクセルの色の値を
//明るさの値に変換する
pixelValue[i]=int(brightness(video.pixels[i]));

//円の塗色(赤の値)に代入
fill(pixelValue[i],0,0);
//円を描画
ellipse((i%8)*20+10,(i/8)*20+10,15,15);

//値を送信
if(start){
port.write(pixelValue[i]);
}
}
}

//キャプチャ映像読み込み
void captureEvent(Capture video) {
video.read();
}

クリックでシリアル通信開始
void mousePressed(){
start=true;
}


Processingの方では、VideoライブラリSerialライブラリの二つを取り込む必要があります。マトリクスLEDが8×8の解像度なので、Webカメラから取り込む映像の解像度も8×8にしておきます(カメラ映像の横縦比は4:3なので、少し縦長の映像になってしまいます)。
*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができません。WinVDIG 1.0.1をインストールする必要があります。
「pixelValue[i]=int(brightness(video.pixels[i]))」では、まず映像の各ピクセルの色をpixels[]で読み込みます。pixels[]は、RGBの三色の値(三つの値)を含んでおり、brightness()で括ると明るさの値(一つの値)に変換されます(0〜255)。変換された値はfloat(小数)なのでint()で括って整数に変換しておきます。この値を、fill()の赤の値に代入し(緑と青は0)、LEDのような赤い円をellipse()を使って64個描画します。8×8を160×160の画面で表示しているので、20×20ピクセルのグリッド状に配置されます。ellipse()の直径はとりあえず15にしておきました。ellipse()のXとY座標は、「%」と「/」を使って計算します(X座標となる「(i%8)*20+10」は、iを8(横幅)で割った余りに20ピクセル掛けて、さらに10ピクセル足すことでellipse()が20×20のグリッドの中心に来るように位置調整しています)。最後に「port.write(pixelValue[i])」で、Arduinoへ各ピクセルの明るさの値を送信します。今回は画面をクリックしたらシリアル通信が開始されるようにしています。

次にArduinoの方に移ります。冒頭で書いたように、今回はマトリクスLEDを、ICを使わず直結します。個々のLEDはダイナミック点灯しているので、点灯時間の長さによって明るさを調整することになります。点灯時間が短ければ暗くなり、長くなれば明るくなります。つまり、Processingから送られて来た明るさの値(0〜255)を、個々のLEDの点灯時間に反映させるプログラムになるということです。マトリクスLEDとの接続方法や詳細については「Arduino マトリクスLED1」を参照してください。

Arduinoのプログラム:

//8x8の二次元配列を用意
byte matrix[8][8];

void setup(){
//出力ピンの設定、すべてオフにする
for(int i=2;i<=17;i++){
pinMode(i,OUTPUT);
digitalWrite(i,LOW);
}
//シリアル通信開始
Serial.begin(9600);
}

void loop(){
//シリアル通信(64個分のデータ)
if(Serial.available()>63){
for(int k=0;k<8;k++){
for(int l=0;l<8;l++){
//読み込んだ値を配列に代入
matrix[k][l]=Serial.read();
}
}
}

//各LEDの点灯制御
for(int i=2;i<=9;i++){
//列の点灯
digitalWrite(i,HIGH);

for(int j=10;j<=17;j++){
//行の点灯
digitalWrite(j,LOW);
//行の点灯継続時間
delayMicroseconds(1+matrix[i-2][j-10]);
//行の消灯
digitalWrite(j,HIGH);
//行の消灯継続時間
delayMicroseconds(256-matrix[i-2][j-10]);
}
//列の消灯
digitalWrite(i,LOW);
}
}


以前の「Arduino マトリクスLED1」とほぼプログラム内容は同じです。異なる部分は、シリアル通信と各LEDを点灯/消灯させる継続時間の部分です。用意する二次元配列は、boolean型ではなくbyte型(0~255の値なので)にしています。
シリアル通信上で干渉しないようにするため、Arduino基盤の0番ピンと1番ピンには何も接続しないことにしています(2〜17番ピンを使用)。シリアル通信では、Processingから送られてくる64個のデータをSerial.available()でカウントして、それぞれの値を予め用意しておいた二次元配列matrixに保存しておきます。送られてくるデータは0〜255(明るさの値)となります。そしてダイナミック点灯していく際に、明るさの値をdelayMicroseconds()に代入して、点灯継続時間と消灯継続時間に割り当てます。delayMicroseconds(0)としてしまうと、0マイクロ秒としては扱ってくれないので、delayMicroseconds()の括弧内に入れられる最小値は1にしてあります。最小1マイクロ秒の点灯時間かつ最大256マイクロ秒の消灯時間のときが最も暗くなるときです。その逆で、最大256マイクロ秒の点灯時間かつ最小1マイクロ秒の消灯時間のときが最も明るくなります。個々のLEDは257マイクロ秒ごとにダイナミック点灯していることになります。個々のLEDの点滅を300マイクロ秒程度にすると点滅しているようには見えないので、今回の257マイクロ秒周期で点滅させれば、ほぼ問題ないでしょう。

関連:
・「シリアル通信1〜5
・「Arduino マトリクスLED1
・「Processing Video(Webカメラ)

ロジクールストア(ウェブカメラカテゴリ)

8/09/2008

Processing Video (Webカメラ)

ProcessingのVideoライブラリを使用することで、パソコンに接続した(あるいは内蔵された)Webカメラからの映像を取り込むことができます。このライブラリを使用するには、パソコンにQuickTimeがインストールされている必要があるので、もしインストールされていない場合は、アップルのQuickTimeのサイトからダウンロード/インストールして下さい。
USB接続する外付けのWebカメラの場合は必要なドライバをメーカーのサイトなどからダウンロード/インストールして使用可能な状態にしておいて下さい。Webカメラがパソコンに内蔵されている場合は、そのまま使うことができるはずです。まずは、簡単な映像の取り込みかたから始めます。

*Windowsの場合、そのままの設定ではこのVideoライブラリを使用することができないことがあります。その場合、WinVDIG 1.0.1をインストールする必要があります。


//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;

void setup() {
size(200, 200);
//キャプチャする映像の設定
myCapture = new Capture(this, width, height, 30);
}

void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
}

//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}

//クリックでカメラセッティング画面になる
void mousePressed(){
myCapture.settings();
}


上記プログラムでは、画面サイズが200×200の正方形であるため、Webカメラでキャプチャされた映像は縦長になってしまうかもしれません。通常画面の比率は4:3(横:縦)であるため、もし比率を合わせるのであれば、320×240(4:3)などに合わせてください。
Capture()によって、親オブジェクト(thisのままでよい)と映像の幅と高さ、フレームレートを設定できます。映像が滑らかに動かない場合は、フレームレートを下げるか、画像サイズを縮小して調整して下さい。
キャプチャされた映像は、毎フレームごとにimage()によって画面内に配置されます。image()の括弧内の数値は、配置するX座標、Y座標となります。上記プログラムでは0,0に設定されているので、左上角の座標を基準に映像が画面内に配置されます。
captureEvent()は、Webカメラから信号が送られてくる度に作動します。read()によって、毎回送られてくる映像信号を読み込んでいます。
今回は最後にクリックするとsettings()によって、カメラのセッティング画面(Webカメラ用の設定アプリケーション画面)が現れるようにしてあります。ここで、カメラの解像度やコントラストなどの設定を行うことができるはずです。

次に映像にフィルタをかけてみるプログラムをしてみます。
画像用のfilter()というコマンドがあり、
THRESHOLD 白黒ニ値化:0.0~1.0(黒〜白)/初期設定0.5
GRAY    グレースケール:パラメータなし
INVERT   反転色:パラメータなし
POSTERIZE ポスタライズ:2~255(各チャンネルの色数の限定)
BLUR    ぼかし:指定半径範囲でぼかす
それぞれをfilter()の括弧内に入れれば、映像にフィルタをかけることができます。フィルタの種類の後にパラメータを入れることで、フィルタのかかり具合を調整することができます。
複数のフィルタを重ねて使うこともできます。ただ、フィルタの種類(特にBLUR)によっては処理速度に影響がでる場合があるので、適宜フレームレートや画素数などを調整する必要がでてくるときがあります。
以下は、キャプチャした映像にぼかしをいれノイズを取払い、その後白黒でニ値化し、白黒の単純な映像に変換するサンプルです。尚、映像の比率は4:3にすることにします。


「フィルタ(ぼかし+白黒ニ値化)をかけた映像(上画像)」


//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;

void setup() {
size(320, 240);//比率4:3
//キャプチャする映像の設定
myCapture = new Capture(this, width, height, 30);
}

void draw() {
//映像を画面に配置
image(myCapture, 0, 0);
filter(BLUR,1.8);//ぼかし
filter(THRESHOLD,0.7);//白黒ニ値化
}

//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}


次に、映像のモザイク化のプログラムをしてみます。画面サイズを320×240とし、横を32分割、縦を24分割し、10×10のモザイク処理をすることにします。まずloadPixels()によって映像の全ピクセルを読み込み、pixels[]によって選択したピクセルの色を取得します。取得した色をもとにrect()でモザイクの矩形を描くことにします。モザイク化されるには、必要なキャプチャ映像は結果的に32×24の解像度があれば済むので、予め32×24のサイズでキャプチャすることにします。


「モザイク映像(上画像)」


//ライブラリの取り込み
import processing.video.*;
//キャプチャする映像のオブジェクトを用意
Capture myCapture;

void setup() {
size(320, 240);//比率4:3
//キャプチャする映像を32×24に設定
myCapture = new Capture(this, 32, 24, 30);
//noStroke(); //モザイクの黒枠をなしにする場合
}

void draw() {
//キャプチャ画像の各ピクセルの色を
//塗色に割当て、矩形を描く
for(int i=0;i<32*24;i++){
fill(myCapture.pixels[i]);
rect((i%32)*10,(i/32)*10,10,10);
}
}

//映像の読み込み
void captureEvent(Capture myCapture) {
myCapture.read();
}


最終的に32×24のモザイクになるので、キャプチャする画像も同様の解像度にしておけば、処理速度が遅くならなくて済みます。pixels[]によってキャプチャされた映像の各ピクセルの色を取得します。32×24なので合計768ピクセル分となります。rect()による矩形も768個必要になるので、まずfill()で塗色を指定してから描きます。pixel[i]のiは画面左上から数えていき最後は右下のピクセルの番号になります。pixel[i]のiは0~767(合計768個)までの連続した数値なので、「%」と「/」を使ってXとYの座標値に変換します。変換したXとYの座標値をrect()に代入することで、320×240の画面に10ピクセル単位で横方向と縦方向に32×24のモザイク矩形として配置されます。今回はnoStroke()を使っていないので、黒い枠のついたモザイク矩形にしています。


ドライバなしですぐにコンピュータに接続可能(UVC対応)なWebカメラとして以下のようなものがあります。
Macintosh/Windows兼用です。
      

関連:
Arduino+Processing マトリクスLED+Webカメラ」--Webカメラ映像をマトリクスLEDに映す。
Processing Webカメラを光センサとして使う」--点光源で画面内に線を描く。
Processing Webカメラ/定点記録画像」--Webカメラ映像を0.5秒おきに画像保存(JPEG)する。
Processing Webカメラ/カラートラッキング」--Webカメラを使い、色を手がかりに物体を追いかける。
Processing Webカメラ/モーショントラッキング」--Webカメラを使って動体検知する。


[目次:Processing関係]  [HOMEへ戻る]  [目次:Arduino関係]