INDEX(各項目ごとの目次)

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

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

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を通信させる)

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を通信させる)

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を通信させる)

Arduino 圧電スピーカ

圧電スピーカは、ブザー(音が鳴る)として機能する一種のスピーカです。圧電スピーカについている2本の線に、そのまま電気を流しても音は鳴りません。音を出すためには、高速でオンとオフを繰り返し(パルス)、内部の金属板を振動させます。プログラム上では、digitalWrite()を用いてHIGHとLOWの切替を行い、delay()によってオン/オフの時間の間隔(周波数)をつくりだすことで制御することができます。
以下では、前回使用した可変抵抗器を用いて、可変的に周波数をつくりだし、圧電スピーカを鳴らす実験をしてみます。

Arduinoのプログラム:
int val=0;

void setup(){
pinMode(13,OUTPUT);
}

void loop(){
val=analogRead(0);
digitalWrite(13,HIGH);
delay(val);
digitalWrite(13,LOW);
delay(val);
}

音はでますが、あまりいい音ではないので、周波数を細かくするために、delay()のかわりにdelayMicroseconds()を用いて同様にテストしてみます。delayMicroseconds()は、delay()の1/1000の時間、つまり1マイクロ秒(1/1000000秒)が単位となります。高音領域が高周波になりすぎないように、valに予め+500のオフセットを設け、500〜1523までの値がdelayMicroseconds()に入ることにします。ちなみに、Arduinoサイトの説明によると、delayMicroseconds()の()内に入れられる数値は、最大で「16383」であり、delayMicroseconds(0)というように()内に「0」を入れると0秒ではなく、それよりも長い時間(~1020マイクロ秒)ディレイしてしまうと書いてあります。設定するときは注意して下さい。

int val=0;

void setup(){
pinMode(13,OUTPUT);
}

void loop(){
val=analogRead(0)+500;
digitalWrite(13,HIGH);
delayMicroseconds(val);
digitalWrite(13,LOW);
delayMicroseconds(val);
}

圧電スピーカは、音を鳴らす以外にセンサとして使うこともできます。圧電スピーカとLEDを直結し、圧電スピーカを指先でたたいて衝撃を与えると電源がなくてもLEDが一瞬発光します。

この発電原理を利用して、圧電スピーカをマイクのような衝撃センサとして用いることが可能となります。圧電スピーカからの電圧をanalogRead()で読み取って、どの程度の値が得られるかテストしてみます。
読み取り値などを画面に出力するには、シリアル通信機能を用いて以下のようなプログラムを付け足し、プログラムが開始したら、Arduinoの画面上のSerial Monitorボタンを押します。

初期設定のSerial.begin(9600)は、通信速度を9600に設定し、シリアル通信を開始するという意味です。Serial.println(val)は、モニタリングするためにvalの値をシリアル通信を用いて出力します。Serial.println()は、データを毎回改行しながら出力します。もうひとつSerial.print()という、改行せずにそのままデータを送り出すものもあります。今回はモニタリングするために、改行して出力したほうが見やすいので、Serial.println()の方を使います。

圧電スピーカに衝撃を与えると値が変化することが確認できます。出力される値が10以上であれば、衝撃を加えたことに反応しているとみなすこととします。以下に、圧電スピーカからの衝撃によってオン/オフするLEDのプログラムを書きます。boolean型の変数を用いて、以前Processingで用いたトグルスイッチのプログラムを付け足します。boolean型の変数checkがfalseの時はLEDがオフの状態、checkがtrueの時はオンの状態とします。
int val=0;
boolean check=false;

void setup(){
//13番ピンをLEDの出力に設定
pinMode(13,OUTPUT);
}

void loop(){
//圧電スピーカ0番ピンの読み取り値
val=analogRead(0);
//読み取り値が10以上の場合
if(val>10){
if(check==false){ //LEDオフ状態の場合
digitalWrite(13,HIGH); //オンに切替
check=true; //オンの状態として記憶
}else{ //LEDオン状態の場合
digitalWrite(13,LOW); //オフに切替
check=false; //オフの状態として記憶
}
}
delay(100);
}


Arduinoのサイト内のLearning/Examples/SoundページにもPlay Melodies with a Piezo Speakerという名前で、圧電スピーカのサンプルが掲載されています。

Arduino アナログ入出力

前回までは、LEDをオン/オフ(5V/0V)するプログラムでした。今回は、オン/オフの制御ではなく、外部からの入力によってLEDの明暗を変化させるプログラムをします。
analogWrite()を用いれば、0〜255の256段階でLEDの明るさが調節できます。モータの出力に使えば、スピード調節が可能となります。PWM(パルス幅変調)という方法で256段階を調整しますが、パルスについては後で説明したいと思います。まずはanalogWrite()の使い方からマスターしていくこととします。
analogWrite(ピン番号,出力値)というように二つの値を設定する必要があります。「ピン番号」は出力したいピンの番号を入れますが、Arduino基盤の0〜13番ピンのうちの3、5、6、9、10、11の6つのピン(基盤上のピン番号下にPWMと書かれている番号)のどれかになります。「出力値」は、0〜255(0V〜5Vに対応)の値をいれます。
analogWrite(3,0);

と書けば、3番ピンを0(0V)で出力となるので、LEDであれば消灯します。
analogWrite(3,255);

であれば、一番明るい状態となり、
analogWrite(3,127);

であれば、約半分の明るさとなります。

次に、外部からの入力(センサ入力)の際に使用するanalogRead()について説明します。analogRead()は、0〜1023の1024段階で値を読み取ることができ、0〜1023が0V〜5Vに対応しています。Arduino基盤の右下に「ANALOG IN」と書かれた0〜5番ピンを使用します。
analogRead(0);

と書けば、「ANALOG IN」の0番ピンに接続したワイヤからの電圧を読み取って0〜1023の値が得られることになります。
入力用に使われるセンサは様々なものがありますが、今回は「可変抵抗器(ボリューム)」を使用することにします。一般的な可変抵抗器には3つの端子があり、両端の二つの端子を0V(GND)と5Vにつなぎ、ツマミを回すと中央の端子から任意の電圧(0V〜5V)が出力されます。つまり、中央の端子からの可変電圧をanalogRead()で読み取って、その入力値をanalogWrite()の出力値に入れれば、LEDの明るさをツマミをひねることで調整できるようになります。
ひとつ注意しなければいけないことは、analogRead()によって得られる値は0〜1023に対して、analogWrite()の出力値が0〜255までなので、入力値(読み取り値)を4で割った値を出力値に入れないといけません。
尚、analogWrite()analogRead()の場合は、初期設定でpinMode()の入出力を設定せずに直接使うことが出来ます。

以下に、analogWrite()analogRead()を用いて、外部からの入力(可変抵抗器)によってLEDの明るさを変えるプログラムを書きます。
int val=0; //入力値の変数を用意し、0に設定

void setup(){
//pinMode()の設定は不要
}

void loop(){
//ANALOG INの0番ピンを読み取りvalに代入
val=analogRead(0);
//アナログ出力(PWM)の3番ピンを出力とし
//valを4で割った値を入れる
analogWrite(3,val/4);
//0.1秒ループにする
delay(100);
}


可変抵抗器のツマミの回し方(時計回り/半時計回り)と出力値の増減の向きを変えたい場合は、可変抵抗器の両端の端子(0V端子/5V端子)を入れ替えてください。

5/23/2008

Arduino 5/24授業

今週5/24も先週に引き続きArduinoを行います。パソコン、Arduino基盤、USBケーブル、ブレッドボード、ジャンプワイヤ、7セグLED(先週使った部品)を持って来て下さい。Processingも同時に行います。

5/18/2008

Arduino 7セグLEDの点灯

7セグLEDは、数字の形を表示するための細長い7個のセグメントと数字右下にある「.(ドット)」の合計8個のLEDで構成されています。つまり8個のLEDを制御するプログラムになるということです。授業で用いた7セグLEDは、秋月電子で購入したものでデータシートは付属していましたが、部品単体で販売されていることもあるので、その際にはメーカーや型番をインターネットで検索しデータシートを探し出すか、自分自身でどのセグメントがどの端子に対応しているのかなどをテストする必要があります。今回の7セグLEDは、アノードコモンタイプ、8個のLED、10本の端子です。アノードコモンタイプは、8個のLEDのプラス側の端子を共有するつくりになっています。
Arduino基盤につなぐには、Arduinoの電圧が5Vに対してLEDの使用電圧が2.5V前後なので、前回同様、抵抗(220〜470Ω程度)が必要になります。一つの抵抗を8個のLEDに対して共有することもできないわけでもないのですが、数字を表示する際には、「0」の場合は6個のLEDセグメント、「1」の場合は2個のLEDセグメントを発光させるというように、その数字によって、発光させるLEDセグメントの数が異なるので、セグメント数が少ないほど明るく発光してしまいます。それぞれの発光を均一にするためにも、抵抗はセグメントの数と同じだけ必要となります。今回はアノードコモン(プラス側の端子は共有)なので、各抵抗はカソード側(マイナス)に接続する回路にします。
1秒ごとに0〜9までカウントアップしていき、それをループするプログラムにしたいと思います。数字右下の「.(ドット)」は今回使わないで、合計7個のLEDセグメントを制御します。

まず、7セグLED裏面に10本端子があるので、どの端子がどのセグメントであるか、ひとつずつ点灯実験してみます(Arduino基盤の5V端子とGND端子に接続してテストしますが、この際にも抵抗を直列つなぎしてください)。ブレッドボードとジャンプワイヤがあると便利です。7セグLEDの場合、共有端子が真ん中にあることが多いので、データシートがない場合は、そのようなことを想定してテストしてみるといいかもしれません。



それぞれの端子は、上図のように各セグメントに対応していることが分かりました。cとhはアノード共有端子です。今回は、eのドットは使わず、a、b、d、f、g、i、jの7個を制御表示させることにします。例えば「1」を表示させるには、dとfをオンにし、残りはオフになるように設定します。アノードコモンであることから、cにはプラスの電圧がかかり、dとfを発光させるには、dとfがマイナスにならなければいけません。前回用いた図の「抵抗をカソード側につけた場合」を参考とし、a、b、d、f、g、i、jの7個の端子にそれぞれ別個の抵抗(220Ω)を取付け、Arduino基盤のデジタル出力の端子に接続します。
とりあえず、aの端子をArduino基盤の1番ピン、bを 2番ピンという順番で以下のようにつなげることにします。
a---1番ピン
b---2番ピン
d---3番ピン
f---4番ピン
g---5番ピン
i---6番ピン
j---7番ピン



「1」を表示するためには、dとfを0V(LOW)にすることで電位差が生じ発光します(cの端子から5V、dのLEDを通して2.5Vに降下し、抵抗によって2.5Vから0Vに降下する)。プログラム上では、
digitalWrite(3,LOW);
digitalWrite(4,LOW);

に設定すると3番ピン(dのLED)とが4番ピン(fのLED)が発光し、「1」の数字が表示されることになります。ただし、光らせたいピンだけではなく、残りのピンを光らせないプログラムも必要となります。残りのピンについては、すべてLOWのかわりにHIGHに設定します。よって、「1」を表示させるプログラムは以下のようになります。
void setup(){
//1〜7番ピンを出力に設定
pinMode(1,OUTPUT);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
}

void loop(){
//「1」を表示
digitalWrite(1,HIGH);
digitalWrite(2,HIGH);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
digitalWrite(7,HIGH);
delay(1000);
}

他の数字に関しても同様にプログラムしていきます(ここでは省略して、0〜3までの表示とします)。
void setup(){
//1〜7番ピンを出力に設定
pinMode(1,OUTPUT);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
}

void loop(){
//「0」を表示
digitalWrite(1,LOW);
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
delay(1000);
//「1」を表示
digitalWrite(1,HIGH);
digitalWrite(2,HIGH);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
digitalWrite(7,HIGH);
delay(1000);
//「2」を表示
digitalWrite(1,LOW);
digitalWrite(2,LOW);
digitalWrite(3,HIGH);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
delay(1000);
//「3」を表示
digitalWrite(1,HIGH);
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
delay(1000);
}

setup()の中のpinMode()for文という繰り返しの構文を用いた書き方にします。以下のfor()の中の「int i=1; i<=7; i++」は、1から7までを順番(+1ずつ)に7回分繰り返し処理するという意味です。もし「int i=3; i<=5; i++」と書いていれば、3から5までの3回分繰り返し処理することになります。この場合なら、3から5がpinMode()内のiに代入されるので、3〜5番ピンをOUTPUTに設定するということになります。「int i=1; i<=7; i+=2」と書けば、「i++」の部分を「i+=2」にしたので、1〜7までを+2ずつということになり、「1、3、5、7」だけを処理させるということになります。上記プログラムでは、1〜7番ピンを一気にOUTPUTに設定したいので、以下のように「int i=1; i<=7; i++」とします。
それから、loop()の中が長くなりすぎて見づらいので、それぞれの数字の表示に対してファンクション名(任意の名前)をつけて、以下のようにloop()の外に定義しておくことができます。
void setup(){
for(int i=1; i<=7;i++){ //iを1から7までの数とし
pinMode(i,OUTPUT); //1から7までのピンを出力に設定
}
}

void loop(){
zero();
delay(1000);
one();
delay(1000);
two();
delay(1000);
three();
delay(1000);
}

void zero(){
digitalWrite(1,LOW);
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
}

void one(){
digitalWrite(1,HIGH);
digitalWrite(2,HIGH);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
digitalWrite(7,HIGH);
}

void two(){
digitalWrite(1,LOW);
digitalWrite(2,LOW);
digitalWrite(3,HIGH);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
}

void three(){
digitalWrite(1,HIGH);
digitalWrite(2,LOW);
digitalWrite(3,LOW);
digitalWrite(4,LOW);
digitalWrite(5,LOW);
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
}

このように各数字に対するファンクションを定義することで、必要に応じてloop()内でファンクション名を呼び出す使い方が可能になります。loop()内では、全体の流れが上から順に書かれており、loop()外には、それぞれの数字の内訳のプログラムが書いてあり、全体と部分という関係でプログラムしていくことができます。部分(数字の内訳のプログラム)を修正すれば、loop()内で処理される全体の流れにもすぐ反映され、全体の流れだけを修正したい時には、いちいち部分のプログラム内容に触れなくても済むという利点があります。

また、数字がカウントアップしていくプログラムであれば、更に以下のように配列(Array)を利用して、反復する内容をできるかぎり省略して書くこともできます。先ほどまでは、pinMode()、digitalWrite()、delay()が繰り返し書かれてきましたが、以下のようにすれば、それぞれを一回書くだけで済みます。
boolean table[4][7]={ {0,0,0,0,0,0,1},
{1,1,0,0,1,1,1},
{0,0,1,0,0,1,0},
{1,0,0,0,0,1,0} };

void setup(){
for(int i=1; i<=7;i++){
pinMode(i,OUTPUT);
}
}

void loop(){
for(int i=0;i<=3;i++){
for(int j=0;j<=6;j++){
digitalWrite(j+1,table[i][j]);
}
delay(1000);
}
}

配列によって複数の値をグループとして用いることが可能となります。配列は[]の括弧をもちいてあらわします。もし、数字の「0」についてのグループをつくるなら、

boolean zero[]={0,0,0,0,0,0,1};

となります。zeroというグループには7つの値が含まれており、それぞれが順番にLEDセグメントのLOWかHIGH(0か1)の設定に対応しています。0か1しかないので、boolean型を用いています。zero[6]という表記は、配列zeroの6番目の値ということになります。配列では、{}内に含まれる最初の値を0番目として扱います。よって、zero[0]からzero[5]までは0で、配列zeroに含まれる最後の値であるzero[6]は1となります。
zero[]と同様にして数字「1」、「2」、「3」に関しては
boolean one[]={1,1,0,0,1,1,1};
boolean two[]={0,0,1,0,0,1,0};
boolean three[]={1,0,0,0,0,1,0}

となります。
さらに、これらの各数字グループをまとめる全体グループをもう一つの配列を用いてつくります(その配列名をtableとします)。
一行で書くと横に長くなるので、改行して少し見やすくします。

boolean table[4][7]={ {0,0,0,0,0,0,1},
{1,1,0,0,1,1,1},
{0,0,1,0,0,1,0},
{1,0,0,0,0,1,0} };

配列tableは、4つ要素を持ち、それぞれの要素がさらに7つの値を含んでいるということになります。例えば、table[2][2]は、数字「2」の2番目の値で1(HIGH)であり、table[2][5]も1(HIGH)となります。
この全体の配列tableは、loop()内で処理される全体の流れと、それぞれの内訳を0と1だけを用いて書き直した表のようなものです。loop()内では、この表に従って順にカウントアップされる処理が行われます。
void loop(){
for(int i=0;i<=3;i++){
for(int j=0;j<=6;j++){
digitalWrite(j+1,table[i][j]);
}
delay(1000);
}
}

このloop()内のfor文では、iをint型の変数にして0〜3までの数字を順番に処理していき、その処理のさらに内部では、jをint型の変数にして各配列の0〜6番目までの値を順番に処理させ、digitalWrite()のピン番号とLOWかHIGHかを指定する部分に0か1が入るようになっています(digitalWrite()の中のj+1という部分は、配列の0番目が今回使用したArduino基盤のピン番号の1番目に対応するため+1してあります。本来、基盤の0番ピンから使えば、配列の0番目がピン番号の0番目に対応するので、このようなことをしなくても済んだはずです)。
配列(Array)for文に関しては、プログラミングではよく出てきますので、詳細については再び授業あるいはブログで説明していきたいと思います。

関連:
Arduino:7 セグ+照度センサNJL7502L」--照度センサで得た値を7セグを用いて表示する


Arduino LEDの点滅



LEDを点滅させるプログラム(上画像)です。
まずsetup()loop()を用いて、以下のようなフォーマットを用意します。ほぼProcessingと同じような感じです。
void setup(){
//初期設定のプログラム
}

void loop(){
//ループ処理のプログラム
}

初期設定setup()の中には、pinMode()を使って、基盤上のどのピンを出力または入力で使いたいのかを設定します。
pinMode()の()内には、数字でピンの番号(0〜13)とOUTPUTかINPUTのどちらかをコンマで区切って入れます。LEDを光らせる電源としてOUTPUT(出力)に設定します。
ループ処理loop()の中には、LEDを点滅させる一連の処理についてのプログラムを書きます。
digitalWrite()の()内には、数字でピンの番号(0〜13)とHIGHかLOWのどちらかをコンマで区切って入れます。HIGHは5Vを出力し、LOWは0Vを出力します。delay()は、()内に入れた数字の分だけ、時間を保持します。単位はミリ秒で、1秒は1000ミリ秒に相当します。上記のプログラムでは、delay(1000)を二回挿入しているので、2秒ループのプログラムになります。
プログラムを新たに書き直したら、一旦「Verify」ボタンを押してプログラムをコンパイルします。Arduino基盤とパソコンがUSB接続されていれば、「Upload to I/O Board」ボタンをクリックし、基盤にプログラムをアップロードします。


LEDは電流を一方向にしか流さない特性があるため、+と-を電源に対して正しくつながないと発光しません(逆につないでも壊れるということは、ほぼありません)。上図のように、通常二つの端子(アノードとカソード)があります。アノード側をプラスに、カソード側をマイナスに接続します。LEDの多くは2.5V前後の電源で発光するようにつくられているので、Arduino基盤上の5V電源とGND(0V)に直接つなぐと壊れる恐れがあります。そのため、抵抗をかませる必要があります。Arduino基盤の13番ピンには抵抗なしで直接つなぐことができますが、0〜12番ピンに接続する際には、抵抗(220〜470Ω程度)を直列つなぎしてください。LEDによって特性が異なりますので、より精確に行いたい場合は、購入する際に使用電圧や最大電流についてメモしておくか、付属のデータシートを参考にしてください。



アノード側に抵抗をつないだ場合は、抵抗を通して5Vの電圧が2.5Vまで下げられ、LEDによって2.5Vから0Vに下げられます。
カソード側に抵抗をつないだ場合は、LEDを通過することで5Vの電圧が2.5Vまで下げられ、抵抗によって2.5Vから0Vに下げられます。
最初にプラス側で電圧をさげておくか、最後にマイナス側で電圧を下げるかという違いです。もし、抵抗を取付けなければ、LEDにおいて5Vから0Vに一気に下げられ、電位差が5Vになってしまい使用電圧である2.5Vをはるかに上回り破損してしまうという感じです。抵抗の取付けについては、回路設計やLEDの特性に応じて使い分けてください。

5/17/2008

Arduino基盤の概要


上画像は旧型のArduino Decimilaボードです。

Arduino基盤には、大きく分けてデジタル出力、デジタル入力、アナログ出力、アナログ入力の端子があります。LED、センサ、アクチュエータ、その他電子部品を接続して使用します。基盤上方にある0〜13番ピンについては、デジタル入出力の際に、使用するピンを出力用に使うのか、入力用に使うのかをプログラム上のpinMode()で設定する必要があります。基盤の下方にある5Vピンからは、5V電圧をとることができます。GNDピン(0V)は、上方13番ピンの隣と、下方5Vピンの隣に2つ、合計3箇所あります。
Arduino基盤では、基本的に、0〜5Vの電圧を扱います。

デジタル出力:
デジタル出力/digitalWrite()では、LOWかHIGHの二段階の出力方法しかありません。LOWは0Vに、HIGHは5Vに対応します。あるいは、二進法ではLOWが0、HIGHが1、またboolean型変数におけるfalse/trueに対応します。
例えば、LEDの点灯/消灯させるときに使います。

デジタル入力:
デジタル入力/digitalRead()も同様にLOW/HIGHの二段階です。
例えば、接続したセンサ/スイッチを通してオンになっているのかオフになっているのかを読み取るときに使います。

アナログ出力(PWM):
アナログ出力/analogWrite()は、上方の3、5、6、9、10、11番ピンの6箇所に接続でき、0〜255の256段階の出力が可能です(0V〜5Vを256段階に分けています)。
例えば、LEDの明暗を調節して光らせるときに使います。モーターならスピード調節になります。

アナログ入力:
アナログ入力/analogRead()は、センサなどから0〜1023の1024段階の読み取りが可能です(0V〜5Vを1024段階に分けています)。
例えば音量調節、照度調節、スピード調節などするために接続したセンサの度合いを読み取ります。

アナログ入出力においては、pinMode()を設定する必要はありません。

電源(外部電源):
通常は、USB接続によってパソコンから5V電源がArduino基盤に供給されます。外部電源から供給したい場合には、外部電源端子にバッテリやACアダプタ(6~20V/推奨は7~12V)などを接続します。例えば、DC12V/1AのACアダプター
差し込むプラグは内径2.1mm、外形5.5mmで、中心軸がプラス極になります。
*Arduino Decimilaなどの旧型の場合は、USB/外部電源のジャンパピンを差し替える必要があります(基盤上に明記されている文字:USBからEXT側へ)。パソコンからプログラムをアップロードする際には、再度USBケーブルを接続し、USB側へジャンパピンを差し替えます。

Arduinoのセッティング



ソフトのダウンロードとインストール:
・Arduinoサイトへアクセス→http://www.arduino.cc
・サイト内Downloadページから開発環境ソフト「Arduino 0018」(最新版)をダウンロード(Win用/Mac用あり)。
(注意)初めて使う場合は、「Arduino開発環境ソフト」だけでなく「USBドライバソフト」もインストールする必要があります。

Windows:
・ダウンロードした「arduino-0018.zip」を展開する。
・「arduino-0018」ファイルを「C:¥Program Files」へ移動しインストール。
・ArduinoボードをUSB接続する。
・「USBドライバソフト」のアップデート自動検索画面が出るので(初回のみ)、
 「Program Files>arduino-0018>drivers>FTDI USB Drivers」フォルダを指定しインストールする。
 (Vistaの場合は自動的に探してインストールされる)。
・「arduino-0018」フォルダ内の「arduino.exe」を開く。
・Arduinoソフトのメニューバー「Tools>Board」から接続しているArduinoボードの種類を選択。
「Arduino Duemilanove 328」なら「Arduino Duemilanove or Nano w/ATmega 328」を選択。
・メニューバー「Tools>Serial Port」から「COM*」を選択(COM3などと表示)。
・以上でセットアップ完了。
*「USBドライバ」がインストールされたか確認するには:
ArduinoボードをUSB接続したまま「コントロールパネル>システム」を開き、「システムのプロパティ」画面内「ハードウェア」タブを選択、「デバイスマネージャ」ボタンをクリック、「デバイスマネージャ」内のリストから「ポート(COMとLPT)」を選択、「ポート(COMとLPT)」内に「USB Serial Port(COM3)」(COM4やCOM5の場合あり)があるか確認。Arduinoソフトのメニューバー「Tools>Serial Port」で上記のPort(COM3など)を選択する。

Macintosh:
・ダウンロードした「arduino-0018.dmg」を開く。
・「Arduino.app」を「Applications」フォルダに移動。
・「FTDIUSBSerialDriver_10_4_10_5_10_6.mpkg」をダブルクリックし、ドライバを画面上の指示に従いインストール。
・ArduinoボードをUSB接続する。
・ダウンロードしたArduino.appを開く。
・Arduinoソフトのメニューバー「Tools>Board」からArduinoボードの種類を選択。
「Arduino Duemilanove 328なら」「Arduino Duemilanove or Nano w/ATmega 328」を選択。
・メニューバー「Tools>Serial Port」から「/dev/tty.usbserial-********」を選択。
 上記「********」はボードによって異なります。
・以上でセットアップ完了。
*「USBドライバ」がインストールされたか確認するには:
ArduinoボードをUSB接続したまま、メニューバー左上アップルマーク>このMacについて」を選択、画面内で「詳しい情報...」ボタンをクリック、次の画面上左側のリストから「ハードウェア>USB」を選択、「USBバス」内に「FT232R USB UART」があるか確認する。「FT232R USB UART」を選択し、画面内「シリアル番号」欄の番号が上記「/dev/tty.usbserial-********」の「********」になります。

動作確認:
無事ソフトとUSBドライバのインストールが済んだら、動作確認として以下のサンプルプログラムを試してみて下さい。
Arduino画面メニューバーのFile>Sketchbook>Examples>Digital>Blinkを選択すると、「Blink(LEDの点滅)」のサンプルプログラムが現れます(Arduinoサイト内にも同じサンプルがあります)。

「Upload to I/O Board」ボタンかFile>Upload to I/O Boardを選択すると、Arduino基盤にプログラムのアップロードが開始されます。画面の下の方に「Done uploading.」と表示されれば、アップロード完了です。

Arduino DuemilanoveやDiecimilaの場合は、基盤上のリセットボタンを押す必要はありませんが、Arduino NG基盤(旧型)の場合は、リセットボタンを押した直後に「Upload to I/O Board」ボタンを押して下さい。

問題なければ、Arduino基盤上のLED(13番ピン用内蔵LED/13番ピンの真下あたりにある基盤上の小さいLED)が一秒ごとに点滅します。Arduino NG基盤(旧型)の場合は、LEDが内蔵されていないので、13番ピンとGNDピンにLEDを差し込む必要があります(LEDについてはブログ内の「Arduino LEDの点滅」を参照)。
Arduinoサイト上のLearning(上画像/赤印)は、学習用のサンプルプログラムが記載されているページです。Reference(上画像/赤印)は、プログラムの各言語について説明してあるページです。それぞれ参照してみて下さい。
尚、四谷工作研究所(2007年度)のブログでもセッティングや使用法について記載されているので参考にしてください。

5/14/2008

電子工作 5/17(土)



5/17(土)から電子工作を始めます。パソコン、Arduino基盤、USBケーブル(Arduino-パソコン間)、ブレッドボード(上画像/上)、ジャンプワイヤ(上画像/下)を各自用意して来て下さい。もし用意できない場合は、学校に幾つかありますので、それを使うことになります。できれば、ArduinoのサイトからArduinoのソフトをダウンロード、インストールして来て下さい。
Processingは、今後もArduinoと連動して使いますので、各自プログラムの練習をしておいて下さい。
「Wooden Stick」については、スケールや身体についてどのような表現ができるかアイデア段階でもいいので考えておいてください。コンピュータプログラムで出来ること、電子工作で出来ること、素材加工で出来ることを最終的に組み合わせたいと思います。

Processing 文字と画像

文字の表示についてはPFontというクラスを用います。文字を使う場合、Processingを開いたあと、メニューバーにあるTools>Create Font...をクリックします。そうするとCreate Fontという別のウィンドウが現れ、使用したいフォントとそのサイズ選択します。視覚的に滑らかなフォントを使いたいのであればSmoothにチェックを入れます。基本的な記号、数字、アルファベットを使うのであればAll Charactersのチェックを外したままで大丈夫です。
日本語などを使う場合はチェックを入れて使いますがデータはその分大きくなります。All Charactersにチェックを入れると、全てのフォントデータを取り込むためにやや時間がかかるときがあります。日本語の大きなサイズのフォントを取り込む際にエラーが出る場合は、上記の方法のかわりにcreateFont()をつかった方法を用いてみてください(サンプルは以下にあります)。
ここでは、Monacoというフォント、サイズは12、Smoothにチェックを入れることにします。Filename欄にはMonaco-12が表示され、その拡張子.vlwがあることが確認できます。OKボタンを押してウィンドウを閉じると指定したフォントの準備が整います。現在開いているsketchファイル(例えば「sketch_08513a」という名前)を一旦保存(File>save)すると、Macintoshであれば、/User/username/Documents/Processing/sketch_08513a/data内にフォントのファイル(例えばMonaco-12.vlw) が入ってます。WindowsならC:¥Documents and Setting¥username¥My Documents¥Processing¥sketch_08513a¥data内に入っています。文字を使用する場合、必要なフォントがsketchフォルダ内のdataフォルダに入っていないとエラーがでます。同様に、jpegなどの画像や音源などを使用する際も、dataフォルダに入れておく必要があります。
以下では、クリックによって文字が切り替わるプログラムをします。一文字ごとの変数にはchar、そして単語などの連なった文字(文字列)にはString型の変数を用います。尚、文字列は「"文字"」のようにダブルクオーテーションマークで文字列の両端を括ります。一文字だけのcharなら「'A'」のようにシングルクオーテーションマークで括ります。

PFont font; //フォントの使用
String tx; //文字列の変数を用意

void setup(){
size(400,200);
//指定フォントのロード
font = loadFont("Monaco-12.vlw");
//フォントを使用開始、サイズ:12
textFont(font,12);
//初期の表示文字を"CLICK"に設定
tx="CLICK";
}

void draw(){
text(tx,200,100);
}

void mousePressed(){
tx="HELLO";
}
void mouseReleased(){
tx="CLICK";
}

日本語フォントを使う場合は、createFont()を使用します。その際「Tools>Create Font...」でフォントを選択する必要はありません。

PFont myFont;

void setup() {
size(400, 200);
myFont = createFont("Osaka", 32);
textFont(myFont);
}

void draw(){
background(0);
text("建築発明工作ゼミ", 10, height/2);
}

画像の取り込みについては、PImageというクラスを使います。Processingでは、gif、jpeg、tga、pngの画像フォーマットに対応しています。予め用意した画像をdataフォルダ(前述)に入れておく必要があります(dataフォルダがない場合は、sketchフォルダ内に「data」という名前をつけてフォルダを作成しておきます)。
以下のサンプルでは画像を二種類(start.jpgとstop.jpg)用意し、最初に画像Aが表示されており、マウスボタンを押したら画像Bに切り替わり、放したら画像Aに戻るというプログラムをします。切り替えには前回用いたflagというboolean型の変数を用いて、現在画像Aが表示されているか画像Bが表示されているか記憶させておきます。

PImage imgA;//画像A用にimgAを用意
PImage imgB;//画像B用にimgBを用意
boolean flag;//切り替えのフラグを用意

void setup(){
size(400,200);
//imgAには"start.jpg"という画像をロード
imgA=loadImage("start.jpg");
//imgBには"stop.jpg"という画像をロード
imgB=loadImage("stop.jpg");
//最初にimgAを100,50の位置に表示しておく
image(imgA,100,50);
//フラグはfalse(imgA表示)に設定
flag=false;
}

void draw(){
background(0);
if(flag==false){//falseの場合imgA表示
image(imgA,100,50);
}else{//それ以外(true)の場合imgB表示
image(imgB,100,50);
}
}
void mousePressed(){
//押すとtrue(imgB表示)
flag=true;
}
void mouseReleased(){
//放すとfalse(imgA表示)
flag=false;
}

5/13/2008

Processing マウス入力4

今までのボタン操作において、「押したらオン、放したらオフ」になるというプログラムを書いてきましたが、「押したらオン、もう一回押したらオフ」になるトグルスイッチというものもあります。トグルスイッチのプログラムには、変数を用意しておいて、オンやオフになっている状態を記憶させておく必要があります。そのようなものをフラグといいます。サンプルとして、正方形をクリックし、オンなら緑、オフなら赤というプログラムを書きます。まず、オン/オフ用としてflag(変数名は任意)という変数を用意しておきます。いままで使ってきたint型の変数を使うことも可能ですが、オン/オフの二つの状態しかないので、より単純なboolean型の変数を用います。変数の値としては、truefalseだけになります。つまり、flagがtrueのときは、スイッチがオンになっている状態とし、flagがfalseのときはオフになっている状態であるという設定にします。

boolean flag; //boolean型の変数flagを用意

void setup(){
//画面サイズ
size(400,200);
//スイッチの初期値はfalse(オフ)に設定
flag=false;
//図形の初期色を赤(オフ)に設定
fill(255,0,0);
}

void draw(){
background(100);
rect(200,100,50,50);
}

void mousePressed(){
//マウス座標が正方形の範囲内の時
if(mouseX>=200 && mouseX<=250 && mouseY>=100 && mouseY<=150){
if(flag==false){ //クリックする前がオフの時
fill(0,255,0);
flag=true; //クリックしたらオンの状態に変更する
}else{ //クリックする前がオンの時
fill(255,0,0);
flag=false; //クリックしたらオフの状態に変更する
}
}
}

if()内の条件式では、flag==falseというように「==」イコールを二つ用いて下さい。ただし、その後の「クリックしたらオンの状態に変更する」箇所では、flag=trueというように「=」イコールが一つになります。
フラグを用いることで、もう既に済んでしまっている出来事の状態を記憶させておくことができます。それに応じて、条件式を設定すれば、より複雑な状況をプログラムしていくことが可能になります。例えば3回押したらオンになるスイッチもint型変数をカウントとして使えば可能となります。

boolean flag; //オンかオフを判定するフラグ変数
int count; //クリック回数をカウントする変数

void setup(){
size(400,200);
flag=false; //オフに設定しておく
fill(255,0,0);//正方形の色(オフ)を赤にしておく
count=0; //0回目に設定しておく
}

void draw(){
background(100);
rect(200,100,50,50);
}

void mousePressed(){
if(mouseX>=200 && mouseX<=250 && mouseY>=100 && mouseY<=150){
count++; //正方形内をクリックするごとに回数が+1される
if(count>=3){ //クリック回数が3以上なら
if(flag==false){ //スイッチがオフなら
fill(0,255,0); //緑(オン)に変更する
flag=true; //スイッチをオンに変更する
}else{ //スイッチがオンなら
fill(255,0,0); //オフ(赤)に変更する
flag=false; //スイッチをオフに変更する
}
count=0; //カウントを0に戻す
}
}
}

クリックされる前の状態がオンのときはオフへ、オフのときはオンへ切り替えるboolean型の変数flagと同時に、クリック回数を記憶しておくint型変数countがあります。それぞれ切り替わる際には、flagをfalseからtrueへ、あるいはtrueからfalseへ、そして回数も3から0へと変更するような後処理についても忘れずプログラムしておく必要があります。

Processing マウス入力3

クリックやドラッグ以外に、マウス(カーソル)を図形の上に重ねた時に、色や形が変わるロールオーバーという機能があります。Processingでは、ロールオーバーの関数は用意されていないので、自前でプログラムする必要があります。原理的には、マウス(カーソル)の座標mouseXmouseYが、その図形上にあるかどうかをif文を用いて判定するプログラムになります。
例として、画面上の座標(200,100)に配置された一辺50pixelの正方形(赤)にマウス(カーソル)が重なった ら黄色に変化し、マウスボタンを押したら緑に、放したらもとの赤に戻るというプログラムを書きます。

void setup(){
size(400,200);//画面サイズ
fill(255,0,0);//正方形の初期色を赤に設定
}
void draw(){
background(100);
rect(200,100,50,50);

//マウスが正方形内にある場合
if(mouseX>=200 && mouseX<=250 && mouseY>=100 && mouseY<=150){
if(mousePressed){//クリックした場合:緑
fill(0,255,0);
}else{//それ以外(クリックしない場合):黄
fill(255,255,0);
}
}else{ //それ以外(マウスが正方形外にある場合):赤
fill(255,0,0);
}
}

マウスの座標であるmouseXmouseYに対して、if文によって正方形内にマウスがあるかないかを判定しています。X座標に関しては正方形の左端(200)から右端(250)の座標、Y座標に関しては上端(100)から下端(150)の座標の範囲にマウスがある場合ということを、複数の条件としてif文に設定しています。&&は、複数の条件「Aという条件かつBという条件」という意味です。マウスの座標が200以上かつ250以下なので、200<=mouseX<=250と書きたいところですが、mouseX>=200 && mouseX<=250というように分けて書かないとエラーがでます。ちなみに「Aという条件またはBという条件」の場合は、||を用います。

このプログラムでは条件式が少し複雑ですが、まずマウスが正方形内にあるかないかという条件を設定します。もし正方形外ならそのままfill(255,0,0)で赤、もし正方形内であれば、ロールオーバーかクリックかという二つの条件に分かれて、mousePressedされれば、fill(0,255,0)で緑、そうでなければ、ロールオーバーのままfill(255,255,0)で黄色になるという仕組みです。
if(mousePressed){};というようにmousePressedは、if文の()内に入れて使うことはできますが、mouseReleasedはmouseReleased()として使うのであって、if文の()内に直接入れることはできません。

Processing マウス入力2



mouseXmouseYという関数を使えば、動かしているマウスのXY 座標を直接用いることができます。
矩形を描くrect()のXY座標値にmouseXmouseYを入れれば、マウス(カーソル)の動きに合わせて図形が動きます。例として、正方形(50pixel角)を動かすプログラムを以下に書いてみます。さらに、mousePressed()mouseReleased()を加えて、マウスボタンを押したら緑、放したら赤に戻る正方形の色も変化する内容にします。

int a; //正方形の1辺の長さの変数を用意する

void setup(){
//画面サイズ400×200に設定
size(400,200);
//正方形の一辺aを50に設定
a=50;
//正方形の位置基準を図形中央に設定
rectMode(CENTER);
//最初の塗り色を赤に設定
fill(255,0,0);
}

void draw(){
//背景色をとりあえず100に設定
background(100);
//正方形のXY座標にmouseX,mouseYを設定
rect(mouseX,mouseY,a,a);
}

void mousePressed(){
//押されたら塗り色を緑へ変える
fill(0,255,0);
}

void mouseReleased(){
//放したら塗り色を赤へ戻す
fill(255,0,0);
}

この場合、正方形は常にマウス(カーソル)に合わせて動きます。
さらに、正方形をクリックしてドラッグできるようなプログラムにするなら、正方形のXY座標用の変数も用意して、以下のようになります。

int a; //正方形の1辺の長さの変数を用意する
int x; //正方形のX座標の変数を用意する
int y; //正方形のY座標の変数を用意する

void setup(){
//画面サイズ400×200に設定
size(400,200);
//正方形の一辺aを50に設定
a=50;
//正方形の位置基準を図形中央に設定
rectMode(CENTER);
//最初の塗り色を赤に設定
fill(255,0,0);
//正方形の初期位置を画面中央にしておく
x=width/2;
y=height/2;
}

void draw(){
//背景色をとりあえず100に設定
background(100);
//描画される正方形に各変数を代入しておく
rect(x,y,a,a);
}

void mousePressed(){
//押されたら塗り色を緑へ変える
fill(0,255,0);
}

void mouseDragged(){
//ドラッグ中はrect()に代入されたXY座標用の
//変数x,yにマウス座標のmouseXとmouseYが
//対応するようにしておく
x=mouseX;
y=mouseY;
}

void mouseReleased(){
//放したら塗り色を赤へ戻す
fill(255,0,0);
}

setup()内にあるwidthは画面サイズ幅、heightは画面サイズ高さです。一度画面サイズをsize(400,200);と設定してしまえば、その後画面サイズである400や200という数値はwidthheightを使って代入することができます。
以上のプログラムでも問題ないかもしれないですが、やや不自然な挙動がひとつあります。正方形をクリックしてドラッグした時に正方形が少し瞬間移動してしまう点です(正方形の中心以外の箇所をクリックしてドラッグするとその不自然な挙動ははっきりします)。正方形の中心以外の箇所をクリックしたままドラッグできるようにするためには、クリックした地点の座標と正方形の中心座標との差分を計算に入れなければなりません。そのため、その差分の変数をとりあえずdx,dyとして用意しておき、以下のようになります。

int a; //正方形の1辺の長さの変数を用意する
int x; //正方形のX座標の変数を用意する
int y; //正方形のY座標の変数を用意する
int dx; //差分用のX座標変数
int dy; //差分用のY座標変数

void setup(){
//画面サイズ400×300に設定
size(400,300);
//正方形の一辺aを50に設定
a=50;
//正方形の位置基準を図形中央に設定
rectMode(CENTER);
//最初の塗り色を赤に設定
fill(255,0,0);
//正方形の初期位置を画面中央にしておく
x=width/2;
y=height/2;
//初期設定ではとりあえず差分を0にしておく
//(これは書かなくても大丈夫ですが、
// 一応書いておきます)
dx=0;
dy=0;
}

void draw(){
//背景色をとりあえず100に設定
background(100);
//描画される正方形に各変数を代入しておく
rect(x,y,a,a);
}

void mousePressed(){
//押されたら塗り色を緑へ変える
fill(0,255,0);
//クリックされた瞬間に正方形の座標と
//マウス座標の差分を求めておく
dx=x-mouseX;
dy=y-mouseY;
}

void mouseDragged(){
//ドラッグ中はrect()に代入されたXY座標用の
//変数x,yにマウス座標のmouseXとmouseYが
//対応するようにしておき、
//mousePressed()の中で求めた差分dx,dyを
//付け足す
x=mouseX+dx;
y=mouseY+dy;
}

void mouseReleased(){
//放したら塗り色を赤へ戻す
fill(255,0,0);
}
このプログラムでは、クリックした時に、正方形の位置座標であるx,yとマウスのmouseX,mouseYのズレを予め用意した変数dx,dyへ記憶させておき、最終的に正方形の座標にその差分であるdx,dyを付け足してズレを解消する微調整を行っています。インタラクティブな内容になるほど、ユーザ側への配慮が必要となってくるので、このようにプログラムもやや複雑で細かくなってきますが、逆に表現の幅を広げる工夫にもつながると思います。

マルチパッドフィルム Multi pad Slick Film #601AFAG for MacBook Late 2008 Series / MPSF601AFAG
マイクロソリューション Micro Solution Inc.
売り上げランキング: 3020

5/12/2008

Processing マウス入力1

前回までは、ループ処理を使って図形を動かしていました。ただ、このままでは一方的に動画を表示していることに過ぎないので、録画されたコンテンツを再生していることと、何ら違いがありません。今回は、ユーザ側からのマウス入力のプログラムを加えることで、一方的に表示されている内容を、相互作用的な内容へと変化させます。
例として、前回の入れ子で動く正方形のプログラム(「Processingの描画サンプル」)にマウス入力に反応するプログラムを書き足します。ここでは、mousePressed()というマウスのボタン(左クリック)が押された時に発動するプログラムを付け足してみます。
そのためには、

void mousePressed(){
//ここにボタンが押されたときに発動するプログラムを書く
}

というプログラムを前回のプログラムの最後に付け足します。

例えば、クリックしたら二つの正方形の位置がそれぞれ0に戻るというプログラムであれば、

int a=10;
int b=a*12;
int c=b*3;
int ax; //小さい正方形(黒)のX座標の変数
int bx; //大きい正方形(赤)のX座標の変数

void setup(){
size(360,120);
noStroke();
}

void draw(){
background(0);
fill(250,20,20);
rect(bx,height/2-b/2,b,b);
bx=bx+1;
if(bx>c){
bx=-b;
}
fill(0);
rect(ax+bx,height/2-a/2,a,a);
ax++;
if(ax>b){
ax=-a;
}
}

void mousePressed(){
ax=0;
bx=0;
}

となります(axは前回用いたプログラムの小さな黒い正方形のx座標のための変数、bxは大きな赤い正方形のx座標のための変数)。draw()の中の上から4行目の「bx=bx+1;」を「bx+=1;」あるいは「bx++;」と書くこともできます。同様にさらに6行下の「ax++;」は「ax=ax+1;」あるいは「ax+=1;」と同じことです。以前の「Processingの基本操作 その3」でも触れましたが、「++」はインクリメントと呼ばれ、変数に+1を自己代入して+1ずつ増加させていくことです。
mousePressed()のほかにmouseReleased()mouseDragged()mouseMoved()があります。
mousePressed()は、マウスボタンを押した瞬間に発動します。
mouseRelease()は、マウスボタンを押して放される瞬間に発動します。
mouseDragged()は、クリックし、そのままドラッグしている間発動し続けます。
mouseMoved()は、マウスが動いている間(クリックしなくても)発動し続けます。
それぞれの挙動の違いを各自確かめてみてください。

5/03/2008

Processingの描画サンプル

以下は、「One inch /One foot / One yard」のテーマをもとにProcessingで作成したプログラムの例です。



このプログラムでは、画面の横幅を1yard、大きな正方形(赤)を1footの正方形、小さな正方形(黒)を1inchの正方形とみなしています。入れ子になった正方形が左から右へ動くというサンプルです。
「One inch /One foot / One yard」は、単位やスケールに関わるテーマです。このようなシンプルな表現で構わないので、次回の授業までに作成してきてください。
ちなみに、このプログラムでは、noStroke()という関数を使っています。noStroke()は、rect()などの「図形の外形線を描かない」というコマンドです。それ以外は、このブログで説明してある方法を用いてプログラムできると思います。

以下がプログラムソースです。

int a=10;
int b=a*12;
int c=b*3;
int ax;
int bx;

void setup(){
size(360,120);
noStroke();
}
void draw(){
background(0);
fill(250,20,20);
rect(bx,height/2-b/2,b,b);
bx=bx+1;
if(bx>c){
bx=-b;
}
fill(0);
rect(ax+bx,height/2-a/2,a,a);
ax++;
if(ax>b){
ax=-a;
}
}


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