This tutorial is part of: ESP32-S3 RGB LED Matrix
โปรเจ็กต์เจ๋งๆ ที่สร้างได้ทั้งเพื่อความสนุกและการใช้งานจริง โดยใช้โมดูล ESP32-S3 RGB Matrix ลิงก์ไปยังวิดีโออื่นๆ อยู่ด้านล่างบทความนี้
โปรเจกต์ ESP32-S3 RGB LED Matrix 5 - ลูกศรชี้ขึ้นเสมอ
โปรเจกต์ 5 – ลูกศรชี้ขึ้นเสมอ (ตัวบ่งชี้ทิศทางโดยใช้ QMI8658C)
โปรเจกต์ 5 ใช้เซนเซอร์ตรวจจับการเคลื่อนไหว QMI8658C เพื่อตรวจจับทิศทางของ ESP32-S3 RGB LED Matrix และแสดงลูกศรที่ชี้ขึ้นโดยสัมพันธ์กับแรงโน้มถ่วงเสมอ ไม่ว่าคุณจะหมุนบอร์ดอย่างไร—ด้าน USB ขึ้น ด้าน OUSB ขึ้น ด้าน “15” หรือด้าน “34”—ลูกศรจะหมุนโดยอัตโนมัติและชี้ไปยังทิศทางที่อยู่ด้านบนตามจริงทางกายภาพ
นี่คือการสาธิตอันทรงพลังของการตรวจจับทิศทางแบบเรียลไทม์โดยใช้มาตรความเร่งในตัว โปรเจกต์ทั้งหกของโมดูลนี้สาธิตในวิดีโอ YouTube หนึ่งรายการ ซึ่งฝังอยู่ในหน้านี้ด้วย โค้ดที่สมบูรณ์สำหรับโปรเจกต์ 5 จะโหลดโดยอัตโนมัติด้านล่างบทความ และลิงก์พันธมิตรจะปรากฏใต้ส่วนโค้ด

ภาพรวมโมดูล ESP32-S3 RGB LED Matrix
โมดูล ESP32-S3 RGB LED Matrix มีส่วนประกอบหลายอย่างที่ทำให้โปรเจกต์นี้เป็นไปได้:

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

โปรเจกต์ที่ครอบคลุมในวิดีโอ (ไทม์สแตมป์)
- 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 - เลือกพอร์ต USB COM ที่ถูกต้องภายใต้
Tools > Port
การติดตั้งไลบรารีที่จำเป็น
โปรเจกต์ 5 ใช้:
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFXQMI8658(เซนเซอร์ตรวจจับการเคลื่อนไหว)
Sketch > Include Library > Manage Libraries…- ค้นหา: NeoMatrix → ติดตั้ง
- ติดตั้งไลบรารีที่ต้องพึ่งพา: NeoPixel + GFX
- ค้นหาและติดตั้ง QMI8658 โดยผู้เขียน
โปรเจกต์ 5 ทำงานอย่างไร
QMI8658C วัดแรงโน้มถ่วงบนแกน X, Y และ Z โดยการเปรียบเทียบค่าเหล่านี้ สเก็ตช์จะกำหนดว่าด้านใดของบอร์ดที่หงายขึ้นทางกายภาพ:
- ด้าน USB ขึ้น
- ด้าน OUSB ขึ้น (ตรงข้ามกับ USB)
- ด้าน “15” ขึ้น
- ด้าน “34” ขึ้น
แต่ละทิศทางสอดคล้องกับรูปแบบลูกศรที่แตกต่างกันบนเมทริกซ์ 8×8 การแมปเป็นไปตามตรรกะการวางแนวที่คุณยืนยันแล้วจากการดีบักครั้งก่อน การหมุนของบอร์ดจะถูกอ่านอย่างต่อเนื่อง และลูกศรจะอัปเดตทันทีที่ด้านที่หงายขึ้นเปลี่ยนแปลง
โปรเจกต์ 5 – การตั้งค่าโค้ด (ลูกศรชี้ขึ้นเสมอ)
ด้านล่างคือค่าที่ผู้ใช้ปรับได้จากพื้นที่การกำหนดค่า โค้ดโปรเจกต์ที่สมบูรณ์จะปรากฏโดยอัตโนมัติด้านล่างบทความ
การกำหนดค่าเมทริกซ์
// การกำหนดค่าเมทริกซ์
const int MATRIX_PIN = 14; // คงที่สำหรับโมดูลนี้
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
// การวางแนวที่แนะนำ: จุดเริ่มต้นมุมบนซ้าย โหมด progressive
// (คอนสตรักเตอร์จริงอยู่ในโค้ดที่โหลดด้านล่าง)
โปรเจกต์นี้ใช้รูปแบบ NEO_MATRIX_PROGRESSIVE เพื่อให้แน่ใจว่าลูกศรชี้ถูกต้องตามการเคลื่อนไหวจริง
ความสว่าง
uint8_t matrixBrightness = 40; // 0–255
คุณสามารถเพิ่มค่านี้สำหรับสภาพแวดล้อมที่สว่างกว่า สำหรับการใช้ในร่ม 30–60 ก็สบายตา
สีลูกศร
// สีลูกศร
uint8_t arrowRed = 255;
uint8_t arrowGreen = 0;
uint8_t arrowBlue = 0;
เปลี่ยนค่าเหล่านี้เพื่อปรับสีของลูกศร ตัวอย่างเช่น:
- ลูกศรสีเขียว:
(0, 255, 0) - ลูกศรสีน้ำเงิน:
(0, 0, 255) - ลูกศรสีขาว:
(255, 255, 255)
ความไวและการปรับให้เรียบ
เพื่อหลีกเลี่ยงการกระตุก โค้ดจึงรวมตรรกะการปรับให้เรียบและค่าเกณฑ์ ในการตั้งค่าคุณอาจพบสิ่งเช่น:
// การปรับความไว / การปรับให้เรียบ
float tiltThreshold = 0.30f; // ปรับหากลูกศรเปลี่ยนง่ายเกินไป
- หากลูกศรของคุณพลิกง่ายเกินไป → เพิ่ม ค่าเกณฑ์
- หากลูกศรเปลี่ยนช้าเกินไป → ลด ค่าเกณฑ์
รูปแบบลูกศร
สเก็ตช์นี้มีรูปแบบบิตแมปของลูกศรสำหรับ:
- ↑ ขึ้น
- ↓ ลง
- ← ซ้าย
- → ขวา
คุณไม่จำเป็นต้องแก้ไขสิ่งเหล่านี้ แต่คุณสามารถเปลี่ยนรูปร่างภายในโค้ดได้หากต้องการสไตล์ที่แตกต่าง
สรุป
โปรเจกต์ 5 สาธิตการทำงานร่วมกันของ ESP32-S3 RGB LED Matrix และเซนเซอร์วัดความเร่ง QMI8658C เพื่อตรวจจับทิศทางและแสดงลูกศรที่ชี้ขึ้นด้านบนเสมอ โปรเจกต์นี้ต่อยอดจาก Tilt Dot (โปรเจกต์ 4) และเตรียมคุณให้พร้อมสำหรับเกมอินเทอร์แอคทีฟสุดท้ายในโปรเจกต์ 6
สเก็ตช์เต็ม “Arrow Always Up” มีให้ด้านล่างบทความนี้ (โหลดอัตโนมัติ) การดูวิดีโอส่วนที่เกี่ยวข้องเป็นสิ่งที่แนะนำอย่างยิ่งเพื่อให้เห็นว่าลูกศรตอบสนองต่อการหมุนบอร์ดได้ทันทีเพียงใด หากคุณต้องการสร้างโปรเจกต์นี้ที่บ้าน ลิงก์พันธมิตรสำหรับโมดูล 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 6 - เกม Cible
- โปรเจกต์นาฬิกา 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 5: Arrow Always Up – 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/RJT833
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
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800
);
// -------- QMI8658 IMU SETUP --------
QMI8658 imu;
QMI8658_Data imuData;
// -------- USER SETTINGS --------
// true -> arrow points to opposite side
// USB↔OUSB, 34↔15
// false -> arrow points to the same side that is UP
bool useOppositeMapping = false;
// Arrow color (0–255 each)
uint8_t dotRed = 0;
uint8_t dotGreen = 150;
uint8_t dotBlue = 0;
// Board sides
enum Side {
SIDE_CENTER = 0,
SIDE_USB,
SIDE_OUSB,
SIDE_15,
SIDE_34
};
// Direction for arrow drawing
enum ArrowDir {
ARROW_CENTER,
ARROW_UP,
ARROW_DOWN,
ARROW_LEFT,
ARROW_RIGHT
};
bool isFlat = false;
const char* sideName(Side s) {
switch (s) {
case SIDE_CENTER: return "CENTER";
case SIDE_USB: return "USB";
case SIDE_OUSB: return "OUSB";
case SIDE_15: return "15";
case SIDE_34: return "34";
default: return "?";
}
}
// -------- ARROW DRAWING (YOUR CODE, UNCHANGED) --------
// Draw a simple arrow on 8x8 matrix pointing in the given direction
void drawArrow(ArrowDir dir, uint16_t color) {
matrix.fillScreen(0);
switch (dir) {
case ARROW_UP:
// Tip
matrix.drawPixel(3, 0, color);
matrix.drawPixel(4, 0, color);
// Second row
matrix.drawPixel(2, 1, color);
matrix.drawPixel(3, 1, color);
matrix.drawPixel(4, 1, color);
matrix.drawPixel(5, 1, color);
// Shaft
matrix.drawLine(3, 2, 3, 6, color);
matrix.drawLine(4, 2, 4, 6, color);
break;
case ARROW_DOWN:
// Tip
matrix.drawPixel(3, 7, color);
matrix.drawPixel(4, 7, color);
// Row above tip
matrix.drawPixel(2, 6, color);
matrix.drawPixel(3, 6, color);
matrix.drawPixel(4, 6, color);
matrix.drawPixel(5, 6, color);
// Shaft
matrix.drawLine(3, 1, 3, 5, color);
matrix.drawLine(4, 1, 4, 5, color);
break;
case ARROW_LEFT:
// Tip
matrix.drawPixel(0, 3, color);
matrix.drawPixel(0, 4, color);
// Column after tip
matrix.drawPixel(1, 2, color);
matrix.drawPixel(1, 3, color);
matrix.drawPixel(1, 4, color);
matrix.drawPixel(1, 5, color);
// Shaft
matrix.drawLine(2, 3, 6, 3, color);
matrix.drawLine(2, 4, 6, 4, color);
break;
case ARROW_RIGHT:
// Tip
matrix.drawPixel(7, 3, color);
matrix.drawPixel(7, 4, color);
// Column before tip
matrix.drawPixel(6, 2, color);
matrix.drawPixel(6, 3, color);
matrix.drawPixel(6, 4, color);
matrix.drawPixel(6, 5, color);
// Shaft
matrix.drawLine(1, 3, 5, 3, color);
matrix.drawLine(1, 4, 5, 4, color);
break;
case ARROW_CENTER:
default:
// Simple plus in the center
matrix.drawLine(3, 3, 4, 3, color);
matrix.drawLine(3, 4, 4, 4, color);
matrix.drawLine(3, 3, 3, 4, color);
matrix.drawLine(4, 3, 4, 4, color);
break;
}
matrix.show();
}
// -------- IMU → SIDE DETECTION --------
// We calibrated earlier:
// +X = USB, -X = OUSB
// +Y = 15, -Y = 34 (after your correction)
Side detectSideUp(float ax_g, float ay_g, float az_g) {
// Flat detection
const float flatThreshXY = 0.15f;
const float flatThreshZ = 0.15f;
if (fabs(ax_g) < flatThreshXY &&
fabs(ay_g) < flatThreshXY &&
fabs(az_g - 1.0f) < flatThreshZ) {
isFlat = true;
return SIDE_CENTER;
}
isFlat = false;
// Thresholds to say "this axis is really tilted"
const float tiltThreshY = 0.5f;
const float tiltThreshX = 0.5f;
// Prefer Y axis for 15 / 34
if (fabs(ay_g) >= tiltThreshY) {
if (ay_g > 0) {
return SIDE_34; // +Y = 34 up
} else {
return SIDE_15; // -Y = 15 up
}
}
// Otherwise, use X axis for USB / OUSB
if (fabs(ax_g) >= tiltThreshX) {
if (ax_g > 0) {
return SIDE_USB; // +X = USB up
} else {
return SIDE_OUSB; // -X = OUSB up
}
}
// Not clearly tilted → treat as center
return SIDE_CENTER;
}
// Map from UP side to where the arrow should point
Side arrowSideFromUpSide(Side upSide) {
if (!useOppositeMapping) {
// Arrow shows the side that is UP
return upSide;
}
// Arrow shows the opposite side
switch (upSide) {
case SIDE_USB: return SIDE_OUSB;
case SIDE_OUSB: return SIDE_USB;
case SIDE_15: return SIDE_34;
case SIDE_34: return SIDE_15;
case SIDE_CENTER:
default: return SIDE_CENTER;
}
}
// Convert SIDE to ArrowDir
ArrowDir arrowDirFromSide(Side s) {
switch (s) {
case SIDE_USB: return ARROW_UP;
case SIDE_OUSB: return ARROW_DOWN;
case SIDE_15: return ARROW_LEFT;
case SIDE_34: return ARROW_RIGHT;
case SIDE_CENTER:
default: return ARROW_CENTER;
}
}
// ---------------- SETUP & LOOP ----------------
void setup() {
Serial.begin(115200);
delay(500);
matrix.begin();
matrix.setBrightness(20);
matrix.fillScreen(0);
matrix.show();
// IMU: SDA=11, SCL=12 on ESP32-S3-Matrix
if (!imu.begin(11, 12)) {
Serial.println("Failed to initialize QMI8658!");
while (1) { delay(1000); }
}
imu.setAccelUnit_mg(true);
imu.setGyroUnit_dps(true);
imu.setDisplayPrecision(4);
Serial.print("QMI8658 initialized. useOppositeMapping = ");
Serial.println(useOppositeMapping ? "TRUE" : "FALSE");
}
void loop() {
if (!imu.readSensorData(imuData)) {
return;
}
float ax_g = imuData.accelX / 1000.0f;
float ay_g = imuData.accelY / 1000.0f;
float az_g = imuData.accelZ / 1000.0f;
Side upSide = detectSideUp(ax_g, ay_g, az_g);
Side arrowSide = arrowSideFromUpSide(upSide);
ArrowDir dir = arrowDirFromSide(arrowSide);
uint16_t color = matrix.Color(dotRed, dotGreen, dotBlue);
drawArrow(dir, color);
// Debug
Serial.print("AX="); Serial.print(ax_g, 3);
Serial.print(" AY="); Serial.print(ay_g, 3);
Serial.print(" AZ="); Serial.print(az_g, 3);
Serial.print(" | UP="); Serial.print(sideName(upSide));
Serial.print(" | ARROW="); Serial.println(sideName(arrowSide));
delay(80);
}
สิ่งที่คุณอาจต้องการ
-
อเมซอน
-
อีเบย์
-
อาลีเอ็กซ์เพรส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