INDEX(各項目ごとの目次)

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

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

9/17/2008

後期授業について

9/20(土)14:00から後期授業を開始します。後期授業説明をしたあとに、実験/作業を行います。

当日(9/20)に必要な道具/材料など:
・カッター(またはハサミ)
・不要な新聞紙や雑誌(不要な紙類)
・粘着テープ(ガムテープ、セロテープ、マスキングテープなど)




後期授業概要:
前期には、基本的な電子工作やプログラミングについて学習してきましたが、後期は実際の場面に対してそれらの技術を応用/表現していきたいと思います。
前半では、「BODY」というテーマで実際の身体を対象にしながら作業していきます。
中半では、「FURNI」というテーマで「BODY」で行った結果を家具的な道具/装置へ発展させます。
後半では、「ROOM」というテーマで、1階のギャラリーを実在するサイトとして、空間を変容させる実験を行います。
後期最後には、1階ギャラリーにて展覧会を行う予定です。

09/20:後期授業概要説明
    BODY01
09/27:BODY02
10/04:BODY03
10/11:FURNI01
10/18:FURNI02
10/25:FURNI03
11/01:中間発表/レクチャー
11/15:ROOM01
11/22:ROOM02
11/29:ROOM03
12/06:STRUCTURALIZATION
12/13:最終発表/展示(約1週間開催)

電子工作/プログラミングの技術的な内容については、必ずしも今までの内容(あるいはブログに掲載されている内容)をすべて習得していなくても、各自のレベルや作品制作の必要性に応じて随時復習していきます。

9/14/2008

Processing 緊急モーションセンサー(Mac)

Appleの2005年以降のPowerBook/iBook/MacBook(ノート型)には、緊急モーションセンサーが内蔵されています。緊急モーションセンサーは、ハードディスクを保護するために、あやまってコンピュータを落としたときの衝撃を感知します。
Processingには、この緊急モーションセンサーから値を得る「Sudden Motion Sensorライブラリ」があります。緊急モーションセンサーでは、以前扱った「加速度センサ」のように、コンピュータ本体を傾けたり衝撃を与えたりすることによって変化する値(XYZ軸に対する3つの値)が得られます。



Sudden Motion Sensorライブラリのサイトに従えば、3つの値は以下の方法で読み込むことが可能になります。尚、ライブラリをダウンロード+インストールする必要があります。

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

void setup() {
//画面サイズをとりあえず200角
size(200,200);
}

void draw() {
//3つの値を読み込み、配列に代入
int[] vals = Unimotion.getSMSArray();
//3つの値を出力
println(vals[0] + " " + vals[1] + " " + vals[2]);
}

上記プログラムによって出力された値は以下のようになりました(機種や状況によって多少誤差が含まれるかもしれません)。

水平時 x: 0, y: -3, z:56
左90度 x: 52, y: -3, z: 6
右90度 x:-51, y: -3, z: 5
前90度 x: 1, y: 49, z: 6
後90度 x: 1, y:-54, z: 5

xの振り幅:103(-51から52までの±51.5)
yの振り幅:103(-54から49までの±51.5)

になります。それぞれの振り幅からxとyの中点(水平時の値)を新たに求めると、

xの中点:(-51+52)/2=0.5
yの中点:(-54+49)/2=-2.5

になります。これら中点の値をオフセット値として用いることにします。つまり、計測された値からオフセット値を差し引いて角度の計算をすることになります。以前の「Arduino 加速度センサ」のときと同様に、出力値からそれぞれの角度を求める式を用意します。それぞれの角度をradX、radY、オフセット値をoffsetX、offsetY、読み取り値をx、yとすると、

//atan2()で求める場合
radX=atan2((x-offsetX),sqrt(51.5*51.5-(x-offsetX)*(x-offsetX)))
radY=atan2((y-offsetY),sqrt(51.5*51.5-(y-offsetY)*(y-offsetY)))

//またはacos()、asin()で求める場合
radX=asin((x-offsetX)/51.5)
radY=acos((y-offsetY)/51.5)

になります。式中の51.5は加速度1G(重力)の時の値です(機種によっては256くらいのときもあります)。

以上の式を使って、コンピュータ本体を傾けることでProcessing画面上の3Dモデルを動かしてみます。
3Dモデルに関しては、前回の記事「Processing 3Dモデル/OBJ Loader」のものを使うことにします。コンピュータを傾けた方向に、画面内の3Dモデルも同様に傾く内容とします。
スケッチフォルダ内にdataフォルダを作成し、3Dモデルのデータを入れておいて下さい(3Dデータは、ここからダウンロードできます/.objファイルと.mtlファイルの二つが必要です)。


(コンピュータを傾けた時の3Dモデル/前回ブログの3Dモデルを使用)


//ライブラリのインポート
import sms.*;
import saito.objloader.*;

//モデルのオブジェクトを用意
OBJModel model;

void setup() {
//3D画面サイズ設定
size(400,400,P3D);
//モデルのオブジェクトを生成
model=new OBJModel(this);
//3Dデータ読み込み
model.load("macbook.obj");
//ワイヤーフレームなし
noStroke();
}

void draw() {
//3つの値を読み込み、配列に代入
int[] vals = Unimotion.getSMSArray();
//println(vals[0] + " " + vals[1] + " " + vals[2]);

//背景描画
background(50);
//直線光の設定
directionalLight(200, 200, 200, -1, 1, -1);
//環境光の設定
ambientLight(200, 200, 200);

//3Dモデルの位置座標設定
translate(width/2,height*2/3,0);

//オフセット値
float offsetX=-2.5;
float offsetY=0.5;
//角度の計算:atan2()で求める場合
float radX=-atan2(vals[1]-offsetX,sqrt(51.5*51.5-(vals[1]-offsetX)*(vals[1]-offsetX)));
float radY=-atan2(vals[0]-offsetY,sqrt(51.5*51.5-(vals[0]-offsetY)*(vals[0]-offsetY)));
//またはacos()、asin()で求める場合
//float radX=asin((vals[1]-offsetX)/51.5);
//float radY=acos((vals[0]-offsetY)/51.5);

//回転角度
rotateX(radX+PI/2);
rotateY(radY);

//三角形分割で面を生成する
model.drawMode(TRIANGLES);
//スケール(200倍)
scale(200);
//モデル描画
model.draw();
}

画面内の3D座標は、
左:-X
右:+X
上:-Y
下:+Y
後:-Z
前:+Z
という関係になります。
緊急モーションセンサーのX軸は、Processing上のY軸に対応しているので、vals[0]の値を3DモデルのY軸回転角度へ代入し、val[1]の値は3DモデルのX軸回転角度へ代入します。表示上90度X軸に対してずれていたので、rotateX(radX+PI/2)というようにradXにPI/2(90度)足しておきました。
directionalLight()は太陽光のような直線光であり、括弧内の数値については、最初の3つがRGBで光の色を指定、最後の3つが(0,0,0)の原点を基準に光の向きを設定することになります。
ambientLight()は環境光であり、光の向きはなく、空間全体を明るくしたり暗くしたりし(あるいは色を変える)、RGBの3つの数値で指定します。


もう一つのサンプルとして、コンピュータ自体をコントローラとして傾けて、水平面上のボールを転がすプログラムをしてみます。今回は、setup(){...}内で、一度緊急モーションセンサーから値を読み込み、それらをオフセット値として使うことにします。こうすることで、コンピュータを平らな場所においてプログラムを開始したときの状態(オフセット値)を記憶させておくことができます。ellipse()で擬似的な影を地面に落とすことで立体感がでるようにします。


(コンピュータの傾きに合わせてボールが転がる)


//ライブラリのインポート
import sms.*;

//ボールの座標用変数
float xPos,yPos;

//オフセット用変数
float xOffset;
float yOffset;

void setup() {
//3D画面設定
size(400,400,P3D);
//ワイヤーフレームなし
noStroke();
//水平状態の読み込み
int[] vals = Unimotion.getSMSArray();
//読み込み値をオフセット値に設定する
xOffset=vals[0];
yOffset=vals[1];
}

void draw() {
//モーションセンサーからの読み込み
int[] vals = Unimotion.getSMSArray();
//背景色
background(220);
//画面上半分の塗色
fill(50);
//画面上半分の矩形
rect(0,0,width,height/2);

//ボールの速度の計算
float xSpeed=vals[0]-xOffset;
float ySpeed=vals[1]-yOffset;
//ボール移動量の計算
xPos+=-xSpeed;
yPos+=ySpeed;
//ボール位置の設定
translate(width/2+xPos,height*4/5,-200+yPos);

//影の塗色
fill(50);
//影の座標と大きさ
ellipse(-25,30,80,80/5);

//直線光の設定
directionalLight(255, 255, 255, -1, 1, 0);
//ボールの塗色
fill(255,100,50);
//ボール描画
sphere(30);
}

緊急モーションセンサーの読み取り値からオフセット値を差し引いた値を、そのままボールのスピードに反映させています。読み取られたY方向の値は、画面内のZ座標(前後の軸)に対応するので、yPosをtranslate()のZ軸に代入してあります。実際に動かしてみて、向きが逆であったり、座標軸がきちんと対応していない場合は、値にマイナスを掛けたり、代入先を入れ替えたりして調整してみて下さい。
ボールの位置設定のためのtranslate()は、まずX座標をwidth/2で左右中央、Y座標をheight*4/5で画面上下4/5の位置、Z座標を-200奥とした座標を基準とし、その基準の座標に変化する値となるxPosとyPosを追加して、最終的な位置を決定しています。
疑似の影として用いたellipse()は2D用の図形でありX座標とY座標しか設定できませんが、translate()以後に挿入してあるので、translate()のZ軸の値に合わせて、前後に動きつつ大きさも変化します(2D図形は、3D空間上ではZ座標値が0の位置に配置されており、translate()以後に書いた2D図形は、Z軸の値を変化させれば、見た目の大きさや位置も影響を受けて変化します)。同様に、directionalLight()に対しても、2D図形をdirectionalLight()以前に書けば、光の影響を受けませんが、directionalLight()以後に2D図形を書くと、光の影響を受けて図形自体に陰影がつきます。そのため、directionalLight()は、プログラムの冒頭の方に書かずに、ボール描画の直前(2D図形描画以降)に書いておきます。

9/11/2008

Processing 3Dモデル/OBJ Loader

Processingのライブラリには、3Dモデリングソフトで制作した3Dモデルを読み込むOBJ Loaderライブラリがあります。OBJ Loaderでは、拡張子が「.obj」の3Dモデルを扱うことができます。3Dモデリングソフトがあれば、制作した3Dモデルを「.obj」フォーマットで書き出して、3DデータをOBJ Loaderで読み込みます。読み込みに使用する3Dデータは、スケッチフォルダ内に入れておきます。
また、モデリングが面倒であれば、インターネットからフリーの3Dデータを検索しダウンロードして利用する方法もあります。この場合「.obj」フォーマットのデータでなければならないのですが、それ以外のフォーマットであっても、一旦3Dモデリングソフトで読み込んで「.obj」フォーマットにして書き出せば利用可能です。最近はフリーの3Dモデリングソフトも多く存在するので、ダウンロード/インストールしてすぐに使うことができるはずです(ブログページ右側にもフリーのモデリングソフトのリストがあります)。

参考3Dモデリングソフト(フリーウェア):
Blender (Win,Mac)
Maya 2010体験版(30日)(Win,Mac)
Rhino (Mac用ベータ版/要登録)
Metasequoia/LE (Win)
DoGA (Win)
CB Model Pro (Win,Mac)
SketchUp (Win,Mac)
SketchyPhysics (Win):SketchUp物理演算プラグイン
trueSpace7 (Win)
CoCreate (Win/要登録)

今回はインターネット上から無料の3Dモデルのデータをダウンロードし、Processing上に表示してみたいと思います。Turbo Squidという3Dモデルのデータライブラリのサイトから無料の3Dモデルを探し出し、以下の3Dモデルを利用してみたいと思います(データをダウンロードするにはTurbo Squidに登録する必要があります)。

http://www.turbosquid.com/3d-models/max-apple-macbook/391534

このモデルは拡張子が「.3DS」なので3ds Max用のデータです。フリーウェアのBlenderという3Dモデリングソフトで、この「.3DS」フォーマットのデータを読み込み(File>Import>.3ds)、「.obj」フォーマットで書き出して(File>Export.obj)利用してみたいと思います(「.obj」に変換したファイルのリンクはこの記事の最後にあります)。

はじめてのBlender (I・O BOOKS)
山崎 聡
工学社
売り上げランキング: 6131


そのまま読み込むと、各パーツの位置が少しずれていたので、修正して「.obj」フォーマットで書き出すことにしました。「.obj」フォーマットを選択して書き出すと、「~.obj」と「~.mtl」という二つのファイルが出来上がります。「~.obj」はポリゴンの座標についてのデータであり、「~.mtl」は色や材質、テクスチャなどのデータが含まれています。以下のプログラムで、3Dデータを読み込んでみます(「~.obj」ファイルと「~.mtl」ファイルは、スケッチフォルダ内に入れておいてください)。

//ライブラリのインポート
import saito.objloader.*;

//モデルのオブジェクトを用意
OBJModel model;

void setup() {
//3D用の画面設定
size(400,400,P3D);
//モデルのオブジェクトを生成
model=new OBJModel(this);
//objファイルの読み込み
model.load("macbook.obj");
//ワイヤーフレームなし
noStroke();
}

void draw(){
//背景描画
background(50);
//直線光の設定
directionalLight(200, 200, 200, -1, 1, -1);
//環境光の設定
ambientLight(200, 200, 200);

//3Dモデルの位置設定
translate(width/2,height/2,0);
//スケール設定(200倍)
scale(200);

//マウス入力で回転させる
rotateX(PI*mouseY/height);

//三角形分割で面を生成する
model.drawMode(TRIANGLES);
//3Dモデルの描画
model.draw();
}


Blenderでは、細かな出力設定はせずに、そのまま「.3DS」データを読み込み(File>Import>.3ds)、「.obj」フォーマットで書き出す(File>Export>.obj)ことにします(書き出す際には、予め画面上で3DモデルをSelectしておく必要があります)。表示されるスケールが小さすぎたので、scale()で200倍の大きさに変換しています。そのまま表示させると、3Dモデルの色が真っ黒のままだったので、多少の修正が必要になります。



色などの内容を確かめるために「.mtl」ファイルをテキストエディタなどで開くと、以下のような内容が記述されていることが分かります。

# Blender3D MTL File: macbook.blend
# Material Count: 2
newmtl Screen
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.084706 0.084706 0.084706
Ks 0.449020 0.449020 0.449020
Ni 1.000000
d 1.000000
illum 2

newmtl Plastic
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.800000 0.800000 0.800000
Ks 0.449020 0.449020 0.449020
Ni 1.000000
d 1.000000
illum 2

このデータには、ScreenとPlasticという名前の二つの材質についての数値が含まれており、以下のような内訳になります。
# コメント
newmtl 材料名
Ns 輝度
Ka 環境色
Kd 拡散色
Ks 反射色
Ni 光の屈折率
d  アルファ値
illum 0:照明なし、1:反射ハイライトなし、2:Ksの値で反射ハイライトあり

恐らくKaの値がそれぞれ0.000000, 0.000000, 0.000000なので真っ黒な状態になったのでしょう。それぞれの値を以下のように変えます。

ScreenのKaの値を
Ka 0.1 0.01 0.01

PlasticのKaの値を
Ka 0.7 0.7 0.7

上記三つの値はRGB(赤,緑,青)に対応しています。
それぞれの値を変更すると、ScreenのKaは少し赤みがかった黒、PlasticのKaは白に近いグレーになります。
先ほどのプログラムで再度描画させれば、以下のようにかたちが認識できるようになるはずです。


マウス上下で3Dモデルも上下に回転します。
見えない場合はこちらへ


Processingでは、box()sphere()vertex()などの基本的な3D描画のコマンドはありますが、複雑な3Dモデルを制作する際には、モデリングソフトを利用して取り込んだ方がいいでしょう。あるいは、3Dモデルのデータもインターネット上に数多く存在しているので、検索すれば相応しいものが見つかるかもしれません。
尚、上記プログラムで使用したmacbook.objとmacbook.mtlのファイルは、ここからダウンロードできます。


3Dキャラクタアニメーション Blender(DVD付)
トニー・マレン
アスキー
売り上げランキング: 118200

8/30/2008

Arduino タッチパネル(4線式)4-wire touch panel

*Some are written in English at the moment(sorry not all of them...)
This example shows how to use a touch panel/screen with an Arduino board plus a serial communication to a Processing program, which draws where to touch on the touch panel.
This is not about a multi-touch function, only single point on the touch panel can be detected.

今回は、4線式のタッチパネルをArduino基盤に接続し操作実験してみたいと思います。
タッチパネルには、4線式や5線式という比較的簡単な構造になっているものがあります。今回使うタッチパネルは、指先やペン先で触れた一点の位置(X座標値とY座標値)を検出可能にするものです(複数の点を同時検出可能なマルチタッチではありません)。
基本的には、X座標に2線、Y座標に2線あり、合計4線あります。手順としては、まずX座標を検出、そしてY座標を検出というように別々(交互)に行います。タッチパネル自体がX座標用とY座標用に対応した2層の抵抗になっており、X座標(横方向)だけで考えれば、タッチパネルの左端に0V、右端に5Vを接続しておいて、指先で触れた箇所で分圧される仕組みになっています。つまり、X座標の左に行くほど0Vに近く、中心に触れれば約2.5V、右に行くほど5Vに近い電圧が読み取れることになります。X座標を読み取る際には、使用していないY座標の2線のうちの1本を使います。X座標を検出したら、検出対象をY座標に切り替えて同様の方法で検出を続けます。下の図では、タッチパネルの2層あるうちのX座標用の層を押せば、下にあるY座標用の層と接触し、その地点での分圧された電圧の値をY座標用の層から読み込むことができます。
There are two layers of conductive films on a 4-wire touch panel, the one for x-coordinate and the other for y-coordinate. Each layer is connected to GND and 5V on the egdes. Pressing the x-coordinate layer with your finger, then the x-coordinate layer will contact to the other layer(y-coordinate layer) underneath. At this moment the voltage is devided at the point where the two layers are touching, and the devided valtage can be read from the edge of the y-coordinate layer(the y-coordinate layer is working as a conductive film for the x-coordinate film at this time).



Arduino基盤との接続は、以下のようにアナログ入力の0〜3番ピンに接続することにします(X座標用に0番ピンと1番ピン、Y座標用に2番ピンと3番ピンを使用)。通常タッチパネルなどの薄型の機器にはFPC(フレキシブルプリント基板)/FFC(フレキシブルフラットケーブル)の端子がついています。Arduino基盤からのワイヤーと接続するためにはFFC用コネクタを介して接続します(直接ハンダ付けできないので)。
X座標を計測中にはyLowの端子からX座標の分圧された電圧を読み取るので(Y座標を計測中にはxLowの端子で読み取る)、タッチパネル上に何も触れていない時は、xLow端子に0Vが接続されるようにするため、プルダウン抵抗を接続しておきます(xLowやxHighとyHighにもプルダウン抵抗をつけておきます)。


Needs a pull-down resistor for each wire from the touch panel.

処理の手順は、まずX座標(横方向)の検出を行う際には、アナログ入力の「0番ピンと1番ピン」を「14番ピンと15番ピン」としてデジタル出力に切り替え、14番ピンを0V(LOW)、15番ピンを5V(HIGH)で出力しておきます。そして、Y座標用のアナログ入力2番ピンを通してanalogRead()で値を読み込みます。読み込まれた値は、X座標の値になります。このとき、Y座標用のアナログ入力「2番ピン」がデジタル出力にならないように「16番ピン」として予めデジタル入力にしておきます。「3番ピン」も同様に「17番ピン」としてデジタル入力にしておきます。
Y座標(縦方向)の検出の際には、アナログ入力の「2番ピンと3番ピン」を「16番ピンと17番ピン」としてデジタル出力に切り替え、16番ピンを0V(LOW)、17番ピンを5V(HIGH)で出力しておきます。X座標用であった「14番ピンと15番ピン」をデジタル入力に切り替えておいてから、アナログ入力「0番ピン」を通してY座標の値をanalogRead()で読み込みます。このように1ループのなかで、X座標とY座標の検出処理を順番に行い、それぞれの座標値を得ます。
Basically using the analog pins 0,1,2,3 on an Arduino board, those pins can be both analogRead pins and digitalWrite pins(in this case:pin numbers are 14,15,16,17) depending on setting.
First, to read an x-coordinate value, set the pin14 as 0V(LOW) and the pin15 as 5V(HIGH), then the rest of the pins(either of 16 and 17) can be analogRead pins. Next, to read a y-coordinate value, set the pin16 as 0V(LOW) and the pin16 as 5V(HIGH), then read the value from either of the pin14 and the pin15. Reading the both value one after another then send them through a serial communication to Processing.

//デジタル出力用ピン番号の定義:the digital output pins
#define xLow  14
#define xHigh 15
#define yLow  16
#define yHigh 17

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

void loop(){
  //X座標用端子をデジタル出力に設定し、それぞれをLOWとHIGHで出力しておく
  //set the both x-coordinate pins as digital output:one is Low the other is HIGH  
  pinMode(xLow,OUTPUT);
  pinMode(xHigh,OUTPUT);
  digitalWrite(xLow,LOW);
  digitalWrite(xHigh,HIGH);

  //Y座標用端子をLOWにしておく:the both y-coordinate pins are set to be LOW
  digitalWrite(yLow,LOW);
  digitalWrite(yHigh,LOW);

  //Y座標用端子をデジタル入力に設定:change the y-coordinate pins as digital input
  pinMode(yLow,INPUT);
  pinMode(yHigh,INPUT);
  delay(10);

  //アナログ入力2番ピン(yLowピン)で読み込み
  //read analog pin2(yLow pin) to get an x-coordinate value
  int x=analogRead(2);
  
  //Y座標用端子をデジタル出力に設定し、それぞれをLOWとHIGHで出力しておく
  //set the both y-coordinate pins as digital output:one is Low the other is HIGH 
  pinMode(yLow,OUTPUT);
  pinMode(yHigh,OUTPUT);
  digitalWrite(yLow,LOW);
  digitalWrite(yHigh,HIGH);

  //X座標用端子をLOWにしておく:the both x-coordinate pins are set to be LOW
  digitalWrite(xLow,LOW);
  digitalWrite(xHigh,LOW);

  //X座標用端子をデジタル入力に設定:change the x-coordinate pins as digital input
  pinMode(xLow,INPUT);
  pinMode(xHigh,INPUT);
  delay(10);

  //アナログ入力0番ピン(xLowピン)で読み込み
  //read analog pin0(xLow pin) to get an y-coordinate value
  int y=analogRead(0);

  if(Serial.available()>0){
    //文字列でシリアル通信:send the values as a DEC format with a delimiter
    Serial.print(x,DEC);   //X座標:x-coordinate
    Serial.print(",");     //デリミタ:delimiter
    Serial.println(y,DEC); //Y座標:y-coordinate

    //合図用信号読み込みでバッファを空にする
    //read a handshake signal from Processing and clear the buffer
    Serial.read();
  }
}

今回実験で用いたタッチパネルは、12.1インチのサイズ(横:縦=4:3)であり、指先で触れた位置が
パネル左端: 70 :a minimum value when touching the left edge of the touch panel
パネル右端:781 :a maxmum value when touching the right edge of the touch panel
パネル上端: 81 :a minimum value when touching the upper edge of the touch panel
パネル下端:822 :a maxmum value when touching the lower edge of the touch panel
の値として検出されました。パネルに触れないときには、プルダウン抵抗により0が出力されます(以下Processingのプログラムでは、XとYの読み取り値が10以上のときタッチしていることとして判別しています)。
In this example, I used a 12.1-inch(width:height=4:3) touch panel.
When touching each edge of the touch panel, the values are like the above.
When not touching the touch panel, you can read zero value from the analog pins because of the pull-down resistors.

それでは、座標値をProcessingへシリアル通信し、Processingの画面上に描画することにします。Processingへは、座標値を文字列として送信することにします(文字列のシリアル通信については「Arduino-Processing シリアル通信5」を参照して下さい。Processing側では、タッチパネル上の指先の動きに合わせて円が動くようにします。タッチパネルに触れている時といない時では円の色が変化するようにします。「s」キーを押してシリアル通信開始です。
The below Processing code is that:
a circle on the screen moves and follows where to touch on the touch panel,
the color of the circle changes depending on touching or not touching.
*Press 's' key to start the serial communication with the Arduino.

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

//読み込み値の変数を用意:variables for data from the Arduino
int x,y;
//座標用変数を用意:variables for xy-coordinates to draw a circle on the screen
float xPos,yPos;

void setup(){
  //画面サイズ設定
  size(800,600);
  smooth();
  //シリアルポート設定
  port = new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
  //「10」(ラインフィード)が来る度に
  //serialEvent()を作動させる
  port.bufferUntil(10);
  background(0);
  stroke(255); 
}

void draw(){
  //背景描画(黒)
  background(0);

  if(x>10 && y>10){//タッチしている時:when touching
    //塗り色を白にする
    fill(255);
    //読み取り値を座標にマッピングする
    xPos=map(x,70,781,0,width);
    yPos=map(y,81,822,0,height);
  }else{//タッチしていない時:when not touching
    //塗り色を黒にする
    fill(0);
  }

  //マッピングした座標を代入し円を描写:draw a circle
  ellipse(xPos,yPos,20,20);
}

//シリアル通信:serial communication
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[]内のデータが2つなら、
    if(data.length==2){
      //最初のデータをxに代入
      x=data[0];
      //次のデータをyに代入
      y=data[1];

      //合図用データ送信:send a handshake signal
      port.write(65);
    }
  }  
}

//キー「s」が押されたら通信開始
void keyPressed(){
  if(key=='s'){
    //開始用データ送信:send a first handshake signal
    port.write(65);
  }
}

Arduinoから送られてくるXY座標値をmap()をつかってProcessingの画面上のXY座標値に対応させます。今回の場合、読み取りの最小値(70,81)を画面上の(0,0)に、読み取りの最大値(781,822)を(width=800,height=600)に対応させます。

通常タッチパネルはモニターと一体型になっていますが、タッチパネルだけを用いて透明で平面的な入力デバイスとして利用することも考えられます。仕組みはそれほど複雑ではないので、中古やジャンクのタッチスクリーンなどを分解して手に入れてもいいかもしれません。

以下のサイトでは、タッチパネルの構造や仕組みについて説明してあります。Other sites explaining about touch panels/touch screens.
グンゼ/タッチパネル製造
DMC/タッチパネル製造

また、以下のようなタッチパネル製品/部品などもあります。Shops selling touchpanel parts.
aitendo/タッチパネル部品販売
ストロベリーリナックス/PSP用タッチパネル
スイッチサイエンス/NintendoDSタッチスクリーン
Liquidware/Arduino TouchShield
Sparkfun/OLED+Touchscreen
iPodパーツショップ/iPhone 3G タッチスクリーン(部品)



Logitec USB対応15型タッチパネル LTP-15U
ロジテック (2004-10-31)
売り上げランキング: 13452

8/23/2008

Arduino 距離センサ/超音波レンジファインダー

今回は、Parallax社の超音波レンジファインダー「PING)))」で距離の計測実験を行います。距離センサとして、以前に赤外線で検出する「GP2Y0A21YK」を扱いましたが、「PING)))」は超音波を使って検出するタイプです。測定距離は3cm〜3.35mとなっているので、「GP2Y0A21YK」(測定距離10cm〜80cm)より測定範囲の幅はあります。「GP2Y0A21YK」は、信号端子をPWM端子に接続しanalogRead()によって簡単に読み込みが可能ですが、「PING)))」では1本の信号端子(SIG)に対してパルスを用いて測定します。まず「PING)))」から超音波を発します(5マイクロ秒間)。その超音波が物体に当たれば反射して戻ってくるので、戻ってくるまでの時間を計測し、音速と時間の関係から距離を導き出します。
サンプルソースがArduinoサイトのPlaygroundLearning>Examples>Complex Sensorsの中にあります。前者はpulseIn()を使って反射波の時間を計測しており、後者は変数を用いて時間をカウントしています。今回は前者のpulseIn()を用いた方法を参考にします。pulseIn()の場合は、unsigned long(正の整数値:0〜4,294,967,295までの値)の変数タイプを用います。尚、接続方法は以下の通りです。




//反射波の変数を用意
unsigned long echo = 0;
//信号ピンを9番ピンに設定
int signalPin = 9;

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

void loop(){
//まず信号ピンを出力に設定(発信用)
pinMode(signalPin, OUTPUT);
//2マイクロ秒間LOWで出力
digitalWrite(signalPin, LOW);
delayMicroseconds(2);
//5マイクロ秒間HIGHで出力
digitalWrite(signalPin, HIGH);
delayMicroseconds(5);//超音波発信
//信号ピンをLOWに戻す
digitalWrite(signalPin, LOW);

//信号ピンを入力に設定(受信用)
pinMode(signalPin, INPUT);
//信号ピンをHIGHに設定
digitalWrite(signalPin, HIGH);
//反射波が戻ってくるまでの時間を計測し
//片道の時間(半分の値)にする
echo = pulseIn(signalPin, HIGH)/2;
//ミリメートル単位に変換
int distance = echo*0.34442;

//距離を出力
Serial.println(distance);
delay(250);
}


PING)))」では、ひとつの信号端子(SIG)だけで超音波の発信と受信を切り替えて制御する必要があります。まず最初に信号端子をLOWに設定(2マイクロ秒程度)しておき、その後5マイクロ秒間HIGHにすると、超音波が発信します。その後、物体に反射して戻ってくる超音波を感知させるために、信号端子を「デジタル出力」から「デジタル入力」に切り替えます。「デジタル入力」に切り替えられた信号端子は、反射波を受信するとHIGHになります。反射波がなくなればLOWになるので、それまでの継続時間をpulseIn()でカウントします。pulseIn()の括弧内には、ピン番号とHIGHかLOWの値を入れます。HIGHを入れれば、そのピンがHIGHになるまで待機し、HIGHになったときに時間(マイクロ秒単位)の計測を開始し、次にLOWになるときに時間の計測を終了します。今回の場合は、発信した超音波が反射して戻ってくるまでの時間を計測してくれることになります。計測した時間は超音波が往復して戻ってくるまでの時間なので、計測時間の半分が実際の距離に要した時間となります。音速は344.42m/secなので、1マイクロ秒で0.34442mmの距離を進むことになります。従って、pulseIn()で求めた時間(往復)を片道分の時間にするため2で割り、0.34442をかければミリメートル単位で出力することになります。


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