اصنع عيون روبوت متحركة باستخدام ESP32 وشاشة OLED

في الحلقة الحادية عشرة من سلسلة ESP32 من الصفر سنتعرف على شاشة OLED وطريقة توصيلها بلوحة ESP32 باستخدام بروتوكول I2C. سنبدأ بعرض نص بسيط، ثم نستخدم نفس الدائرة لإنشاء عينين متحركتين لروبوت تستطيعان الرمش والنظر إلى اليمين واليسار.

فيديو المشروع

يمكنكم مشاهدة الشرح والتجربة العملية كاملة في الفيديو رقم 11 من سلسلة ESP32 من الصفر على قناة Naadi Tech – نادي الابتكار.

فكرة المشروع

سنستخدم شاشة OLED بدقة 128×64 بكسل مع ESP32. في التجربة الأولى سنتعلم أساسيات التحكم في الشاشة وعرض النصوص، ثم سنرسم عينين لروبوت ونحركهما برمجيًا باستخدام نفس التوصيلات.

التعرف على شاشة OLED

تتميز شاشة OLED بأن كل بكسل يصدر الضوء بنفسه، ولذلك لا تحتاج إلى إضاءة خلفية تقليدية وتوفر تباينًا جيدًا. تستخدم الوحدة في المشروع متحكم العرض SSD1306 وتتواصل مع ESP32 بواسطة واجهة I2C.

ملاحظة: ورد في الشرح الصوتي تعبير قريب من “I2C 1306”، والمقصود هو متحكم الشاشة SSD1306 مع بروتوكول الاتصال I2C.

ما هو بروتوكول I2C؟

يسمح I2C بتبادل البيانات بين المتحكم والمكونات الإلكترونية باستخدام خطين رئيسيين للاتصال، بالإضافة إلى التغذية والأرضي.

المنفذالوظيفة
SDAنقل البيانات
SCLإشارة التوقيت
VCCالتغذية
GNDالأرضي

المكونات المطلوبة

  • لوحة ESP32.
  • شاشة OLED بدقة 128×64 تعتمد على SSD1306 وI2C.
  • لوحة تجارب عند الحاجة.
  • أسلاك توصيل.
  • كابل USB.
  • Arduino IDE.

مخطط توصيل OLED مع ESP32

نغذي الشاشة من خرج 3.3V للوحة ESP32، ثم نوصل خطي I2C إلى GPIO21 وGPIO22.

OLEDESP32الوظيفة
VCC3.3Vالتغذية
GNDGNDالأرضي
SDAGPIO21البيانات
SCLGPIO22التوقيت

مهم: اتبع جهد التشغيل المدعوم من وحدة OLED التي لديك. في هذا المشروع تم توصيل VCC مع 3.3V للـ ESP32.

تثبيت مكتبات شاشة OLED

من مدير المكتبات في Arduino IDE ابحث عن Adafruit SSD1306 وثبت مكتبة Adafruit. نحتاج أيضًا إلى Adafruit GFX Library التي توفر دوال رسم النصوص والخطوط والأشكال الهندسية. وافق على تثبيت التبعيات إذا طلب Arduino IDE ذلك.

التجربة الأولى: عرض نص على شاشة OLED

نبدأ باستدعاء Wire وAdafruit_GFX وAdafruit_SSD1306، ثم نحدد أبعاد الشاشة 128×64 وننشئ عنصر التحكم في الشاشة.

تهيئة I2C والشاشة

داخل setup() نستخدم Wire.begin() مع GPIO21 للبيانات وGPIO22 للتوقيت، ثم display.begin() لتهيئة الشاشة. يستخدم المشروع عنوان I2C بقيمة 0x3C، وهو عنوان شائع في وحدات SSD1306.

كتابة النص وإظهاره

نمسح الذاكرة الرسومية باستخدام clearDisplay()، ثم نحدد لون النص وحجمه وموضعه. بعد كتابة النص نستدعي display.display() لإرسال محتوى الذاكرة إلى الشاشة.

كود التجربة الأولى: عرض النص


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(
  SCREEN_WIDTH,
  SCREEN_HEIGHT,
  &Wire,
  OLED_RESET
);

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

  // I2C pins: SDA = 21, SCL = 22
  Wire.begin(21, 22);

  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED not found");
    while (true);
  }

  // Clear the screen
  display.clearDisplay();

  // Text color and size
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);

  // Text position
  display.setCursor(0, 10);
  display.println("Naadi");

  display.setCursor(0, 35);
  display.println("Tech");

  // Show on OLED
  display.display();
}

void loop() {
}

بعد رفع البرنامج ظهر اسم نادي تك على شاشة OLED، وبذلك نتأكد من نجاح التوصيل والاتصال.

التجربة الثانية: عيون روبوت متحركة

نستخدم نفس المكتبات ونفس الدائرة، لكن بدل عرض الحروف سنستخدم الدوال الرسومية لإنشاء عينين وتحريكهما.

رسم العينين

نحدد عرض العين وارتفاعها والمسافة بين العينين، ثم ننشئ دالة drawEyes(). يتم رسم كل عين باستخدام fillRoundRect() لرسم مستطيل ممتلئ بحواف دائرية.

تحريك العينين يمينًا ويسارًا

تقوم دالة lookAround() بتغيير إحداثيات العينين تدريجيًا لتحريكهما إلى اليسار ثم اليمين وإعادتهما إلى الوسط.

إنشاء حركة الرمش

تقوم دالة blinkEyes() بتقليل ارتفاع العينين تدريجيًا حتى تبدوا شبه مغلقتين، ثم تعيد فتحهما للحصول على تأثير الرمش.

تشغيل الحركات

داخل setup() تتم تهيئة الشاشة ورسم العينين لأول مرة. أما داخل loop() فتتكرر حركات الرمش والنظر إلى اليسار واليمين ثم العودة إلى الوسط.

كود التجربة الثانية: عيون الروبوت المتحركة


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SSD1306 display(
  SCREEN_WIDTH,
  SCREEN_HEIGHT,
  &Wire,
  OLED_RESET
);

// Eye dimensions
const int eyeWidth = 34;
const int eyeHeight = 44;
const int eyeSpacing = 12;

// Draw both eyes
void drawEyes(int offsetX, int height) {
  display.clearDisplay();

  int totalWidth = 2 * eyeWidth + eyeSpacing;
  int startX = (SCREEN_WIDTH - totalWidth) / 2;

  int y = (SCREEN_HEIGHT - height) / 2;
  int radius = min(10, height / 2);

  display.fillRoundRect(
    startX + offsetX,
    y,
    eyeWidth,
    height,
    radius,
    SSD1306_WHITE
  );

  display.fillRoundRect(
    startX + eyeWidth + eyeSpacing + offsetX,
    y,
    eyeWidth,
    height,
    radius,
    SSD1306_WHITE
  );

  display.display();
}

// Blink animation
void blinkEyes() {
  for (int h = eyeHeight; h >= 4; h -= 4) {
    drawEyes(0, h);
    delay(20);
  }

  delay(100);

  for (int h = 4; h <= eyeHeight; h += 4) {
    drawEyes(0, h);
    delay(20);
  }
}

// Move eyes horizontally
void lookAround() {
  // Look left
  for (int x = 0; x >= -12; x -= 2) {
    drawEyes(x, eyeHeight);
    delay(40);
  }

  delay(500);

  // Look right
  for (int x = -12; x <= 12; x += 2) {
    drawEyes(x, eyeHeight);
    delay(40);
  }

  delay(500);

  // Return to center
  for (int x = 12; x >= 0; x -= 2) {
    drawEyes(x, eyeHeight);
    delay(40);
  }
}

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

  Wire.begin(21, 22);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("OLED not found");
    while (true);
  }

  display.clearDisplay();
  drawEyes(0, eyeHeight);
}

void loop() {
  // Eyes open
  drawEyes(0, eyeHeight);
  delay(1000);

  // Blink
  blinkEyes();
  delay(400);

  // Look left and right
  lookAround();
  delay(700);

  // Blink again
  blinkEyes();
  delay(1500);
}

كيف تعمل الحركة على شاشة OLED؟

الشاشة لا تحرك الأشكال فعليًا. يرسم البرنامج الشكل في موضع، ثم يعيد رسمه في موضع مختلف. عند تكرار العملية بسرعة مناسبة نرى سلسلة الرسومات كأنها حركة مستمرة.

مشاكل شائعة وحلولها

المشكلةالحل
الشاشة لا تعرض شيئًاتحقق من VCC وGND وSDA وSCL.
البرنامج لا يجد الشاشةتحقق من عنوان I2C؛ يستخدم المشروع 0x3C وقد تختلف بعض الوحدات.
خطأ أثناء Compilationتأكد من تثبيت Adafruit SSD1306 وAdafruit GFX والتبعيات.
الرسم لا يظهرتأكد من استدعاء display.display() بعد أوامر الرسم.
الحركة سريعة أو بطيئةعدّل التأخير ومقدار تغير الإحداثيات بين الإطارات.

ماذا تعلمنا؟

  • توصيل OLED مع ESP32.
  • فهم SDA وSCL في I2C.
  • استخدام Adafruit SSD1306 وAdafruit GFX.
  • عرض النصوص.
  • رسم الأشكال الهندسية.
  • إنشاء حركة بتغيير الإحداثيات.
  • محاكاة رمش وحركة عيني روبوت.

أفكار لتطوير المشروع

يمكن إضافة تعابير مثل الدهشة والغضب والنعاس والسعادة، أو ربط الحركات بحساسات وأزرار لتتغير تعابير الروبوت حسب ما يحدث حوله. ويمكن استخدام OLED أيضًا لعرض درجات الحرارة وحالة الحساسات والرسائل والقوائم.

الخلاصة

تعلمنا تشغيل شاشة OLED باستخدام ESP32 وI2C، ثم انتقلنا من عرض نص بسيط إلى إنشاء رسوم متحركة لعيني روبوت. يوضح المشروع كيف يمكن لشاشة صغيرة وأشكال هندسية بسيطة إضافة شخصية وتفاعل بصري إلى مشاريع الروبوتات.

تابعوا باقي حلقات سلسلة ESP32 من الصفر على Naadi Tech – نادي الابتكار للمزيد من المشاريع والتجارب العملية.

موضوعات ذات صلة