Search Code

ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 5 - ቀስት ሁልጊዜ ወደ ላይ

ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 5 - ቀስት ሁልጊዜ ወደ ላይ

ፕሮጀክት 5 – ቀስት ሁልጊዜ ወደላይ (የአቅጣጫ አመልካች QMI8658C በመጠቀም)

ፕሮጀክት 5 የQMI8658C እንቅስቃሴ ዳሳሽ በመጠቀም የESP32-S3 RGB LED ማትሪክስ አቅጣጫን ይለያል እና ሁልጊዜ ከስበት ኃይል አንጻር ወደላይ የሚያመለክት ቀስት ያሳያል። ቦርዱን እንዴት ብታዞሩት—የUSB ጎን ወደላይ፣ የOUSB ጎን ወደላይ፣ ጎን “15”፣ ወይም ጎን “34”—ቀስቱ በራስ-ሰር ዞሮ ወደ አካላዊው ወደላይ አቅጣጫ ይጠቁማል።

ይህ በቦርዱ ላይ ያለውን አክስሌሮሜትር በመጠቀም የእውነተኛ-ጊዜ አቅጣጫ ዳሰስ ኃይለኛ ማሳያ ነው። ለዚህ ሞጁል ያሉት ስድስቱም ፕሮጀክቶች በአንድ YouTube ቪዲዮ ውስጥ ተብራርተዋል፣ ይህም በዚህ ገጽ ላይ ተካቷል። ለፕሮጀክት 5 የተሟላ ኮድ ከጽሑፉ በታች በራስ-ሰር ይጫናል፣ እና የአጋር አገናኞች ከኮድ ክፍሉ በታች ይታያሉ።

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

የESP32-S3 RGB LED ማትሪክስ ሞጁል ይህን ፕሮጀክት ሊያሳኩ የሚችሉ በርካታ ክፍሎችን ያካትታል፦

  • 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}

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

ከዚህ ቀደም ማንኛውንም ፕሮጀክት ካጠናቀቁ፣ የቦርድ ማዋቀሩ ቀድሞውኑ ተከናውኗል። አለበለዚያ፦

  1. File > Preferences → የESP32 ቦርድ URL ያክሉ
  2. Tools > Board > Boards Manager… → “ESP32” ይጫኑ
  3. Tools > Board ስር የESP32-S3 ቦርዱን ይምረጡ
  4. Tools > Port ስር ትክክለኛውን የUSB COM ወደብ ይምረጡ

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

ፕሮጀክት 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);
}

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

ምንጮች እና ምንጮች

ፋይሎች📁

ፍሪትዚንግ ፋይል