Search Code

Projekt ESP32-S3 RGB LED Matrix 4 - Náklon bodky

Projekt ESP32-S3 RGB LED Matrix 4 - Náklon bodky

Projekt 4 – Náklonová bodka (Pohyb bodky nakláňaním ESP32-S3 RGB LED Matrix)

Projekt 4 predstavuje pohybový senzor zabudovaný v module ESP32-S3 RGB LED Matrix. Namiesto automatického pohybu bodky (ako v projekte 1) alebo posúvania textu (projekty 2 a 3) vám tento projekt umožňuje ovládať polohu bodky jednoduchým nakláňaním dosky. Bodka sa plynulo pohybuje po 8×8 RGB displeji na základe živých údajov z akcelerometra QMI8658C na zadnej strane modulu.

Všetkých šesť projektov v tejto sérii je predvedených v jednom YouTube videu. Rovnaké video je vložené na tejto stránke, takže môžete presne vidieť, ako sa bodka pohybuje v reálnom čase pri nakláňaní dosky. Kompletný kód tohto projektu sa automaticky načíta nižšie pod článkom a affiliate odkazy na nákup modulu sa nachádzajú pod sekciou s kódom.

Prehľad modulu ESP32-S3 RGB LED Matrix

Tento projekt používa modul ESP32-S3 RGB LED Matrix, ktorý obsahuje:

  • Mikrokontrolér ESP32-S3 s Wi-Fi a Bluetooth
  • 8×8 RGB LED maticu (64 samostatne adresovateľných LED)
  • Akcelerometer QMI8658C na zadnej strane na detekciu náklonu a pohybu
  • USB port na programovanie a napájanie
  • Tlačidlá Boot / Reset
  • Použiteľné GPIO piny na budúce rozšírenia

Senzor QMI8658C číta hodnoty zrýchlenia a orientácie na osiach X, Y a Z, čo umožňuje pohyb bodky hore/dole/doľava/doprava podľa toho, ako je doska naklonená.

Projekty zahrnuté vo videu (Časové značky)

  • 00:00 – Úvod
  • 02:01 – Inštalácia dosiek ESP32
  • 03:32 – Inštalácia knižníc
  • 05:32 – Projekt 1: Pohybujúca sa bodka
  • 11:11 – Projekt 2: Posúvanie textu
  • 12:59 – Projekt 3: HTTP text
  • 16:41Projekt 4: Náklonová bodka (tento projekt)
  • 18:55 – Projekt 5: Šípka hore
  • 20:02 – Projekt 6: Cieľová hra

Dôrazne odporúčame pozrieť si ukážku nakláňania vo videu, pretože môžete vidieť, ako bodka plynulo reaguje na orientáciu dosky.

Inštalácia dosiek ESP32 v Arduino IDE

Ak ste už dokončili niektorý z predchádzajúcich projektov, podpora dosiek je už nainštalovaná. V opačnom prípade postupujte podľa týchto krokov:

  1. Otvorte Súbor > Predvoľby → Pridajte URL pre dosky ESP32.
  2. Prejdite na Nástroje > Doska > Správca dosiek… a nainštalujte ESP32.
  3. Vyberte svoju dosku ESP32-S3 v časti Nástroje > Doska.
  4. Vyberte správny COM port v časti Nástroje > Port.

Inštalácia požadovaných knižníc

Tento projekt vyžaduje nasledujúce knižnice:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library
  • QMI8658 (pohybový senzor)

Nainštalujte ich v Správcovi knižníc:

  1. Otvorte Náčrt > Zahrnúť knižnicu > Spravovať knižnice….
  2. Vyhľadajte Adafruit NeoMatrix → Inštalovať.
  3. Povoľte automatickú inštaláciu Adafruit GFX a Adafruit NeoPixel.
  4. Vyhľadajte QMI8658 podľa uvedeného autora → Inštalovať.

Ako funguje Projekt 4

Senzor QMI8658C nepretržite poskytuje údaje o zrýchlení na osiach X, Y a Z. Pre tento projekt používame iba osi X a Y na určenie:

  • Ako ďaleko sa bodka posunie doľava alebo doprava (os X)
  • Ako ďaleko sa bodka posunie hore alebo dole (os Y)

Hodnoty senzora sú mapované do rozsahu súradníc od 0 do 7 (pre 8×8 LED maticu). Poloha bodky sa aktualizuje mnohokrát za sekundu, čo vytvára plynulý posuvný efekt pri nakláňaní modulu.

Projekt 4 – Nastavenia kódu (Náklonová bodka)

Nižšie sú uvedené používateľsky upraviteľné nastavenia nachádzajúce sa v hornej časti kódu projektu. Úplný náčrt sa automaticky zobrazí nižšie pod článkom.

Pin a veľkosť matice


// Konfigurácia 8×8 RGB matice
const int MATRIX_PIN    = 14;   // pevný pin pre túto dosku
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

Ponechajte MATRIX_PIN na hodnote 14. Je pevne zapojený k matici na doske.

Jas


// Celkový jas (0–255)
uint8_t matrixBrightness = 40;

V prípade potreby zvýšte, ale pri pohľade zblízka sa vyhnite extrémnemu jasu.

Farba bodky


// Farba bodky (R, G, B)
uint8_t dotRed   = 0;
uint8_t dotGreen = 200;   // svetlozelená (predvolená)
uint8_t dotBlue  = 0;

Zmeňte tieto hodnoty na vytvorenie ľubovoľnej farby. Príklady:

  • Červená: (255, 0, 0)
  • Žltá: (255, 255, 0)
  • Biela: (255, 255, 255)

Citlivosť pohybu

Aby sa predišlo extrémnym skokom, hodnoty akcelerometra sa zvyčajne obmedzujú alebo škálujú. Typické nastavenie vyzerá takto:


// Ako agresívne náklon ovplyvňuje pohyb
float sensitivity = 4.0f;   // väčšia hodnota = rýchlejší pohyb po obrazovke

Ak sa bodka pohybuje príliš pomaly → zvýšte hodnotu. Ak sa bodka pohybuje príliš náhle → znížte ju.

Rýchlosť aktualizácie (Obnovovacia frekvencia)

Medzi aktualizáciami môžete pridať malé oneskorenie na vyhladenie pohybu:


// Oneskorenie medzi aktualizáciami polohy (ms)
int refreshDelayMs = 20;   // nižšie = plynulejšia a rýchlejšia odozva

Hodnoty medzi 10–30 ms pôsobia veľmi citlivo.

Zhrnutie

Projekt 4 oživuje vstavaný akcelerometer QMI8658C na ESP32-S3 tým, že vám umožňuje ovládať LED maticu fyzickým pohybom. Malý náklon dosky posunie bod v rovnakom smere, čo robí tento projekt ideálnym odrazovým mostíkom pre pokročilejšie projekty “Arrow Up” a “Target Game”.

Plný náčrt Tilt Dot je načítaný nižšie v tomto článku (automaticky). Pre najlepšie pochopenie si pozrite ukážku nakláňania vo videu, kde môžete vidieť, ako plynulo sa bod pohybuje pri otáčaní dosky. Odkazy na zakúpenie modulu ESP32-S3 RGB LED Matrix sú uvedené pod časťou s kódom.

Images

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 displaying rainbow heart
ESP32 S3 Matrix displaying rainbow heart
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3_RGB_8x8_matrix-2
802-ESP32-S3 RGB LED Matrix Project 4 - Tilt dot
Language: C++
/* 
  Project 4: Tilt Dot – 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/RJT829

  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  -> dot on opposite side: USB↔OUSB, 34↔15
// false -> dot on same side as UP
bool useOppositeMapping = false;

// Dot color (0–255 each)
uint8_t dotRed   = 0;
uint8_t dotGreen = 100;
uint8_t dotBlue  = 0;

// Board sides
enum Side {
  SIDE_CENTER = 0,
  SIDE_USB,
  SIDE_OUSB,
  SIDE_15,
  SIDE_34
};

// Smooth dot position (in pixel coordinates, but kept as float for easing)
float dotPosX = 3.0f;   // start at center
float dotPosY = 3.0f;

// Smoothing factor: smaller = slower movement (0.1 very slow, 0.5 faster)
const float dotSmooth = 0.25f;


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 "?";
  }
}

// Detect which side is UP using calibrated axes:
// +X = USB, -X = OUSB, +Y = 34, -Y = 15
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;

  // 1) Prefer Y axis for 15 / 34 if it's clearly tilted
  if (fabs(ay_g) >= tiltThreshY) {
    if (ay_g > 0) {
      return SIDE_15;   // +Y = 34 up
    } else {
      return SIDE_34;   // -Y = 15 up
    }
  }

  // 2) Otherwise, check 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
    }
  }

  // 3) If nothing is strongly tilted, just call it CENTER
  return SIDE_CENTER;
}

// Map from UP side to where the dot should go
Side dotSideFromUpSide(Side upSide) {
  switch (upSide) {
    case SIDE_USB:
      return useOppositeMapping ? SIDE_OUSB : SIDE_USB;

    case SIDE_OUSB:
      return useOppositeMapping ? SIDE_USB : SIDE_OUSB;

    case SIDE_34:
      return useOppositeMapping ? SIDE_15 : SIDE_34;

    case SIDE_15:
      return useOppositeMapping ? SIDE_34 : SIDE_15;

    case SIDE_CENTER:
    default:
      return SIDE_CENTER;
  }
}

// Convert dot side to matrix coordinates
void getDotPixel(Side dotSide, int &px, int &py) {
  // Matrix (0,0) = top-left
  // top center:    (3,0) → USB
  // bottom center: (3,7) → OUSB
  // left center:   (0,3) → 15
  // right center:  (7,3) → 34
  // center:        (3,3)

  switch (dotSide) {
    case SIDE_USB:   px = 3; py = 0; break;
    case SIDE_OUSB:  px = 3; py = 7; break;
    case SIDE_15:    px = 0; py = 3; break;
    case SIDE_34:    px = 7; py = 3; break;
    case SIDE_CENTER:
    default:         px = 3; py = 3; break;
  }
}

void setup() {
  Serial.begin(115200);
  delay(500);

  matrix.begin();
  matrix.setBrightness(20);
  matrix.fillScreen(0);
  matrix.show();

  // IMU: SDA=11, SCL=12 for 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 dotSide = dotSideFromUpSide(upSide);

  int targetX, targetY;
  getDotPixel(dotSide, targetX, targetY);

  // --- Smooth movement toward target ---
  dotPosX += (targetX - dotPosX) * dotSmooth;
  dotPosY += (targetY - dotPosY) * dotSmooth;

  // Convert to integer pixel coordinates
  int px = (int)round(dotPosX);
  int py = (int)round(dotPosY);

  // Clamp just in case
  if (px < 0) px = 0;
  if (px > 7) px = 7;
  if (py < 0) py = 0;
  if (py > 7) py = 7;

  // --- Draw dot ---
  matrix.fillScreen(0);
  uint16_t color = matrix.Color(dotRed, dotGreen, dotBlue);
  matrix.drawPixel(px, py, color);
  matrix.show();

  // 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(" | DOT="); Serial.print(sideName(dotSide));
  Serial.print(" | px=");  Serial.print(px);
  Serial.print(" py=");    Serial.println(py);

  delay(80);
}



Things you might need

Resources & references

Files📁

Fritzing File