Search Code

Proiect ESP32-S3 cu matrice LED RGB 5 - Săgeata mereu în sus

Proiect ESP32-S3 cu matrice LED RGB 5 - Săgeata mereu în sus

Proiectul 5 – Săgeata Întotdeauna în Sus (Indicator de Orientare folosind QMI8658C)

Proiectul 5 folosește senzorul de mișcare QMI8658C pentru a detecta orientarea matricei LED RGB ESP32-S3 și pentru a afișa întotdeauna o săgeată îndreptată în SUS în raport cu gravitația. Indiferent cum rotiți placa—cu partea USB în sus, cu partea OUSB în sus, cu partea “15” sau cu partea “34”—săgeata se rotește automat și indică direcția fizică în sus.

Aceasta este o demonstrație puternică a detectării orientării în timp real folosind accelerometrul integrat. Toate cele șase proiecte pentru acest modul sunt demonstrate într-un singur videoclip YouTube, care este de asemenea încorporat pe această pagină. Codul complet pentru Proiectul 5 se încarcă automat mai jos de articol, iar linkurile de afiliere apar sub secțiunea de cod.

Prezentare Generală a Modulului Matrice LED RGB ESP32-S3

Modulul Matrice LED RGB ESP32-S3 include mai multe componente care fac posibil acest proiect:

  • Microcontrolerul ESP32-S3 — oferă Wi-Fi, BLE și rulează logica LED/IMU.
  • Matrice LED RGB 8×8 — afișează săgeata în oricare dintre cele patru orientări.
  • Accelerometrul QMI8658C — detectează înclinarea, mișcarea și orientarea.:contentReference[oaicite:0]{index=0}
  • Port USB-C pentru alimentare și programare în Arduino IDE.
  • Butoanele Reset și Boot pentru încărcarea schițelor.
  • Pinii GPIO disponibili în jurul plăcii pentru proiecte suplimentare.

Direcția săgeții este determinată în întregime de citirile accelerometrului. Când placa este rotită, QMI8658C detectează noile valori X/Y/Z, iar schița alege ce model de săgeată (↑, ↓, ←, →) trebuie desenat.

Proiecte Acoperite în Videoclip (Marcaje de Timp)

  • 00:00 – Introducere
  • 02:01 – Instalarea plăcilor ESP32
  • 03:32 – Instalarea bibliotecilor
  • 05:32 – Proiectul 1: Punct în Mișcare
  • 11:11 – Proiectul 2: Derulare Text
  • 12:59 – Proiectul 3: Text HTTP
  • 16:41 – Proiectul 4: Punct de Înclinare
  • 18:55Proiectul 5: Săgeata Întotdeauna în Sus (acest proiect)
  • 20:02 – Proiectul 6: Jocul Țintă

Videoclipul arată clar cum săgeata își schimbă direcția instantaneu în funcție de modul în care este rotit modulul. Vizionarea acestei secțiuni este puternic recomandată.:contentReference[oaicite:1]{index=1}

Instalarea Plăcilor ESP32 în Arduino IDE

Dacă ați finalizat orice proiect anterior, configurarea plăcii este deja făcută. În caz contrar:

  1. Fișier > Preferințe → Adăugați URL-ul plăcii ESP32
  2. Instrumente > Placă > Manager de Plăci… → Instalați “ESP32”
  3. Selectați placa ESP32-S3 sub Instrumente > Placă
  4. Selectați portul USB COM corect sub Instrumente > Port

Instalarea Bibliotecilor Necesare

Proiectul 5 folosește:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX
  • QMI8658 (senzor de mișcare)
  1. Schiță > Include Bibliotecă > Gestionați Bibliotecile…
  2. Căutați: NeoMatrix → Instalați
  3. Instalați dependențele: NeoPixel + GFX
  4. Căutați și instalați QMI8658 de autorul său

Cum Funcționează Proiectul 5

QMI8658C măsoară gravitația pe axele X, Y și Z. Comparând aceste valori, schița determină ce parte fizică a plăcii este orientată în sus:

  • Partea USB în sus
  • Partea OUSB în sus (opusă USB)
  • Partea “15” în sus
  • Partea “34” în sus

Fiecare orientare corespunde unui model diferit de săgeată pe matricea 8×8. Maparea urmează logica dvs. confirmată de orientare din sesiunile anterioare de depanare. Rotația plăcii este citită continuu, iar săgeata se actualizează imediat ce partea orientată în sus se schimbă.

Proiectul 5 – Setări de Cod (Săgeata Întotdeauna în Sus)

Mai jos sunt valorile reglabile de utilizator din zona de configurare. Codul complet al proiectului apare automat mai jos de articol.

Configurarea Matricei


// Configurarea matricei
const int MATRIX_PIN    = 14;   // fix pentru acest modul
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

// Orientare recomandată: origine Colț-Sus-Stânga, mod progresiv
// (constructorul real este în codul încărcat mai jos)

Acest proiect folosește aspectul NEO_MATRIX_PROGRESSIVE pentru a asigura că săgeata indică corect în funcție de mișcarea reală.

Luminozitate


uint8_t matrixBrightness = 40;   // 0–255

Puteți crește această valoare pentru medii mai luminoase. Pentru utilizare în interior, 30–60 este confortabil.

Culoarea Săgeții


// Culoarea săgeții
uint8_t arrowRed   = 255;
uint8_t arrowGreen = 0;
uint8_t arrowBlue  = 0;

Schimbați aceste valori pentru a modifica culoarea săgeții. De exemplu:

  • Săgeată verde: (0, 255, 0)
  • Săgeată albastră: (0, 0, 255)
  • Săgeată albă: (255, 255, 255)

Sensibilitate și Netezire

Pentru a evita tremurul, codul include logică de netezire și prag. În setări puteți găsi ceva de genul:


// Ajustare sensibilitate / netezire
float tiltThreshold = 0.30f;   // ajustați dacă săgeata se schimbă prea ușor
  • Dacă săgeata ta se răstoarnă prea ușor → crește pragul.
  • Dacă săgeata este prea lentă la schimbare → scade pragul.

Modele de săgeți

Schița include modele bitmap de săgeți pentru:

  • ↑ sus
  • ↓ jos
  • ← stânga
  • → dreapta

Nu trebuie să le modifici, dar poți schimba formele din cod dacă dorești un stil diferit.

Rezumat

Proiectul 5 demonstrează cum matricea LED RGB ESP32-S3 și accelerometrul QMI8658C lucrează împreună pentru a detecta orientarea și a afișa o săgeată care indică întotdeauna în sus. Acest proiect se bazează pe Tilt Dot (Proiectul 4) și te pregătește pentru jocul interactiv final din Proiectul 6.

Schița completă “Arrow Always Up” este disponibilă mai jos în acest articol (încărcată automat). Vizionarea părții corespunzătoare din video este foarte recomandată pentru a vedea cât de instantaneu răspunde săgeata la rotația plăcii. Dacă dorești să construiești acest proiect acasă, linkurile afiliate pentru modulul matricei LED RGB ESP32-S3 apar sub secțiunea de cod.

Imagini

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
Limba: 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);
}

Lucruri de care ai putea avea nevoie

Resurse și referințe

Fișiere📁

Fișier Fritzing