كود البحث

مشروع مصفوفة LED RGB ESP32-S3 5 - السهم دائما لأعلى

مشروع مصفوفة LED RGB ESP32-S3 5 - السهم دائما لأعلى

المشروع 5 - السهم دائمًا لأعلى (مؤشر الاتجاه باستخدام QMI8658C)

يستخدم المشروع 5 مستشعر الحركة QMI8658C لاكتشاف اتجاه مصفوفة LED RGB ESP32-S3 ويعرض دائمًا سهمًا يشير إلى الأعلى بالنسبة للجاذبية. بغض النظر عن كيفية تدوير اللوحة - جانب USB إلى الأعلى، أو جانب OUSB إلى الأعلى، أو الجانب "15"، أو الجانب "34" - يدور السهم تلقائيًا ويشير نحو الاتجاه الأعلى الفعلي.

هذه عرض قوي لاستشعار الاتجاه في الوقت الحقيقي باستخدام مقياس التسارع المدمج. يتم عرض جميع المشاريع الستة لهذا الوحدة في فيديو واحد على يوتيوب، والذي تم تضمينه أيضًا في هذه الصفحة. يتم تحميل الكود الكامل لمشروع 5 تلقائيًا أسفل المقالة، وتظهر روابط الشركاء تحت قسم الكود.

نظرة عامة على وحدة مصفوفة LED RGB ESP32-S3

يتضمن وحدة مصفوفة LED RGB ESP32-S3 العديد من المكونات التي تجعل هذا المشروع ممكنًا:

  • ميكروكنترولر ESP32-S3يوفر Wi-Fi وBLE، ويشغّل منطق LED/IMU.
  • شبكة LED RGB بحجم 8×8يعرض السهم في أي من الاتجاهات الأربعة.
  • QMI8658C مقياس تسارع- يكتشف الميل والحركة والتوجه.:contentReference[oaicite:0]{index=0}
  • منفذ USB-Cللكهرباء والبرمجة في بيئة Arduino IDE.
  • أزرار إعادة التعيين والتمهيدلتحميل الرسومات.
  • أطراف GPIOمتاحة حول الطاولة لمشاريع إضافية.

يتم تحديد اتجاه السهم بالكامل بواسطة قراءات مقياس التسارع. عند تدوير اللوح، يقوم جهاز QMI8658C باستشعار القيم الجديدة لـ X/Y/Z، ويختار الرسم التخطيطي أي نمط سهم (↑، ↓، ←، →) يجب رسمه.

المشاريع المشمولة في الفيديو (الأوقات المحددة)

  • 00:00- المقدمة
  • 02:01- تثبيت لوحات ESP32
  • 03:32- تثبيت المكتبات
  • 05:32- المشروع 1: النقطة المتحركة
  • 11:11- المشروع 2: تمرير النص
  • ١٢:٥٩- المشروع 3: نص HTTP
  • 16:41- المشروع 4: نقطة الميل
  • ١٨:٥٥-المشروع 5: السهم دائماً لأعلى (هذا المشروع)
  • ٢٠:٠٢- المشروع 6: لعبة الهدف

يوضح الفيديو بوضوح كيف يتغير اتجاه السهم على الفور بناءً على كيفية دوران الوحدة. يُوصى بشدة بمشاهدة هذا المقطع.:contentReference[oaicite:1]{index=1}

تثبيت لوحات ESP32 في بيئة Arduino IDE

إذا كنت قد أنجزت أي مشروع سابق، فإن إعداد اللوحة قد تم بالفعل. خلاف ذلك:

  1. File > Preferences→ أضف عنوان URL للوحة ESP32
  2. Tools > Board > Boards Manager…→ تثبيت "ESP32"
  3. اختر لوح ESP32-S3 تحتTools > Board
  4. اختر منفذ USB COM الصحيح تحتTools > Port

تثبيت المكتبات المطلوبة

المشروع 5 يستخدم:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX
  • QMI8658حساس الحركة
  1. Sketch > Include Library > Manage Libraries…
  2. بحث:نيو ماتريكس→ تثبيت
  3. تثبيت التبعيات:نيوبكسل+جرافيكس
  4. بحث وتثبيتQMI8658بواسطة مؤلفه

كيفية عمل المشروع 5

يقيس جهاز QMI8658C الجاذبية على محاور X وY وZ. من خلال مقارنة هذه القيم، يحدد الرسم التخطيطي أي جانب مادي من اللوحة يواجه الأعلى:

  • أعلى جانب USB
  • جهة OUSB لأعلى(مقابل USB)
  • الجانب "15" لأعلى
  • الجانب "34" لأعلى

تتوافق كل توجيه مع نمط سهم مختلف على مصفوفة 8×8. تتبع الترجمة منطق التوجيه الذي أكّدته في جلسات التصحيح السابقة. يتم قراءة دوران اللوح بشكل مستمر، وتحدث تحديثات السهم بمجرد تغيير الجانب العلوي.

المشروع 5 - إعدادات الكود (السهم دائماً للأعلى)

فيما يلي القيم القابلة للتعديل من قبل المستخدم من منطقة التكوين. يظهر رمز المشروع الكامل تلقائيًا أدناه المقالة.

تكوين المصفوفة


// Matrix configuration
const int MATRIX_PIN    = 14;   // fixed for this module
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

// Recommended orientation: Top-Left origin, progressive mode
// (actual constructor is inside the code loaded below)

هذا المشروع يستخدمNEO_MATRIX_PROGRESSIVEتخطيط لضمان توجيه السهم بشكل صحيح بناءً على الحركة الفعلية.

سطوع


uint8_t matrixBrightness = 40;   // 0–255

يمكنك رفع هذه القيمة للبيئات الأكثر سطوعًا. للاستخدام الداخلي، فإن القيمة 30-60 مريحة.

لون السهم


// Arrow color
uint8_t arrowRed   = 255;
uint8_t arrowGreen = 0;
uint8_t arrowBlue  = 0;

غيّر هذه القيم لتعديل لون السهم. على سبيل المثال:

  • السهم الأخضر:(0, 255, 0)
  • سهم أزرق:(0, 0, 255)
  • سهم أبيض:(255, 255, 255)

الحساسية والتنعيم

لتجنب الاهتزاز، يتضمن الكود منطق التنعيم والعتبة. في الإعدادات، يمكنك أن تجد شيئًا مثل:


// Sensitivity / smoothing adjustment
float tiltThreshold = 0.30f;   // adjust if arrow changes too easily
  • إذا انقلب سهمك بسهولة كبيرة →زيادةعتبة.
  • إذا كان السهم بطيئًا جدًا للتغيير →تقليلعتبة.

أنماط الأسهم

تتضمن الرسمة أنماط صورة متجهة للأسهم لـ:

  • ↑ أعلى
  • ↓ أسفل
  • ← يسار
  • → يمين

لا تحتاج إلى تعديل هذه، ولكن يمكنك تغيير الأشكال داخل الكود إذا كنت ترغب في نمط مختلف.

ملخص

يستعرض المشروع 5 كيف يعمل مصفوفة LED RGB ESP32-S3 ومقياس التسارع QMI8658C معًا لاكتشاف الاتجاه وعرض سهم يشير دائمًا إلى الأعلى. يبني هذا المشروع على مشروع "Tilt Dot" (المشروع 4) ويجهزك للعبة التفاعلية النهائية في المشروع 6.

التخطيط الكامل "السهم دائمًا لأعلى" متاح أدناه هذا المقال (يتم تحميله تلقائيًا). يُوصى بشدة بمشاهدة الجزء المقابل من الفيديو لرؤية كيفية استجابة السهم على الفور لدوران اللوحة. إذا كنت ترغب في تنفيذ هذا المشروع في المنزل، فإن روابط الشركات التابعة لوحدة مصفوفة LED RGB ESP32-S3 تظهر تحت قسم الكود.

الصور

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++
/*
 * المشروع 5: السهم دائمًا لأعلى - مصفوفة LED RGB ESP32-S3 (Waveshare) 
 * هذه الشيفرة تقرأ الميل من جهاز الاستشعار IMU QMI8658C وتتحرك بسلاسة نقطة على مصفوفة LED RGB 8×8 بناءً على توجيه اللوحة.
 * 
 * ▶️ فيديو تعليمي: 
 * https://youtu.be/JKLuYrRcLMI
 * 
 * 📚⬇️ الموارد وصفحة الشيفرة: 
 * 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> // بواسطة لاهاف جلاهى

 // -------- إعداد مصفوفة LED --------
#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
);

 // -------- إعداد IMU QMI8658 --------
QMI8658 imu;
QMI8658_Data imuData;

 // -------- إعدادات المستخدم --------

 // السهم يشير إلى الجهة المعاكسة
 // USB↔OUSB، 34↔15
 // زائف -> السهم يشير إلى نفس الجانب الذي هو لأعلى
bool useOppositeMapping = false;

 // لون السهم (0-255 لكل واحد)
uint8_t dotRed   = 0;
uint8_t dotGreen = 150;
uint8_t dotBlue  = 0;

 // أطراف اللوحة
enum Side {
  SIDE_CENTER = 0,
  SIDE_USB,
  SIDE_OUSB,
  SIDE_15,
  SIDE_34
};

 // اتجاه رسم السهم
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 "?";
  }
}

 // -------- رسم السهم (شفرتك، دون تغيير) --------

 // ارسم سهمًا بسيطًا على مصفوفة 8x8 يشير في الاتجاه المعطى
void drawArrow(ArrowDir dir, uint16_t color) {
  matrix.fillScreen(0);

  switch (dir) {
    case ARROW_UP:
 // نصيحة
      matrix.drawPixel(3, 0, color);
      matrix.drawPixel(4, 0, color);
 // الصف الثاني
      matrix.drawPixel(2, 1, color);
      matrix.drawPixel(3, 1, color);
      matrix.drawPixel(4, 1, color);
      matrix.drawPixel(5, 1, color);
 // عمود
      matrix.drawLine(3, 2, 3, 6, color);
      matrix.drawLine(4, 2, 4, 6, color);
      break;

    case ARROW_DOWN:
 // نصيحة
      matrix.drawPixel(3, 7, color);
      matrix.drawPixel(4, 7, color);
 // الصف فوق القمة
      matrix.drawPixel(2, 6, color);
      matrix.drawPixel(3, 6, color);
      matrix.drawPixel(4, 6, color);
      matrix.drawPixel(5, 6, color);
 // عمود
      matrix.drawLine(3, 1, 3, 5, color);
      matrix.drawLine(4, 1, 4, 5, color);
      break;

    case ARROW_LEFT:
 // نصيحة
      matrix.drawPixel(0, 3, color);
      matrix.drawPixel(0, 4, color);
 // عمود بعد الإكرامية
      matrix.drawPixel(1, 2, color);
      matrix.drawPixel(1, 3, color);
      matrix.drawPixel(1, 4, color);
      matrix.drawPixel(1, 5, color);
 // عمود
      matrix.drawLine(2, 3, 6, 3, color);
      matrix.drawLine(2, 4, 6, 4, color);
      break;

    case ARROW_RIGHT:
 // نصيحة
      matrix.drawPixel(7, 3, color);
      matrix.drawPixel(7, 4, color);
 // عمود قبل الإكرامية
      matrix.drawPixel(6, 2, color);
      matrix.drawPixel(6, 3, color);
      matrix.drawPixel(6, 4, color);
      matrix.drawPixel(6, 5, color);
 // عمود
      matrix.drawLine(1, 3, 5, 3, color);
      matrix.drawLine(1, 4, 5, 4, color);
      break;

    case ARROW_CENTER:
    default:
 // بسيط زائد في المنتصف
      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 → كشف الجانب --------
 // قمنا بمعايرة في وقت سابق:
 // +X = USB، -X = OUSB
 // +ص = 15، -ص = 34 (بعد تصحيحك)

Side detectSideUp(float ax_g, float ay_g, float az_g) {
 // كشف الشقة
  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;

 // عتبات لتحديد "هذه المحور مائل حقًا"
  const float tiltThreshY = 0.5f;
  const float tiltThreshX = 0.5f;

 // يفضل المحور Y لـ 15 / 34
  if (fabs(ay_g) >= tiltThreshY) {
    if (ay_g > 0) {
      return SIDE_34; // +ص = ٣٤ إلى الأعلى
    } else {
      return SIDE_15; // -ص = 15 للأعلى
    }
  }

 // بخلاف ذلك، استخدم المحور X لـ USB / OUSB
  if (fabs(ax_g) >= tiltThreshX) {
    if (ax_g > 0) {
      return SIDE_USB; // +X = يو اس بي للأعلى
    } else {
      return SIDE_OUSB; // -X = OUSB لأعلى
    }
  }

 // ليس مائلًا بوضوح → يعتبر في المركز
  return SIDE_CENTER;
}

 // رسم خريطة من جانب UP إلى حيث ينبغي أن تشير السهم
Side arrowSideFromUpSide(Side upSide) {
  if (!useOppositeMapping) {
 // السهم يشير إلى الجانب الذي يتجه لأعلى
    return upSide;
  }

 // السهم يشير إلى الجانب المعاكس
  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;
  }
}

 // تحويل SIDE إلى 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;
  }
}

 // ---------------- الإعداد والتكرار ----------------

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

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

 // IMU: SDA=11, SCL=12 على 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);

 // تصحيح الأخطاء
  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);
}

الأشياء التي قد تحتاجها

الموارد والمراجع

ملفات📁

Fritzing File