يحتوي هذا المقال على روابط تسويق بالعمولة مُعلَّمة بعلامة *. بصفتي شريكًا في برنامج Amazon Associates، أربح من عمليات الشراء المؤهلة، دون أي تكلفة إضافية عليك. يساعد ذلك على إبقاء الشروحات مجانية.
📋 ملخص سريع
يطوّر هذا المشروع الذراع الروبوتية المطبوعة بالطباعة ثلاثية الأبعاد (3D) التي يُتحكَّم بها بمقاومات متغيرة (Potentiometer) من درسي السابق لتصبح قابلة للتحكم عبر البلوتوث. تستقبل وحدة HC-05 الأوامر من تطبيق Android مصمَّم في MIT App Inventor، وتقود لوحة Arduino Uno محركات السيرفو الستة عبر لوحة قيادة السيرفو PCA9685. يمكن للذراع حفظ ما يصل إلى 10 وضعيات وإعادة تشغيلها مرة واحدة أو بشكل متكرر. برنامج Arduino والتطبيق متاحان على GitHub؛ أما ملفات STL (ملفات النماذج ثلاثية الأبعاد 3D المعدّة للطباعة) فتجدها في متجر OmArTronics.
ما الذراع الروبوتية بست درجات حرية (6-DOF)؟
DOF اختصار لـ Degrees of Freedom، أي درجات الحرية، وهي عدد المفاصل التي يستطيع الروبوت تحريكها بشكل مستقل. تمتلك هذه الذراع ستة مفاصل يحرّك كلًّا منها محرك سيرفو. خمسة منها محاور دوران تحدد وضعية الذراع (Pose، أي مجموعة زوايا جميع المفاصل في لحظة واحدة). أما السادس فيفتح القابض ويغلقه (القابض هو المستجيب الطرفي، أي الأداة الموجودة في طرف الذراع). المحاور الخمسة هي: دوران القاعدة، والكتف، والمرفق، وميل المعصم (Wrist Pitch: يميل المعصم لأعلى ولأسفل)، ودوران المعصم (Wrist Roll: يدور المعصم حول محوره). وبالمعنى الدقيق لا يُعَدّ القابض درجة حرية، لكن أذرع الهواة تحتسبه عادةً.
للتعرّف على طريقة عمل محركات السيرفو وكيفية التحكم بها باستخدام Arduino، راجع دليل التحكم بمحرك السيرفو.
نظرة عامة على المشروع وبنية النظام
في قلب النظام توجد لوحة Arduino Uno. تتواصل اللوحة مع لوحة قيادة السيرفو PCA9685 عبر I2C، وهو ناقل بسلكين (SDA ينقل البيانات وSCL ينقل إشارة الساعة) يستطيع فيه متحكم واحد مخاطبة عدة شرائح. تولّد PCA9685 ست إشارات PWM مستقلة (تعديل عرض النبضة: طول نبضة متكررة يخبر السيرفو بالزاوية التي يجب أن يثبت عندها). تصل أوامر الحركة من هاتفك إلى Arduino عبر وحدة HC-05.
بُني التطبيق باستخدام MIT App Inventor، وهي أداة مجانية من MIT تعمل في المتصفح وتُنشئ تطبيقات Android من كتل برمجية مرئية بدلًا من كتابة الكود. يرسل التطبيق أوامر نصية قصيرة عبر البلوتوث: قيم أشرطة التمرير (Slider) للتحكم المباشر في المفاصل، وأمرًا واحدًا لكلٍّ من حفظ الوضعيات وتشغيلها وإيقافها وإعادة ضبطها وتكرارها (راجع جدول الأوامر في قسم الكود). عندما يصل أمر ما، يحلّله Arduino ويختار قناة السيرفو المطابقة ثم يحرّك السيرفو إلى الموضع المطلوب خطوة بخطوة حتى لا تتحرك الذراع بحركات مفاجئة.
قائمة المواد
مقارنةً بالنسخة التي يُتحكَّم بها بالمقاومات المتغيرة، تضيف هذه النسخة وحدة HC-05 وتستغني عن المقاومات المتغيرة الست. وبدونها يصبح الطرفان A4 وA5 في لوحة Uno متاحين لخطَّي I2C، لذا تكفي لوحة Uno هنا؛ أما نسخة المقاومات المتغيرة فتحتاج إلى لوحة Mega.
| البند | الكمية | الجزء | الوصف |
|---|---|---|---|
| 1 | 1 | Base_1 | لوح القاعدة (ثابت) |
| 2 | 1 | base_link_upper1 | المنصة العلوية (دوّارة) |
| 3 | 1 | arm_link_1 | الوصلة الأولى في الذراع |
| 4 | 1 | arm_link_2 | الوصلة الثانية في الذراع |
| 5 | 1 | arm_link_3 | الوصلة الثالثة في الذراع |
| 6 | 1 | gripper_base | قاعدة القابض |
| 7 | 1 | Gripper_2 | إصبع القابض |
| 8 | 1 | Gear_right | ترس القابض (الأيمن) |
| 9 | 1 | Gear_left | ترس القابض (الأيسر) |
| 10 | 1 | القابض | تجميع القابض |
| 11 | 4 | الوصلة | أجزاء وصلات القابض |
| 12 | 2 | فاصل | فواصل مفصل القابض |
| 12a | 1 | محور المفصل | محور مفصل مطبوع (pin.stl) |
| 13 | 3 | محرك سيرفو MG996R | سيرفو عالي العزم، إصدار 180° (القاعدة، الكتف، المرفق) |
| 14 | 3 | محرك سيرفو مصغّر SG90 | سيرفو مصغّر (المعصم، القابض) |
| 15 | 16 | ANSI B18.6.4 No.2-32 3/8″ | برغي برأس مقبب عريض (Truss)، No.2-32 |
| 16 | 2 | ANSI B18.6.4 No.2-32 1/4″ | برغي برأس مقبب عريض (Truss)، No.2-32 |
| 17 | 3 | DIN 7985 M1.6×2-Z | برغي برأس صليبي M1.6×2 |
| 18 | 7 | ISO 4762 M3x16 (AS 1420) | برغي برأس سداسي التجويف (ألن) M3×16 |
| 19 | 12 | ISO 4032 M3 (AS 1112) | صامولة سداسية M3 |
| 20 | 2 | ANSI B18.6.4 No.2-32 1/2″ | برغي برأس مقبب عريض (Truss)، No.2-32 |
| 21 | 3 | ذراع سيرفو MG996R (Horn) | الذراع (Horn) المرفقة مع MG996R |
| 22 | 3 | DIN 7985 M3x6-Z | برغي برأس صليبي M3×6 |
| 23 | 3 | ذراع سيرفو SG90 (Horn) | ذراع (Horn) لسيرفو SG90 |
| 24 | 12 | ANSI B18.6.4 No.3-28 1/2″ | برغي برأس مقبب عريض (Truss)، No.3-28 |
| 25 | 1 | محمل كروي 6806ZZ (30x42x7) | محمل كروي ذو أخدود عميق (30×42×7 mm) |
| 26 | 1 | Arduino Uno أو Mega | وحدة التحكم الرئيسية |
| 27 | 1 | لوحة قيادة السيرفو PCA9685 | وحدة قيادة PWM بـ 16 قناة (I2C) |
| 28 | 1 | وحدة HC-05 | وحدة بلوتوث للتحكم اللاسلكي |
| 29 | 1 | لوحة التجارب (Breadboard) | قاعدة لتوصيل الأسلاك |
| 30 | 1 | مزود طاقة 5 V 10 A | مصدر تغذية محركات السيرفو |
| 31 | 1 | أسلاك توصيل Jumper (ذكر-أنثى) | من Arduino إلى PCA9685 |
| 32 | 1 | أسلاك توصيل Jumper (ذكر-ذكر) | من لوحة التجارب إلى Arduino |
| 33 | 1 | لوح خشبي | منصة تثبيت الذراع |
| 34 | 1 من كل نوع | مقاومتان 1 kΩ و2 kΩ | مقسم جهد للطرف RX في وحدة HC-05 |
التصميم الميكانيكي في Autodesk Inventor
صمّمت كل القطع في Autodesk Inventor، وهو برنامج CAD بارامتري. كل بُعد فيه قيمة مخزَّنة، لذا فإن تغيير رقم واحد، مثل عرض تجويف السيرفو، يحدّث القطعة بأكملها. إذا كنت جديدًا على Inventor أو على الطباعة ثلاثية الأبعاد (3D)، فابدأ بقراءة مقدمتي إلى الطباعة ثلاثية الأبعاد (3D) والتصميم ثلاثي الأبعاد (3D) باستخدام Inventor.
رُسم كل تجويف للسيرفو وكل موضع لتثبيت ذراع السيرفو (Horn) وكل مقعد للمحمل وفق الأبعاد الواردة في أوراق بيانات (Datasheet) MG996R وSG90. أضفت حافة أسطوانية إلى كل مفصل ليبقى دورانه متمركزًا. يوضح الرسم الفني أبعاد القطع والمقاطع العرضية وطريقة تركيب القطع معًا. استخدمه مرجعًا عند التحقق من دقة الطباعة.
عند الكتف، تحتوي المنصة العلوية الدوّارة والوصلة الأولى من الذراع على نقاط تثبيت لشريط مطاطي أو نابض شد. يحمل الشريط أو النابض جزءًا من وزن الذراع ويخفف الحمل عن سيرفو الكتف. أستخدم نابضًا من مصباح مكتب قديم، طوله نحو 2 cm في وضع الراحة وقطره 9 mm. النابض اختياري وغير مدرج في قائمة القطع.

الطباعة ثلاثية الأبعاد (3D) للمكونات
اطبع القطع من ملفات STL. خيط الطباعة PLA سهل الطباعة ويحافظ على دقة الأبعاد. للقطع الإنشائية مثل القاعدة ووصلات الذراع، استخدم ارتفاع طبقة (سُمك كل طبقة مطبوعة) قدره 0.2 mm. واجعل نسبة الملء (Infill، أي نسبة الجزء الداخلي المملوء بالمادة) فيها 40 بالمئة على الأقل. أما القطع الرقيقة مثل تروس القابض فتكفيها نسبة ملء 20 بالمئة، وهذا يوفّر المادة.
انتبه إلى تجاويف تثبيت السيرفو. يجب أن تكون دقيقة حتى يستقر كل سيرفو بتركيب بالضغط (Press Fit، أي يُثبَّت بإحكام بفعل الاحتكاك) دون أي تأرجح. بعد الطباعة، أزل الدعامات (هياكل مؤقتة تُطبع تحت الأجزاء البارزة)، وصنفر الأسطح المتلامسة بورق صنفرة بدرجة خشونة 220، وجرّب تركيب كل سيرفو قبل التجميع. إذا كان التجويف ضيقًا جدًا، فتمريرة بمشرط (Hobby Knife) أو بمبرد إبري أسرع من إعادة الطباعة. يحوّل Cura، وهو برنامج التقطيع (Slicer) الظاهر في لقطة الشاشة أدناه، ملفات STL إلى تعليمات للطابعة. لصفيحة الطباعة هذه (القاعدة العلوية ووصلتا الذراع) قدّر البرنامج استهلاك 280 g من PLA وزمن طباعة قدره 1 يوم و12 ساعة و43 دقيقة.


اختيار محرك السيرفو: SG90 أم MG996R
تحمل القاعدة والكتف والمرفق وزن كل ما فوقها، لذا تستخدم محركات سيرفو MG996R ذات تروس معدنية. تذكر ورقة البيانات عزم توقف (أقصى عزم دوران قبل أن يتوقف السيرفو) قدره 11 kg·cm عند 6 V ونحو 9.4 kg·cm عند 4.8 V؛ وأنا أشغّلها عند 6 V. يعني عزم دوران قدره 11 kg·cm أن السيرفو يستطيع حمل 11 kg على بعد 1 cm من عمود الإدارة، أو 1.1 kg على بعد 10 cm. أما ميل المعصم ودوران المعصم والقابض فتحمل حملًا قليلًا، لذا تكفيها محركات سيرفو صغيرة SG90 (1.8 kg·cm، 23 × 12 × 29 mm)، وهي تُبقي طرف الذراع خفيفًا.
يقبل كلا النوعين إشارة PWM القياسية بتردد 50 Hz (يضبط البرنامج التردد على 60 Hz، وهو ما تتحمله هذه المحركات)، لذا يُوصَلان بأطراف التوصيل في PCA9685 دون أي تعديل. الفرق المهم في التوصيلات هو التيار. يسحب MG996R نحو 0.5 إلى 0.9 A أثناء الحركة، وحتى نحو 2.5 A عندما يُعاق عن الحركة (تيار التوقف). ويسحب SG90 نحو 100 mA أثناء الدوران دون حمل، وحتى نحو 650 mA عند التوقف. إذا توقفت محركات السيرفو الستة كلها في الوقت نفسه، فإنها تسحب حتى 3 × 2.5 A + 3 × 0.65 A = 9.45 A. لهذا السبب تتضمن قائمة القطع مزود طاقة منفصلًا 5 V 10 A لمحركات السيرفو. لا تحاول تغذية ستة محركات سيرفو من الطرف 5 V في Arduino.
تجميع الذراع خطوة بخطوة
اعمل من القاعدة صعودًا، واختبر سلاسة دوران كل مفصل قبل الانتقال إلى التالي. لا تستعجل عند ربط البراغي، لأن الشد الزائد في البلاستيك المطبوع بالطباعة ثلاثية الأبعاد (3D) يُتلف أسنان اللولبة بسرعة.

الخطوة 1: تجميع القاعدة
ركّب أول سيرفو MG996R في حامل القاعدة باستخدام البراغي المرفقة. يمنح هذا السيرفو القاعدة مدى دوران قدره 180 درجة. اضغط المحمل الكروي ذا الأخدود العميق (6806ZZ، 30 × 42 × 7 mm) عموديًا إلى الأسفل في مقعده داخل المنصة العلوية الدوّارة. يقع المحمل بين هذه المنصة ولوح القاعدة الثابت، فيحافظ على تمركز المنصة ويسمح لها بالدوران بسلاسة دون ميلان. المحمل اختياري، لكنني أنصح به. ثبّت ذراع السيرفو (Horn) على المنصة العلوية الدوّارة ببراغي M2×12 ذاتية التسنين (براغي تشق لولبتها بنفسها في البلاستيك). ينقل ذراع السيرفو هذا دوران سيرفو القاعدة إلى بقية الذراع. اضغط المنصة عموديًا إلى الأسفل على عمود السيرفو وثبّتها بالبرغي المركزي الموجود في عبوة السيرفو.



الخطوة 2: تثبيت أذرع السيرفو (Horns) على وصلات الذراع
قبل تركيب ذراع السيرفو (Horn)، اضبط السيرفو على موضع المنتصف: وصّله بـ PCA9685، وارفع البرنامج إلى اللوحة، وشغّل تغذية السيرفو. ترسل الدالة setup() في البرنامج القيمة 375 لإشارة PWM (90°) إلى كل القنوات. وعندما يكون السيرفو عند 90°، ركّب ذراع السيرفو بحيث تشير الوصلة إلى منتصف مداها، ثم ثبّته ببرغيين. إذا لم تتطابق ثقوب البراغي، فسيعلق ذراع السيرفو ويتحرك المفصل بشكل غير منتظم. كانت أذرع SG90 أطول من الثقوب التي صممتها في القطع المطبوعة، فقصصت طرفي كل ذراع بسكين. اقطع في اتجاه بعيد عن أصابعك.

الخطوة 3: تثبيت محركات السيرفو على وصلات الذراع
ضع كل سيرفو في تجويفه المطبوع بالطباعة ثلاثية الأبعاد (3D) على وصلة الذراع. يجب أن يتطابق عمود الخرج مع محور المفصل الموضح في الرسم الفني. ثبّته ببرغيين واضغط برفق لاختبار التركيب. يجب ألا يتزحزح السيرفو أو يتأرجح.

الخطوة 4: ربط وصلات الذراع
اربط مجموعات الوصلات والسيرفو ببعضها. ضع ذراع السيرفو (Horn) على إحدى الوصلات بحيث يدخل في الوصلة التالية، ثم ثبّته بالبراغي. اربط البراغي بشدٍّ متساوٍ حتى يتحرك المفصل بسلاسة على كامل مداه.

الخطوة 5: تجميع القابض
ثبّت مجموعة القابض الفرعية على الوصلة الأخيرة من الذراع. يستخدم القابض سيرفو صغيرًا SG90 وزوجًا من التروس المطبوعة بالطباعة ثلاثية الأبعاد (3D) لفتح الأصابع وإغلاقها. استخدم براغي M3×20 لمفاصل القابض. تأكد من أن الأصابع تنفتح وتنغلق بحرية قبل المتابعة.

الخطوة 6: تثبيت الذراع على قاعدة خشبية
ثبّت الذراع المجمَّعة على لوح خشبي مستوٍ ببراغي M3×12 ذاتية التسنين. يمنع اللوح الذراع من الانقلاب ويوفر لك مكانًا للوحة التجارب (Breadboard) ولوحة Arduino ومزود الطاقة.

فهم لوحة قيادة السيرفو PCA9685
تستطيع مكتبة Servo في Arduino قيادة ما يصل إلى 12 محرك سيرفو على لوحة Uno، لكنها تولّد النبضات برمجيًا باستخدام مقاطعة مؤقِّت (Timer Interrupt). أما SoftwareSerial، التي يستخدمها هذا المشروع للبلوتوث، فتعطّل المقاطعات أثناء استقبال كل بايت، لذا ترتعش محركات السيرفو التي تقودها مكتبة Servo. في المقابل، تولّد PCA9685 كل النبضات عتاديًا، فلا تستطيع بيانات البلوتوث الواردة التشويش عليها، ولا تحتاج إلا إلى سلكَي إشارة (SDA وSCL). تحتوي اللوحة الواحدة على 16 قناة، فتبقى عشر قنوات حرة بعد توصيل ستة محركات سيرفو.
مرجع أطراف PCA9685 (Pinout)
- GND: أرضي مشترك مع Arduino.
- OE (Output Enable، أي تمكين الخرج): فعّال عند المستوى المنخفض، أي أن المخارج تعمل ما دام الطرف عند LOW. اتركه دون توصيل؛ فاللوحة تُبقيه عند LOW.
- SCL / SDA: خطّا الساعة والبيانات لناقل I2C.
- VCC: تغذية منطقية من 3.3 إلى 5 V للشريحة فقط، وليست لمحركات السيرفو.
- V+: تغذية محركات السيرفو من مزود الطاقة الخارجي، حتى 6 V، عبر الطرف اللولبي (Screw Terminal).
- القنوات من 0 إلى 15: لكل قناة موصل من 3 أطراف (PWM، V+، GND) يناسب قابس السيرفو القياسي.

الاتصال عبر البلوتوث باستخدام وحدة HC-05
HC-05 وحدة بلوتوث تنشئ اتصالًا تسلسليًا لاسلكيًا بين هاتف Android الخاص بك ولوحة Arduino. تعمل بمستوى منطقي 3.3 V، وقد يؤدي جهد 5 V إلى إتلاف طرف RX فيها. لذلك يحتاج الخط الممتد من الطرف TX في Arduino (5 V) إلى الطرف RX في HC-05 إلى مقسم جهد. مقسم الجهد مقاومتان موصولتان على التوالي تقسمان الجهد. وصّل مقاومة 1 kΩ من الطرف 11 في Arduino إلى الطرف RX في HC-05، ومقاومة 2 kΩ من الطرف RX في HC-05 إلى GND. عندها تستقبل HC-05 جهدًا قدره 5 V × 2/3 ≈ 3.3 V. أما الخط من TX في HC-05 إلى RX في Arduino فلا يحتاج إلى مقسم، لأن لوحة Arduino تقرأ 3.3 V على أنها HIGH منطقي.
SoftwareSerial مكتبة تحوّل طرفين رقميين عاديين إلى منفذ تسلسلي. في SoftwareSerial BTSerial(10, 11)، الرقم الأول هو طرف الاستقبال (RX) في Arduino والثاني طرف الإرسال (TX). الخطوط متقاطعة: يتصل TX في HC-05 بالطرف 10، ويتصل RX في HC-05 بالطرف 11. يبقى الطرفان 0 و1 متاحين لرفع البرنامج إلى اللوحة وللشاشة التسلسلية (Serial Monitor، وهي نافذة النصوص في Arduino IDE). تعمل HC-05 افتراضيًا بسرعة 9600 baud (سرعة النقل بالبت في الثانية)، وهي تطابق إعداد SoftwareSerial في البرنامج. لإعداد HC-05 وأوامر AT (أوامر نصية تغيّر إعدادات مثل اسم الوحدة ورمز PIN ومعدل الباود)، راجع شرح وحدة البلوتوث HC-05.
توصيلات الدائرة الإلكترونية مع البلوتوث
يتكون نظام التحكم من أربعة أجزاء: لوحة Arduino Uno، وPCA9685 لتوليد إشارات PWM، وHC-05 للاتصال اللاسلكي، ومزود طاقة 5 V 10 A لمحركات السيرفو.
جدول التوصيل: من Arduino إلى PCA9685
| طرف Arduino | طرف PCA9685 | الوظيفة |
|---|---|---|
| 5 V | VCC | التغذية المنطقية لشريحة PCA9685 |
| GND | GND | أرضي مشترك |
| A4 (SDA) | SDA | خط بيانات I2C |
| A5 (SCL) | SCL | خط ساعة I2C |
جدول التوصيل: من Arduino إلى وحدة HC-05
| طرف Arduino | طرف HC-05 | الوظيفة |
|---|---|---|
| الطرف 10 (SoftwareSerial RX) | TX | يستقبل البيانات من البلوتوث |
| الطرف 11 (SoftwareSerial TX) | RX (عبر مقسم الجهد) | يرسل البيانات إلى البلوتوث |
| 5 V | VCC | يغذّي وحدة HC-05 |
| GND | GND | أرضي مشترك |
تغذية محركات السيرفو وتوصيلات PCA9685
وصّل محركات السيرفو بالقنوات المذكورة في المصفوفة servoChannels. يتحكم شريط التمرير 1 في السيرفو الموصول بالقناة 0، والشريط 2 بالقناة 4، والشريط 3 بالقناة 8، والشريط 4 بالقناة 9، والشريط 5 بالقناة 12، والشريط 6 بالقناة 13. في مخطط Fritzing، توصَل محركات السيرفو الثلاثة MG996R بالقنوات 0 و4 و8، ومحركات السيرفو الثلاثة SG90 بالقنوات 9 و12 و13. لا يُشترط أن تكون القنوات متتالية: لاستخدام قنوات أخرى، غيّر الأرقام في المصفوفة servoChannels. طابِق السلك الأرضي للسيرفو (البني أو الأسود) مع صف الأطراف المعلَّم بـ GND على اللوحة.
وصّل مزود الطاقة 5 V 10 A بالطرفين اللولبيين V+ وGND في PCA9685، وغذِّ لوحة Arduino عبر USB. بهذا يبقى تيار محركات السيرفو بعيدًا عن Arduino، إذ قد تتسبب قفزة مفاجئة في التيار على خط التغذية 5 V في Arduino بهبوط الجهد (Brownout) وإعادة تشغيل اللوحة. أشغّل محركات السيرفو عند 6 V من مزود الطاقة المختبري Hanmatek HM305P الخاص بي، كما في مخطط Fritzing. يعمل الجهدان 5 V و6 V كلاهما، لأن V+ يقبل حتى 6 V. يوفر HM305P تيارًا يصل إلى 5 A، وهذا يكفي للحركات العادية لذراعي. أما مزود الطاقة 10 A المذكور في قائمة القطع فيغطي أيضًا حالة توقف عدة مفاصل في الوقت نفسه.
لا يتضمن المخطط أدناه مقاومتَي مقسم الجهد، لذا أضفهما على لوحة التجارب كما هو موضح في قسم HC-05. كما يغذّي المخطط وحدة HC-05 من الطرف 3.3 V؛ ويعمل جهد 5 V كما في جدول التوصيل أيضًا، لأن الطرف VCC في الوحدة يقبل من 3.3 إلى 5 V. أما أطراف الإشارة فيها فتبقى عند 3.3 V.

برنامج Arduino (Sketch)
يؤدي البرنامج أربع مهام: استقبال أوامر البلوتوث، وتحليل الأوامر، وتحريك السيرفو خطوة بخطوة، وحفظ الوضعيات مع إعادة تشغيلها. قبل الترجمة البرمجية (Compile)، ثبّت مكتبة Adafruit PWM Servo Driver Library عبر مدير المكتبات (Library Manager) (تأتي Wire وSoftwareSerial مع Arduino IDE). اختر Arduino Uno أو Mega ومنفذ COM الصحيح (المنفذ التسلسلي الذي يخصصه حاسوبك لاتصال USB باللوحة)، ثم انقر على Upload.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <SoftwareSerial.h>
// Constants and definitions
const int numServos = 6;
const int maxConfigurations = 10;
const int stepDelay = 10;
const int stepSize = 1;
// Servo channels on the PCA9685
const int servoChannels[numServos] = {0, 4, 8, 9, 12, 13};
// Storage structures
int savedConfigurations[maxConfigurations][numServos];
int currentServoPositions[numServos] = {375, 375, 375, 375, 375, 375};
int configCount = 0;
bool isPlaying = false;
bool loopPlayback = false;
bool stopPlaying = false;
int currentPoseIndex = 0;
bool initialized = false;
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
SoftwareSerial BTSerial(10, 11);
// Setup initialization
void setup() {
Serial.begin(9600);
BTSerial.begin(9600);
pwm.begin();
pwm.setPWMFreq(60);
for (int i = 0; i < numServos; i++) {
pwm.setPWM(servoChannels[i], 0, currentServoPositions[i]);
}
initialized = true;
Serial.println("Bluetooth Servo Controller started. Waiting for commands...");
}
// Main loop
void loop() {
if (BTSerial.available()) {
String input = BTSerial.readStringUntil('\n');
input.trim();
Serial.println("Received data: " + input);
if (input.equalsIgnoreCase("S")) {
saveCurrentPose();
} else if (input.equalsIgnoreCase("P")) {
startPlayingPoses();
} else if (input.equalsIgnoreCase("R")) {
resetPoses();
} else if (input.equalsIgnoreCase("St")) {
stopPlayingPoses();
} else if (input.equalsIgnoreCase("LoopON")) {
loopPlayback = true;
Serial.println("Loop playback enabled.");
} else if (input.equalsIgnoreCase("LoopOFF")) {
loopPlayback = false;
Serial.println("Loop playback disabled.");
} else if (input.indexOf(',') > 0) {
processLastValue(input);
} else {
Serial.println("Unknown command: " + input);
}
}
if (isPlaying && !stopPlaying) {
if (loopPlayback) {
playPosesInLoop();
} else {
playNextPose();
}
}
}
التحكم في السيرفو ومعالجة الأوامر
// Process servo commands
void processLastValue(String command) {
int lastCommaIndex = command.lastIndexOf(',');
if (lastCommaIndex > 0 && lastCommaIndex < command.length() - 1) {
int servoIndex = command.substring(0, lastCommaIndex).toInt() - 1;
float lastValue = command.substring(lastCommaIndex + 1).toFloat();
int targetPos = (int)lastValue;
int targetPwmValue = map(targetPos, 0, 180, 150, 600);
moveToPositionSmoothly(servoIndex, targetPwmValue);
} else {
Serial.println("Invalid command for servo control: " + command);
}
}
// Smooth movement function
void moveToPositionSmoothly(int servoIndex, int targetPwmValue) {
int currentPwmValue = currentServoPositions[servoIndex];
if (targetPwmValue > currentPwmValue) {
for (int pos = currentPwmValue; pos <= targetPwmValue; pos += stepSize) {
pwm.setPWM(servoChannels[servoIndex], 0, pos);
delay(stepDelay);
}
} else {
for (int pos = currentPwmValue; pos >= targetPwmValue; pos -= stepSize) {
pwm.setPWM(servoChannels[servoIndex], 0, pos);
delay(stepDelay);
}
}
currentServoPositions[servoIndex] = targetPwmValue;
Serial.println("Servo " + String(servoIndex + 1) + " set to PWM value: " + String(targetPwmValue));
}
حفظ الوضعيات وتشغيلها وإعادة ضبطها
// Save pose function
void saveCurrentPose() {
if (configCount < maxConfigurations) {
for (int i = 0; i < numServos; i++) {
savedConfigurations[configCount][i] = currentServoPositions[i];
Serial.print("Servo "); Serial.print(i + 1);
Serial.print(" saved at PWM value: ");
Serial.println(savedConfigurations[configCount][i]);
}
configCount++;
Serial.println("Pose saved. Total saved poses: " + String(configCount));
} else {
Serial.println("Memory full, cannot save more poses.");
}
}
// Start playback
void startPlayingPoses() {
if (configCount == 0) {
Serial.println("No poses saved, nothing to play.");
return;
}
Serial.println("Playback of saved poses started...");
isPlaying = true;
stopPlaying = false;
currentPoseIndex = 0;
}
// Play next pose
void playNextPose() {
if (currentPoseIndex < configCount) {
Serial.println("Playing pose " + String(currentPoseIndex + 1));
for (int i = 0; i < numServos; i++) {
moveToPositionSmoothly(i, savedConfigurations[currentPoseIndex][i]);
}
delay(1000);
currentPoseIndex++;
} else {
isPlaying = false;
Serial.println("Playback of poses finished.");
}
}
// Loop playback
void playPosesInLoop() {
for (int j = 0; j < configCount; j++) {
Serial.println("Playing pose " + String(j + 1));
for (int i = 0; i < numServos; i++) {
moveToPositionSmoothly(i, savedConfigurations[j][i]);
}
delay(1000);
if (stopPlaying) break;
}
}
// Stop playback
void stopPlayingPoses() {
stopPlaying = true;
isPlaying = false;
Serial.println("Playback of poses stopped.");
}
// Reset all poses
void resetPoses() {
configCount = 0;
isPlaying = false;
loopPlayback = false;
currentPoseIndex = 0;
Serial.println("All saved poses have been deleted.");
}
كيف يعمل كود Arduino
يستدعي قسم المكتبات Wire.h لناقل I2C، وAdafruit_PWMServoDriver.h للوحة PCA9685، وSoftwareSerial.h للبلوتوث. تحدد الثوابت عدد محركات السيرفو (6)، وزمن التأخير بين الخطوات (10 ms)، وحجم الخطوة (كل خطوة تغيّر قيمة PWM بمقدار 1). ويمثّل maxConfigurations (10) الحد الأقصى لعدد الوضعيات المحفوظة. يسمّي البرنامج الوضعية المحفوظة “configuration” (savedConfigurations)، والدالة processLastValue() هي التي تعالج أمر شريط التمرير مثل 2,90.
تبدأ الدالة setup() تشغيل المنفذين التسلسليين بسرعة 9600 baud، وتشغّل PCA9685 بتردد PWM قدره 60 Hz، وتضبط كل محركات السيرفو على نقطة المنتصف (قيمة PWM 375، أي 90°). بذلك يعرف البرنامج موضعًا محددًا لكل سيرفو، وتُنفَّذ كل الحركات التالية خطوة بخطوة. تقفز محركات السيرفو إلى نقطة المنتصف بأقصى سرعة عند وصول التغذية، لذا أبعد يديك عن الذراع عند تشغيلها. تتحقق الحلقة الرئيسية loop() من وصول بيانات البلوتوث وترسل كل أمر إلى الدالة التي تعالجه. يُعامَل أي أمر يحتوي على فاصلة على أنه موضع سيرفو بالصيغة servoIndex,angle، حيث تتراوح قيمة servoIndex من 1 إلى 6 وقيمة angle من 0 إلى 180.
| الأمر | يُرسَل عبر | التأثير |
|---|---|---|
| 1,90 … 6,90 | أشرطة التمرير من 1 إلى 6 | يحرّك ذلك السيرفو إلى الزاوية المحددة (من 0 إلى 180°) |
| S | حفظ | يحفظ المواضع الحالية كوضعية (10 كحد أقصى) |
| P | تشغيل | يشغّل الوضعيات المحفوظة بالترتيب |
| St | إيقاف | ينهي التشغيل (بعد الوضعية الحالية أو دورة التكرار الحالية، راجع قسم المعايرة والاختبار) |
| R | إعادة الضبط | يحذف كل الوضعيات المحفوظة |
| LoopON / LoopOFF | مفتاح التكرار (Loop) | يفعّل التشغيل المتكرر أو يعطّله (يستمر التكرار حتى الضغط على إيقاف) |
يُنهي التطبيق كل أمر بمحرف سطر جديد (\n)، وتقرأ الدالة readStringUntil(‘\n’) في برنامج Arduino البيانات حتى هذا المحرف.
تغيّر الدالة moveToPositionSmoothly() قيمة PWM بمقدار stepSize (1) كل stepDelay (10 ms) حتى تبلغ القيمة المستهدفة، لذا تستغرق الحركة الكاملة من 150 إلى 600 نحو 4.5 ثانية. وهي تحرّك محرك سيرفو واحدًا في كل مرة: أثناء تشغيل الوضعيات المحفوظة تتحرك المفاصل واحدًا تلو الآخر لا معًا. وفي أثناء حركة السيرفو لا يقرأ البرنامج أوامر بلوتوث جديدة. وتمنع الخطوات البطيئة الذراعَ من القفزات المفاجئة التي قد تُتلف التروس أو تُسقط الذراع.
تطبيق Android (MIT App Inventor)
RobotArmControl هو تطبيق Android الخاص بهذه الذراع، وقد بُني في MIT App Inventor. يضم التطبيق زر اتصال بالبلوتوث، وستة أشرطة تمرير (Slider، واحد لكل محرك سيرفو)، وأزرار Save وPlay وStop وReset، ومفتاح Loop، وتسمية نصية (PoseCountLabel) تعرض عدد الوضعيات المحفوظة. يرسل كل عنصر تحكم أحد الأوامر الواردة في الجدول أعلاه.

كتل App Inventor البرمجية
تُنشئ كتلة التهيئة العامة متغيرًا اسمه receivedText وتضبط قيمته على 0. ورغم اسمه، فهو يعدّ الوضعيات المحفوظة: كل نقرة على Save تضيف 1 وتعرض العدد الجديد في PoseCountLabel. تملأ كتلة BeforePicking الخاصة بعنصر ListPicker قائمة أجهزة البلوتوث لتختار منها HC-05، وتفتح كتلة AfterPicking اتصال البلوتوث التسلسلي بمجرد اختيارك جهازًا. بعد ذلك يعرض Label1 عبارة Connected على خلفية خضراء أو Not Connected على خلفية حمراء.
تحوّل كتلة PositionChanged الخاصة بكل شريط تمرير رقمَ السيرفو والزاوية إلى نص مثل 2,90 وترسله عبر BluetoothClient.SendText. ويرسل كل زر من أزرار Save وPlay وStop وReset أمره النصي القصير (S أو P أو St أو R). وتقرأ كتلة LoopSwitch.Changed حالة المفتاح وترسل LoopON أو LoopOFF.




تثبيت التطبيق والاقتران
نزّل ملف APK لتطبيق RobotArmControl (ملف التثبيت على Android) من GitHub وثبّته. سيسألك Android مرة واحدة عمّا إذا كنت تسمح بالتثبيت من هذا المصدر. اقرن هاتفك بوحدة HC-05 من إعدادات البلوتوث في Android (رمز PIN الافتراضي 1234)، ثم افتح التطبيق، واضغط على قائمة اختيار أجهزة البلوتوث، واختر HC-05.
معايرة الذراع واختبارها
حرّك كل شريط تمرير ببطء وتأكد من أن المفصل الصحيح هو الذي يستجيب. تحوّل الدالة processLastValue() زاوية شريط التمرير (targetPos في الكود) إلى قيمة PWM باستخدام map(targetPos, 0, 180, 150, 600): تتحول 0° إلى 150، و90° إلى 375، و180° إلى 600. تُقاس قيمة PWM بوحدات العدّ (Ticks)، وهي الخطوات الـ 4096 في كل دورة PWM. عند التردد 60 Hz المضبوط في البرنامج تساوي وحدة العدّ الواحدة نحو 4.07 µs، لذا تعادل 150 إلى 600 وحدة عدّ نحو 0.61 إلى 2.44 ms. إذا تحرك مفصل في الاتجاه الخاطئ، فبدّل الحدين الأدنى والأعلى لشريط التمرير في App Inventor، أو بدّل 150 و600 في استدعاء map() هذا.
اضبط نطاق PWM بدقة (من 150 إلى 600 في الكود) لكل محرك سيرفو. تحتاج بعض محركات السيرفو إلى قيم دنيا وقصوى مختلفة قليلًا لتجنب الطنين عند نقاط التوقف الطرفية (الحدود الميكانيكية لدوران السيرفو). اختبر الذراع تحت الحمل بالتقاط أجسام صغيرة بالقابض عند أقصى مدى للوصول. في فيديو النسخة التي تعمل بالمقاومات المتغيرة، استخدمت هذه الذراع لالتقاط مجسم صغير لبرج إيفل ووضعه على لوح.
لاختبار نظام الوضعيات، حرّك الذراع إلى موضع ما واضغط Save. كرّر ذلك لعدة مواضع، ثم اضغط Play: تعيد الذراع تشغيل التسلسل كاملًا. فعّل وضع Loop واضغط Play: تكرر الذراع التسلسل. اضغط Stop لإنهائه. لا يقرأ البرنامج أمر Stop إلا بعد انتهاء الدورة الحالية، لذا تُكمل الذراع التسلسل أولًا. لإيقاف الذراع فورًا، أطفئ مزود الطاقة الخاص بمحركات السيرفو.
تحسينات مستقبلية
يمكنك إضافة الحركيات العكسية (Inverse Kinematics) لتتحرك الذراع إلى إحداثيات X-Y-Z بدلًا من زوايا المفاصل كلٍّ على حدة. ويمكنك أيضًا استخدام مقياس التسارع المدمج في الهاتف (مكوّن AccelerometerSensor في App Inventor) لتحريك الذراع بإمالة الهاتف. واستبدال HC-05 بلوحة ESP32 (متحكم دقيق مزوّد بواي فاي مدمج) سيتيح لك التحكم في الذراع من المتصفح عبر Wi-Fi، كما في OmArm Zero.
من ناحية البرمجيات، يمكنك نقل تخزين الوضعيات إلى EEPROM (ذاكرة في Arduino تحتفظ ببياناتها دون طاقة) لتبقى التسلسلات المحفوظة بعد فصل الطاقة وإعادة توصيلها. ومن الخيارات الأخرى سرعة متغيرة لكل مفصل، أو وضع التعليم وإعادة التشغيل (Teach-and-Playback) الذي تحرّك فيه الذراع بيدك فتسجّل هي المواضع. OmObiArm يدمج هذه الذراع مع قاعدة روبوت متنقل (Rover).
دروس ذات صلة: روبوت تتبع الخط و التحكم في محرك السيرفو بعصا التحكم (Joystick).
التنزيلات
- برنامج Arduino (.ino) وتطبيق Android (APK): مستودع GitHub
- ملفات STL: متجر OmArTronics
مخطط التوصيل وقائمة القطع موجودان في هذا المقال.
الأسئلة الشائعة (FAQ)
نعم. تشغّل لوحة Mega الكود نفسه. الاختلاف الوحيد في أطراف I2C: يكون SDA على الطرف 20 وSCL على الطرف 21 بدلًا من A4 وA5. ويعمل الطرفان 10 و11 مع SoftwareSerial على لوحة Mega أيضًا.
يعني الارتجاف عادةً أن قيمة PWM تصل إلى نقطة التوقف الطرفية للسيرفو. اضبط نطاق map() وتحقق من تيار مزود الطاقة لديك.
تستخدم وحدة HC-05 ملف تعريف البلوتوث التسلسلي الكلاسيكي (SPP)، ولا تستطيع تطبيقات iPhone استخدامه. لاستخدام iPhone، استبدل HC-05 بوحدة HM-10 التي تعمل بتقنية البلوتوث منخفض الطاقة (BLE)، وأعد بناء التطبيق على منصة تدعم BLE.
يخزّن الكود افتراضيًا ما يصل إلى 10 وضعيات في ذاكرة RAM. يمكنك زيادة maxConfigurations، لكن لوحة Uno لا تملك سوى 2 KB من ذاكرة SRAM (ذاكرة العمل التي تُمحى عند انقطاع الطاقة). للتخزين الدائم، احفظ الوضعيات في EEPROM.
مقارنة بين كل أذرعي الروبوتية: كيف تبني ذراعًا روبوتية بست محاور في المنزل يشرح ماذا يعني ست محاور، ويضع التصاميم الأربعة في جدول واحد، ويخبرك أيها تبني أولًا.

اشتريت النموذج، لكنه لا يتضمن قيمة مقاس المحمل
شكرًا على تعليقك يا Fernando! يُرجى إضافة محمل كروي 6806ZZ بأبعاد 30*42*7.
مرحبًا،
هل يمكنك أن تخبرني أين توجد قائمة القطع لأتمكن من شراء القطع؟ لديّ ملفات STL الخاصة بك من موقع Cults
شكرًا لك
Antonio Mayor
أعيش بالقرب من برشلونة
مرحبًا، مشروع مثير للاهتمام ويصلح أيضًا للتنفيذ مع مراهق. بخصوص محرك السيرفو MG996R، فهو متوفر بنسختين: إما 180° أو 360°. بماذا تنصح؟
مع أطيب التحيات،
Emmanuel
مرحبًا Emmanuel، شكرًا لك على كلماتك اللطيفة! أنصح باستخدام نسخة 180° من محرك السيرفو MG996R في هذا المشروع، لأن سيرفو 180° يتيح التحكم الدقيق في الزاوية، وهذا ضروري لتحديد المواضع والحركة في الأذرع الروبوتية والتطبيقات المشابهة. أما سيرفو 360° فمصمم للدوران المستمر، وهو أنسب لمهام مثل تحريك العجلات حيث لا حاجة إلى التحكم في الزاوية. مع أطيب التحيات، OmArTronics.
سيدي، نفّذت التوصيلات نفسها لكنها لا تعمل، من فضلك أخبرني كم
من التيار يجب أن أزوّد به لوحة قيادة السيرفو pca9685
تستهلك لوحة قيادة السيرفو PCA9685 نفسها تيارًا ضئيلًا جدًا، عادةً أقل من 10mA. لكن التيار الإجمالي المطلوب يعتمد على محركات السيرفو التي تستخدمها. فكل محرك سيرفو MG996R مثلًا قد يسحب ما يصل إلى 2A (وبحد أقصى 2,5 A) تحت الحمل. تأكد من أن مزود الطاقة لديك قادر على توفير تيار كافٍ لجميع محركات السيرفو الموصولة، مع مراعاة مجموع أقصى تيار تسحبه معًا.
من فضلك يا سيدي، ردّ بسرعة في أقرب وقت ممكن
مرحبًا، أحاول تشغيله لكن يظهر لي الخطأ 507 باستمرار، ولا أستطيع توصيل التطبيق بالروبوت. كيف أجعله يعمل؟
مرحبًا، كيف يمكنني العثور على هذه المسامير الملولبة والبراغي في مكان واحد؟ هل يوجد موقع تسوق على الإنترنت تتوفر فيه جميعها؟
لتشغيل المحركات الـ 6، ما مقدار الطاقة اللازمة، أي الجهد والتيار بالأمبير، وما المحوّل الذي استخدمته لذلك
أستخدم ستة محركات سيرفو تتغذى عبر لوحة قيادة PCA9685 من مزود طاقة خارجي بجهد 6 V.
يسحب كل محرك سيرفو عادةً من 300 إلى 600 mA حسب الحمل، لذا عليك أن تحسب لستة محركات سيرفو تيارًا إجماليًا يبلغ نحو 3 إلى 5 A.
أستخدم مزود الطاقة القابل للضبط Hanmatek HM305P، لكن أي محوّل بجهد من 5 V إلى 6 V وبتيار مقنَّن لا يقل عن 5 A سيعمل جيدًا.
أما لوحة Arduino نفسها فتتغذى بالطاقة بشكل منفصل عبر USB.
مرحبًا، أتمنى أن تكون بخير. لديّ سؤال عن البراغي: ما نوع البراغي اللازمة لتجميع القطع؟ أعتقد أنني سأحصل معها على براغي محركات السيرفو، لذا هل يمكنك من فضلك أن تخبرني بالبراغي المطلوبة وكميتها لتجميع القطع.