التحكم بالسيرفو بعصا التحكم (Joystick) مع Arduino وشاشة OLED (شرح)

يحتوي هذا المقال على روابط تسويق بالعمولة مُعلَّمة بعلامة *. بصفتي شريكًا في برنامج Amazon Associates، أربح من عمليات الشراء المؤهلة، دون أي تكلفة إضافية عليك. يساعد ذلك على إبقاء الشروحات مجانية.

في الفيديو أدناه، أبني الدائرة على مرحلتين: في البداية تحرّك عصا التحكم (Joystick) محركَي السيرفو دون شاشة، ثم أضيف شاشة OLED. أما الخطوات المكتوبة فتتناول النسخة النهائية مع الشاشة.

يُحمَّل الفيديو من YouTube (Google)، وقد يضع ملفات تعريف الارتباط (Cookies). سياسة الخصوصية

ملخص سريع

ستبني وحدة تحكم بمحركات السيرفو على محورين باستخدام Arduino Uno: تحرّك عصا التحكم محركَي سيرفو SG90، وتعرض شاشة SSD1306 OLED الزاوية المرسلة إلى كل محرك. يغطي المشروع الإدخال التناظري، والتحكم بمحركات السيرفو، وشاشة OLED على ناقل I2C الذي لا يحتاج إلا إلى سلكين للإشارة. والدائرة نفسها هي الأساس لحامل كاميرا بمحوري دوران أفقي وعمودي (Pan-Tilt) أو لنموذج صغير من الذراع الروبوتية.

ما الذي ستتعلمه

  • كيف توفّر وحدة عصا التحكم محورين تناظريين (X وY).
  • كيف يقرأ Arduino قيم عصا التحكم ويحوّلها إلى زوايا سيرفو باستخدام الدالة map() .
  • كيف توصّل محركَي سيرفو SG90 وشاشة SSD1306 OLED بلوحة Arduino Uno.
  • كيف تعرض شاشة OLED الزاوية المرسلة إلى كل سيرفو أثناء تحريكك لعصا التحكم.
  • كيف تغذّي محركات السيرفو من مزود طاقة خارجي بجهد 5 V مع أرضي (GND) مشترك.
  • كيف توقف اهتزاز السيرفو (حركاته الصغيرة غير المرغوب فيها) عند المنتصف باستخدام منطقة ميتة (Dead Zone): وهي نطاق حول القيمة المركزية يتجاهل فيه الكود التغيرات الصغيرة في عصا التحكم.
  • كيف تعكس اتجاه محور أو تحدّ من نطاق حركة السيرفو.

كيف تعمل الدائرة

تتكون حلقة التحكم من أربعة أجزاء:

  • وحدة عصا التحكم: تحتوي على مقاومتين متغيرتين (Potentiometers)، هما VRx للمحور X وVRy للمحور Y. تُخرج كل منهما جهدًا بين 0 و5 V، يقرؤه Arduino كقيمة من 0 إلى 1023.
  • Arduino Uno: يشغّل برنامج Arduino (Sketch). يقرأ البرنامج القيمتين، ويحوّلهما إلى زوايا من 0 إلى 180 درجة باستخدام map()، ويرسل الزوايا إلى محركات السيرفو، ويحدّث شاشة OLED.
  • محركا سيرفو: يستقبل كل سيرفو إشارة PWM (تعديل عرض النبضة) من طرف خاص به في Arduino. الإشارة نبضة تتكرر كل 20 ms، وعرضها هو الذي يحدد الزاوية، ويتراوح بين 0.5 و2.4 ms تقريبًا في مكتبة Servo الخاصة بـ Arduino. يتحكم المحور X بالسيرفو الموصول بالطرف D9، والمحور Y بالسيرفو الموصول بالطرف D10.
  • شاشة SSD1306 OLED: شاشة OLED هذه بدقة 128×64 بكسل. تتواصل مع Arduino عبر I2C: ينقل الخط SDA البيانات، وينقل الخط SCL إشارة الساعة.

تستغرق الدورة الواحدة للحلقة 50 ms إضافة إلى زمن تحديث شاشة OLED، لذا تتبع محركات السيرفو عصا التحكم دون تأخير ملحوظ. هل أنت جديد على محركات السيرفو؟ يشرح دليل التحكم بالسيرفو مع Arduino الأساسيات.

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

المكوّنالكميةالغرضملاحظات
Arduino Uno (أو Nano)1لوحة المتحكم الدقيق الرئيسيةتعمل أي لوحة Arduino مزودة بشريحة المتحكم الدقيق ATmega328P
وحدة عصا التحكم (XY + SW)1إدخال تناظري بمحورينتوفّر VRx وVRy وزر ضغط اختياريًا (SW)
محرك سيرفو (SG90 أو MG90S)2مشغّلات للمحورين X وYمحركات سيرفو صغيرة للهواة مصممة لجهد من 4.8 إلى 6 V
شاشة OLED (SSD1306، I2C)1تعرض الزاوية المرسلة إلى كل سيرفو128×64 بكسل، من 3.3 إلى 5 V
لوحة التجارب (Breadboard) + أسلاك التوصيل (Jumper)حسب الحاجةالتوصيلاتأسلاك توصيل ذكر-ذكر وذكر-أنثى
مزود طاقة خارجي 5 V1تغذية السيرفو2 A على الأقل لمحركَي سيرفو

مخطط التوصيل

وصّل المكونات كما هو موضح في الجدول. إذا كنت جديدًا على توصيلات Arduino، فاقرأ أساسيات برمجة Arduino أولًا.

طرف المكوّنطرف Arduinoملاحظات
عصا التحكم VRxA0الخرج التناظري للمحور X
عصا التحكم VRyA1الخرج التناظري للمحور Y
عصا التحكم SWD2 (اختياري)زر ضغط، غير مستخدم في هذا البرنامج
إشارة السيرفو 1D9خرج PWM لسيرفو المحور X
إشارة السيرفو 2D10خرج PWM لسيرفو المحور Y
OLED SDAA4خط بيانات I2C
OLED SCLA5خط ساعة I2C
السيرفو +V (كلاهما)مصدر خارجي 5 Vلا تغذِّ محركات السيرفو من الطرف 5 V في Arduino
السيرفو GND (كلاهما)GND مشتركوصّل GND لمزود الطاقة الخارجي بـ GND في Arduino

ملاحظات مهمة حول التوصيلات:

  • مزود طاقة خارجي 5 V لمحركات السيرفو: يسحب محرك SG90 نحو 100 mA عندما يتحرك بحرية، وما يصل إلى نحو 650 mA عند التوقف (Stall). والسيرفو المتوقف هو سيرفو محجوز الحركة لا يستطيع بلوغ موضعه المستهدف. يسحب محركان متوقفان ما يصل إلى 1.3 A، بينما يوفّر منفذ USB تيارًا قدره 500 mA. والنتيجة انخفاضات في الجهد، أو اهتزاز السيرفو، أو إعادة تشغيل اللوحة. استخدم مزود طاقة خارجيًا بجهد 5 V وتيار 2 A على الأقل.
  • أرضي مشترك: يجب توصيل GND لمزود الطاقة الخارجي، وGND في Arduino، وجميع أطراف GND للمكونات معًا. فمن دون أرضي مشترك، لا يكون لدى محركات السيرفو مرجع لجهد الإشارة، فتستجيب بشكل عشوائي أو لا تستجيب إطلاقًا.
  • مقاومات الرفع (Pull-up) لناقل I2C: تحتوي معظم وحدات SSD1306 على مقاومات رفع (Pull-up) على خطي SDA وSCL. مقاومة الرفع تُبقي الخط عند جهد محدد عندما لا يسحبه أي جهاز إلى المستوى المنخفض. إذا لم تكن على شاشتك مقاومات رفع، فأضف مقاومات رفع بقيمة 4.7 kΩ إلى 3.3 V أو 5 V.
Wiring diagram: Arduino Uno, joystick on A0 and A1, two SG90 servos on D9 and D10, SSD1306 OLED on A4 and A5, external 5 V supply with common ground

برمجة Arduino

قبل الرفع، ثبّت هذه المكتبات في Arduino IDE (البرنامج الذي تستخدمه لكتابة البرامج ورفعها إلى اللوحة): Servo (مدمجة)، وAdafruit GFX، وAdafruit SSD1306. افتح Sketch > Include Library > Manage Libraries، وابحث عن Adafruit SSD1306، ثم انقر Install. ووافق على الرسالة التي تطلب تثبيت Adafruit GFX أيضًا.

الكود الكامل

الصق الكود في برنامج جديد (Sketch) في Arduino IDE وارفعه إلى لوحة Uno.

#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Servo setup
Servo servoX;
Servo servoY;
int joyX = A0;
int joyY = A1;
int servoXPin = 9;
int servoYPin = 10;
void setup() {
  servoX.attach(servoXPin);
  servoY.attach(servoYPin);
  // OLED init
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    for(;;); // Halt if the display buffer cannot be allocated
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
}
void loop() {
  int xVal = analogRead(joyX);
  int yVal = analogRead(joyY);
  int angleX = map(xVal, 0, 1023, 0, 180);
  int angleY = map(yVal, 0, 1023, 0, 180);
  servoX.write(angleX);
  servoY.write(angleY);
  // OLED output
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("Servo X: "); display.println(angleX);
  display.print("Servo Y: "); display.println(angleY);
  display.display();
  delay(50); // at most 20 updates per second
}

شرح الكود

المكتبات والإعداد

يستخدم البرنامج ثلاث مكتبات. Servo.h يوفر Servo ، وهو الصنف (Class) الذي يولّد إشارة التحكم لمحركات السيرفو الصغيرة. Adafruit_GFX.h هي مكتبة الرسوميات الخاصة بالنصوص والأشكال والبكسلات. Adafruit_SSD1306.h هي برنامج التشغيل (Driver) لشاشات SSD1306 OLED عبر I2C.

السطر Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1) ينشئ كائن الشاشة لشاشة 128×64. الوسيط &Wire يختار ناقل I2C في لوحة Uno، بينما -1 يعني أنه لا يوجد طرف إعادة ضبط (Reset) موصول. في setup(), attach() يربط كل كائن من نوع Servo بالطرف الخاص به. الاستدعاء display.begin(SSD1306_SWITCHCAPVCC, 0x3C) يشغّل الشاشة على عنوان I2C 0x3C، وهو العنوان الافتراضي لمعظم وحدات SSD1306 بدقة 128×64. الخيار (Flag) SSD1306_SWITCHCAPVCC يجعل الشاشة تولّد داخليًا الجهد العالي اللازم للوحة العرض، فلا تحتاج إلى مصدر تغذية إضافي. الاستدعاء display.begin() يحجز أيضًا 1 KB من ذاكرة RAM البالغة 2 KB في لوحة Uno لمخزن الصورة المؤقت (Image Buffer)، وهو نسخة من محتوى الشاشة محفوظة في ذاكرة Arduino. إذا لم تكن هذه الذاكرة متاحة، begin() يُعيد القيمة false، والسطر for(;;); يوقف البرنامج في حلقة لا نهائية. ولا يتحقق هذا الاستدعاء مما إذا كانت هناك شاشة تستجيب على ناقل I2C.

القراءة التناظرية لعصا التحكم

الاستدعاءان analogRead(joyX) و analogRead(joyY) يقرآن الجهد على A0 وA1. تُخرج كل مقاومة متغيرة في عصا التحكم 0 V عند أحد طرفي مسارها و5 V عند الطرف الآخر. يحوّل محوّل ADC (المحوّل التناظري الرقمي) في Arduino هذا الجهد إلى رقم من 0 إلى 1023. في وضع المنتصف، ستقرأ عادةً قيمًا بين 500 و520 تقريبًا. عندما كانت عصا التحكم لديّ في وضع السكون، عرضت شاشة OLED الزاوية 88 درجة على X و91 على Y، وهو ما يقابل قيمًا خامًا تبلغ نحو 503 و520.

تحويل القيم إلى زوايا باستخدام map()

الاستدعاء map(xVal, 0, 1023, 0, 180) يحوّل قيمة عصا التحكم الخام (من 0 إلى 1023) خطيًا إلى زاوية سيرفو (من 0 إلى 180 درجة). القيمة الخام 0 تعطي 0 درجة، و1023 تعطي 180 درجة، والقيمة المركزية التي تبلغ نحو 510 تعطي نحو 90 درجة. يعتمد اتجاه عصا التحكم الذي يعطي 0 على طريقة تركيب الوحدة؛ وتوضح الخطوة 4 كيفية عكسه. ويستخدم المحور Y التحويل نفسه.

خرج السيرفو

الاستدعاءان servoX.write(angleX) و servoY.write(angleY) يرسلان الزاوية المحسوبة إلى كل سيرفو. وتولّد مكتبة Servo إشارة PWM.

تحديث شاشة OLED

في كل دورة من loop(), display.clearDisplay() يمسح المحتوى السابق، display.setCursor(0,0) ينقل مؤشر النص إلى الزاوية العلوية اليسرى، ثم print() يكتب الزاويتين. الاستدعاء display.display() يرسل مخزن الصورة المؤقت إلى شاشة OLED؛ print() يغيّر هذا المخزن فقط. تعرض الشاشة الزاوية المرسلة إلى كل سيرفو، وهذا يساعد أثناء المعايرة.

لماذا نستخدم delay(50) في الكود

يحدّ التأخير البالغ 50 ms من سرعة الحلقة، فلا تتجاوز 20 تحديثًا في الثانية. ترسل مكتبة Servo نبضتها كل 20 ms بغض النظر عن التأخير، لذا لا يغيّر التأخير إشارة PWM، لكنه يقلّل عدد المرات التي يصل فيها التشويش الصغير من عصا التحكم إلى محركات السيرفو. إذا استمر اهتزاز محركات السيرفو في وضع السكون، فأضف المنطقة الميتة من الخطوة 3.

كيفية اختبار النظام ومعايرته

الخطوة 1: اختبر المحورين

حرّك عصا التحكم يسارًا ويمينًا: يدور السيرفو الموصول بالطرف D9 من 0 إلى 180 درجة وتتغير قيمة Servo X على شاشة OLED. حرّكها للأعلى وللأسفل: يدور السيرفو الموصول بالطرف D10 وتتغير قيمة Servo Y.

الخطوة 2: تحقّق من وضع المنتصف

عندما تكون عصا التحكم في المنتصف، تُظهر القيمتان على شاشة OLED نحو 90 درجة. إذا بقيت الشاشة فارغة، فراجع قسم استكشاف الأخطاء وإصلاحها.

الخطوة 3: أضف منطقة ميتة لتثبيت وضع المنتصف

إذا اهتزت محركات السيرفو بينما تستقر عصا التحكم في المنتصف، فأضف منطقة ميتة. بعد سطرَي map() ، أضف سطرًا واحدًا لكل محور:

if (xVal > 480 && xVal < 540) angleX = 90;
if (yVal > 480 && yVal < 540) angleY = 90;

ما دامت عصا التحكم مستقرة قرب المنتصف، يثبت محركا السيرفو عند 90 درجة ويتجاهلان التشويش التناظري الصغير. وقيم السكون في وحدتي، وهي نحو 503 و520، تقع كلتاهما داخل هذا النطاق.

الخطوة 4: اعكس اتجاه المحور عند الحاجة

إذا تحرك أحد محركات السيرفو عكس اتجاه عصا التحكم، فاعكس نطاق الخرج لهذا المحور: غيّر map(xVal, 0, 1023, 0, 180) إلى map(xVal, 0, 1023, 180, 0).

الخطوة 5: حدّد زوايا السيرفو بما يناسب الأجزاء الميكانيكية لديك

إذا لم تكن الأجزاء الميكانيكية لديك قادرة على استخدام النطاق الكامل من 0 إلى 180 درجة، فغيّر نطاق الخرج. فحامل Pan-Tilt يسمح بالحركة من 30 إلى 150 درجة، مثلًا، يحتاج إلى map(xVal, 0, 1023, 30, 150). عندها لا يضغط السيرفو على المصدّات الميكانيكية، وهو ما قد يتلف التروس مع مرور الوقت. في مشروعي، كان محركا السيرفو موضوعين على الطاولة دون تثبيت، ولم يُركَّب عليهما سوى ذراعَي السيرفو (Horn)، لذا تمكنت من استخدام النطاق الكامل.

استكشاف الأخطاء وإصلاحها

شاشة OLED تبقى فارغة

تحقّق من توصيل SDA بالطرف A4 وSCL بالطرف A5، ومن تثبيت مكتبتَي Adafruit SSD1306 وAdafruit GFX. ثم تحقّق من أن عنوان I2C في display.begin(SSD1306_SWITCHCAPVCC, 0x3C) يطابق شاشتك. تستخدم معظم الوحدات العنوان 0x3C، ومنها وحدة 0.96 بوصة في مشروعي. إذا لم تعمل الشاشة إطلاقًا من قبل، فغيّر العنوان في ذلك السطر إلى 0x3D أو شغّل برنامج فحص I2C، الذي يعرض عناوين جميع أجهزة I2C الموصولة. إذا كانت الشاشة تعمل من قبل ثم توقفت، فابحث عن سلك SDA أو SCL أو سلك تغذية مرتخٍ.

اهتزاز محركات السيرفو في وضع المنتصف

للاهتزاز في المنتصف سببان شائعان: ضعف التغذية (محركات السيرفو موصولة بالطرف 5 V في Arduino) أو التشويش التناظري من عصا التحكم. تحقّق من التغذية أولًا (راجع ملاحظات التوصيل)، ثم أضف المنطقة الميتة من الخطوة 3. يعمل مكثف كهروليتي بسعة 470 µF (بجهد مقنن 10 V أو أكثر) موصول بين خطَّي تغذية السيرفو، وبالقرب من المحركات، على تنعيم انخفاضات الجهد القصيرة. وصّل الطرف المميز بشريط السالب إلى GND.

محركات السيرفو تتحرك في الاتجاه الخاطئ

اعكس نطاق الخرج لهذا المحور، كما هو موضح في الخطوة 4.

أحد محركات السيرفو لا يستجيب

تحقّق من سلك الإشارة لذلك السيرفو ومن الطرف المحدد في الكود (D9 أو D10). اختبر السيرفو وحده باستخدام مثال Sweep (File > Examples > Servo > Sweep)، الذي يدير السيرفو الموصول بالطرف 9 ذهابًا وإيابًا، لتستبعد احتمال أن يكون السيرفو معطوبًا. وتحقّق من أن GND الخاص بالسيرفو موصول بالأرضي المشترك.

الشاشة تعرض بكسلات عشوائية أو نصًا مُزاحًا

تحقّق من شريحة التحكم ومقاس الوحدة لديك. كثير من وحدات 1.3 بوصة تستخدم الشريحة SH1106 التي تحتاج إلى مكتبة مختلفة، كما أن وحدة 128×32 تحتاج إلى SCREEN_HEIGHT 32. إذا عدّلت الكود، فتحقّق من أن display.display() ما زال يُستدعى بعد أوامر الطباعة.

إعادة تشغيل النظام عند تحرك محركَي السيرفو معًا

السبب المعتاد هو عدم كفاية التغذية: فمحركا سيرفو يبدآن الحركة أو يتوقفان (Stall) في الوقت نفسه يسحبان تيارًا أكبر مما يوفّره منفذ USB. غذِّ محركات السيرفو من مزود طاقة خارجي 5 V كما هو موضح في ملاحظات التوصيل، ولا توصّل منه إلى Arduino سوى الأرضي.

قيم عصا التحكم تبدو مشوشة

تعطي بعض وحدات عصا التحكم قراءات تناظرية مشوشة. لتنعيمها، اقرأ كل محور عدة مرات (أربع مرات مثلًا) واستخدم المتوسط، أو أضف المنطقة الميتة من الخطوة 3. واجعل أسلاك عصا التحكم قصيرة وبعيدة عن أسلاك السيرفو.

الأسئلة الشائعة

هل يمكنني استخدام لوحة Arduino أخرى؟

نعم. يعمل هذا المشروع مع أي لوحة Arduino تحتوي على مدخلين تناظريين وطرفين رقميين حرّين. تولّد مكتبة Servo إشارتها باستخدام مؤقّت (Timer) على أي طرف رقمي، لذا لا تحتاج إلى أطراف PWM العتادية المميزة بالرمز ~ على اللوحة. وتعمل أي لوحة Arduino بجهد 5 V لها الأطراف نفسها دون أي تعديل، مثل Nano. وتعمل لوحتا Mega وLeonardo أيضًا، لكن أطراف I2C فيهما ليست A4 وA5 (Mega: 20 و21، Leonardo: 2 و3)، لذا انقل سلكَي SDA وSCL وفقًا لذلك.

كم عدد محركات السيرفو التي يمكنني التحكم بها باستخدام عصا تحكم واحدة؟

لعصا التحكم الواحدة محوران، لذا فهي تتحكم بمحركَي سيرفو. تحتوي لوحة Uno على ستة مداخل تناظرية (من A0 إلى A5)، لكن A4 وA5 تحملان إشارات I2C لشاشة OLED، لذا يمكن استخدام عصوَي تحكم (أربعة محركات سيرفو) إلى جانب الشاشة. ولمزيد من محركات السيرفو، استخدم زر SW لتبديل عصا التحكم بين أزواج السيرفو، أو أضف لوحة قيادة السيرفو PCA9685، التي تتحكم بما يصل إلى 16 محرك سيرفو عبر I2C.

هل أحتاج إلى شاشة OLED لكي يعمل هذا المشروع؟

لا. تتبع محركات السيرفو عصا التحكم من دون الشاشة، لأن display.begin() لا يتحقق مما إذا كانت هناك شاشة موصولة. وتسهّل شاشة OLED الاختبار والمعايرة، لأنها تعرض الزاوية المرسلة إلى كل سيرفو.

هل يمكنني استخدام محركات سيرفو MG996R بدلًا من SG90؟

نعم، لكن محرك MG996R يسحب تيارًا أكبر بكثير: تذكر TowerPro أن تيار التوقف يبلغ 2.5 A عند 6 V. اختر مزود الطاقة الخارجي بحيث يكفي لتيار التوقف لكلا المحركين. يبقى الكود كما هو، لأن نوعَي السيرفو يستخدمان إشارة التحكم نفسها.

المصادر والخطوات التالية

شروحات OmArTronics ذات الصلة

التطويرات المقترحة التالية

  • استخدم الطرف SW في عصا التحكم لحفظ مواضع السيرفو أو للتبديل بين أوضاع التحكم.
  • استبدل عصا التحكم بتطبيق على الهاتف الذكي يتواصل مع Arduino عبر وحدة بلوتوث HC-05.
  • ابنِ حامل كاميرا بمحورين وتحكّم به باستخدام هذه الدائرة.
  • أضف المزيد من محركات السيرفو وعصي التحكم لبناء ذراع روبوتية بمفاصل أكثر.
  • خزّن مواضع السيرفو في EEPROM، وهي ذاكرة Arduino التي تحتفظ بالبيانات دون تغذية كهربائية، ثم أعد تنفيذها كتسلسل حركة.

أضف تعليق