This tutorial is part of: ESP32-S3 RGB LED Matrix
โปรเจ็กต์เจ๋งๆ ที่สร้างได้ทั้งเพื่อความสนุกและการใช้งานจริง โดยใช้โมดูล ESP32-S3 RGB Matrix ลิงก์ไปยังวิดีโออื่นๆ อยู่ด้านล่างบทความนี้
โปรเจกต์ ESP32-S3 RGB LED Matrix 6 - เกม Cible
โปรเจกต์ 6 – เกมเป้าหมาย (เอียงบอร์ดเพื่อให้โดนวงกลม)
โปรเจกต์ 6 เป็นโปรเจกต์สุดท้ายและโต้ตอบได้มากที่สุดในซีรีส์ ESP32-S3 RGB LED Matrix นี้ โดยใช้เซนเซอร์วัดการเคลื่อนไหว QMI8658C ในตัว คุณเอียงบอร์ดเพื่อเลื่อนจุดไปรอบๆ เมทริกซ์ 8×8 “โซนเป้าหมาย” ทรงกลมอยู่ตรงกลางจอแสดงผล เมื่อจุดของคุณแตะวงกลม สีจะเปลี่ยนและ (เลือกได้) ออดจะส่งเสียงบี๊บ สร้างเกมการทรงตัว/การประสานงานที่เรียบง่ายแต่สนุกอย่างน่าประหลาดใจ
โปรเจกต์ทั้งหมดหกโปรเจกต์สาธิตในวิดีโอ YouTube เดียว (ฝังอยู่ในหน้านี้) โค้ดเกมที่สมบูรณ์จะโหลดโดยอัตโนมัติด้านล่างบทความนี้ และลิงก์ซื้อโมดูลแบบพันธมิตรจะปรากฏใต้ส่วนโค้ด

ภาพรวมโมดูล ESP32-S3 RGB LED Matrix
โมดูลนี้ประกอบด้วย:

- ไมโครคอนโทรลเลอร์ ESP32-S3 (Wi-Fi + BLE)
- เมทริกซ์ RGB LED 8×8 (LED ที่ระบุแอดเดรสได้ 64 ดวง)
- มาตรวัดความเร่ง QMI8658C สำหรับการตรวจจับการเอียงและการวางแนว
- พอร์ต USB-C สำหรับจ่ายไฟและการเขียนโปรแกรม
- ปุ่ม Boot / Reset
- พิน GPIO ที่มีให้ใช้งานสำหรับอุปกรณ์เสริม เช่น ออดหรือเซนเซอร์
สำหรับเกมนี้ มาตรวัดความเร่งมีความจำเป็น—มันรายงานการเอียง X/Y อย่างต่อเนื่อง ทำให้จุดเคลื่อนที่ได้อย่างราบรื่นตามมุมของบอร์ด ส่วนวิดีโอของโปรเจกต์นี้แสดงให้เห็นชัดเจนว่าจุดเคลื่อนที่และตอบสนองอย่างไรเมื่อคุณเอียงโมดูลซ้าย/ขวา/หน้า/หลัง

โปรเจกต์ที่ครอบคลุมในวิดีโอ (ไทม์สแตมป์)
- 00:00 – บทนำ
- 02:01 – การติดตั้งบอร์ด ESP32
- 03:32 – การติดตั้งไลบรารี
- 05:32 – โปรเจกต์ 1: จุดเคลื่อนที่
- 11:11 – โปรเจกต์ 2: ข้อความเลื่อน
- 12:59 – โปรเจกต์ 3: ข้อความ HTTP
- 16:41 – โปรเจกต์ 4: จุดเอียง
- 18:55 – โปรเจกต์ 5: ลูกศรชี้ขึ้น
- 20:02 – โปรเจกต์ 6: เกมเป้าหมาย (โปรเจกต์นี้)
ส่วนนี้ของวิดีโอแสดงทั้งการเคลื่อนที่ของจุดและตรรกะการตรวจจับวงกลมในการทำงาน ทำให้เข้าใจพฤติกรรมของพิกัดได้ง่ายขึ้น

การติดตั้งบอร์ด ESP32 ใน Arduino IDE
หากคุณทำโปรเจกต์ก่อนหน้าเสร็จแล้ว การติดตั้งบอร์ดก็เสร็จสิ้นแล้ว มิฉะนั้นทำตาม:
File > Preferences→ เพิ่ม URL บอร์ด ESP32Tools > Board > Boards Manager…→ ติดตั้ง “ESP32”- เลือกบอร์ด ESP32-S3 ภายใต้
Tools > Board - เลือกพอร์ต COM ที่ถูกต้องภายใต้
Tools > Port
การติดตั้งไลบรารีที่จำเป็น
เกมนี้ใช้:
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFXQMI8658(เซนเซอร์วัดการเคลื่อนไหว)
ติดตั้งผ่าน:
Sketch > Include Library > Manage Libraries…- ค้นหา: NeoMatrix → ติดตั้ง
- ติดตั้ง dependencies (GFX + NeoPixel)
- ค้นหาและติดตั้ง QMI8658
เกมเป้าหมายทำงานอย่างไร
มาตรวัดความเร่ง QMI8658C ให้ค่าเอียง X และ Y ค่าเหล่านี้ถูกแมปไปยังพิกัด LED (0–7 ในทั้งสองทิศทาง) จุดของคุณเคลื่อนที่ไปรอบๆ เมทริกซ์ตามมุมของบอร์ด
วงกลม (หรือวงแหวน) ถูกวาดบนจอแสดงผลเป็น “พื้นที่เป้าหมาย” คุณชนะ “การโดน” เมื่อใดก็ตามที่จุดทับวงกลม ในขณะนั้น:
- สีของเป้าหมายเปลี่ยนไป (สุ่มหรือกำหนดไว้ล่วงหน้า)
- ออดจะส่งเสียงบี๊บ (หากเชื่อมต่อ)
เนื่องจากเมทริกซ์มีขนาดเล็ก วงกลมจึงถูกวาดโดยใช้การตรวจสอบรัศมีอย่างง่าย เกมทำงานอย่างต่อเนื่อง ดังนั้นคุณสามารถเอียงไปมาเพื่อโดนวงกลมซ้ำๆ ได้
โปรเจกต์ 6 – การตั้งค่าโค้ด (เกมเป้าหมาย)
ด้านล่างคือการตั้งค่าหลักที่ผู้ใช้ปรับได้ซึ่งอยู่ที่ด้านบนของสเก็ตช์ โค้ดที่สมบูรณ์จะรวมอยู่ด้านล่างบทความนี้โดยอัตโนมัติ
การกำหนดค่าเมทริกซ์
// Matrix configuration
const int MATRIX_PIN = 14;
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
เมทริกซ์ RGB เชื่อมต่อแบบฮาร์ดไวร์กับ GPIO 14—อย่าเปลี่ยนค่านี้
ความสว่าง
uint8_t matrixBrightness = 40; // 0–255
สำหรับใช้ในร่ม 30–60 เหมาะสมที่สุด
สีของจุด
// Dot color (R, G, B)
uint8_t dotRed = 255;
uint8_t dotGreen = 255;
uint8_t dotBlue = 255;
นี่คือจุดที่คุณเคลื่อนที่โดยการเอียงบอร์ด
สีวงกลม (สุ่มหรือคงที่)
// Circle (target) color
uint8_t circleRed = 0;
uint8_t circleGreen = 0;
uint8_t circleBlue = 255;
// If true, choose a new random color each time the dot hits
bool randomCircleColor = true;
ตั้งค่า randomCircleColor = false; หากคุณต้องการสีคงที่
รัศมีวงกลม
// Target size (radius)
int targetRadius = 3; // 3 fits well on 8×8 matrix
รัศมีที่ใหญ่ขึ้นทำให้เกมง่ายขึ้น รัศมีที่เล็กลงทำให้ยากขึ้น
ความไวในการเอียง
// Sensitivity of tilt mapping
float tiltScale = 4.0f; // increase = faster movement across screen
หากจุดเคลื่อนที่เร็วเกินไปหรือกระโดด ให้ลดตัวเลขนี้ลง
การตั้งค่าออด (ไม่บังคับ)
// ขาพินบัซเซอร์ (ไม่บังคับ)
int buzzerPin = 6; // เชื่อมต่อขาบวกของบัซเซอร์เข้ากับพิน 6, ขาลบเข้ากับ GND
bool useBuzzer = true; // ตั้งเป็น false เพื่อปิดเสียง
หากคุณไม่ได้เชื่อมต่อบัซเซอร์ เพียงตั้งค่า useBuzzer = false;
สรุป
โปรเจกต์ 6 ผสมผสานทุกสิ่งที่เรียนรู้จากโปรเจกต์ก่อนหน้า: การวาดบนเมทริกซ์, การรับข้อมูลจาก accelerometer, การควบคุมสี, การปรับการเคลื่อนไหวให้ลื่นไหล และเสียงเสริม การเอียงบอร์ดจะเคลื่อนจุด และการชนวงกลมจะเปลี่ยนสีและ (ไม่บังคับ) ส่งเสียงบี๊บ เป็นการสาธิตการตรวจจับการเคลื่อนไหวบนจอ RGB ขนาดกะทัดรัดที่สนุกสนาน
โค้ดเต็มของ “เกมยิงเป้า” จะแสดงโดยอัตโนมัติด้านล่างบทความนี้ คุณยังสามารถชมส่วนโปรเจกต์ 6 ในวิดีโอเพื่อดูว่าจุดเคลื่อนที่อย่างไรและตรวจจับการชนได้อย่างไร หากคุณต้องการสร้างเกมของคุณเอง ลิงก์พันธมิตรสำหรับซื้อโมดูล ESP32-S3 RGB LED Matrix จะปรากฏใต้ส่วนโค้ด
This tutorial is part of: ESP32-S3 RGB LED Matrix
- โปรเจกต์ ESP32-S3 RGB LED Matrix 1- จุดพื้นฐาน
- โปรเจกต์ ESP32-S3 RGB LED Matrix 2 - ข้อความเลื่อน
- โปรเจกต์ ESP32-S3 RGB LED Matrix 3 - ข้อความจากโทรศัพท์มือถือ
- โปรเจกต์ ESP32-S3 RGB LED Matrix 4 - จุดเอียง
- โปรเจกต์ ESP32-S3 RGB LED Matrix 5 - ลูกศรชี้ขึ้นเสมอ
- โปรเจกต์นาฬิกา ESP32-S3 RGB LED Matrix Wi-Fi + NTP Time Clock -1 นาฬิกาพื้นฐาน
- โปรเจกต์นาฬิกาอินเทอร์เน็ต RGB LED Matrix ESP32-S3 - จอแสดงเวลาและวันที่หลากสี 2 นาฬิกา
- โปรเจกต์นาฬิกาอินเทอร์เน็ต RGB LED Matrix ESP32-S3 - 3 สีกลางคืนพร้อมวันที่
- โครงการนาฬิกาอินเทอร์เน็ตจอ LED Matrix RGB ESP32-S3 - 5 สีรุ้ง
- โปรเจกต์นาฬิกาอินเทอร์เน็ต RGB LED Matrix ESP32-S3 - 4 สีสุ่ม
- ESP32-S3 RGB LED Matrix test for RGB, GRB setting
/*
Project 6: Tilt Circle Game – ESP32-S3 RGB LED Matrix (Waveshare)
This sketch reads tilt from the QMI8658C IMU and smoothly moves a dot
on the 8×8 RGB LED matrix based on board orientation.
▶️ Video Tutorial:
https://youtu.be/JKLuYrRcLMI
📚⬇️ Resources & Code Page:
https://robojax.com/RJT829
QMI8658_RGB_2
*/
#include <Arduino.h>
#include <math.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include <QMI8658.h> // by Lahav Gahali
// -------- LED MATRIX SETUP --------
#define MATRIX_PIN 14
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
// Buzzer pin – change this to your actual buzzer GPIO.
const int BUZZER_PIN = 6; // TODO: set to your buzzer pin
// Matrix brightness (0–255)
const uint8_t MATRIX_BRIGHTNESS = 10;
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_GRB + NEO_KHZ800
);
// -------- IMU SETUP --------
QMI8658 imu;
// -------- GAME CONFIG --------
// How often the dot is allowed to move (ms).
// Bigger = slower movement.
const uint16_t MOVE_INTERVAL_MS = 150; // try 120–250
// How much tilt (m/s^2) before the dot moves.
// Increase if it feels too sensitive.
const float ACC_TILT_THRESHOLD = 2.0f; // about ~0.2 g
// Dot base color (RGB)
const uint8_t DOT_R = 255;
const uint8_t DOT_G = 255;
const uint8_t DOT_B = 255;
// Circle geometry (centered on 8x8)
const float CIRCLE_CENTER_X = (MATRIX_WIDTH - 1) / 2.0f; // 3.5
const float CIRCLE_CENTER_Y = (MATRIX_HEIGHT - 1) / 2.0f; // 3.5
const float CIRCLE_RADIUS = 3.0f;
const float CIRCLE_THICKNESS = 0.8f; // +- thickness around radius
// -------- GAME STATE --------
// Dot position on the 8x8 grid (0..7)
int dotX = 3;
int dotY = 3;
// Colors (16-bit NeoMatrix colors)
uint16_t dotColor;
uint16_t circleColor;
// To detect “just touched circle” vs “still on circle”
bool wasOnCircle = false;
// Timer for rate-limiting movement
unsigned long lastMoveTime = 0;
// -------- HELPER FUNCTIONS --------
// Classic NeoPixel color wheel (0-255 -> rainbow)
uint16_t wheel(byte pos) {
if (pos < 85) {
return matrix.Color(pos * 3, 255 - pos * 3, 0);
} else if (pos < 170) {
pos -= 85;
return matrix.Color(255 - pos * 3, 0, pos * 3);
} else {
pos -= 170;
return matrix.Color(0, pos * 3, 255 - pos * 3);
}
}
// Is a given pixel approximately on the circle?
bool isOnCircle(int x, int y) {
float dx = x - CIRCLE_CENTER_X;
float dy = y - CIRCLE_CENTER_Y;
float d2 = dx * dx + dy * dy;
float rMin = CIRCLE_RADIUS - CIRCLE_THICKNESS;
float rMax = CIRCLE_RADIUS + CIRCLE_THICKNESS;
return (d2 >= rMin * rMin) && (d2 <= rMax * rMax);
}
// Draw circle + dot
void drawScene() {
matrix.fillScreen(0);
// Draw circle
for (int y = 0; y < MATRIX_HEIGHT; y++) {
for (int x = 0; x < MATRIX_WIDTH; x++) {
if (isOnCircle(x, y)) {
matrix.drawPixel(x, y, circleColor);
}
}
}
// Draw dot (on top)
matrix.drawPixel(dotX, dotY, dotColor);
matrix.show();
}
// Simple blocking beep (short)
void buzzOnce() {
digitalWrite(BUZZER_PIN, HIGH);
delay(40);
digitalWrite(BUZZER_PIN, LOW);
}
// Use accelerometer to decide dot movement
void updateDotFromTilt(float ax, float ay) {
unsigned long now = millis();
if (now - lastMoveTime < MOVE_INTERVAL_MS) {
return; // too soon, wait
}
int dx = 0;
int dy = 0;
// On this board, Y tilt feels like "left/right" on the matrix,
// and X tilt feels like "up/down" → so we swap.
// --- Horizontal movement from AY (tilt left/right) ---
if (ay > ACC_TILT_THRESHOLD) {
dx = 1; // tilt to the right → move dot to the right
} else if (ay < -ACC_TILT_THRESHOLD) {
dx = -1; // tilt to the left → move dot to the left
}
// --- Vertical movement from AX (tilt forward/back) ---
// This was inverted. We flip the signs:
// ax > threshold = tilt "forward" (away) → move dot UP (dy = -1)
// ax < -threshold = tilt "back" (toward)→ move dot DOWN(dy = 1)
if (ax > ACC_TILT_THRESHOLD) {
dy = -1; // was +1 before
} else if (ax < -ACC_TILT_THRESHOLD) {
dy = 1; // was -1 before
}
if (dx != 0 || dy != 0) {
dotX = constrain(dotX + dx, 0, MATRIX_WIDTH - 1);
dotY = constrain(dotY + dy, 0, MATRIX_HEIGHT - 1);
lastMoveTime = now;
}
}
// -------- SETUP & LOOP --------
void setup() {
Serial.begin(115200);
delay(100);
// Matrix init
matrix.begin();
matrix.setBrightness(MATRIX_BRIGHTNESS);
matrix.fillScreen(0);
matrix.show();
// Buzzer init
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
// IMU init
if (!imu.begin(11, 12)) {
Serial.println("Failed to initialize QMI8658!");
while (1) {
delay(100);
}
}
// Use m/s^2 and dps (optional, but nice)
imu.setAccelUnit_mps2(true);
imu.setGyroUnit_dps(true);
imu.setDisplayPrecision(3);
Serial.println("QMI8658 initialized.");
// Game initial state
randomSeed((uint32_t)micros());
dotX = MATRIX_WIDTH / 2;
dotY = MATRIX_HEIGHT / 2;
dotColor = matrix.Color(DOT_R, DOT_G, DOT_B);
circleColor = wheel(random(256));
drawScene();
}
void loop() {
// Read accelerometer
float ax, ay, az;
if (imu.readAccelMPS2(ax, ay, az)) {
// Debug if needed:
// Serial.print("AX: "); Serial.print(ax);
// Serial.print(" AY: "); Serial.print(ay);
// Serial.print(" AZ: "); Serial.println(az);
updateDotFromTilt(ax, ay);
}
// Check collision with circle
bool onCircle = isOnCircle(dotX, dotY);
if (onCircle && !wasOnCircle) {
// Just touched circle: change color + beep
circleColor = wheel(random(256));
buzzOnce();
}
wasOnCircle = onCircle;
// Redraw
drawScene();
// Small delay so we don’t hammer I2C too hard
delay(10);
}
สิ่งที่คุณอาจต้องการ
-
อเมซอน
-
อีเบย์
-
อาลีเอ็กซ์เพรสPurchase ESP32-S3 RGB Matrix from AliExpresss.click.aliexpress.com
-
อาลีเอ็กซ์เพรสPurchase ESP32-S3 RGB Matrix from AliExpress (2)s.click.aliexpress.com
แหล่งข้อมูลและเอกสารอ้างอิง
-
ภายใน🎨 Color picker Toolrobojax.com
ไฟล์📁
ไฟล์ Fritzing
-
esp32-S3-supermini-tht fritzing part
esp32-S3-supermini-tht.fzpz0.02 MB