Пребарување код

ESP32-S3 RGB LED матричен проект 5 - Стрелка секогаш нагоре

ESP32-S3 RGB LED матричен проект 5 - Стрелка секогаш нагоре

Проект 5 – Стрелка секогаш нагоре (индикатор за ориентација со QMI8658C)

Проектот 5 го користи сензорот за движење QMI8658C за да ја детектира ориентацијата на ESP32-S3 RGB LED матрицата и секогаш да прикажува стрелка насочена нагоре во однос на гравитацијата. Без разлика како ја ротирате плочата—USB страната нагоре, OUSB страната нагоре, страната „15“ или страната „34“—стрелката автоматски се врти и покажува кон физички насоката нагоре.

Ова е моќна демонстрација на сензорот за ориентација во реално време користејќи го вградениот акцелерометар. Сите шест проекти за овој модул се демонстрирани во едно YouTube видео, кое исто така е вградено на оваа страница. Целосниот код за Проект 5 се вчитува автоматски под статијата, а affiliate линковите се појавуваат под делот со кодот.

Преглед на ESP32-S3 RGB LED Matrix модулот

ESP32-S3 RGB LED Matrix модулот вклучува неколку компоненти кои го овозможуваат овој проект:

  • ESP32-S3 микроконтролер — обезбедува Wi-Fi, BLE и ја извршува LED/IMU логиката.
  • 8×8 RGB LED матрица — ја прикажува стрелката во една од четирите ориентации.
  • QMI8658C акцелерометар — детектира наклон, движење и ориентација.:contentReference[oaicite:0]{index=0}
  • 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: Игра со цел

Видеото јасно покажува како стрелката ја менува насоката веднаш врз основа на тоа како модулот е свртен. Гледањето на овој сегмент е силно препорачано.:contentReference[oaicite:1]{index=1}

Инсталирање на ESP32 плочи во Arduino IDE

Ако сте завршиле некој претходен проект, поставувањето на плочата е веќе направено. Во спротивно:

  1. File > Preferences → Додајте ESP32 board URL
  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. Пребарување: NeoMatrix → Инсталирајте
  3. Инсталирајте ги зависностите: NeoPixel + GFX
  4. Пребарувајте и инсталирајте го 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;

// Препорачана ориентација: Горно-лево потекло, прогресивен режим
// (вистинскиот конструктор е внатре во кодот вчитан подолу)

Овој проект користи 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 матрицата и QMI8658C акцелерометарот работат заедно за да детектираат ориентација и да прикажат стрелка што секогаш покажува нагоре. Овој проект се надоврзува на Tilt Dot (Проект 4) и ве подготвува за финалната интерактивна игра во Проект 6.

Целосната скица “Arrow Always Up” е достапна под овој напис (автоматски вчитана). Се препорачува да го гледате соодветниот дел од видеото за да видите колку веднаш стрелката реагира на ротацијата на плочката. Ако сакате да го изградите овој проект дома, партнерските линкови за ESP32-S3 RGB LED матрица модулот се појавуваат под делот со кодот.

Слики

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 датотека