Этот учебник является частью: ESP32-S3 RGB LED матрица
Замечательный проект для создания развлекательных и практических приложений с использованием модуля RGB-матрицы ESP32-S3. Ссылки на другие видеоролики находятся ниже этой статьи.
Проект матрицы RGB LED на ESP32-S3 5 - Стрелка всегда вверх
Проект 5 - Стрелка всегда вверх (Индикатор ориентации с использованием QMI8658C)
Проект 5 использует датчик движения QMI8658C для определения ориентации RGB LED матрицы ESP32-S3 и всегда отображает стрелку, указывающую ВВЕРХ относительно гравитации. Независимо от того, как вы повернете плату - USB стороной вверх, OUSB стороной вверх, стороной "15" или стороной "34" - стрелка автоматически поворачивается и указывает в физическом вертикальном направлении.
Это мощная демонстрация определения ориентации в реальном времени с использованием встроенного акселерометра. Все шесть проектов для этого модуля продемонстрированы в одном видео на YouTube, которое также встроено на этой странице. Полный код для Проекта 5 загружается автоматически под статьёй, а партнерские ссылки появляются под разделом кода.

Обзор модуля RGB LED-матрицы ESP32-S3
Модуль RGB LED матрицы ESP32-S3 включает в себя несколько компонентов, которые делают этот проект возможным:

- Микроконтроллер ESP32-S3- предоставляет Wi-Fi, BLE и управляет логикой LED/IMU.
- 8×8 RGB светодиодная матрица- отображает стрелку в любом из четырех направлений.
- QMI8658C акселерометр- обнаруживает наклон, движение и ориентацию.:contentReference[oaicite:0]{index=0}
- USB-C портдля питания и программирования в Arduino IDE.
- Кнопки сброса и загрузкидля загрузки эскизов.
- 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: Tilt Dot
- 18:55-Проект 5: Стрелка Всегда Вверх (это проект)
- 20:02- Проект 6: Игра-Цель
В видео четко показано, как стрела мгновенно изменяет направление в зависимости от того, как повернут модуль. Настоятельно рекомендуется посмотреть этот сегмент.:contentReference[oaicite:1]{index=1}

Установка плат 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…- Поиск:НеоМатрикс→ Установить
- Установите зависимости:НеоПиксель+GFX
- Поиск и установкаQMI8658автором текста
Как работает проект 5
QMI8658C измеряет гравитацию по осям X, Y и Z. Сравнивая эти значения, схема определяет, какая физическая сторона платы обращена вверх:
- USB стороной вверх
- Сторона OUSB вверх(противоположный USB)
- Сторона "15" вверх
- Сторона "34" вверх
Каждая ориентация соответствует различному шаблону стрелок на матрице 8×8. Сопоставление соответствует вашей подтвержденной логике ориентации из предыдущих сеансов отладки. Поворот доски считывается непрерывно, и стрелка обновляется, как только изменяется верхняя сторона.
Проект 5 - Настройки кода (Стрелка всегда вверх)
Ниже представлены значения, которые можно настроить пользователю в области конфигурации. Полный код проекта автоматически появляется ниже статьи.
Конфигурация матрицы
// Matrix configuration
const int MATRIX_PIN = 14; // fixed for this module
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
// Recommended orientation: Top-Left origin, progressive mode
// (actual constructor is inside the code loaded below)
Этот проект используетNEO_МАЙТРИКС_ПРОГРЕССИВНЫЙмакет для обеспечения правильного направления стрелки в зависимости от фактического движения.
Яркость
uint8_t matrixBrightness = 40; // 0–255
Вы можете увеличить это значение для более ярких условий. Для использования в помещениях комфортно значение 30-60.
Цвет стрелки
// Arrow color
uint8_t arrowRed = 255;
uint8_t arrowGreen = 0;
uint8_t arrowBlue = 0;
Измените эти значения, чтобы изменить цвет стрелки. Например:
- Зеленая стрелка:
(0, 255, 0) - Синяя стрелка:
(0, 0, 255) - Белая стрелка:
(255, 255, 255)
Чувствительность и сглаживание
Чтобы избежать дрожания, код включает в себя сглаживание и пороговую логику. В настройках вы можете найти что-то вроде:
// Sensitivity / smoothing adjustment
float tiltThreshold = 0.30f; // adjust if arrow changes too easily
- Если ваша стрела слишком легко переворачивается →увеличениепорог.
- Если стрелка слишком медленно меняется →уменьшениепорог.
Стрелочные узоры
Эскиз включает битмап-паттерны стрелок для:
- ↑ вверх
- вниз
- ← влево
- → право
Вам не нужно изменять их, но вы можете менять формы внутри кода, если хотите другой стиль.
Резюме
Проект 5 демонстрирует, как RGB LED матрица ESP32-S3 и акселерометр QMI8658C работают вместе, чтобы определять ориентацию и отображать стрелку, которая всегда указывает вверх. Этот проект основан на проекте Tilt Dot (Проект 4) и подготавливает вас к финальной интерактивной игре в Проекте 6.
Полная схема "Стрела всегда вверх" доступна ниже этой статьи (авто-загрузка). Настоятельно рекомендуется посмотреть соответствующую часть видео, чтобы увидеть, как мгновенно стрелка реагирует на поворот доски. Если вы хотите собрать этот проект дома, партнерские ссылки на модуль RGB LED матрицы ESP32-S3 появляются в разделе кода.
Изображения
Этот учебник является частью: ESP32-S3 RGB LED матрица
- Проект матрицы RGB LED ESP32-S3 1 - Основной штрих
- Проект RGB LED матрицы ESP32-S3 2 - Прокручиваемый текст
- Проект RGB LED матрицы ESP32-S3 3 - Текст с мобильного телефона
- Проект RGB LED матрицы ESP32-S3 4 - Наклоненная точка
- Проект матрицы RGB LED ESP32-S3 6 - Игра цель
- ESP32-S3 RGB LED матрица Wi-Fi + NTP проект часы - 1 базовые часы
- ESP32-S3 RGB светодиодная матрица Интернет-часы - 2-часовой многоцветный дисплей времени и даты
- Проект интернет-часов на матрице RGB LED ESP32-S3 - 3 ночных цвета с датой
- Проект интернет-часов на матрице RGB LED ESP32-S3 - 5 радуга цветов
- Проект интернет-часы с матрицей RGB LED на ESP32-S3 - 4 случайных цвета
- Тест матрицы RGB LED ESP32-S3 для настройки RGB, GRB
/*
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);
}
Вещи, которые могут вам понадобиться
-
Амазонка
-
eBay
-
АлиЭкспрессКупить ESP32-S3 RGB-матрицу на AliExpresss.click.aliexpress.com
-
АлиЭкспрессПриобретите ESP32-S3 RGB Matrix на AliExpress (2)s.click.aliexpress.com
Ресурсы и ссылки
-
Внутренний🎨 Инструмент выбора цветаrobojax.com
Файлы📁
Файл Fritzing
-
esp32-S3-supermini-tht часть фритзинга
esp32-S3-supermini-tht.fzpz0.02 MB