INDEX(各項目ごとの目次)

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

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

10/30/2008

次回授業(11/01)について

次回の授業(11/01)では、今後制作する作品についてのチュートリアル/ディスカッションを行いたいと思います。
各自の作品についてのアイデア、スケッチ、ダイヤグラム、写真、参考文献など、作品の方向性を示すものを持参してください。

尚、来週11/08は休みです。

10/25/2008

Processing-Arduino ネットワーク制御

今回は、ProcessingのNetworkライブラリを使って、ネットワーク越しに複数のクライアントコンピュータから、サーバコンピュータに接続されたArduinoのサーボとLEDを操作することにします。ネットワーク上では、情報を提供する側となるサーバコンピュータに複数のクライアントコンピュータが接続されているような状態になります。



まず、上図のようにローカルネットワーク内での通信を行ってみます(後半にローカルネットワーク外からの通信サンプルを記載しておきました)。

ひとつのクライアントからサーバへ信号が送られると、サーボの角度やLEDの点灯状態が変化しますが、サーバはクライアントからの信号を受け取るだけではなく、現在のサーボの角度やLEDの状態(オン/オフ)についての情報も各クライアントへ送り返します。そうすることで、各クライアントは現在のサーボやLEDの状態を把握しながら制御することができます。
サーバコンピュータとクライアントコンピュータはインターネット越しに通信され、サーバコンピュータとArduinoはシリアル通信されます。


(Processingの画面:画面上半分がサーボ用スライダ、下半分がLED用ボタン)

Processingの画面には、上半分がサーボ用のスライダ、下半分にLED用のボタンを配置することにします。スライダは0~255の値を送信し、ボタンは押すとオン(緑)の状態になり、もう一度押すと白(オフ)に戻ります。あるクライアントがボタンを押せば、サーバとその他のクライアントのボタンの色も同時に変わります。サーバからのコントロールも可能です。

Arduinoでは、サーボの値とLEDの値をサーバコンピュータからシリアル通信を通してデータ受信します。以下のプログラムでは、サーボは3番ピンと接続しPWMで制御することにします(サーボ制御の方法については、「Arduino サーボ制御」を参照して下さい)。LEDは13番ピンに接続しデジタル出力でオン/オフ制御することにします。


Arduinoのプログラム:

//サーボ用変数を用意
int servoVal;
//LED用変数を用意
int ledVal;

void setup(){
//シリアル通信開始
Serial.begin(9600);
//13番ピンをデジタル出力に設定
pinMode(13,OUTPUT);
}

void loop(){
//データが二個きたら(1個より多ければ)
if(Serial.available()>1){
//サーボの回転値として読み込む(0~255)
servoVal=Serial.read();
//LEDの点灯状態(0:OFF,1:ON)
ledVal=Serial.read();
//合図用データ送信
Serial.print('A');
}
//3番ピン(PWM):アナログ出力(サーボ)
analogWrite(3,servoVal);
//13番ピン:デジタル出力(LED)
digitalWrite(13,ledVal);

//0.02秒周期にする
delay(20);
}



「サーバのプログラム」:
サーバ側のプログラムでは、ネットワークとシリアル通信の二つのライブラリが必要となります。スライダは横方向(X座標)に動かし256段階あるので、画面サイズの横幅も256ピクセルにしてあります。ドラッグのためのプログラムは、mouseDragged()を使わず、startDrag(名前は任意)というフラグを用意し、mousePressed()でマウスを押したときにフラグがtrueになり、ドラッグが開始されたことになり、mouseReleased()でマウスが放されたときにドラッグ終了になり、同時にフラグもfalseになるようにしておきます。つまりフラグstartDragによって、ドラッグしているかどうかを判別することになります。ドラッグしていなくてもマウスボタンを押し続けている限りドラッグ中と見なされるので、その間データを送信し続けます。
あまり高速での通信ができないためフレームレートを10にしています。環境に応じてフレームレートを調整してみて下さい(サーバとクライアントのプログラム両方)。
サーバとクライアントの間では、文字列で送受信しています。文字列に含まれるデータは:

サーボの値 + コンマ + LEDの値 + 改行コード

であり、たとえば

"155,1\n"

のような連続した文字列になります。サーボの値は0~255の数値、LEDの値は0か1になり、その間をコンマで区切り(デリミタ)、最後の部分に「\n」改行コードを付け加えて送信します。文字「\n」は、アスキーコード表で十進数の「10」に相当します。受信の際には、readStringUntil(10)を使うことで、改行コード「\n」つまり「10」までをひとまとまりのデータとして読み込み、その文字列データをtrim()で改行コードを取り除き、split()でコンマをもとに配列に分解し、int()で文字列の数値を整数化し、それぞれの値に代入します(文字列を分解して数値化する方法は「Arduino-Processing シリアル通信5」でも説明してあります)。
サーバのプログラムが開始したら、「s」キーを押してArduinoとのシリアル通信を開始します。

Processing サーバのプログラム:

//ネットワークライブラリの取り込み
import processing.net.*;
//シリアル通信ライブラリの取り込み
import processing.serial.*;

//サーバのインスタンス
Server server;
//クライアントのインスタンス
Client client;
//シリアル通信のインスタンス
Serial port;

//サーボの変数
int servoVal;
//LEDの変数
int ledVal;
//ドラッグ中かどうかのフラグ
boolean startDrag=false;

void setup(){
//画面サイズ
size(256,200);
//フレームレートを遅めに設定
frameRate(10);
//サーバの設定(ポート:12345)
server = new Server(this, 12345);
//シリアルポート設定
port=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
//矩形描画を中央配置に設定
rectMode(CENTER);
//外形線なし
noStroke();
}

void draw() {
//クライアントからのデータ受信
client = server.available();
//クライアント受信内容が空ではないとき
if (client != null) {
//文字列データの読み込み(改行コードまで)
String input=client.readStringUntil(10);
//文字列データの改行コードを取り除く
input=trim(input);
//文字列データを整数の配列に変換
int[] data = int(split(input, ','));
//配列の最初の値をサーボ変数に代入
servoVal=data[0];
//配列の次の値をLED変数に代入
ledVal=data[1];
}

//ドラッグ中
if(startDrag){
//サーボ変数にマウスX座標値を代入(最小値:0、最大値:255)
servoVal=constrain(mouseX,0,255);
//クライアント側へ送信(サーボの値、コンマ、LEDの値、改行コード)
server.write(servoVal+","+ledVal+"\n");
}

background(0);//背景(黒)

fill(80);//スライダ溝の塗色(グレー:80)
rect(width/2,50,width,50);//スライダ溝の矩形描画
fill(255);//スライダの塗色(白)
rect(servoVal,50,10,50);//スライダの矩形描画

//LEDボタンの色切替(0:オフ,1:オン)
if(ledVal==1){ //オンの場合
fill(0,255,0);//緑にする
}else{ //オフの場合
fill(255); //白にする
}
//LED用のボタン描画
rect(width/2,150,50,50);
}

//シリアル通信処理
void serialEvent(Serial p){
//合図用データが1個来た場合(0個より多い場合)
if(port.available()>0){
//合図用データを読込んバッファを空にする
port.read();
//サーボの値とLEDの値をシリアル通信で出力
port.write(servoVal);
port.write(ledVal);
}
}

//キーを押した場合
void keyPressed(){
//「s」キーの場合
if(key=='s'){
//シリアル通信開始用データ送信
port.write(servoVal);
port.write(ledVal);
}
}

//マウスボタンを押した場合
void mousePressed(){
//LED用のボタン矩形内にマウスがある場合
if(mouseX>width/2-25 && mouseX<width/2+25 && mouseY>125 && mouseY<175){
//LED点灯切替処理
if(ledVal==0){//オフの場合
ledVal=1; //オンにする
}else{ //オンの場合
ledVal=0; //オフにする
}
//クライアント側へ送信(サーボの値、コンマ、LEDの値、改行コード)
server.write(servoVal+","+ledVal+"\n");
}
//スライダ部分の場合
if(mouseY>25 && mouseY<75){
//ドラッグのフラグをtrueにする
startDrag=true;
}
}

//マウスを放した場合
void mouseReleased(){
//ドラッグのフラグをfalseにする
startDrag=false;
}




「Processing クライアント側のプログラム」:

//ネットワークライブラリを取り込む
import processing.net.*;
//クライアントのインスタンス
Client client;

//サーボ用変数を用意
int servoVal=127;
//LED用変数を用意
int ledVal=0;
//ドラッグ中かどうかのフラグ
boolean startDrag;

void setup() {
size(256, 200);
frameRate(10);
//サーバのIPアドレス、ポートの設定
//(「10.0.1.2」の部分は適宜変更)
client = new Client(this, "10.0.1.2", 12345);
rectMode(CENTER);
noStroke();
}

void draw(){
//サーバからのデータ受信
if (client.available() > 0) {
String input = client.readStringUntil(10);
input = trim(input);
int[] data = int(split(input, ','));
print(data);
servoVal=data[0];
ledVal=data[1];
}

//ドラッグ中の処理
if(startDrag){
servoVal=constrain(mouseX,0,255);
client.write(servoVal + "," +ledVal + "\n");
}

//描画処理
background(0);
fill(20);
rect(width/2,50,width,50);
fill(255);
rect(servoVal,50,10,50);
if(ledVal==1){
fill(0,255,0);
}else{
fill(255);
}
rect(width/2,150,50,50);
}


void mousePressed(){
if(mouseX>width/2-25 && mouseX<width/2+25 && mouseY>125 && mouseY<175){
if(ledVal==0){
ledVal=1;
}else{
ledVal=0;
}
//サーバへ送信(サーボの値、コンマ、LEDの値、改行コード)
client.write(servoVal + "," +ledVal + "\n");
}

if(mouseY>25 && mouseY<75){
startDrag=true;
}
}

void mouseReleased(){
startDrag=false;
}



クライアント側のプログラムでは、setup(){...}内でサーバのIPアドレスを指定する必要があります。上のプログラムでは「10.0.1.2」になっていますが、適宜変更してください。通常ローカルネットワークであれば「127.0.1.2」や「192.168.1.2」、あるいはルーターやAirMacなどを使っていれば、「10.0.1.2」などになっているかもしれません。サーバに設定したコンピュータのIPアドレスを調べるには、MacOSXであれば、「システム環境設定>ネットワーク」を開き、AirMacを使用している場合は「AirMac」を選択、ケーブル接続している場合は「内蔵Ethernet」を選択し、「TCP/IP」タグを選択すると2段目あたりに「IPアドレス:10.0.1.2」などと表示されています。Windowsの場合は、コマンドプロンプトを開いて、「ipconfig」と打ってリターンすれば、幾つかの情報が現れ「IP Address....10.0.1.2」などと表示されるはずです。



「外部からの接続方法」:
ルータを通してインターネットに接続している場合、ローカルネットワーク外から通信するには、ルータのポートマッピングやサーバコンピュータのファイヤーウォールの解除設定する必要がでてきます。
通常、インターネットプロバイダからグローバルIPアドレスがひとつ与えられています。各自のパソコンからグローバルIPアドレスを調べるには以下のようなサイトで調べることができます。
http://dog.tele.jp/lookup.php
「あなたのパソコンのグローバルIPアドレスは」と書かれている場所に表示されるはずです。
あるいは、
http://www.ugtop.com/spill.shtml
のサイトの「現在接続している場所(現IP)」の欄に同じアドレスが表示されるはずです。
このグローバルIPアドレスをメモしておきます。


「接続例」:
以下は、ローカルネットワーク内のひとつのコンピュータをサーバに設定し、ローカルネットワーク外から通信をするための接続例です。例えば、仕事場や学校のコンピュータから、自宅にあるサーバに設定したコンピュータにアクセスする方法です。



上画像では、ADSLモデム-ルータを使用してインターネットに接続しており、さらにそのADSLモデム-ルータにAirMacをケーブルで接続しています。そして複数あるコンピュータは、AirMacの無線通信でインターネットに接続しています。
このネットワークのグローバルIPアドレスは、先ほど調べた方法により「219.196.xxx.xxx」になっています(実際のアドレスに置き換えてください)。「モデム-ルータ」によって、グローバルIPアドレスがプライベートIPアドレスに変換され、複数のプライベートIPアドレスに分けられます(「192.168.xxx.xxx」のようなアドレス)。さらに、AirMacにおいてもルータ機能があるため、さらに細かなプライベートIPアドレスに分けられます(「10.0.1.xxx」のようなアドレス)。
ここでは、二つのルータによって二段階にIPアドレスが割り振られていますが、AirMacを「ブリッジモード」に切り替えることで、以下のようにAirMacのルータ機能を使わないネットワークに変更することができます。



「ブリッジモード」:
「ブリッジモード」は、コンピュータから「AirMacユーティリティ」を開いて変更することができます(ただし、変更できる権限が必要です)。「ブリッジモード」にすることで、AirMacはIPアドレス(「10.0.1.xxx」のようなアドレス)を割り振らなくなるので、元々の「モデム-ルータ」が割り振るアドレスを使うことにします(「192.168.xxx.xxx」のようなアドレス)。ただし、このままだと「モデム-ルータ」が自動的にプライベートIPアドレスをそれぞれのコンピュータに割り振ってしまうので、使用しないコンピュータなどがあるときは、プライベートIPアドレスが入れ替わってしまうことがあります。
そのため、サーバにしたいコンピュータには固定したIPアドレスを与えます。以下のように「コンピュータC」に固定のIPアドレス「192.168.3.10」を与えて、サーバとして機能させることにします。



「固定IPアドレスにする」:
各コンピュータ上のIPアドレス設定では、「DHCPサーバを参照」や「DHCPサーバを使用」というように、ルータから自動的にIPアドレスが割り振られる設定になっていることが多いと思います。MacOSXの場合、「システム環境設定>ネットワーク」へ行き、AirMac(あるいはEthernet:現在インターネットに接続している方法を選択)を選択し、「TCP/IP」の項目内で設定できます。サーバ用に使うコンピュータにおいては、このIPアドレス設定の部分を、「手入力」に変更し、指定したIPアドレスを使うように設定し直します。
Windows XPの場合は、「コントロールパネル>ネットワーク接続」で、使用しているネットワーク接続(「ワイヤレスネットワーク接続」など)のプロパティを右クリックで開き、「インターネットプロトコル(TCP/IP)」を選択しプロパティボタンを押し、「IPアドレスを自動的に取得する」に設定されている部分を「次のIPアドレスを使う」に切り替えて、以下の設定を入力していきます。

上図の場合は、ルータのIPアドレスが「192.168.3.1」になり、AirMacが「192.168.3.2」、以下に続く各コンピュータは「192.168.3.3」、「192.168.3.4」というように最後の数値がひとつずつ増えていきます。IPアドレスが重ならないように、固定するIPアドレスを「192.168.3.10」に設定しておきます(1~254まで可)。サブネットマスクは自動的に「255.255.255.0」になるはずです。ルータのIPアドレス(ゲートウェイ)は、「DHCPサーバを参照」の時と同じなので「192.168.3.1」を記入します。「DNS」あるいは「DNSサーバ」の項目については、先ほど調べたグローバルIPアドレスである「219.196.xxx.xxx」を記入します(グローバルIPアドレスは、実際に調べたアドレスを入れてください)。サーバ用のコンピュータの設定は以上です。


「ポートマッピング設定」:
もうひとつしなければならないことは、ポートマッピング(ポート転送/ポートフォワーディング)の設定です。回線に接続しているルータ自体の設定を変更する必要があります。通常コンピュータ上のブラウザからルータのアドレスにアクセスし操作するようになっています(各ルータのマニュアルを参照してください)。大抵の場合は、「詳細設定」のような項目に入っていると思います。
プロトコル、ポート、転送先のIPアドレス(先ほど固定したサーバ用のIPアドレス)を入力する必要があります。プロトコルは「TCP/UDP」を選択し、WAN側とLAN側のポートは同じものを入れておきますが、今回の場合Processingのコードでポートを「12345」に設定しておいたので、それを入力することにします(「12345」〜「12346」までというように範囲指定する入力にしておきます)。転送先IPアドレスは、固定した「192.168.3.10」を入力しておきます。ポートマッピングの設定は以上です。尚、ポートは、0~65535までの番号が入れられますが、0~1023までは使用目的が決められているので、あまりつかわない方がいいと思います。

ポートマッピングによって、ポート「12345」(あるいは「12346」)を通してローカルネットワーク外からグローバルIPアドレス「219.196.xxx.xxx」に送られた信号は、サーバ用コンピュータのプライベートIPアドレス「192.168.3.10」に転送されることになります。

Processingのクライアント用のプログラム内の、

client = new Client(this, "219.196.xxx.xxx", 12345);

IPアドレス部分をグローバルIPアドレス「219.196.xxx.xxx」(実際に調べたアドレスを入れてください)に書き換えればローカルネットワーク外から通信できるようになります。

参照:YahooBBのモデムのポート転送設定方法


「外部から通信できない場合」:
ファイヤーウォールによって、外部からの通信をブロックしている場合があるので、ファイヤーウォール設定を解除して通信してみてください。ただし、セキュリティ上危険になるので注意してください。

尚、同じローカルネットワーク内にある別のコンピュータからは通信できないので(例えば上図の「コンピュータA」とサーバの「コンピュータC」との通信はできない)、異なるグローバルIPアドレス(外部)から通信してください。「コンピュータA」と「コンピュータC」を通信させる場合は、前半で説明したローカルネットワーク内での通信方法を利用してください。



10/23/2008

Arduino書籍:「Getting Started with Arduino」


Getting Started with Arduino

Arduinoの本「Getting Started with Arduino」が、日本のアマゾンからも購入(予約購入)できるようになりました。

その他、Arduino関連の本であれば、主に以下のようなものがあります。
・「Making Things Talk
・「Physical Computing: Sensing and Controlling the Physical World with Computers

Arduino-Processing BlueTooth通信+曲げセンサ

以前、ワイヤレス通信としてXbeeモジュールを用いましたが、もう一つワイヤレス通信として「BlueTooth」を用いる方法があります。今回は、SparkfunのBlueToothモジュール「BlueSmiRF Gold」を使います(国内ではストロベリーリナックスで販売)。Xbeeは3.3V電源を使用しますが、「BlueSmiRF Gold」は3.3V〜6.0Vまでの電源を使うことができるので、そのままArduinoにも接続しやすい仕様となっています(ただし、日本において、「BlueSmiRF Gold」は技術基準適合証明を受けていないため、実験や開発用のみで使用しなければならないようです)。Xbeeの場合は最低でも二つのモジュールを用意しなければ通信実験できないのですが、多くのノートパソコンにはBlueToothが搭載されているので、一つのBlueToothモジュールがあれば、とりあえずコンピュータから送受信することができます。


(上画像:「BlueSmiRF Gold」/from Sparkfun


今回は、Arduino基板に曲げセンサと「BlueSmiRF Gold」を接続し、コンピュータのBlueTooth機能を利用して、Processingとワイヤレスでシリアル通信してみます。曲げセンサについては、2本を背中合わせに貼り合わせて、まっすぐな状態から両方向に曲げて出力値が変化するように加工します。


「コンピュータとのBluetooth接続設定」
まず、「BlueSmiRF Gold」とコンピュータのBluetoothの接続設定を行います。
「BlueSmiRF Gold」には以下のように6本の端子があります。

CTS:送信要求端子(非接続またはRTS端子へ)
PWR:電源端子(Arduino 5V端子へ)
GND:グランド端子(Arduino GND端子へ)
TX :送信端子(Arduino RX:0番端子へ)
RX :受信端子(Arduino TX:1番端子へ)
RTS:受信準備完了端子(非接続またはCTS端子へ)

「BlueSmiRF Gold」のPWR端子とGND端子をArduinoの5V端子とGND端子に接続し、USBを通して電源供給します(あるいは、外部電源でもかまいません)。そうすれば、「BlueSmiRF Gold」の赤色のLEDが点滅し始めます。他の端子については、今のところ接続する必要はありません。

MacOSXの場合、
・メニューバー右端のBluetoothアイコンをクリック。
・「Bluetooth:入」を選択し機能をオンにする。
・さらに「Bluetoothデバイスを設定...」を選択する。
・「Bluetooth設定アシスタント」の画面が現れる。
・「続ける」を押していき、「任意のデバイス」を選択。
・デバイスが検索されたら「パスキーオプション」を押す。
・「このデバイスではパスキーを使用しない」を選択し「OK」を押す。
・「続ける」を押していき、最後に「終了」を押して完了。

Windowsの「Bluetooth設定」の場合、
アプリケーションを立ち上げて「新しい接続」を押します。「新しい接続の追加ウィザード」の画面で、「エクスプレスモード」を選び「次へ」を押し、「FireFry-D39A」というようなデバイス名で「BlueSmiRF Gold」を認識します。「次へ」を押すとポートが「COM40」あたりに設定されます。設定されれば以下のような画面になります。

「FireFry-D39A」を選択しダブルクリックすれば「接続」しますが、ここでは「接続」せず「ハイパーターミナル」上で「接続」することにします。

Bluetoothが内蔵されていないコンピュータの場合は、以下のようなBluetooth USBアダプタをコンピュータに接続する必要があります。




「Zterm/ハイパーターミナルの設定」
「BlueSmiRF Gold」の赤色のLED点滅が緑色のLED点灯に変われば通信接続されたことになります。
ただし「BlueSmiRF Gold」のデフォルトの通信速度(ボーレート)が115200bpsであるため、9600bpsに設定し直すことにします。そのためには、「BlueSmiRF Gold」の内部設定をATコマンドによって変更します。ATコマンドを使うには、MacOSXなら「ZTerm」、Windowsなら「ハイパーターミナル」などのターミナルアプリケーションを使って送信すると便利です。
「BlueSmiRF Gold」を電源に接続し、コンピュータのBluetooth接続設定をした後、「ZTerm」(MacOSX)あるいは「ハイパーターミナル」(Windows)を起動します。

MacOSXの場合:
ZTermのDial>Directry...を選択すると以下の画面が現れます。

「Dial Directory」画面上の「New」ボタンを押すと以下のような別画面が現れます。

「Service Name:」の欄に任意名を記入します。「Local Echo」にチェックを入れます。その他は上のような設定でも大丈夫です。「OK」ボタンを押します(「Dial Directory」画面上の中央上の「Connection」ボタンでこの画面に戻ることができます)。
「Settings>Terminal...」あるいは「Dial Directory」画面上の「Terminal」ボタンを押すと以下の画面が現れます。

上のような内容で設定し「OK」ボタンを押す。
次に、「Settings>Modem Preferences...」を選択すると以下の画面が現れます。

ここで、画面上段の「Serial Port:」がBluetoothのシリアルポート(「/dev/tty.FireFly-D39A-SPP-1」など)になっているか確認してください(なっていなければ選択する)。「OK」ボタンを押し、「Dial Directory」画面に戻ります。「Dial」ボタンを押して通信接続します。接続中は、「BlueSmiRF Gold」の緑色のLEDが点灯します。接続されない場合は、「BlueSmiRF Gold」の電源を入れなおすか、「Zterm」を再起動してみてください。

Windowsの場合:
ハイパーターミナルを立ち上げます。

この画面上で、「名前:」に接続名(任意名)を記入し、「OK」を押します(次回接続するときは、「キャンセル」を押し、メニューバーの「ファイル>開く」から保存した設定ファイルを選択してください)。


「接続方法:」の欄で、先ほどの「Bluetooth設定」で割り当てられたポート「COM40」を選択し「OK」を押します。


「ビット/秒:」を「9600」、「フロー制御」を「なし」、「適用」と「OK」を押します。
この設定ウィンドウが閉じると自動的に接続が開始されますが、メニューバーの「通信>切断」で通信を中断し、「ファイル>プロパティ」をクリックし、以下の画面を出します。


「ASCII設定」ボタンを押すと、さらに以下の画面が現れます。


上画像のようにチェックをいれます。「OK」を押して戻ります。
メニューバー「通信>電話」をクリックし、通信を開始します。
通信が開始されれば、「BlueSmiRF Gold」の緑のLEDが点灯します。
後は、ATコマンドを入力していきます。


「ATコマンド入力/通信速度の設定変更」
コンピュータ側のBluetoothと接続され、「BlueSmiRF Gold」の緑色のLEDが点灯すれば、以下のようにATコマンドを入力していきます。

$$$

ドルを三回(最後にリターンキーは押さない)を入力すると「CMD」という返事が表示され、ATコマンドモードに切り替わり、緑のLEDが点灯しつつ赤いLEDが点滅し始めます。
注意しなければいけないことは、「BlueSmiRF Gold」にはタイマー機能(デフォルト:60秒)があり、電源を入れてから60秒以内に「$$$」を入力する必要があります。時間切れになると、赤いLEDの点滅速度が遅くなります。「CMD」が表示されなかったり、赤いLEDが高速に点滅しないときは、一旦通信を切断し、「BlueSmiRF Gold」の電源を切って再接続した後、60秒以内に再度「$$$」を入力してみてください。あるいは、以下のように、このタイマー機能の時間を設定し直すことも可能です。

ST,100

を入力し「リターンキー」を押せば、タイマーを100秒に設定することができます(「ST,」の後に数値を入れることで制限時間を設定できます)。ただし、「ST,」の後に「0」を入力すると「遠隔設定不可」、「255」を入力すると「時間制限なし」になります。

通信速度(ボーレート)を9600に変更するには、

SU,96

を入力し「リターンキー」を押します(「SU,」の後にボーレートの最初の2桁を入力、9600の場合「96」、4800の場合「48」を入力)。「AOK」が表示されれば、変更されたことになります。変更内容を確認するには、

D

を入力し「リターンキー」を押します。そうすると各設定が以下のように表示されます。

***Settings***
BTA=00066600D39A
BTName=FireFly-D39A
Baudrt=9600
Parity=None
Mode =Slav
Authen=0
Encryp=0
PinCod=1234
Bonded=0
Rem=NONE SET

「Baudrt=9600」になっているので、通信速度(ボーレート)は9600に変更されています。ATコマンドモードを終了するには、

---

というように、ハイフンを3回入力し、「リターンキー」を押してください。そうすると「END」という返事がきます。
その他のコマンドについては、
http://www.sparkfun.com/datasheets/RF/RN_BlueportII-ref-guide.pdf
に書いてあります。「BlueSmiRF Gold」の基本設定は以上です。
尚、「ZTerm」やATコマンド入力については、「Arduino+Xbee Shield/Processing+XBee Explorer USB」においても説明があります。


(「ZTerm」のATコマンド入力画面)


「曲げセンサの接続方法」
次は、曲げセンサについてです。通常、曲げセンサはまっすぐな状態の時に抵抗値が低く、曲げると抵抗値が高くなる特性があります。反対方向に曲げてもそれ以上抵抗値は変化しないので、曲げる方向は一方向に限られてしまいます。2本の曲げセンサを背中合わせに貼り合わせて1本として使えば、まっすぐな状態からどちらの方向に曲げても抵抗値が変化するようになります。曲げセンサの通電性のある面を外側にし、両面テープなどで貼り合わせ、それぞれの端子の部分は互いにショートしないようにビニルテープや熱収縮チューブなどで絶縁しておきます。
ひとつの曲げセンサにプルアップ抵抗(10KΩ)を取付け、もうひとつの曲げセンサにはプルダウン抵抗(10KΩ)を取付けます(プルアップ/プルダウン抵抗については「センサについて」を参照)。そうすることで、一方へ曲げると読み取られる電圧は下がり、逆方向へ曲げると電圧が上がるようになります。それぞれ読み取った値をプログラム上で合成しProcessingへ送信します。Arduinoのアナログ入力analogRead()で読み込むと、一方の値が約200~500に変化し、もう一方が約500~800に変化するので、合成すると約700~1300前後で値が変化することになります。まっすぐな状態のときは、約1000前後になります。
ちなみに、「Bi-directional Flexible Bend Sensor」という両方向性の曲げセンサがあります。


「スタンドアロン/外部電源の接続方法」

今回はワイヤレス通信なのでコンピュータにUSB接続せずに、外部電源として乾電池006P(9V)を用いスタンドアロンで操作できるようにします。
抵抗を取り付けた曲げセンサを、以下のようにArduinoのアナログ端子の0番ピンと1番ピンに接続します。
Arduinoへプログラムをアップロードする際には、Bluetoothモジュールを外して行って下さい。同時に、Arduino基板上の「USB-EXT」のジャンパピンも「USB」側に差込んでアップロードしてください。
アップロード後は、Arduino基板とBluetoothモジュールを以下のように接続し、「USB-EXT」のジャンパピンを「EXT」側に差し込んでください。




「Arduinoのプログラム」

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

void loop(){
//変数を用意し、二つの読取り値を合成して代入
int val=analogRead(0)+analogRead(1);

//合図用データが届いたら
if(Serial.available()>0){
//合成した値を文字列(改行コード付き)で送信
Serial.println(val,DEC);

//バッファを空にしておく
Serial.read();
}
}



Arduinoからは、値を文字列として送信します。文字列にすることで、大きな値をそのままProcessingへ送信することができます(文字列でシリアル通信する方法については「Arduino-Processing シリアル通信5」を参照して下さい)。


「Processingのプログラム」
Processingの方は、読み取った値に応じて矩形が左右に動く単純なプログラムにします。Arduinoからは改行コードを含んだ文字列データが届くのでbufferUntil()を用い、改行コードまでをひとまとまりのデータとしてreadStringUntil()で読み込み、不要な改行コードをtrim()で取り除き、int()で整数値化し、最終的にmap()でオフセットや最小値/最大値を設定してX座標に代入します。少しゆとりをみて、合成された読み取り値の最小値を500、最大値を1500、図形のX座標値となる最小値を0、最大値を画面幅の600に設定することにします。map()で得られる値はfloat(小数)になるので、X座標用の変数xもfloat型にしておきます。
プログラムを実行し、マウスクリックでシリアル通信を開始することにします。


//シリアル通信ライブラリを取り込む
import processing.serial.*;
//ポートのインスタンス
Serial port;
//X座標用の変数(小数)
float x;

void setup(){
//横長の画面に設定
size(600,200);
//シリアルポート設定(Bluetoothのポート)
port=new Serial(this,"/dev/tty.FireFly-D39A-SPP-1",9600);

//「10」(ラインフィード:改行コード)が来る度に
//serialEvent()を呼び出す
port.bufferUntil(10);
}

void draw(){
//背景
background(100);
//矩形描画
rect(x,100,20,20);
}

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

//文字列データが空ではないとき
if(stringData!=null){
//文字列データに含まれる改行記号を取り除き整数にする
int val=int(trim(stringData));
//値のオフセット、最小値、最大値を設定しxに代入
x=map(val,500,1500,0,600);
//合図用データ送信
port.write('A');
}
}

//マウスをクリックしたらシリアル通信開始
void mousePressed(){
//通信開始用データ送信
port.write('A');
}

10/20/2008

Processing ライブラリのインストール先(v149以降)

現在Processingの最新バージョンは152になっており、いくつかの内容変更があります。特にProcessing 149以降では、ダウンロードしたライブラリをインストールする際(例えば、サウンドライブラリである「minim」など)、スケッチフォルダ内に「libraries」というフォルダを作成し、そのなかにダウンロードしたライブラリを入れるようになりました。
例えば、「minim」の場合なら、ダウンロードした「minim」というフォルダを、MacOSの場合、/Users/username/Documents/Processing/librariesの中に入れるということになります(「username」部分は各ユーザの名前のディレクトリです)。Macintosh HD>ユーザ>各ユーザ名>書類>Processing>libraries>minimという感じです。

追記:
バージョン155以降では、「libraries」フォルダがない場合には自動的に作成されるようになったようです。

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」(複数の値を文字列で送信する)

10/17/2008

Arduino+Xbee Shield/Processing+XBee Explorer USB

Arduinoにはワイヤレス通信するためのXbee Shieldがあります。今回はArduinoのXbee Shieldのサイトを参考に簡単な通信実験から始めたいと思います。Xbee Shiledを装着したArduino基板が2個必要になります。


(Xbee Shiledを装着したArduino基板)

注意しなければいけないことは、Arduino基板にXbee Shiledを装着したままプログラムをアップロードする際、Xbee Shiled上にある二つのジャンパピン(二つの間には「XBEE/USB」と表示されています)を「USB」側に差し替えなければいけないことです(3本のピンのうち、USB側のピンと中央のピンの2本のピンに差し込まれている状態になります)。
尚、アップロード後は「XBEE」側のピンと中央のピンの2本のピンに差し込まれている状態に戻してください。


「二つのArduino間での通信」
以下では、Xbee Shieldのサイトに従って、LEDの点滅実験を行います。一方のXbee Shiledを装着したArduino基板から、一秒おきに'H'か'L'の文字を送信し、受信したもう一方のXbee Shiledを装着したArduino基板の13番ピンに接続されたLEDが点滅する内容です。基本的には、通常のシリアル通信のプログラムと同じような内容になります。

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

void loop(){
  Serial.print('H');//「H」を送信(点灯)
  delay(1000);      //1秒待つ
  Serial.print('L');//「L」を送信(消灯)
  delay(1000);      //1秒待つ
}

送信側は一方的に'H'と'L'を1秒間隔で送信するだけです。受信側は、送信側からのデータが届いたら読み込みをし、データが「H」であれば13番ピンをHIGHで出力し、そうでなければLOWで出力するプログラムになります。

受信側Arduinoのプログラム:
int val;//受信データ用の変数を用意

void setup(){
  //シリアル通信開始
  Serial.begin(9600);
  //13ピンをデジタル出力に設定
  pinMode(13,OUTPUT);
}

void loop(){
  if(Serial.available()>0){ //データが来たら
    val=Serial.read();    //データを読み込み、valへ代入
  }
  if(val=='H'){           //valが「H」の場合
    digitalWrite(13,HIGH);//点灯
  }else{                  //valが「L」の場合
    digitalWrite(13,LOW); //消灯
  }
}

乾電池などの外部電源でArduinoを作動させれば、それぞれスタンドアロンで通信し合います。Decimilaなどの旧型のArduino基板の場合、外部電源を使うにはArduino基板についている「USB/EXT」のジャンパピンを「EXT」側に差し替える必要があります(プログラムをアップロードする際には、パソコンとUSB接続し、ジャンパピンも「USB」側に差し替えて下さい)。



「コンピュータに接続したXbeeと通信」:
コンピュータにXbeeを接続し、Arduinoとワイヤレス通信するには以下のようになります。
Sparkfunで販売されている「XBee Explorer USB」を使うと簡単にコンピュータとUSB接続でき、Processingからワイヤレスにシリアル通信が可能になります。


(左:「XBee Explorer USB」、右:Xbeeを装着した状態)

以下では、先ほどの受信用のXbee Shieldを装着したArduino基板に対して、Xbeeモジュールを装着した「XBee Explorer USB」を通して、Processingからワイヤレスでシリアル通信してみます。
まず、「XBee Explorer USB」のシリアルポートを調べてみます。

import processing.serial.*;
println(Serial.list());

「XBee Explorer USB」をコンピュータに接続し、上記の二行のプログラムをランさせれば、「XBee Explorer USB」のシリアルポートが出力されるはずです。


「Processingのプログラム」
受信側となるArduinoのプログラムは先ほどと同じものを使い、送信側となるProcessingだけのプログラムを以下に書きます。マウスボタンを押したら点灯、放したら消灯する内容とします。

//シリアル通信ライブラリを取り入れる
import processing.serial.*;
//ポートのインスタンス
Serial port;

void setup(){
  //「XBee Explorer USB」のシリアルポート設定
  port=new Serial(this,"/dev/tty.usbserial-A8003VXd",9600);
}
void draw(){
  //特になし  
}

void mousePressed(){//マウスボタンを押したら
  port.write('H');  //「H」を送信(点灯)
}

void mouseReleased(){//マウスボタンを放したら
  port.write('L');   //「L」を送信(消灯)
}

プログラムの内容はこれまでのシリアル通信と同じなので、ポートの設定、接続やジャンパピンの差し替えなどを間違わなければ特に問題はないと思います。



「Xbeeモジュールの設定/ATコマンド」
XbeeにATコマンドを送ることで、Xbeeモジュール自体の設定を確認したり変更することができます。ATコマンドをXbeeモジュールに送信するには、MacOSXなら「ZTerm」など、Windowsなら「ハイパーターミナル」や「Tera Term」などのターミナルアプリケーションで入力すると便利です(「ZTerm」と「ハイパーターミナル」の設定や使い方については、「Arduino-Processing BlueTooth通信+曲げセンサ」にも、説明があります)。

コンフィグレーションモードに入るには、
+++

プラスを3回入力し待機します(リターンキーは押さない)。そうすれば、
OK

という返事が返ってきます(ATコマンドモードでは、「+++」を押したあと1秒後に「OK」が返答され、さらに10秒以内に次のコマンドを送信しなければコマンドモードが自動的に終了してしまうので、返答がない場合は再度「+++」を押す必要があります)。さらに続けて、
ATID(リターンキーを押して送信)

と押せば、デフォルトの状態であれば、
3332

という数値が返ってきます。「3332」という数値は、そのモジュールのネットワークIDであり、このネットワークIDを変更すれば同じネットワークIDを共有しているXbeeモジュール間だけでの通信が可能になります(ひとつのモジュールだけでなく、相手になるモジュールも変える必要があります)。
設定されている通信速度を確認するには、
ATBD(リターンキーを押して送信)

と押せば、デフォルトであれば、
3

という数値が返ってきます。通信速度はそれぞれ
0:1200 bps
1:2400 bps
2:4800 bps
3:9600 bps
4:19200 bps
5:38400 bps
6:57600 bps
7:115200 bps

なので、デフォルトの「3」は9600 bpsということになります。
ATBD4(リターンキーを押して送信)

と打てば(「ATBD」の後に「4」を付け加える)、通信速度は「4」(19200)に変更されます(「OK」という返答がきます)。再度、
ATBD(リターンキーを押して送信)

と打てば、変更した内容を確認できます(この場合「4」という数値が返ってきます)。ただし、この場合電源が切れると設定内容は消えてしまいます。電源を切っても設定内容が戻らないようにするには、
ATWR(リターンキーを押して送信)

を変更後すぐに送信します(「OK」という返答がきます)。あるいは、
ATBD4,WR(リターンキーを押して送信)

という感じで、コマンドを複数合成して送信することもできます(「OK OK」という二つ分の返答がきます)。デフォルトの状態に戻すには、
ATRE(リターンキーを押して送信)

になるのですが、「WR」を付け加えていないので再度電源を入れたときには前回の状態に戻ってしまいます。
ATRE,WR(リターンキーを押して送信)

とすれば、電源を入れ直してもデフォルト状態は保持されます。
尚、コマンドモードから出るには、
ATCN(リターンキーを押して送信)

になります。
デフォルトでは、
ID:3332(ネットワークID)
CH:0x0C(チャンネル)
MY:0(そのモジュールのアドレス)
SH: (シリアルナンバー上位32ビット/モジュールごとに異なる)
SL: (シリアルナンバー下位32ビット/モジュールごとに異なる)
DH:0(送信先アドレス上位32ビット)
DL:0(送信先アドレス下位32ビット)
BD:3(通信速度:9600 bps)

に設定されており、ネットワーク、チャンネル、モジュールのアドレス、送信先アドレスがそれぞれ同じであるため、どのモジュール間でも通信可能です。逆に、ネットワークIDを変更してしまえば、他のモジュール群から干渉を受けずに通信し合うことも可能になります。あるいは、二つのモジュール間で送信先を互いに設定してしまえば、そのアドレスのモジュールだけとの通信が可能になります。そのためには、IDとCHは共有しておき、それぞれのモジュールアドレスを個別に設定しておきます。
ATMY1111,WR(リターンキーを押して送信)
OK OK(Xbeeからの返信)

とすれば、このモジュールの「MY」は「1111」に設定されたことになります(「WR」を付け加えたので、電源を落としても変更内容は記憶されます)。さらに送信先のアドレスを「2222」に設定するには、「DL」を「2222」に「DH」を「0」にします。
ATDL2222,DH0,WR(リターンキーを押して送信)
OK OK OK(Xbeeからの返信)

もう一方のほうも設定する必要があるので、「MY」を「2222」、「DL」を「1111」、「DH」を「0」にします。
ATMY2222,DL1111,DH0,WR(リターンキーを押して送信)
OK OK OK OK(Xbeeからの返信)

とします。こうすることで、「1111」のモジュールと「2222」のモジュールが互いに送信先を特定して通信し合うことができます。

Arduino Xbee Shieldサイトの説明によれば、「DH」を「0」、「DL」を「FFFF」に設定すれば、そのモジュールからの通信は、その他のすべてのモジュールによって受信可能になります。
また、送信先アドレス(上位ビットDHと下位ビットDL)が「FFFF」より大きい値(つまり「DH」が「0」以外の数値に設定したとき)、その「DH」と「DL」が相手モジュールの「SH」と「SL」に等しければ、相手モジュールのみに受信させることが可能になります。ただし、この場合も、ネットワークIDとチャンネルは同じでなければなりません。


「Ztermの設定」
以下は、MacOSXで「ZTerm」を使ったときの画面です。


ATコマンドを打つ画面。



メニューバー>Dial>Directory...をクリックすれば、上画面が現れます。「New」を押せば、新たな接続先を追加する画面(下画像)がでてきます。



「Service Name:」の欄に適当な名前を入れます。「Local Echo」にはチェックをいれておきます。チェックを外すと、自分の打った文字は画面に現れないので、チェックを入れておいた方がいいでしょう。Xbeeがデフォルト状態であれば、その他の項目は上画面のようになります。メニューバー>Setting>Connection...をクリックすることで、再度この画面が現れます。



メニューバー>Setting>Terminal...をクリックすれば、上画面が現れます。ここでは「Auto Line Feed」にチェックをいれておきます。チェックを外すと、ATコマンドが改行されなくなるので、チェックをいれておいたほうがいいでしょう。恐らく、MacOSXの改行コードは、「CR(キャリッジリターン:行頭に戻る)」だけなので、「LF(ラインフィード:次の行に移る)」も付け加えないと改行されなくなるからでしょう。

Zigbee開発ハンドブック (実践入門ネットワーク)
鄭 立
リックテレコム
売り上げランキング: 9866

DESIGNING ZIGBEE NETWORKS AND TRANSCEIVERS: The Complete Guide for Rf/Wireless Engineers
Shanin Farahani
Newnes
売り上げランキング: 21994

10/14/2008

次回授業(10/18):FURNI02



次回(10/18)の授業では、「身体と装置」に関するスライドショーを行います。その後、引き続き連続する姿勢/行為をもとに応用的な実験をします。
・パソコン、Arduino、入出力装置等を各自持参して来て下さい。

10/12/2008

Processing FileChooser2

以前「Processing FileChooser/ファイル選択画面の表示」でJava Swingを用いましたが、Processing 146以降からselectInput()によって、ファイル選択画面を通して任意の場所にあるファイルを読み込むことが簡単にできるようになりました。
以下は、「f」キーを押すとselectInput()で、ファイル選択画面を表示し、コンピュータの任意の場所にある画像を表示するサンプルです。表示された画像は、ドラッグすることで位置を変えられるようにしてあります。

//画像用インスタンス用意
PImage img;

//現在選択中のファイルパスの変数
String currentPath=null;
//画像配置座標の変数
int x,y;
//画像配置座標とクリック座標の差分の変数
int dx,dy;

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

void draw(){
  //背景描画(黒)
  background(0);
  //現在選択中のファイルパスが空ではないとき
  if(currentPath!=null){
    //画像描画
    image(img,x,y);
  }
}

//クリックしたら
void mousePressed(){
  //画像配置座標とクリック座標の差分を求めておく
  dx=x-mouseX;
  dy=y-mouseY;
}

//ドラッグ中
void mouseDragged(){
  //マウス座標に差分座標を加えた値を画像配置座標とする
  x=mouseX+dx;
  y=mouseY+dy;
}

//キーを押した場合
void keyPressed(){
  //「f」キーなら
  if(key=='f'){
    //ファイル選択画面を表示し選択したファイルパス取得
    String loadPath = selectInput();
    //ファイルパスが空の場合
    if (loadPath == null) {
      //「ファイルが選ばれてない」メッセージを出力
      println("No file was selected...");
      //ファイルパスを前回のファイルパスにする
      loadPath=currentPath;
    } 
    else {//ファイルパスが選択された場合
      //ファイルパスのドット以降の文字列を取得(拡張子名を取得)
      String ext = loadPath.substring(loadPath.indexOf('.') + 1);
      //拡張子が「jpg」または「png」なら
      if(ext.equals("jpg") || ext.equals("png")){
        //選択ファイルパスの画像を取り込み
        img = loadImage(loadPath);
        //現在選択中のファイルパスを更新
        currentPath=loadPath;
        //現在選択中のファイルパスを出力
        println(currentPath);
      }else{//拡張子が「jpg」または「png」ではないとき
        //「画像ファイルではない」と出力
        println("Not image file.");
      }      
    }
  }
}


ファイル選択画面上で選択したファイルのパスを取得したら、substring()によってパスの文字列末尾に含まれる拡張子を調べます。その際、indexOf()を使うことで、パスの文字列に含まれる「.」を手掛かりに、パスの文字列末尾の拡張子を抜き出します(indexOf()は、括弧内に入れた文字が文字列中の何番目にあるかを教えてくれます)。
今回は、拡張子が「jpg」か「png」であれば、loadImage()で画像を取り込み、次回のためにファイルパスを記憶させておきます。それ以外の拡張子の場合は、"Not image file."だけを出力します。

selectInput()以外に、フォルダを選択するためのselectFolder()や、保存先を指定するselectOutput()も加えられています。

----------------------------------
以下は頂いたコメントに対するサンプルです。
import java.awt.*;

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

void draw(){  
}

void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } else {
    println("User selected " + selection.getAbsolutePath());
  }
}

void mousePressed(){
  FileDialog fd = new FileDialog(new Frame(),"Choose a file");
  fd.setDirectory("/Users/username/Desktop");//ここのディレクトリを任意に変えてください。
  fd.setVisible(true);
  if(fd.getFile()==null){
    println("Canceled");
  }else{
    println("FILE NAME:"+fd.getFile());
    println("DIRECTORY:"+fd.getDirectory());
  }
}

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カメラを使って動体検知する。

Arduino タッチセンサ

今回は、ArduinoのPlaygroundサイト内のCapacitive Sensing(静電容量式)を参考に、タッチセンサをつくりたいと思います。基本的には、Arduino基盤に抵抗(1MΩ)を接続するだけです(その他ミノムシクリップや金属板などがあるといいかもしれません)。この方法によって、主に抵抗だけでセンサを容易につくることができます。指先などが入力用端子に近づくと静電容量が変化し、その変化量を読み取ることで判断する仕組みになります。
接続方法は以下の通りです。8番、9番ピンに抵抗を接続し、9番ピン側に入力用のタッチセンサとなる金属片を接続しておきます。金属片に指などで触れると感知するセンサとなります。紙などのシートで金属片を覆った上から触れても感知します。



まず以下のプログラムで実験してみることにします。指で金属板に触れると、9番ピンの読み取り値がLOWからHIGHへ変化していきます。HIGHになるまでの時間をカウントアップしていき、その変化量をシリアル通信でモニタリングしてみます。

void setup(){
//モニタリングのためシリアル通信開始
Serial.begin(9600);
//8番ピンをデジタル出力
pinMode(8,OUTPUT);
//9番ピンをデジタル入力
pinMode(9,INPUT);
}

void loop(){
//静電容量変化量の変数を用意
int a=0;
//8番ピンをHIGHで出力
digitalWrite(8, HIGH);
//指が触れたとき9番ピンがHIGHになるまでをカウント
while (digitalRead(9)!=HIGH){
//カウントする
a++;
}
delay(1);
//8番ピンをLOWにする
digitalWrite(8, LOW);
//モニタリング:値を出力
Serial.println(a);
}



モニタリング結果として、指で触れてない時は、

3
3
2
3
3
3
4
3
2
3

という感じで2〜4程度の値が確認されました。
指で触れている間は、

0
32
78
24
0
0
15
32
33
9

という感じで、5以上の値かつ、たまに0を出力していました。
値に多少ばらつきがあるので、プログラムに出力値を滑らかにするフィルタをつけくわえることにします。更に、指先を感知するごとに、13番ピンに接続されたLEDが点灯するプログラムも追加することにします。


int f=0;//フィルタ用変数

void setup(){
//モニタリングのためシリアル通信開始
Serial.begin(9600);
//8番ピンをデジタル出力
pinMode(8,OUTPUT);
//9番ピンをデジタル出力
pinMode(9,INPUT);
//LED点灯用に13番ピンをデジタル出力
pinMode(13,OUTPUT);
}

void loop(){
//静電容量変化量の変数を用意
int a=0;
//8番ピンをHIGHで出力
digitalWrite(8, HIGH);
//指が触れたとき9番ピンがHIGHになるまでをカウント
while (digitalRead(9)!=HIGH){
//カウントする
a++;
}
delay(1);
//8番ピンをLOWにする
digitalWrite(8, LOW);

//値を滑らかにするフィルタ式
f+=(a-f)/2;
//モニタリング:フィルタ値を出力
Serial.println(f);

//LED点灯のプログラム
if(f>5){//値が5より大きい場合点灯
digitalWrite(13,HIGH);
}else{ //それ以外消灯
digitalWrite(13,LOW);
}
}



フィルタ式を付け加えると、指を触れていないときの値は3程度であり、触れている時は

749
375
188
802
401
201
751
376
188

のように、ある程度大きな値が並んで出力されました。よって、LEDのオンとオフのしきい値を5にしておき、5より大きい値であればLEDを点灯させるプログラムにしてみました。1MΩの抵抗のかわりに10MΩの抵抗(より抵抗値が高い)を用いれば感度が高くなり、金属片と指先の距離が離れていても(数センチ)、充分反応するとサイトでは説明しています。

10/06/2008

次回授業(10/11):FURNI01



次回から、「姿勢」、「行為」、「行動」と関わる実験をしていきたいと思います。通常、ある目的やアイデアを最初に設定し、その目的を実現するために、表現方法や技術的解決を行います。プログラミングや電子工作の様々な実験を繰り返していると、「何のための技術であるのか?」という疑問は残るはずです。しかしながら、このゼミでは敢えて最初に目的を設定せず(目的の保留)、方法や技術あるいは表現の冗長な組合わせの実験を行い、その冗長な手続きをヒントに連鎖する「姿勢」の組合わせを導き出します。そして、複数の「姿勢」の組合わせによって、新たな「行為」の発見を試みたいと思います。

パソコン、Webカメラ、Arduino、センサ類、出力部品類を持参してください(学校にあるセンサや出力部品の利用も可)。

The Human Figure in Motion
The Human Figure in Motion
posted with amazlet at 09.03.31
Eadweard Muybridge
Dover Pubns
売り上げランキング: 499

10/04/2008

Processing QRコード/2次元コード

Processingのライブラリには、「QRCode」というものがあります。QRコードとは、以下のような2次元的なマトリクスを利用したコードです。バーコードよりは情報量が多く、様々な場面に用いられています。


このブログのURL情報が含まれたQRコード(上画像:qrcode.png)

Processingの「QRCode」ライブラリを用いることで、QRコードに含まれた情報を解読することができます。逆に、任意の情報のQRコードを生成するには以下のようなサイトで行うことができます。

http://qrcode.kaywa.com
http://qr.quel.jp

QRCode」ライブラリでは、上記サイトなどで直接生成したQRコード以外にも、Webカメラやデジタルカメラで撮影したQRコード(紙上に印刷したQRコード)を認識/解読することができます。尚、このライブラリを使うには「QRCode」ライブラリサイトからライブラリをダウンロード+インストールする必要があります。サイトの説明によれば、以下のようなコードでQRコードを解読することができます。予めQRコードの画像を用意して、スケッチフォルダ内dataフォルダに入れておいて下さい。
以下のサンプルは、上にあるQRコード(qrcode.png)を使って解読するコードです。無事QRコードが解読されれば、link()によって、自動的にこのブログのURLへジャンプするようになっています。


//ライブラリを取り入れる
import pqrcode.*;

//インスタンス名
Decoder decoder;

void setup() {
//オブジェクトの生成
decoder = new Decoder(this);
//イメージのロード
PImage img = loadImage("qrcode.png");
//イメージの解読
decoder.decodeImage(img);
}

void decoderEvent(Decoder decoder) {
//解読結果をテキストとして取り出す
String statusMsg = decoder.getDecodedString();
//テキストを画面に出力
println(statusMsg);
//テキストに書かれているURLへ移動
link(statusMsg, "_new");
}



QRCode」ライブラリのサイトには、Webカメラから撮影したQRコードを読み込んで解読するサンプルがあります。

http://www.shiffman.net/p5/pqrcode_files/Pqrcode_example.zip

このサンプルでは、「スペース」キーでカメラからのQRコードを画像として読み込み解読します。解読されたテキストは画面に文字として表示されます。「f」キーで、既に用意されているテスト用の画像を読み込んで解読します(「http://www.shiffman.net」と表示されるはずです)。「s」キーで、カメラセッティングの画面に切り替わります。
カメラでQRコードを撮影するときに、ピントがずれていると認識できないこともあるので、カメラを調整する必要があるかもしれません。

以下では、デスクトップ上あるいはその他の場所に保存してあるQRコードをファイルチューザーで選び、解読する実験をしてみます。ファイルチューザーについては、前回のブログ「Processing FileChooser/ファイル選択画面の表示」を参照して下さい。
マウスを押したら、ファイルチューザーのダイアログ画面が現れ、任意のQRコードを選択し、解読結果をProcessingのコンソールに表示します。

//JavaのSwingを取り込む
import javax.swing.*;

import pqrcode.*;

//解読用インスタンスを用意
Decoder decoder;

//画像インスタンスを用意
PImage pimage;

//選択ファイル名を用意し
//ファイル名を空にしておく
String getFile = null;

void setup(){
//とりあえず表示画面を400角に設定
size(400,400);
//解読用オブジェクトの生成
decoder = new Decoder(this);
//背景(黒)
background(0);
}

void draw(){
//選択ファイル名が空でないとき
if(getFile != null){
//ファイルを取り込む
fileLoader();
}
}

//マウスを押したら
void mousePressed(){
//選択ファイル取得処理
getFile = getFileName();
}

//ファイルを取り込むファンクション
void fileLoader(){
//選択ファイル名のドット以降の文字列を取得
String ext = getFile.substring(getFile.lastIndexOf('.') + 1);
//その文字列を小文字にする
ext.toLowerCase();
//文字列末尾がjpg,png,gif,tgaのいずれかであれば
if(ext.equals("jpg") || ext.equals("png") || ext.equals("gif") || ext.equals("tga")){
//選択ファイル名のイメージを取り込む
pimage = loadImage(getFile);
//背景(黒)
background(0);
//イメージ表示
image(pimage, 0, 0, pimage.width, pimage.height);
//イメージの解読
decoder.decodeImage(pimage);
}
//選択ファイルパスを空に戻す
getFile = null;
}

//ファイル選択画面、選択ファイル名取得の処理
String getFileName(){
//処理タイミングの設定
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
//ファイル選択画面表示
JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(null);
//「開く」ボタンが押された場合
if (returnVal == JFileChooser.APPROVE_OPTION) {
//選択ファイル取得
File file = fc.getSelectedFile();
//選択ファイルのパス取得
getFile = file.getPath();
}
}
//上記以外の場合
catch (Exception e) {
//エラー出力
e.printStackTrace();
}
}
}
);
//選択ファイルパス取得
return getFile;
}

void decoderEvent(Decoder decoder) {
//解読結果をテキストとして取り出す
String statusMsg = decoder.getDecodedString();
//テキストを画面に出力
println(statusMsg);
}



以下は、授業内で実験した内容です。
数値の情報(100など)を含んだQRコードを生成し、プログラムによって解読された文字列としての数値を整数型の数値に変換します。その数値をArduinoへシリアル通信で送信し、analogWrite()でLEDの輝度やモータの速度あるいはサーボの回転角度などに反映させる内容です。いくつかのQRコードを作成し、ファイルチューザーで選択したQRコードを入れ替わりで送ります。

//シリアル通信ライブラリを取り込む
import processing.serial.*;
//シリアル通信インスタンス
Serial port;

//JavaのSwingを取り込む
import javax.swing.*;
import pqrcode.*;
//解読用インスタンスを用意
Decoder decoder;
//画像インスタンスを用意
PImage pimage;
String getFile = null;

void setup(){
//とりあえず表示画面を400角に設定
size(400,400);
//解読用オブジェクトの生成
decoder = new Decoder(this);
background(0);

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

void draw(){
//選択ファイル名が空でないとき
if(getFile != null){
//ファイルを取り込む
fileLoader();
}
}

void mousePressed(){
getFile = getFileName();
}

void fileLoader(){
//選択ファイル名のドット以降の文字列を取得
String ext = getFile.substring(getFile.lastIndexOf('.') + 1);
//その文字列を小文字にする
ext.toLowerCase();
//文字列末尾がjpg,png,gif,tgaのいずれかであれば
if(ext.equals("jpg") || ext.equals("png") || ext.equals("gif") || ext.equals("tga")){
//選択ファイル名のイメージを取り込む
pimage = loadImage(getFile);
//背景(黒)
background(0);
//イメージ表示
image(pimage, 0, 0, pimage.width, pimage.height);
//イメージの解読
decoder.decodeImage(pimage);
}
//選択ファイルパスを空に戻す
getFile = null;
}

//ファイル選択画面、選択ファイル名取得の処理
String getFileName(){
//処理タイミングの設定
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
//ファイル選択画面表示
JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(null);
//「開く」ボタンが押された場合
if (returnVal == JFileChooser.APPROVE_OPTION) {
//選択ファイル取得
File file = fc.getSelectedFile();
//選択ファイルのパス取得
getFile = file.getPath();
}
}
//上記以外の場合
catch (Exception e) {
//エラー出力
e.printStackTrace();
}
}
}
);
//選択ファイルパス取得
return getFile;
}

void decoderEvent(Decoder decoder) {
//解読結果をテキストとして取り出す
String statusMsg = decoder.getDecodedString();
//テキストを画面に出力
println(statusMsg);

//解読した文字列を整数値に変換
int val=int(statusMsg);
//シリアル通信で送信
port.write(val);
}



Arduino側は、11番ピン(PWMピン)にLEDを接続し、輝度が変化する内容であれば以下のようになります。


int val;

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

void loop(){
//受信データがひとつ届いたら
if(Serial.available()>0){
//受信データ読み込み
val=Serial.read();
}
//11番ピンをアナログ出力する
analogWrite(11,val);
}



QRコードで、「100,20,35,180」のように、幾つかの数値をコンマ(デリミタ)で区切り連続した数値の文字列を作成し、解読した結果として送信すれば、複数の数値データをArduinoへ送信することもできます。
この場合、Processingのプログラムの最後の部分にあるvoid decoderEvent(){...}の部分を以下のようにします。

void decoderEvent(Decoder decoder) {
String statusMsg = decoder.getDecodedString();
int[] data=int(split(statusMsg,',');
for(int i=0;i<data.length;i++){
port.write(val);
}
}

解読される文字列は

statusMsg = "100,20,35,180"

なので、
この文字列statusMsgをsplit()に代入し「,」コンマを区切り記号として複数の文字列を含んだ配列に変換します。同時にその文字列群をint()で括ることで、文字列データを整数値データに変換し、

data = {100,20,35,180}

という整数値の配列になります。data.lengthによって配列dataに何個のデータが含まれているか確認し(この場合4個、data[0]からdata[3]まで)、for()文でデータ数の分だけport.write()で繰り返しシリアル通信で送信します(4回分送信)。Arduino側で、順番にこれらの数値を受け取ることで、LEDの輝度調整のプログラムであれば、連続した値をもとに変化する輝度調整が可能になります。

応用的な使い方として、LEDの点灯やサーボの回転角度などの連続する動きのデータをQRコードで幾つか作成しておき、Webカメラを通して解読させる度に異なる動作をさせたり、マトリクスLEDなどに文字や模様として表示させたりできます。

10/03/2008

Processing FileChooser/ファイル選択画面の表示

通常Processingでは、プログラム上で使われる画像データや音源データなどは、スケッチフォルダ内のdataフォルダ内に入れておく必要があります。ProcessingはJavaでつくられているため、JavaのGUIライブラリであるSwingを使うことで、ファイルチューザーのダイアログ画面(ファイル選択画面)を表示し、パソコン上にある任意のファイルを選択し開くことができます(尚、この方法はProcessing/Hacks/filechooserで紹介されています)。
関連:「Processing FileChooser2」(Processing 146以降/selectInput()の使い方)


(Windows XPのファイルチューザー画面/ファイル選択ダイアログ)

dataフォルダ内のデータだけでなく、デスクトップ上にある画像データなどを読み込むことができるので、入れ替わりで画像表示させるときなどに便利です。
以下は、クリックするとファイルチューザー(ファイル選択画面)というダイアログ画面が現れ、コンピュータ上の任意の場所にある画像ファイル(jpeg、png、gif、tga)を取り込んで表示するサンプルです。


//JavaのSwingを取り込む
import javax.swing.*;

//画像インスタンスを用意
PImage pimage;

//選択ファイルを用意し
//ファイルを空にしておく
String getFile = null;

void setup(){
//とりあえず表示画面を400角に設定
size(400,400);
}

void draw(){
//選択ファイル名が空でないとき
if(getFile != null){
//ファイルを取り込む
fileLoader();
}
}

//マウスを押したら
void mousePressed(){
//選択ファイル取得処理
getFile = getFileName();
}

//ファイルを取り込むファンクション
void fileLoader(){
//選択ファイルパスのドット以降の文字列を取得
String ext = getFile.substring(getFile.lastIndexOf('.') + 1);
//その文字列を小文字にする
ext.toLowerCase();
//文字列末尾がjpg,png,gif,tgaのいずれかであれば
if(ext.equals("jpg") || ext.equals("png") || ext.equals("gif") || ext.equals("tga")){
//選択ファイルパスの画像を取り込む
pimage = loadImage(getFile);
//イメージ表示
image(pimage, 0, 0, pimage.width, pimage.height);
}
//選択ファイルパスを空に戻す
getFile = null;
}

//ファイル選択画面、選択ファイルパス取得の処理
String getFileName(){
//処理タイミングの設定
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
//ファイル選択画面表示
JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(null);
//「開く」ボタンが押された場合
if (returnVal == JFileChooser.APPROVE_OPTION) {
//選択ファイル取得
File file = fc.getSelectedFile();
//選択ファイルのパス取得
getFile = file.getPath();
}
}
//上記以外の場合
catch (Exception e) {
//エラー出力
e.printStackTrace();
}
}
}
);
//選択ファイルパス取得
return getFile;
}


選択ファイルが画像ファイルとして相応しいものであるかどうかを

if(ext.equals("jpg") || ext.equals("png") || ext.equals("gif") || ext.equals("tga")){...}

によって判別しています。選択したファイル名の「.」ドット以降が、「jpg」、「png」、「gif」、「tga」であれば、読み込み可能な画像フォーマットとして処理されます。以下の

String getFileName(){...}

以降はJavaのSwingによるファイルチューザーを呼び出して選択ファイルまでのパスを得るコードなので、そのままコピー&ペーストしても構わないでしょう。
PImageでは、jpg、png、gif、tgaの4種類が読み込み可能ですが、この部分を音源のファイルフォーマットに指定し、PImageのかわりにサウンドライブラリを使えば、音源の選択/読み込み/再生も可能になります。
ファイルチューザー画面を用いて、Processingのサウンドライブラリである「Ess」による音源再生のプログラムを以下に書きます。画面中央の白い正方形をクリックすれば、音源選択の画面が現れます。今回利用できる音源のフォーマットは、「wav」だけとします。dataフォルダの中にある音源だけでなく、iTuneなどの音楽ライブラリの中から曲を選ぶこともできるはずです。白い正方形以外の周辺の場所をクリックすれば、再度音源が再生されます。尚、「Ess」ライブラリをダウンロード+インストールしておく必要があります。また、曲などの大きな音源データの場合は、ProcessingのメニューバーからPreferencesあるいは環境設定で、メモリーを増やしておく必要があります(「Increase maximum available memory to [ ]MB」という欄にチェックを入れ、データ量に相当するメモリー数を記入して下さい)。


//Essサウンドライブラリの取り込み
import krister.Ess.*;
//音源インスタンスの用意
AudioChannel mySample;

//JavaのSwingライブラリの取り込み
import javax.swing.*;

String getFile = null;

void setup(){
size(200,200);
//Ess使用開始
Ess.start(this);
background(100,100,30);
rectMode(CORNER);
}

void draw(){
//画面中央白い正方形の描画
rect(width/2-25,height/2-25,50,50);
if(getFile != null){
fileLoader();
}
}

void mousePressed(){
//クリックの箇所が白い正方形以内なら
if(mouseX>width/2-25 && mouseX<width/2-25+50 && mouseY>height/2-25 && mouseY<height/2-25+50){
//選択ファイル所得処理
getFile = getFileName();
}
else{//白い正方形以外の箇所をクリックしたら
//音源ファイルが空ではないとき
if(mySample!=null){
//音源再生
mySample.play();
}
}
}

void fileLoader(){
String ext = getFile.substring(getFile.lastIndexOf('.') + 1);
ext.toLowerCase();
//選択したファイルが「wav」フォーマットなら
if(ext.equals("wav") ){
//音源ファイルの指定
mySample=new AudioChannel(getFile);
//音源再生
mySample.play();
}
getFile = null;
}

//ファイル選択画面、選択ファイルパス取得の処理
String getFileName(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
getFile = file.getPath();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
);
return getFile;
}

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


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