กลับไปหน้ารวมไฟล์
how-to-play-rock-paper-scissor-with-a-time-of-flight-sensor-3d27ec.md

สวัสดีน้องๆ ทุกคน ยินดีต้อนรับเข้าสู่บทเรียนนี้ คราวนี้เราจะมาลองทำเกมเป่ายิ้งฉุบกัน โดยใช้เซ็นเซอร์ Time of Flight และโปรแกรม NanoEdge AI Studio ในการสร้างโมเดลเพื่อจำแนกว่ามือที่เราทำคือรูปอะไร

บทความนี้เป็นเวอร์ชันง่ายๆ ของบทความเต็มจาก STMicroelectronics ที่น้องๆ สามารถไปอ่านเพิ่มเติมได้

ขั้นตอนที่ 1: เตรียมตัวและวางแผน

เซ็นเซอร์ Time-of-Flight (ToF) จะส่งค่าอาร์เรย์ของระยะห่างออกมา คิดซะว่าเป็นภาพก็ได้ แต่ความละเอียดต่ำมาก (8x8 = 64 พิกเซล)

เซ็นเซอร์พวกนี้จะยิงพัลส์แสงสั้นๆ ที่กินเวลาแค่ไม่กี่นาโนวินาที แล้ววัดเวลาที่แสงส่วนหนึ่งสะท้อนกลับมา เพราะมันทำงานด้วยพัลส์แสง มันจึงทำงานได้ดีกว่าในที่มืดมากกว่าในที่สว่างจ้า ระยะสูงสุดที่เซ็นเซอร์วัดได้ในที่มืดคือประมาณ 3 เมตร แต่ถ้าแสงจ้ามากๆ เซ็นเซอร์อาจจะทำงานไม่ปกติหรือไม่ทำงานเลย

รายละเอียดเทคนิคเพิ่มเติม: ฟิสิกส์ของ Time of Flight (VL53L5CX) ต่างจากโซนาร์ราคาถูกอย่าง HC-SR04 ที่ใช้เสียงและสะท้อนเป็นกรวยกว้างๆ เซ็นเซอร์ ToF อย่าง VL53L5CX ยิงลำแสงเลเซอร์ที่มองไม่เห็น (ความยาวคลื่น 940nm) จริงๆ ไปเลย มันจะวัดเวลาในหน่วยพิโควินาทีที่แสงใช้เดินทางไปชนวัตถุ (เช่น มือเรา) และสะท้อนกลับมาที่เซ็นเซอร์ Arduino ของเราจะได้รับค่าการวัดระยะในหน่วยมิลลิเมตรสำหรับแต่ละพิกเซลจากทั้งหมด 64 พิกเซลในอาร์เรย์ สร้างเป็นแผนที่ภูมิประเทศ (topographical map) ที่แม่นยำของฉากหน้าเซ็นเซอร์

การเก็บข้อมูลที่ดีจาก ToF นี่มันยากอยู่นะน้อง อยากเก็บข้อมูลดีๆ ต้อง:

  1. อยู่ในสภาพแวดล้อมที่แสงไม่จ้าเกินไป
  2. มีพื้นหลัง (background)
  3. ต้องมั่นใจว่าอยู่ตรงหน้าเซ็นเซอร์ ToF
  4. ตรวจสอบข้อมูลที่เก็บมาว่าเราไม่ได้อยู่ใกล้/ไกลเกินไป

รู้อย่างนี้แล้ว เราก็แค่เสียบบอร์ด X-NUCLEO-53L5A1 เข้ากับ Arduino Uno R4 WiFi ของเรา แล้วก็ต้องยึดเซ็นเซอร์ ToF ให้หันลงพื้น ในกรณีของพี่ พี่ยึดมันไว้ใต้โต๊ะ ให้มันหันลงพื้น แล้วก็เล่นเกมโดยเอามือไปไว้ใต้โต๊ะนั่นแหละ ในบทความของ ST เค้าทำที่ยึดขึ้นมาเลย น้องๆ ลองไปดูไอเดียได้

เพื่อจะเล่นเป่ายิ้งฉุบได้ เราต้องเก็บข้อมูลที่แทนการกระทำ 4 แบบ:

  1. ไม่มีอะไร (ว่าง)
  2. ค้อน (กำมือ)
  3. กระดาษ (แบมือ)
  4. กรรไกร (ชูสองนิ้ว)

ขั้นตอนที่ 2: Data Logger เวลาเราทำงานกับเซ็นเซอร์ Time-of-Flight (ToF) น้องๆ สามารถเลือกได้ว่าจะทำงานกับอาร์เรย์ระยะห่างเดี่ยวๆ หรือจะใช้ลำดับของอาร์เรย์เพื่อจับการเคลื่อนไหว (gesture) ในเคสนี้ ทั้งสองวิธีน่าจะใช้ได้ แต่เพื่อประหยัดการใช้หน่วยความจำ พี่เลือกที่จะทำงานกับอาร์เรย์เดี่ยว

พี่ใช้เครื่องมือ NanoEdge AI Studio ในการสร้างโค้ดสำหรับเก็บข้อมูลจาก ToF โค้ดแนบไว้ด้านล่างแล้ว แต่ถ้าน้องอยากสร้างโค้ดแบบเดียวกันเอง ให้ทำตามนี้:

  1. เปิด NanoEdge AI Studio
  2. ไปที่แท็บ Data Logger
  3. เลือกบอร์ด Arduino
  4. เลือกเซ็นเซอร์ VL53L5CX

พี่ใช้พารามิเตอร์ตามนี้:

  1. Data rate (Hz): 15Hz (สูงสุด)
  2. Frame resolution: 64 (8x8)
  3. Frames: 1

คลิก Generate Data Logger แล้วน้องจะได้ไฟล์ .zip ที่ข้างในมีไฟล์ .ino พร้อมอัปโหลดลงบอร์ดได้เลย

คำเตือน: น้องต้องติดตั้งไลบรารี SparkFun_VL53L5CX_Library ก่อนนะ ไปที่ Sketch > Include Library > Manage libraries... > แล้วค้นหา SparkFun_VL53L5CX_Library

ต่อไปเราจะสร้างโปรเจคใน NanoEdge AI Studio เพื่อเก็บข้อมูลและสร้างโมเดลที่สามารถจำแนกรูปมือทั้งหมดได้:

  1. เปิด NanoEdge AI Studio
  2. สร้างโปรเจคประเภท N-class classification

ในส่วน Project Settings:

ตั้งแต่เวอร์ชัน 4.5 เป็นต้นมา การตั้งค่าโปรเจคเปลี่ยนไปนิดหน่อย น้องต้องเลือกว่าทำงานกับข้อมูลแบบ Time series หรือ Cross sectional data พูดง่ายๆ คือข้อมูลของเรามีหลายตัวอย่างที่จุดเวลาต่างกันหรือเปล่า ในกรณีของเรา เราใช้เฟรม/อาร์เรย์เดี่ยว ไม่เกี่ยวกับเวลา: ดังนั้นเราเลือก Cross sectional data

  1. เลือก Arduino UNO R4 WiFi เป็นเป้าหมาย (target)

  2. เลือก Cross sectional

  3. เลือก Time of Flight และความละเอียด 8x8

  4. คลิก Next

ในส่วน Signals: เราต้องเก็บข้อมูลสำหรับแต่ละสัญญาณ (ค้อน, กระดาษ, กรรไกร และ "ว่าง" หรือไม่มีอะไร) ต้องมั่นใจว่าเก็บข้อมูลด้วยการทำสัญลักษณ์มือไว้หน้าเซ็นเซอร์ ToF และอย่าให้ใกล้หรือไกลเกินไป ถ้าใกล้เกินไป เซ็นเซอร์จะเห็นแค่วัตถุใหญ่ (มือเรา) บดบังวิสัยทัศน์ทั้งหมดของมัน

ต้องมั่นใจว่าสัญลักษณ์ที่เราบันทึกข้อมูลอยู่ภายในเฟรมทั้งหมด (ดูรูปด้านล่างที่แสดงสัญลักษณ์กรรไกร) การมีข้อมูลที่ดีเป็นสิ่งสำคัญมากสำหรับโปรเจคนี้

การรู้ว่าเรากำลังเก็บข้อมูลอยู่หรือไม่ มันง่ายมากหลังจากอัพเดตล่าสุดของ NanoEdge เพราะเราสามารถเห็นเมทริกซ์ในขั้นตอน Signal ได้เลย หลังจากเก็บข้อมูลแล้ว (ดูด้านล่าง) เราสามารถดูเมทริกซ์ที่เก็บมาได้ (ดูรูปที่แนบ)

สำหรับแต่ละคลาส เราจะทำตามนี้:

  1. คลิก Add Signal
  2. คลิก From Serial (usb)
  3. เลือก COM Port ให้ถูกต้อง
  4. พยายามวางมือให้อยู่ในโซนประมาณนึงก่อนคลิก start
  5. บันทึกสัญญาณประมาณ 200 สัญญาณต่อหนึ่งสัญลักษณ์
  6. หยุดการบันทึก

ทำกระบวนการเดิมซ้ำสำหรับทั้ง 3 สัญลักษณ์ และคลาส "ว่าง" (ตอนที่เราไม่เอามือไปวางหน้าเซ็นเซอร์)

ในส่วน Benchmark:

Benchmark คือหัวใจของ NanoEdge AI Studio ตรงนี้เราจะใช้ข้อมูลทั้งหมดที่เก็บมา เพื่อพยายามหาคอมโบที่ดีที่สุดของการประมวลผลข้อมูลเบื้องต้น (preprocessing) และโมเดลที่ดีที่สุดที่สามารถแยกแยะข้อมูลได้

  1. คลิก New Benchmark
  2. เลือก datasets ทั้งหมด
  3. คลิก start

Benchmark จะลองคอมโบต่างๆ ของ preprocessing และโมเดลกับข้อมูลซ้ำๆ และประเมินประสิทธิภาพ มันจะแบ่งข้อมูลออกเป็นชุดฝึก (training) และชุดทดสอบ (testing) หลายรอบเพื่อให้ได้ผลลัพธ์ที่มั่นคง Benchmark อาจใช้เวลาหลายชั่วโมงกว่าจะเสร็จ ขึ้นอยู่กับปริมาณข้อมูลที่ใช้ ถ้าคะแนนถึง 90% ขึ้นไป เราสามารถหยุดชั่วคราว/หยุดมันและไปต่อได้ Benchmark จะพยายามปรับแต่งโมเดลให้ดีที่สุด แต่เราหยุดได้เมื่อพอใจแล้ว

ในส่วน Validation: ระหว่างกระบวนการทำ Benchmark ทุกครั้งที่พบไลบรารีที่ดีที่สุดใหม่ มันจะถูกเพิ่มเข้ามาในขั้นตอน Validation เมื่อเรามีไลบรารีที่ดีบางตัวแล้ว เราสามารถทดสอบมันแบบเรียลไทม์ได้ เหมือนกับที่มันถูก deploy ลงไมโครคอนโทรลเลอร์จริงๆ เพื่อดูว่ามันทำงานได้ดีไหม ทำได้โดยคลิกปุ่ม play ในคอลัมน์ Serial Emulator เลือก COM Port ให้ถูกต้องแล้วคลิก Start จากนั้นเราจะสามารถทดสอบโมเดลและดูประสิทธิภาพได้ ถ้าสังเกตเห็นว่าบางคลาสมีปัญหาในการถูกจดจำ เราสามารถกลับไปที่ขั้นตอนการบันทึกข้อมูลและทำ Benchmark ใหม่ได้ ตัวพี่เองเคยมีปัญหามาเพราะมืออยู่ใกล้เซ็นเซอร์ ToF เกินไปตอนบันทึกข้อมูลคลาสกรรไกร

ในส่วน Compilation: แค่คลิก compile เพื่อรับโมเดลที่เทรนเสร็จแล้ว จัดไปวัยรุ่น!

ขั้นตอนที่ 4: ใส่โมเดล AI เข้าไปในโค้ดของเรา

จะเอา AI ไปใส่ในโค้ด Arduino ยังไง? ง่ายนิดเดียว ตามนี้เลย:

  1. เอาไลบรารี่เข้า Arduino IDE
  2. เอาโค้ดที่แนบมาไปใช้
  3. แก้ไขตัวแปร id2class

แค่นั้นแหละ!

1 - เอาไลบรารี่เข้า Arduino IDE: ก่อนอื่นต้องเอาไลบรารี่เข้าไปก่อน วิธีเซฟๆ สำหรับคนที่อาจจะเคยมีไลบรารี่เก่าของ NanoEdge AI อยู่แล้ว ให้ทำแบบนี้:

  1. หาไฟล์ .zip ที่ได้มาจากการคอมไพล์ใน NanoEdge AI Studio
  2. คัดลอกโฟลเดอร์ nanoedge (อยู่ใน YOUR_LIBRARY.zip\arduino\nanoedgeai_for_arduino.zip\)
  3. วางลงใน Document\Arduino\libraries

2 - อธิบายโค้ดที่แนบมา: ในโค้ดที่แนบมา เขาทำอะไรบ้าง มาดูกัน:

  1. Include ไฟล์ NanoEdgeAI.h และ knowledge.h (โมเดลและฟังก์ชัน)
  2. ประกาศตัวแปรที่ NanoEdge ใช้
  3. ใส่ฟังก์ชันเริ่มต้น (initialization)
  4. ใส่ส่วนตรวจจับ (detection)

ส่วนที่เพิ่มเข้ามามีหน้าตาแบบนี้:

#include "NanoEdgeAI.h"
#include "knowledge.h"
/* Global variables definitions */
static uint8_t neai_code = 0;
static uint16_t neai_ptr = 0;
static float neai_buffer[SENSOR_FRAME_RESOLUTION * SENSOR_FRAMES] = {0.0};
/* NEAI library variables */
uint16_t id_class = 0; // Point to id class (see argument of neai_classification fct)
float input_user_buffer[DATA_INPUT_USER * AXIS_NUMBER]; // Buffer of input values
float output_class_buffer[CLASS_NUMBER]; // Buffer of class probabilities
const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
};
void setup() {
	 //some code
	 /* Initialize NanoEdgeAI AI */
	 neai_code = neai_classification_init(knowledge);
	 if (neai_code != NEAI_OK) {
	   Serial.print("Not supported board.\n");
	 }
}
/* Main function: Code run indefinitely */
void loop() {
	   //classification
	   neai_classification(neai_buffer, output_class_buffer, &id_class);
	  //actions to perform based on id_class (the detected class)
}

3 - แก้ไข id2class: ในโค้ดจะมีตัวแปร id2class ที่เก็บชื่อคลาสและลำดับของมัน (ลำดับนี้ขึ้นกับว่าคุณบันทึกข้อมูลคลาสไหนก่อนใน NanoEdge AI Studio ดังนั้นลำดับในโค้ดคุณอาจจะไม่เหมือนของพี่) คุณต้องเอาตัวแปรจากในโค้ดที่แนบมา ไปแทนที่ด้วยตัวแปรที่อยู่ในไฟล์ NanoEdgeAI.h ในไฟล์ .zip ของคุณเอง:

  1. YOUR_LIBRARY.zip\arduino\nanoedgeai_for_arduino.zip\nanoedgeai\src\NanoEdgeIA.h

หมายเหตุ: ถ้าเจอ Error เรื่อง RAM ไม่พอ มันอาจจะเพราะไลบรารี่ใน NanoEdge ใหญ่ไป ให้กลับไปที่ขั้นตอน VALIDATION STEP ใน NanoEdge แล้วเลือกไลบรารี่ที่เล็กกว่า (คลิกที่มงกุฎทางขวา) จากนั้นคอมไพล์ใหม่แล้วเอามาแทนที่ใน Arduino IDE อีกที


ขั้นตอนที่ 5: สร้างเกม

เพื่อให้ง่าย เราจะเล่นเกมผ่าน Serial ไปเลย สิ่งที่ต้องทำมีดังนี้:

  1. สร้างลูปสำหรับเล่นเกม
  2. สร้างตัวนับถอยหลังให้ผู้เล่นรู้ว่าเมื่อไหร่จะเล่น
  3. รอให้คุณเล่น
  4. ใช้โมเดลตรวจจับว่าผู้เล่นออกอะไร
  5. ให้บอร์ดสุ่มออกเอง (เป็นคู่ต่อสู้)
  6. นับคะแนน (ใครถึง 3 คะแนนก่อนชนะ)

โค้ดตัวอย่างอยู่ด้านล่าง ระวังให้ดี! คุณต้องเช็คให้แน่ใจว่าลำดับคลาส (class order) และวิธีที่เรากำหนดว่าใครชนะนั้นตรงกัน

ในกรณีของพี่ ตัวแปร id2Class เป็นแบบนี้:

const char *id2class[CLASS_NUMBER + 1] = { // Buffer for mapping class id to class name
	"unknown",
	"nothing",
	"scissors",
	"rock",
	"paper",
};

แปลว่า index ของกรรไกรคือ 2, ค้อนคือ 3, กระดาษคือ 4 โค้ดสำหรับตัดสินว่าใครชนะจะเป็นแบบนี้:

	   if (id_class == random_play) {
	     Serial.println("Draw, play again!");
	   } else {
	     if (
	       // scisoor vs paper
	       (id_class == 2 && random_play == 4) or
	       // rock vs scissors
	       (id_class == 3 && random_play == 2) or
	       //paper vs rock
	       (id_class == 4 && random_play == 3)
	     ) {
	       Serial.println("You won");
	       player_score ++;
	     } else {
	       Serial.println("You loose");
	       arduino_score ++;
	     }

คุณต้องไปปรับกฎการชนะ-แพ้ให้ตรงกับลำดับคลาสของคุณเอง

เรียบร้อย! ตอนนี้คุณก็เล่นเกมเป่ายิ้งฉุบบน Arduino Uno R4 WiFi ด้วยเซ็นเซอร์ Time of Flight ได้แล้ววว! สู้งานนะน้อง!

มาดูกันว่าเราจะสร้างอะไรได้บ้าง!

1. เริ่มต้นด้วยการสร้างไฟล์ index.html

สร้างไฟล์ index.html ขึ้นมา แล้วก็อปโค้ดด้านล่างนี้ไปวางเลยจ้า

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Awesome Project</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h1>Hello, World! สวัสดีชาวโลก!</h1>
    <p>นี่คือโปรเจคแรกของเรา เริ่มต้นง่ายๆ แบบนี้แหละ</p>
    <script src="script.js"></script>
</body>
</html>

2. แต่งสไตล์ด้วย style.css

สร้างไฟล์ style.css ขึ้นมา แล้วแต่งหน้าเว็บให้สวยปังตามสไตล์เรา

body {
    font-family: sans-serif;
    text-align: center;
    padding: 50px;
    background-color: #f0f0f0;
}

h1 {
    color: #333;
}

p {
    color: #666;
}

3. ใส่ความฉลาดด้วย script.js

สร้างไฟล์ script.js ขึ้นมา เพื่อให้เว็บเรามีชีวิตชีวา

console.log("Script loaded successfully! สคริปต์โหลดเรียบร้อยแล้วจ้า!");

// ตัวอย่างฟังก์ชันง่ายๆ
function sayHello() {
    alert("สวัสดีจาก JavaScript!");
}

// เรียกใช้ฟังก์ชันเมื่อหน้าเว็บโหลดเสร็จ
window.onload = function() {
    console.log("Page is ready! หน้าเว็บพร้อมแล้ว!");
};

4. ดูผลลัพธ์

เปิดไฟล์ index.html ในเบราว์เซอร์ (ดับเบิลคลิกที่ไฟล์เลย) แล้วดูผลงานของเรา! ถ้าทุกอย่างถูกต้อง จะเห็นข้อความ "Hello, World! สวัสดีชาวโลก!" แสดงอยู่กลางหน้า

เคล็ดลับจากรุ่นพี่ (Tips & Tricks)

  • จัดไปวัยรุ่น: อย่ากลัวที่จะลองเปลี่ยนค่าต่างๆ ใน CSS หรือ JavaScript ลองเล่นดูสิ!
  • ห้ามช็อตนะตัวนี้: ถ้าโค้ดไม่ทำงาน ให้เปิด Developer Tools (F12) ในเบราว์เซอร์แล้วดูที่ Console Tab มันจะบอกเราว่าผิดตรงไหน
  • สู้งานนะน้อง: การเขียนโค้ดคือการฝึกฝน ยิ่งทำบ่อยยิ่งเก่ง

ขอให้สนุกกับการเขียนโค้ดนะ!

ข้อมูล Frontmatter ดั้งเดิม

apps:
  - "1x Arduino IDE 1.8.19"
  - "1x NanoEdge AI Studio"
author: "mad_mcu"
category: "Gaming & Entertainment"
components:
  - "1x Arduino® UNO R4 WiFi"
  - "1x X-NUCLEO-53L5A1"
description: "Quantum distance mechanics! Substitute unreliable button presses with the absolute precision of physical photon measurement, mapping micro-millimeter gestures utilizing an intense laser VL53L0X optical grid array."
difficulty: "Advanced"
documentationLinks: []
downloadableFiles:
  - "https://projects.arduinocontent.cc/85f33cdd-93e2-4d0f-8983-fd2b10fb0230.ino"
  - "https://projects.arduinocontent.cc/8968d585-8c2d-4141-871a-0d732d058de9.ino"
encryptedPayload: "U2FsdGVkX18x1PlYmu17mYgbM/bz/rQMv7ANkt7ykx7xc8DQJnac3XqTnmVKxRxF5nO1sR4ZC/KJnDQtOf+Q/VQT24ki1LMSYKhLRotpiF/iTKoogDQCSs/m+JNQxRk7k8U2IrOh3mwtiDvH9ePfOQ=="
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/how-to-play-rock-paper-scissor-with-a-time-of-flight-sensor-3d27ec_cover.gif"
lang: "en"
likes: 5
passwordHash: "40c01955728cafce88a8c50d57c2ec59353d685874b97f88364761ff554dc9a7"
price: 2450
seoDescription: "Learn to play Rock Paper Scissor using Time of Flight sensor, Arduino, and NanoEdge AI Studio. Build an AI model to classify hand signs easily."
tags:
  - "Games"
  - "Arduino User Group"
  - "Data Collection"
title: "How to play Rock Paper Scissor with a Time of Flight sensor!"
tools: []
videoLinks: []
views: 13733