Search Code

ESP32-S3 RGB LED ম্যাট্রিক্স প্রজেক্ট ৬ - সিবল গেম

ESP32-S3 RGB LED ম্যাট্রিক্স প্রজেক্ট ৬ - সিবল গেম

প্রজেক্ট ৬ – টার্গেট গেম (বোর্ড কাত করে সার্কেল আঘাত করুন)

প্রজেক্ট ৬ হলো এই ESP32-S3 RGB LED ম্যাট্রিক্স সিরিজের চূড়ান্ত এবং সবচেয়ে ইন্টারেক্টিভ প্রজেক্ট। অনবোর্ড QMI8658C মোশন সেন্সর ব্যবহার করে, আপনি বোর্ড কাত করে ৮×৮ ম্যাট্রিক্সে একটি বিন্দু ঘোরান। ডিসপ্লের মাঝখানে একটি বৃত্তাকার “টার্গেট জোন” থাকে। যখন আপনার বিন্দুটি বৃত্তটি স্পর্শ করে, তখন রঙ পরিবর্তিত হয় এবং (ঐচ্ছিকভাবে) একটি বুজার বীপ শব্দ করে। এটি একটি সহজ কিন্তু আশ্চর্যজনকভাবে মজাদার ভারসাম্য/সমন্বয় খেলা তৈরি করে।

সমস্ত ছয়টি প্রজেক্ট একটি একক YouTube ভিডিওতে প্রদর্শিত হয়েছে (এই পৃষ্ঠায় এমবেড করা)। সম্পূর্ণ গেম কোডটি এই নিবন্ধের নীচে স্বয়ংক্রিয়ভাবে লোড হয় এবং মডিউলটির জন্য অ্যাফিলিয়েট কেনার লিঙ্কগুলি কোড বিভাগের নীচে প্রদর্শিত হয়।

ESP32-S3 RGB LED ম্যাট্রিক্স মডিউল ওভারভিউ

এই মডিউলটিতে রয়েছে:

  • ESP32-S3 মাইক্রোকন্ট্রোলার (Wi-Fi + BLE)
  • ৮×৮ RGB LED ম্যাট্রিক্স (৬৪টি অ্যাড্রেসযোগ্য LED)
  • QMI8658C অ্যাক্সিলেরোমিটার কাত এবং অভিযোজন অনুধাবনের জন্য
  • USB-C পোর্ট পাওয়ার এবং প্রোগ্রামিংয়ের জন্য
  • Boot / Reset বোতাম
  • উপলব্ধ GPIO পিন বুজার বা সেন্সরের মতো অতিরিক্ত যন্ত্রাংশের জন্য

এই গেমের জন্য, অ্যাক্সিলেরোমিটার অপরিহার্য—এটি ক্রমাগত X/Y কাত রিপোর্ট করে, যা বোর্ডের কোণের উপর ভিত্তি করে বিন্দুটিকে মসৃণভাবে চলতে দেয়। এই প্রজেক্টের ভিডিও বিভাগটি স্পষ্টভাবে দেখায় যে আপনি মডিউলটি বাম/ডান/সামনে/পিছনে কাত করলে বিন্দুটি কীভাবে গ্লাইড করে এবং প্রতিক্রিয়া জানায়।

ভিডিওতে কভার করা প্রজেক্ট (টাইমস্ট্যাম্প)

  • 00:00 – ভূমিকা
  • 02:01 – ESP32 বোর্ড ইনস্টল করা
  • 03:32 – লাইব্রেরি ইনস্টল করা
  • 05:32 – প্রজেক্ট ১: মুভিং ডট
  • 11:11 – প্রজেক্ট ২: টেক্সট স্ক্রল
  • 12:59 – প্রজেক্ট ৩: HTTP টেক্সট
  • 16:41 – প্রজেক্ট ৪: টিল্ট ডট
  • 18:55 – প্রজেক্ট ৫: অ্যারো আপ
  • 20:02প্রজেক্ট ৬: টার্গেট গেম (এই প্রজেক্ট)

ভিডিওর এই অংশটি বিন্দুর গতিবিধি এবং বৃত্ত সনাক্তকরণ লজিক উভয়ই কর্মক্ষেত্রে দেখায়, যা স্থানাঙ্কগুলি কীভাবে আচরণ করে তা বোঝা সহজ করে তোলে।

Arduino IDE-তে ESP32 বোর্ড ইনস্টল করা

আপনি যদি আগের প্রজেক্টগুলি ইতিমধ্যে সম্পন্ন করে থাকেন, তবে বোর্ড ইনস্টলেশন সম্পন্ন। অন্যথায় অনুসরণ করুন:

  1. File > Preferences → ESP32 বোর্ড URL যোগ করুন।
  2. Tools > Board > Boards Manager… → “ESP32” ইনস্টল করুন।
  3. Tools > Board-এর অধীনে ESP32-S3 বোর্ড নির্বাচন করুন।
  4. Tools > Port-এর অধীনে সঠিক COM পোর্ট নির্বাচন করুন।

প্রয়োজনীয় লাইব্রেরি ইনস্টল করা

এই গেমটি ব্যবহার করে:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX
  • QMI8658 (মোশন সেন্সর)

এগুলি ইনস্টল করুন:

  1. Sketch > Include Library > Manage Libraries…
  2. অনুসন্ধান: NeoMatrix → ইনস্টল করুন
  3. নির্ভরতা ইনস্টল করুন (GFX + NeoPixel)
  4. QMI8658 অনুসন্ধান এবং ইনস্টল করুন

টার্গেট গেম কীভাবে কাজ করে

QMI8658C অ্যাক্সিলেরোমিটার X এবং Y কাত মান সরবরাহ করে। এগুলি LED স্থানাঙ্কে (উভয় দিকে ০–৭) ম্যাপ করা হয়। আপনার বিন্দুটি বোর্ডের কোণের উপর ভিত্তি করে ম্যাট্রিক্স জুড়ে চলে।

ডিসপ্লেতে “টার্গেট এলাকা” হিসাবে একটি বৃত্ত (বা রিং) আঁকা হয়। যখনই বিন্দুটি বৃত্তটিকে ওভারল্যাপ করে আপনি একটি “হিট” পান। সেই মুহূর্তে:

  • টার্গেটের রঙ পরিবর্তিত হয় (এলোমেলো বা পূর্বনির্ধারিত)
  • একটি ঐচ্ছিক বুজার বীপ শব্দ করে (যদি সংযুক্ত থাকে)

যেহেতু ম্যাট্রিক্সটি ছোট, বৃত্তটি একটি সাধারণ ব্যাসার্ধ পরীক্ষা ব্যবহার করে আঁকা হয়। গেমটি ক্রমাগত চলে, তাই আপনি বারবার বৃত্তটি আঘাত করতে সামনে-পিছনে কাত করতে পারেন।

প্রজেক্ট ৬ – কোড সেটিংস (টার্গেট গেম)

নীচে স্কেচের শীর্ষে অবস্থিত প্রধান ব্যবহারকারী-সামঞ্জস্যযোগ্য সেটিংস দেওয়া হল। সম্পূর্ণ কোডটি এই নিবন্ধের নীচে স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত।

ম্যাট্রিক্স কনফিগারেশন


// Matrix configuration
const int MATRIX_PIN    = 14;
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

RGB ম্যাট্রিক্সটি GPIO 14-তে হার্ড-ওয়্যার্ড—এটি পরিবর্তন করবেন না।

উজ্জ্বলতা


uint8_t matrixBrightness = 40;   // 0–255

অভ্যন্তরীণ ব্যবহারের জন্য, ৩০–৬০ আদর্শ।

ডটের রঙ


// Dot color (R, G, B)
uint8_t dotRed   = 255;
uint8_t dotGreen = 255;
uint8_t dotBlue  = 255;

এটি সেই বিন্দু যা আপনি বোর্ড কাত করে সরান।

বৃত্তের রঙ (এলোমেলো বা নির্দিষ্ট)


// Circle (target) color
uint8_t circleRed   = 0;
uint8_t circleGreen = 0;
uint8_t circleBlue  = 255;

// If true, choose a new random color each time the dot hits
bool randomCircleColor = true;

একটি নির্দিষ্ট রঙ চাইলে randomCircleColor = false; সেট করুন।

বৃত্তের ব্যাসার্ধ


// Target size (radius)
int targetRadius = 3;   // 3 fits well on 8×8 matrix

বড় ব্যাসার্ধ গেমটি সহজ করে; ছোট ব্যাসার্ধ এটিকে কঠিন করে।

কাত সংবেদনশীলতা


// Sensitivity of tilt mapping
float tiltScale = 4.0f;   // increase = faster movement across screen

যদি বিন্দুটি খুব দ্রুত চলে বা লাফ দেয়, এই সংখ্যাটি কমিয়ে দিন।

বুজার সেটিংস (ঐচ্ছিক)


// বাজারের পিন (ঐচ্ছিক)
int buzzerPin = 6;      // বাজার + পিন ৬-এ সংযোগ করুন, – GND-তে
bool useBuzzer = true;  // শব্দ নিষ্ক্রিয় করতে false সেট করুন

আপনি যদি বাজার সংযোগ না করেন, তবে সহজভাবে useBuzzer = false; সেট করুন

সারসংক্ষেপ

প্রজেক্ট ৬ আগের প্রজেক্টগুলো থেকে শেখা সবকিছু একত্রিত করে: ম্যাট্রিক্স অঙ্কন, অ্যাক্সিলেরোমিটার ইনপুট, রঙ নিয়ন্ত্রণ, চলাচলের মসৃণকরণ, এবং ঐচ্ছিক শব্দ। বোর্ড কাত করলে বিন্দুটি সরে যায়, এবং বৃত্তে আঘাত করলে এর রঙ পরিবর্তন হয় এবং (ঐচ্ছিকভাবে) একটি বিপ শব্দ হয়। এটি একটি কমপ্যাক্ট RGB ডিসপ্লেতে গতি-সংবেদনের একটি মজার প্রদর্শনী।

সম্পূর্ণ “টার্গেট গেম” কোডটি এই নিবন্ধের নিচে স্বয়ংক্রিয়ভাবে প্রদর্শিত হয়। আপনি ভিডিওর প্রজেক্ট ৬ অংশটিও দেখতে পারেন যাতে বিন্দুটি কীভাবে সরে এবং আঘাত কীভাবে শনাক্ত হয় তা দেখতে পারেন। আপনি যদি নিজের গেম তৈরি করতে চান, তাহলে 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 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
804-ESP32-S3 RGB LED Matrix Project 6 - Cible game
ভাষা: C++
/* 
  Project 6: Tilt Circle Game – 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

// Buzzer pin – change this to your actual buzzer GPIO.
const int BUZZER_PIN = 6;   // TODO: set to your buzzer pin

// Matrix brightness (0–255)
const uint8_t MATRIX_BRIGHTNESS = 10;

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
  MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
  NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
  NEO_GRB + NEO_KHZ800
);

// -------- IMU SETUP --------
QMI8658 imu;

// -------- GAME CONFIG --------

// How often the dot is allowed to move (ms).
// Bigger = slower movement.
const uint16_t MOVE_INTERVAL_MS = 150;   // try 120–250

// How much tilt (m/s^2) before the dot moves.
// Increase if it feels too sensitive.
const float ACC_TILT_THRESHOLD = 2.0f;   // about ~0.2 g

// Dot base color (RGB)
const uint8_t DOT_R = 255;
const uint8_t DOT_G = 255;
const uint8_t DOT_B = 255;


// Circle geometry (centered on 8x8)
const float CIRCLE_CENTER_X = (MATRIX_WIDTH - 1) / 2.0f;   // 3.5
const float CIRCLE_CENTER_Y = (MATRIX_HEIGHT - 1) / 2.0f;  // 3.5
const float CIRCLE_RADIUS   = 3.0f;
const float CIRCLE_THICKNESS = 0.8f; // +- thickness around radius

// -------- GAME STATE --------

// Dot position on the 8x8 grid (0..7)
int dotX = 3;
int dotY = 3;

// Colors (16-bit NeoMatrix colors)
uint16_t dotColor;
uint16_t circleColor;

// To detect “just touched circle” vs “still on circle”
bool wasOnCircle = false;

// Timer for rate-limiting movement
unsigned long lastMoveTime = 0;

// -------- HELPER FUNCTIONS --------

// Classic NeoPixel color wheel (0-255 -> rainbow)
uint16_t wheel(byte pos) {
  if (pos < 85) {
    return matrix.Color(pos * 3, 255 - pos * 3, 0);
  } else if (pos < 170) {
    pos -= 85;
    return matrix.Color(255 - pos * 3, 0, pos * 3);
  } else {
    pos -= 170;
    return matrix.Color(0, pos * 3, 255 - pos * 3);
  }
}

// Is a given pixel approximately on the circle?
bool isOnCircle(int x, int y) {
  float dx = x - CIRCLE_CENTER_X;
  float dy = y - CIRCLE_CENTER_Y;
  float d2 = dx * dx + dy * dy;

  float rMin = CIRCLE_RADIUS - CIRCLE_THICKNESS;
  float rMax = CIRCLE_RADIUS + CIRCLE_THICKNESS;

  return (d2 >= rMin * rMin) && (d2 <= rMax * rMax);
}

// Draw circle + dot
void drawScene() {
  matrix.fillScreen(0);

  // Draw circle
  for (int y = 0; y < MATRIX_HEIGHT; y++) {
    for (int x = 0; x < MATRIX_WIDTH; x++) {
      if (isOnCircle(x, y)) {
        matrix.drawPixel(x, y, circleColor);
      }
    }
  }

  // Draw dot (on top)
  matrix.drawPixel(dotX, dotY, dotColor);

  matrix.show();
}

// Simple blocking beep (short)
void buzzOnce() {
  digitalWrite(BUZZER_PIN, HIGH);
  delay(40);
  digitalWrite(BUZZER_PIN, LOW);
}

// Use accelerometer to decide dot movement
void updateDotFromTilt(float ax, float ay) {
  unsigned long now = millis();
  if (now - lastMoveTime < MOVE_INTERVAL_MS) {
    return; // too soon, wait
  }

  int dx = 0;
  int dy = 0;

  // On this board, Y tilt feels like "left/right" on the matrix,
  // and X tilt feels like "up/down" → so we swap.

  // --- Horizontal movement from AY (tilt left/right) ---
  if (ay > ACC_TILT_THRESHOLD) {
    dx = 1;   // tilt to the right → move dot to the right
  } else if (ay < -ACC_TILT_THRESHOLD) {
    dx = -1;  // tilt to the left → move dot to the left
  }

  // --- Vertical movement from AX (tilt forward/back) ---
  // This was inverted. We flip the signs:
  // ax >  threshold  = tilt "forward" (away)  → move dot UP  (dy = -1)
  // ax < -threshold  = tilt "back"    (toward)→ move dot DOWN(dy =  1)
  if (ax > ACC_TILT_THRESHOLD) {
    dy = -1;  // was +1 before
  } else if (ax < -ACC_TILT_THRESHOLD) {
    dy = 1;   // was -1 before
  }

  if (dx != 0 || dy != 0) {
    dotX = constrain(dotX + dx, 0, MATRIX_WIDTH  - 1);
    dotY = constrain(dotY + dy, 0, MATRIX_HEIGHT - 1);
    lastMoveTime = now;
  }
}


// -------- SETUP & LOOP --------

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

  // Matrix init
  matrix.begin();
  matrix.setBrightness(MATRIX_BRIGHTNESS);
  matrix.fillScreen(0);
  matrix.show();

  // Buzzer init
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);

  // IMU init
if (!imu.begin(11, 12)) {
    Serial.println("Failed to initialize QMI8658!");
    while (1) {
      delay(100);
    }
  }

  // Use m/s^2 and dps (optional, but nice)
  imu.setAccelUnit_mps2(true);
  imu.setGyroUnit_dps(true);
  imu.setDisplayPrecision(3);

  Serial.println("QMI8658 initialized.");

  // Game initial state
  randomSeed((uint32_t)micros());

  dotX = MATRIX_WIDTH  / 2;
  dotY = MATRIX_HEIGHT / 2;

  dotColor    = matrix.Color(DOT_R, DOT_G, DOT_B);
  circleColor = wheel(random(256));

  drawScene();
}

void loop() {
  // Read accelerometer
  float ax, ay, az;
  if (imu.readAccelMPS2(ax, ay, az)) {
    // Debug if needed:
    // Serial.print("AX: "); Serial.print(ax);
    // Serial.print("  AY: "); Serial.print(ay);
    // Serial.print("  AZ: "); Serial.println(az);

    updateDotFromTilt(ax, ay);
  }

  // Check collision with circle
  bool onCircle = isOnCircle(dotX, dotY);
  if (onCircle && !wasOnCircle) {
    // Just touched circle: change color + beep
    circleColor = wheel(random(256));
    buzzOnce();
  }
  wasOnCircle = onCircle;

  // Redraw
  drawScene();

  // Small delay so we don’t hammer I2C too hard
  delay(10);
}

আপনাকে যা প্রয়োজন হতে পারে

সম্পদ ও রেফারেন্সসমূহ

ফাইলসমূহ📁

ফ্রিটজিং ফাইল