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 タッチスクリーン(部品)
CQ出版
ロジテック (2004-10-31)
売り上げランキング: 13452
売り上げランキング: 13452