Search Code

Projekt matrycy LED RGB ESP32-S3 5 - Strzałka zawsze w górę

Projekt matrycy LED RGB ESP32-S3 5 - Strzałka zawsze w górę

Projekt 5 – Strzałka zawsze w górę (wskaźnik orientacji z użyciem QMI8658C)

Projekt 5 wykorzystuje czujnik ruchu QMI8658C do wykrywania orientacji matrycy LED RGB ESP32-S3 i zawsze wyświetla strzałkę wskazującą GÓRĘ względem grawitacji. Niezależnie od tego, jak obrócisz płytkę—stroną USB do góry, stroną OUSB do góry, bokiem „15” lub bokiem „34”—strzałka automatycznie się obraca i wskazuje fizycznie kierunek ku górze.

To doskonała demonstracja wykrywania orientacji w czasie rzeczywistym z użyciem wbudowanego akcelerometru. Wszystkie sześć projektów dla tego modułu jest zaprezentowanych w jednym filmie na YouTube, który jest również osadzony na tej stronie. Kompletny kod Projektu 5 ładuje się automatycznie poniżej artykułu, a linki afiliacyjne pojawiają się pod sekcją z kodem.

Przegląd modułu matrycy LED RGB ESP32-S3

Moduł matrycy LED RGB ESP32-S3 zawiera kilka komponentów, które umożliwiają realizację tego projektu:

  • Mikrokontroler ESP32-S3 — zapewnia Wi-Fi, BLE i obsługuje logikę LED/IMU.
  • Matryca LED RGB 8×8 — wyświetla strzałkę w jednej z czterech orientacji.
  • Akcelerometr QMI8658C — wykrywa przechylenie, ruch i orientację.
  • Port USB-C do zasilania i programowania w Arduino IDE.
  • Przyciski Reset i Boot do przesyłania szkiców.
  • Piny GPIO dostępne wokół płytki do dodatkowych projektów.

Kierunek strzałki jest określany wyłącznie na podstawie odczytów akcelerometru. Gdy płytka jest obracana, QMI8658C wykrywa nowe wartości X/Y/Z, a szkic wybiera, który wzór strzałki (↑, ↓, ←, →) powinien zostać narysowany.

Projekty omówione w filmie (znaczniki czasu)

  • 00:00 – Wprowadzenie
  • 02:01 – Instalacja płytek ESP32
  • 03:32 – Instalacja bibliotek
  • 05:32 – Projekt 1: Ruchoma kropka
  • 11:11 – Projekt 2: Przewijanie tekstu
  • 12:59 – Projekt 3: Tekst HTTP
  • 16:41 – Projekt 4: Kropka przechylenia
  • 18:55Projekt 5: Strzałka zawsze w górę (ten projekt)
  • 20:02 – Projekt 6: Gra w cel

Film wyraźnie pokazuje, jak strzałka natychmiast zmienia kierunek w zależności od obrotu modułu. Obejrzenie tego fragmentu jest zdecydowanie zalecane.

Instalacja płytek ESP32 w Arduino IDE

Jeśli ukończyłeś którykolwiek wcześniejszy projekt, konfiguracja płytki jest już gotowa. W przeciwnym razie:

  1. Plik > Preferencje → Dodaj adres URL płytki ESP32
  2. Narzędzia > Płytka > Menedżer płytek… → Zainstaluj „ESP32”
  3. Wybierz płytkę ESP32-S3 w Narzędzia > Płytka
  4. Wybierz właściwy port USB COM w Narzędzia > Port

Instalacja wymaganych bibliotek

Projekt 5 wykorzystuje:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX
  • QMI8658 (czujnik ruchu)
  1. Szkic > Dołącz bibliotekę > Zarządzaj bibliotekami…
  2. Szukaj: NeoMatrix → Zainstaluj
  3. Zainstaluj zależności: NeoPixel + GFX
  4. Wyszukaj i zainstaluj QMI8658 według autora

Jak działa Projekt 5

QMI8658C mierzy grawitację na osiach X, Y i Z. Porównując te wartości, szkic określa, która fizyczna strona płytki jest skierowana ku górze:

  • Strona USB do góry
  • Strona OUSB do góry (przeciwna do USB)
  • Bok „15” do góry
  • Bok „34” do góry

Każda orientacja odpowiada innemu wzorowi strzałki na matrycy 8×8. Mapowanie jest zgodne z potwierdzoną logiką orientacji z wcześniejszych sesji debugowania. Obrót płytki jest odczytywany w sposób ciągły, a strzałka aktualizuje się natychmiast po zmianie strony skierowanej ku górze.

Projekt 5 – Ustawienia kodu (Strzałka zawsze w górę)

Poniżej znajdują się wartości regulowane przez użytkownika z obszaru konfiguracji. Pełny kod projektu pojawia się automatycznie poniżej artykułu.

Konfiguracja matrycy


// Konfiguracja matrycy
const int MATRIX_PIN    = 14;   // stałe dla tego modułu
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

// Zalecana orientacja: początek w lewym górnym rogu, tryb progresywny
// (rzeczywisty konstruktor znajduje się w kodzie załadowanym poniżej)

Ten projekt wykorzystuje układ NEO_MATRIX_PROGRESSIVE, aby zapewnić prawidłowe wskazywanie strzałki na podstawie rzeczywistego ruchu.

Jasność


uint8_t matrixBrightness = 40;   // 0–255

Możesz zwiększyć tę wartość w jaśniejszym otoczeniu. Do użytku wewnątrz pomieszczeń wygodny jest zakres 30–60.

Kolor strzałki


// Kolor strzałki
uint8_t arrowRed   = 255;
uint8_t arrowGreen = 0;
uint8_t arrowBlue  = 0;

Zmień te wartości, aby zmodyfikować kolor strzałki. Na przykład:

  • Zielona strzałka: (0, 255, 0)
  • Niebieska strzałka: (0, 0, 255)
  • Biała strzałka: (255, 255, 255)

Czułość i wygładzanie

Aby uniknąć drgań, kod zawiera logikę wygładzania i progów. W ustawieniach możesz znaleźć coś takiego:


// Regulacja czułości / wygładzania
float tiltThreshold = 0.30f;   // dostosuj, jeśli strzałka zmienia się zbyt łatwo
  • Jeśli twoja strzałka zbyt łatwo się zmienia → zwiększ próg.
  • Jeśli strzałka zmienia się zbyt wolno → zmniejsz próg.

Wzory strzałek

Szkic zawiera wzory bitmapowe strzałek dla:

  • ↑ góra
  • ↓ dół
  • ← lewo
  • → prawo

Nie musisz ich modyfikować, ale możesz zmienić kształty w kodzie, jeśli chcesz inny styl.

Podsumowanie

Projekt 5 pokazuje, jak ESP32-S3 RGB LED Matrix i akcelerometr QMI8658C współpracują, aby wykrywać orientację i wyświetlać strzałkę, która zawsze wskazuje górę. Projekt ten opiera się na Tilt Dot (Projekt 4) i przygotowuje cię do końcowej interaktywnej gry w Projekcie 6.

Pełny szkic “Strzałka zawsze w górę” jest dostępny poniżej tego artykułu (automatycznie ładowany). Zaleca się obejrzenie odpowiedniej części wideo, aby zobaczyć, jak natychmiast strzałka reaguje na obrót płytki. Jeśli chcesz zbudować ten projekt w domu, linki partnerskie do modułu ESP32-S3 RGB LED Matrix znajdują się pod sekcją z kodem.

Obrazy

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
Język: 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);
}

Rzeczy, których możesz potrzebować

Zasoby i odniesienia

Pliki📁

Plik Fritzing