http://www.youtube.com/watch?v=NbM7Ni2_eEQ&list=UUyt09UeQcMrj8QUSr5BEmaQ
จะทำการอ่านค่าจากพอร์ท Analog ของ Arduino มาแสดงบนหน้าจอ Android
ตอนนี้จะเรียนรู้การนำภาพมาแสดงบนจอ การวาดเส้นขยับตามค่าโวลต์ที่อ่านจากพอร์ท แสดงตัวเลขแบบกราฟฟิก
ไฟลต่างๆที่ต้องใช้ โหลดมาครับ
1. ไฟล์หน้าปัทม์ https://www.dropbox.com/s/q5ouvwpmr7188sr/voltmeter.JPG
2. ไฟล์ตัวเลขกราฟฟิก https://www.dropbox.com/s/0er5h40u5zoiwo3/flipnumber.png
การนำตัวเลขมาใช้งาน
ทำได้ด้วยการเจาะเอาเฉพาะภาพในส่วนที่ตัวเลขนั้นอยู่ ที่เราคุ้นเคยก็คือการ Crop นั่นเอง วิธีการนี้ใช้ทั่วไปกับการทำเกมส์ โดยการวาดท่าทางต่างๆของตัวแสดง เช่นรูปนกบิน โดยวาดการขยับปีกขึ้นลงในแต่ละช่อง จากนั้นก็ให้โปรแกรมนำช่องที่ต้องการมาแสดง แต่ของเราก็จะเอาค่าที่อ่านได้ของหลักใดหลักหนึ่งมาบอกว่าจะเจาะเอาช่องไหนมาแสดง
ในรูปตัวเลขที่ให้มาจะมีระยะห่างระหว่างตัวเลขเท่ากับ 128 ดังนั้นถ้าต้องการตัวเลข 4 ก็จะไป crop ที่ X = (128 * (4 - 1)) = 384, Y = 0; ความกว้าง = 128, ความสูง = 174 ส่วนของการนำภาพที่ crop ไปใช้ก็ให้คำนวณค่าก่อน หาตัวเลขที่อยู่ในแต่ละหลัก แล้วก็มาหาตำแหน่งที่ต้องการดึงมาใช้
สร้าง Processing Sketch ใหม่ ตั้งขื่อตามใจชอบ บันทึก จากนั้นลากไฟล์รูปภาพทั้งสองวางลงในพื้นที่ของ Editor ตรงไหนก็ได้ครับ โปรแกรมจะทำการสร้างโฟลเดอร์ชื่อ data เพื่อเก็บไฟล์ทั้งสอง ลองเปิดดูในโฟลเดอร์ของ sketch ดูครับ ทีนี้ถ้าต้องการใช้ไฟล์อะไร ก็ลากไปวางตรงพื้นที่ที่ใช้พิมพ์โค๊ดนั่นแหละ มันก็จะเอาไปเก็บให้เราเอง
ทีนี้เอาไฟล์ AndroidManifest.xml และโฟลเดอร์ res (ย้อนกลับไปดูตอนที่ 7 AndroidSerial Library) ยกมาวางในโฟลเดอร์ของ Sketch อันนี้ลากมาวางในพื้นที่โค๊ดไม่ได้นะครับ เพราะมันจะเอาไปใส่ในโฟลเดอร์ data โปรแกรมจะมองไม่เห็น ให้วางอยู่ในระนายเดียวกับตัว sketch
Arduino โค๊ด
void setup(){
pinMode(11,OUTPUT);
digitalWrite(11,LOW);
Serial.begin(9600);
}
char c;
String str = "";
boolean active = false;
void loop(){
//delay(200);
if(Serial.available()){
while(Serial.available() > 0){
c = Serial.read();
if(c == '\n'){
if(str[0] == 'B')
{
digitalWrite(11, !digitalRead(11));
active = true;
}
if(str[0] == 'S')
active = false;
str = "";
}else{
str += c;
}
}
}
else
{
if(active)
{
Serial.println(map(analogRead(A0),0,1023,0,255));
active = false;
}
}
}
ตัวโค๊ดจะอ่านตัวอักษรมาตรวจสอบว่ามีตัว newline (\n) หรือไม่ ถ้ามีก็ให้ดูว่าตัวคำสั่งคืออะไร ถ้าเป็นตัวอักษร B ก็จะสั่งให้ LED ติด-ดับ และเปิดให้ส่งข้อมูลของ A0 กลับไป สังเกตุว่าเมื่อส่งค่าคืนไปแล้วก็จะปิดการส่ง ด้วยคำสั่ง active = false; การทำแบบนี้ก็เพื่อไม่ให้ส่งข้อมูลกลับมากเกินไป ซึ่งจะทำให้ตัวรับต้องมาตอบสนองข้อมูลจนไม่สามารถไปทำงานอื่นได้ เมื่อส่งข้อมูลกลับแล้วก็จะมารอรับคำสั่งต่อไป วิธีการนี้สามารถประยุกต์ไปใช้ได้กับงานอื่นๆได้นะครับ
โค๊ดสำหรับ Processing
import com.yourinventit.processing.android.serial.*;
import java.net.*;
PImage pimage;
PImage nimage;
Serial port;
String voltRead="0"; // เก็บค่าโวลต์
void setup(){
size(400,342);
originX = 205;
originY = 245;
frameRate(10); // กำหนดความเร็วในการวาดภาพ ตอนนี้เป็น 10 ครั้งต่อวินาที
pimage = loadImage("voltmeter.JPG"); // โหลดรูปหน้าปัทม์
nimage = loadImage("flipnumber.png"); // โหลดรูปตัวเลข
println(Serial.list(this));
port = new Serial(this,Serial.list(this)[0],9600);
port.clear();
port.bufferUntil('\n');
port.write("B\n"); // ส่งคำสั่งไปที่ Arduino สังเกตุว่าต้องมี \n ตามไปด้วย
}
int originX, originY;
float measureVolt;
long lastMillis = millis();
int digit = 0;
int count = 0;
boolean portReady = true;
void draw(){
try{ // ใส่คำสั่ง try ไว้เผื่อว่าเกิดข้อผิดพลาดใดๆ ตอนทำงาน โปรแกรมจะได้ไม่หยุดทำงาน
background(0);
image(pimage,0,0); // วางรูปหน้าปัทม์
needle(originX, originY, measureVolt); // วาดรูปเข็มตามค่าที่รับมาจาก Arduno
//
// ส่วนนี้เป็นการ Crop ตัวเลขมาจากรูปตัวเลข
//
int c = int(measureVolt) % 1000; // ดึงค่าตัวเลขที่น้อยกว่า 1000 มาใช้งาน
// ส่วนนี้เป็นหลักร้อย โดยที่ c/100 จะดึงตัวเลขที่หลักร้อยมาใช้งาน เพื่อหาว่าจะนำช่องไหนของรูปตัวเลขมาแสดง
// นี้คือตำแหน่งที่ของตัวเลข
int iStart = ((c / 100) * 128);
// คำสั่ง copy จะ crop รูปตัวเลข nimage ที่ตำแหน่ง x = iStart, y = 0, กว้าง 128 สูง 174 จากนั้นเอาไป
//วาดไว้ที่ตำแหน่ง x = 152, y = 250 ย่อขนาดกว้างลงมาเป็น 32 และสูง 45
copy(nimage,iStart,0,128,174,152,250,32,45);
// หลักสิบ
c = c % 100;
int iStart1 = (( c / 10) * 128);
copy(nimage,iStart1,0,128,174,184,250,32,45);
// หลักหน่วย
c = c % 10;
int iStart2 = (c * 128);
copy(nimage,iStart2,0,128,174,216,250,32,45);
// ส่วนนี้ให้รอ 300 ms แล้วค่อยส่งคำสั่งไปอีกครั้ง
if((millis() - lastMillis) > 300){
lastMillis = millis();
port.write("B\n");
}
}
catch(Exception e){
// ส่วนนี้เพื่อให้รู้ว่าตอนทำงานพบปัญหา เพื่อให้สามารถ debug เพื่อแก้ไข
println("Something happen: " + (++count));
lastMillis = millis();
}
}
//
// ส่วนนี้จะทำการวาดเข็มให้เคลื่อนไปในตำแหน่งที่ได้รับมาจาก Arduino
//
void needle(int originX, int originY, float measureVolt){
int minToMaxAngle = 90; // มุมที่วัดจากตำแหน่งค่าเท่ากับ 0 ไปถึงค่าสูงสุดในที่นี้คอที่ตำแหน่ง 50
int maxVolt = 50; // ค่าโวลต์สูงสุด
int startAngle = 45; //มุมที่วัดจากตำแหน่ง 0 องศา (ซ้ายมือ) มาถึงตำแหน่ง 50 โวลต์
// มุมที่เข็มเคลื่อนที่
float angle = (PI/180) * ((minToMaxAngle * (maxVolt - measureVolt) / maxVolt) + startAngle);
// ความยาวของเข็ม
float needleLength = 200;
strokeWeight(2); // ขนาดความหนาของเข็ม
stroke(255,0,0); // สีของเข็ม (สีแดง)
// วาดเส้น
line(originX, originY, originX+cos(angle)*needleLength, originY-sin(angle)*needleLength);
fill(0);
noStroke();
// วาดรูปวงกลมปิดเข็มในส่วนที่ไม่ต้องการ
ellipse(originX,originY,100,100);
}
// ส่วนการรับข้อมูลและแปลงค่าที่อ่านได้เป็นขนาดโวลต์
void serialEvent(Serial port){
// อ่านค่าที่ส่งมาจาก Arduino เมื่อพบตัว \n ให้เก็บค่าไว้ที่ voltRead
voltRead = port.readStringUntil('\n');
port.clear();
voltRead = trim(voltRead);
// นำ voltRead มาแปลงค่าเป็น measureVolt เพื่อใช้ในการวาดเข็มและแสดงตัวเลข
measureVolt = float(voltRead) * 50 / 255;
}
บทความตอนนี้ จะเน้นในการนำค่าที่ได้มาแสดงให้เกิดความน่าสนใจ โดยที่อาจทำการสร้างหน้าปัทม์ขึ้นเองด้วยโปรแกรม Graphic Editor ต่างๆ เช่น Photoshop, Paint แล้วก็บันทึกเป็นไฟล์ jpg, gif หรือ png นำมาวางเป็นพิ้นหลัง จากนั้นก็สร้างการเคลื่อนที่ของเข็ม การแสดงตัวเลข การติดดับของหลอดไฟ แบบที่แสดงในห้องควบคุมในเครื่องบิน
หวังว่าจะทำให้เกิดไอเดีย ไปทำงานอื่นๆนะครับ
ส่วนของการเขียนบทความ อาจไม่สม่ำเสมอ ยังไงก็ follow ได้นะครับ
ไม่มีความคิดเห็น:
แสดงความคิดเห็น