Код для поиска

Проект матрицы RGB LED на ESP32-S3 5 - Стрелка всегда вверх

Проект матрицы 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

Если вы завершили какой-либо предыдущий проект, настройка доски уже выполнена. В противном случае:

  1. File > Preferences→ Добавить URL-адрес платы ESP32
  2. Tools > Board > Boards Manager…→ Установите "ESP32"
  3. Выберите плату ESP32-S3 в разделеTools > Board
  4. Выберите правильный USB COM-порт подTools > Port

Установка необходимых библиотек

Проект 5 использует:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX
  • QMI8658(датчик движения)
  1. Sketch > Include Library > Manage Libraries…
  2. Поиск:НеоМатрикс→ Установить
  3. Установите зависимости:НеоПиксель+GFX
  4. Поиск и установка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 Matrix
ESP32 S3 Matrix
ESP32 S3 Matrix  pin out
ESP32 S3 Matrix pin out
ESP32-S3_RGB_8x8_matrix-3
ESP32-S3_RGB_8x8_matrix-3
ESP32 S3 Matrix attached with buzzer to pin6 and GND
ESP32 S3 Matrix attached with buzzer to pin6 and GND
ESP32 S3 Matrix displaying red heart
ESP32 S3 Matrix displaying red heart
ESP32 S3 Matrix displaying green heart
ESP32 S3 Matrix displaying green heart
ESP32 S3 Matrix displaying rainbow heart 3
ESP32 S3 Matrix displaying rainbow heart 3
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3-Mtrix - Alway Up
ESP32-S3-Mtrix - Alway Up
803-ESP32-S3 RGB LED Matrix Project 5 - Arrow always up
Язык: C++
/* 
  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);
}

Вещи, которые могут вам понадобиться

Ресурсы и ссылки

Файлы📁

Файл Fritzing