Search Code

ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 4 - ዘንበል ነጥብ

ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 4 - ዘንበል ነጥብ

ፕሮጀክት 4 – ቲልት ዶት (ESP32-S3 RGB LED ማትሪክስን በማዘንበል ነጥቡን ያንቀሳቅሱ)

ፕሮጀክት 4 በESP32-S3 RGB LED ማትሪክስ ሞጁል ውስጥ የተሰራውን የእንቅስቃሴ ዳሳሽ ያስተዋውቃል። ነጥቡን በራስ-ሰር ከማንቀሳቀስ (እንደ ፕሮጀክት 1) ወይም ጽሑፍን ከማሸብለል (ፕሮጀክቶች 2 እና 3) ይልቅ፣ ይህ ፕሮጀክት ቦርዱን በማዘንበል ብቻ የነጥቡን ቦታ እንዲቆጣጠሩ ያስችልዎታል። ነጥቡ በሞጁሉ ጀርባ ላይ ካለው የQMI8658C አክስሌሮሜትር የቀጥታ ንባቦች ላይ በመመስረት በ8×8 RGB ማሳያ ላይ በተቀላጠፈ ሁኔታ ይንቀሳቀሳል።

በዚህ ተከታታይ ውስጥ ያሉት ስድስቱም ፕሮጀክቶች በአንድ የYouTube ቪዲዮ ውስጥ ተብራርተዋል። ተመሳሳዩ ቪዲዮ በዚህ ገጽ ላይ ተካቷል፣ ስለዚህ ቦርዱ ሲዘነበል ነጥቡ በእውነተኛ ጊዜ እንዴት እንደሚንቀሳቀስ በትክክል ማየት ይችላሉ። ለዚህ ፕሮጀክት የተሟላ ኮድ ከጽሑፉ በታች በራስ-ሰር ይጫናል፣ እና ለሞጁሉ የተባበሩት የግዢ አገናኞች ከኮድ ክፍሉ በታች ይታያሉ።

የESP32-S3 RGB LED ማትሪክስ ሞጁል አጠቃላይ እይታ

ይህ ፕሮጀክት የሚከተሉትን ያካተተውን የESP32-S3 RGB LED ማትሪክስ ሞጁል ይጠቀማል፦

  • ESP32-S3 ማይክሮኮንትሮለር ከWi-Fi እና ብሉቱዝ ጋር
  • 8×8 RGB LED ማትሪክስ (64 በተናጠል አድራሻ የሚያገኙ LEDs)
  • QMI8658C አክስሌሮሜትር በጀርባ ላይ ለማዘንበል እና ለእንቅስቃሴ መለየት
  • USB ወደብ ለፕሮግራም አወጣጥ እና ለኃይል
  • Boot / Reset አዝራሮች
  • ጥቅም ላይ ሊውሉ የሚችሉ GPIO ፒኖች ለወደፊት ማስፋፊያ

የQMI8658C ዳሳሽ XY እና 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፡ ዒላማ ጨዋታ

በቪዲዮው ውስጥ ያለውን የማዘንበል ማሳያ መመልከት በጣም ይመከራል፣ ምክንያቱም ነጥቡ ለቦርዱ አቅጣጫ በተቀላጠፈ ሁኔታ እንዴት ምላሽ እንደሚሰጥ ማየት ይችላሉ።

ESP32 ቦርዶችን በArduino IDE ውስጥ መጫን

ከዚህ ቀደም ማንኛውንም ፕሮጀክት ካጠናቀቁ፣ የቦርድ ድጋፉ አስቀድሞ ተጭኗል። አለበለዚያ፣ እነዚህን ደረጃዎች ይከተሉ፦

  1. File > Preferences ይክፈቱ → የESP32 ቦርዶች URL ያክሉ።
  2. ወደ Tools > Board > Boards Manager… ይሂዱ እና ESP32 ይጫኑ።
  3. የESP32-S3 ቦርድዎን በTools > Board ስር ይምረጡ።
  4. ትክክለኛውን COM ወደብ በTools > Port ስር ይምረጡ።

የሚፈለጉ ቤተ-መጻሕፍትን መጫን

ይህ ፕሮጀክት የሚከተሉትን ቤተ-መጻሕፍት ይፈልጋል፦

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library
  • QMI8658 (የእንቅስቃሴ ዳሳሽ)

በቤተ-መጻሕፍት አስተዳዳሪ ውስጥ ይጫኗቸው፦

  1. Sketch > Include Library > Manage Libraries… ይክፈቱ።
  2. Adafruit NeoMatrix ይፈልጉ → ይጫኑ።
  3. Adafruit GFX እና Adafruit NeoPixel በራስ-ሰር እንዲጫኑ ይፍቀዱ።
  4. QMI8658 በተዘረዘረው ደራሲ ይፈልጉ → ይጫኑ።

ፕሮጀክት 4 እንዴት እንደሚሰራ

የQMI8658C ዳሳሽ በX፣ Y እና Z ዘንጎች ላይ የፍጥነት መረጃን ያለማቋረጥ ያቀርባል። ለዚህ ፕሮጀክት፣ ለመወሰን X እና Y ዘንጎችን ብቻ እንጠቀማለን፦

  • ነጥቡ ወደ ግራ ወይም ወደ ቀኝ ምን ያህል እንደሚንቀሳቀስ (X ዘንግ)
  • ነጥቡ ወደ ላይ ወይም ወደ ታች ምን ያህል እንደሚንቀሳቀስ (Y ዘንግ)

የዳሳሽ እሴቶቹ ከ0 እስከ 7 ባለው የመጋጠሚያ ክልል ውስጥ (ለ8×8 LED ማትሪክስ) ይቀረጻሉ። የነጥቡ ቦታ በሰከንድ ብዙ ጊዜ ይዘምናል፣ ይህም ሞጁሉን ሲያዘነብሉ ለስላሳ የመንሸራተት ውጤት ይሰጣል።

ፕሮጀክት 4 – የኮድ ቅንብሮች (ቲልት ዶት)

ከዚህ በታች በፕሮጀክቱ ኮድ አናት አጠገብ የሚገኙት በተጠቃሚ ሊስተካከሉ የሚችሉ ቅንብሮች ናቸው። ሙሉው ስኬች ከጽሑፉ በታች በራስ-ሰር ይታያል።

የማትሪክስ ፒን እና መጠን


// 8×8 RGB ማትሪክስ ውቅር
const int MATRIX_PIN    = 14;   // ለዚህ ቦርድ ቋሚ ፒን
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

MATRIX_PINን በ14 ላይ ይተዉት። በቦርዱ ላይ ካለው ማትሪክስ ጋር በቋሚነት የተገናኘ ነው።

ብሩህነት


// አጠቃላይ ብሩህነት (0–255)
uint8_t matrixBrightness = 40;

አስፈላጊ ከሆነ ይጨምሩ፣ ነገር ግን በቅርብ ሲመለከቱ ከፍተኛ ብሩህነትን ያስወግዱ።

የነጥብ ቀለም


// የነጥብ ቀለም (R, G, B)
uint8_t dotRed   = 0;
uint8_t dotGreen = 200;   // ቀላል አረንጓዴ (ነባሪ)
uint8_t dotBlue  = 0;

ማንኛውንም ቀለም ለመፍጠር እነዚህን እሴቶች ይቀይሩ። ምሳሌዎች፦

  • ቀይ፡ (255, 0, 0)
  • ቢጫ፡ (255, 255, 0)
  • ነጭ፡ (255, 255, 255)

የእንቅስቃሴ ስሜታዊነት

ከፍተኛ ዝላይዎችን ለመከላከል፣ የአክስሌሮሜትር እሴቶች ብዙውን ጊዜ ይገደባሉ ወይም ይስተካከላሉ። የተለመደ ቅንብር ይህን ይመስላል፦


// ማዘንበል በእንቅስቃሴ ላይ ያለው ተጽዕኖ ምን ያህል ኃይለኛ እንደሆነ
float sensitivity = 4.0f;   // ትልቅ = በማያ ገጽ ላይ ፈጣን እንቅስቃሴ

ነጥቡ በጣም በዝግታ ከተንቀሳቀሰ → እሴቱን ይጨምሩ። ነጥቡ በጣም በድንገት ከተንቀሳቀሰ → ይቀንሱት።

የማዘመን ፍጥነት (የማደስ መጠን)

በዝማኔዎች መካከል እንቅስቃሴን ለማለስለስ ትንሽ መዘግየት ማከል ይችላሉ፦


// በቦታ ዝማኔዎች መካከል መዘግየት (ሚሴኮንድ)
int refreshDelayMs = 20;   // ዝቅተኛ = ለስላሳ እና ፈጣን ምላሽ

ከ10–30 ሚሴኮንድ መካከል ያሉ እሴቶች በጣም ፈጣን ምላሽ ይሰጣሉ።

ማጠቃለያ

ፕሮጀክት 4 የESP32-S3 አብሮ የተሰራውን QMI8658C አክስለሮሜትር በአካላዊ እንቅስቃሴ የLED ማትሪክስ እንዲቆጣጠሩ በማድረግ ህያው ያደርገዋል። የቦርዱ ትንሽ ዘንበል ነጥቡን ወደ ተመሳሳይ አቅጣጫ ያንቀሳቅሰዋል፣ ይህም ፕሮጀክቱን ለበለጠ የላቁ የ“Arrow Up” እና የ“Target Game” ፕሮጀክቶች ፍጹም መሰላል ያደርገዋል።

ሙሉው የTilt Dot ስኬች ከዚህ ጽሑፍ በታች (በራስ-ሰር) ተጭኗል። ለተሻለ ግንዛቤ፣ ቦርዱ ሲሽከረከር ነጥቡ እንዴት በተለሰለሰ ሁኔታ እንደሚንቀሳቀስ በሚታይበት ቪዲዮ ውስጥ የማዘንበል ማሳያውን ይመልከቱ። የ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 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
ቋንቋ: 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);
}



እንደሚያስፈልግዎት ይችላል

ምንጮች እና ምንጮች

ፋይሎች📁

ፍሪትዚንግ ፋይል