اصنع بنفسك ذراعًا روبوتية بست درجات حرية (6-DOF) يُتحكَّم بها عبر البلوتوث: دليل البناء الكامل

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

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

📋 ملخص سريع

يطوّر هذا المشروع الذراع الروبوتية المطبوعة بالطباعة ثلاثية الأبعاد (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.

البندالكميةالجزءالوصف
11Base_1لوح القاعدة (ثابت)
21base_link_upper1المنصة العلوية (دوّارة)
31arm_link_1الوصلة الأولى في الذراع
41arm_link_2الوصلة الثانية في الذراع
51arm_link_3الوصلة الثالثة في الذراع
61gripper_baseقاعدة القابض
71Gripper_2إصبع القابض
81Gear_rightترس القابض (الأيمن)
91Gear_leftترس القابض (الأيسر)
101القابضتجميع القابض
114الوصلةأجزاء وصلات القابض
122فاصلفواصل مفصل القابض
12a1محور المفصلمحور مفصل مطبوع (pin.stl)
133محرك سيرفو MG996Rسيرفو عالي العزم، إصدار 180° (القاعدة، الكتف، المرفق)
143محرك سيرفو مصغّر SG90سيرفو مصغّر (المعصم، القابض)
1516ANSI B18.6.4 No.2-32 3/8″برغي برأس مقبب عريض (Truss)، No.2-32
162ANSI B18.6.4 No.2-32 1/4″برغي برأس مقبب عريض (Truss)، No.2-32
173DIN 7985 M1.6×2-Zبرغي برأس صليبي M1.6×2
187ISO 4762 M3x16 (AS 1420)برغي برأس سداسي التجويف (ألن) M3×16
1912ISO 4032 M3 (AS 1112)صامولة سداسية M3
202ANSI B18.6.4 No.2-32 1/2″برغي برأس مقبب عريض (Truss)، No.2-32
213ذراع سيرفو MG996R (Horn)الذراع (Horn) المرفقة مع MG996R
223DIN 7985 M3x6-Zبرغي برأس صليبي M3×6
233ذراع سيرفو SG90 (Horn)ذراع (Horn) لسيرفو SG90
2412ANSI B18.6.4 No.3-28 1/2″برغي برأس مقبب عريض (Truss)، No.3-28
251محمل كروي 6806ZZ (30x42x7)محمل كروي ذو أخدود عميق (30×42×7 mm)
261Arduino Uno أو Megaوحدة التحكم الرئيسية
271لوحة قيادة السيرفو PCA9685وحدة قيادة PWM بـ 16 قناة (I2C)
281وحدة HC-05وحدة بلوتوث للتحكم اللاسلكي
291لوحة التجارب (Breadboard)قاعدة لتوصيل الأسلاك
301مزود طاقة 5 V 10 Aمصدر تغذية محركات السيرفو
311أسلاك توصيل Jumper (ذكر-أنثى)من Arduino إلى PCA9685
321أسلاك توصيل Jumper (ذكر-ذكر)من لوحة التجارب إلى Arduino
331لوح خشبيمنصة تثبيت الذراع
341 من كل نوعمقاومتان 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. النابض اختياري وغير مدرج في قائمة القطع.

Technical drawing of the robotic arm with part dimensions, sectional views and servo positions.

الطباعة ثلاثية الأبعاد (3D) للمكونات

اطبع القطع من ملفات STL. خيط الطباعة PLA سهل الطباعة ويحافظ على دقة الأبعاد. للقطع الإنشائية مثل القاعدة ووصلات الذراع، استخدم ارتفاع طبقة (سُمك كل طبقة مطبوعة) قدره 0.2 mm. واجعل نسبة الملء (Infill، أي نسبة الجزء الداخلي المملوء بالمادة) فيها 40 بالمئة على الأقل. أما القطع الرقيقة مثل تروس القابض فتكفيها نسبة ملء 20 بالمئة، وهذا يوفّر المادة.

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

Ultimaker Cura slicer with the robotic arm parts arranged on the build plate.
Anycubic 3D printer printing the PLA parts of the arm.

اختيار محرك السيرفو: 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) يُتلف أسنان اللولبة بسرعة.

All 3D printed parts, servos, bearing, screws and hardware for the arm laid out on a cutting mat before assembly.

الخطوة 1: تجميع القاعدة

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

Installing an MG996R servo in the 3D printed base mount.
Pressing the 6806ZZ ball bearing into the rotating upper platform.
Fastening the rotating upper platform to the base servo with the screw from the servo package.

الخطوة 2: تثبيت أذرع السيرفو (Horns) على وصلات الذراع

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

Three-panel view of servo horns being aligned and screwed to the 3D printed arm links.

الخطوة 3: تثبيت محركات السيرفو على وصلات الذراع

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

Three-panel view of MG996R and SG90 servos being screwed into their pockets in the 3D printed parts.

الخطوة 4: ربط وصلات الذراع

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

Three-panel view of the arm links being joined with servo horns and screws.

الخطوة 5: تجميع القابض

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

Assembling the gripper with an SG90 micro servo and 3D printed gear-driven fingers.

الخطوة 6: تثبيت الذراع على قاعدة خشبية

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

Assembled 6-DOF robotic arm mounted on a wooden base board.

فهم لوحة قيادة السيرفو 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) يناسب قابس السيرفو القياسي.
PCA9685 16-channel PWM servo driver board with labeled I2C, power and servo output pins.

الاتصال عبر البلوتوث باستخدام وحدة 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 VVCCالتغذية المنطقية لشريحة PCA9685
GNDGNDأرضي مشترك
A4 (SDA)SDAخط بيانات I2C
A5 (SCL)SCLخط ساعة I2C

جدول التوصيل: من Arduino إلى وحدة HC-05

طرف Arduinoطرف HC-05الوظيفة
الطرف 10 (SoftwareSerial RX)TXيستقبل البيانات من البلوتوث
الطرف 11 (SoftwareSerial TX)RX (عبر مقسم الجهد)يرسل البيانات إلى البلوتوث
5 VVCCيغذّي وحدة HC-05
GNDGNDأرضي مشترك

تغذية محركات السيرفو وتوصيلات 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.

Fritzing wiring diagram: Arduino Uno connected to the PCA9685 servo driver, the HC-05 module, six servos and the external power supply.

برنامج 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) تعرض عدد الوضعيات المحفوظة. يرسل كل عنصر تحكم أحد الأوامر الواردة في الجدول أعلاه.

Screenshot of the RobotArmControl Android app with six servo sliders, the Bluetooth connect button and the Save, Play, Reset and Stop buttons.

كتل 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.

App Inventor blocks for the receivedText variable and the ListPicker that connects to the HC-05.
App Inventor block for the LoopSwitch that sends LoopON or LoopOFF over Bluetooth.
App Inventor blocks for the six slider PositionChanged handlers that send the angle over Bluetooth.
App Inventor blocks for the Stop, Save and Play button click handlers.

تثبيت التطبيق والاقتران

نزّل ملف 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).

التنزيلات

مخطط التوصيل وقائمة القطع موجودان في هذا المقال.

الأسئلة الشائعة (FAQ)

هل يمكنني استخدام Arduino Mega بدلًا من Arduino Uno؟

نعم. تشغّل لوحة Mega الكود نفسه. الاختلاف الوحيد في أطراف I2C: يكون SDA على الطرف 20 وSCL على الطرف 21 بدلًا من A4 وA5. ويعمل الطرفان 10 و11 مع SoftwareSerial على لوحة Mega أيضًا.

لماذا ترتجف محركات السيرفو لديّ أو تصدر طنينًا في مواضع معينة؟

يعني الارتجاف عادةً أن قيمة PWM تصل إلى نقطة التوقف الطرفية للسيرفو. اضبط نطاق map() وتحقق من تيار مزود الطاقة لديك.

هل يمكنني التحكم في هذه الذراع بهاتف iPhone؟

تستخدم وحدة HC-05 ملف تعريف البلوتوث التسلسلي الكلاسيكي (SPP)، ولا تستطيع تطبيقات iPhone استخدامه. لاستخدام iPhone، استبدل HC-05 بوحدة HM-10 التي تعمل بتقنية البلوتوث منخفض الطاقة (BLE)، وأعد بناء التطبيق على منصة تدعم BLE.

كم وضعية تستطيع الذراع حفظها؟

يخزّن الكود افتراضيًا ما يصل إلى 10 وضعيات في ذاكرة RAM. يمكنك زيادة maxConfigurations، لكن لوحة Uno لا تملك سوى 2 KB من ذاكرة SRAM (ذاكرة العمل التي تُمحى عند انقطاع الطاقة). للتخزين الدائم، احفظ الوضعيات في EEPROM.

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

14 رأي حول “DIY 6-DOF Robotic Arm with Bluetooth Control: Complete Build Guide”

  1. مرحبًا،
    هل يمكنك أن تخبرني أين توجد قائمة القطع لأتمكن من شراء القطع؟ لديّ ملفات STL الخاصة بك من موقع Cults
    شكرًا لك
    Antonio Mayor
    أعيش بالقرب من برشلونة

    رد
  2. مرحبًا، مشروع مثير للاهتمام ويصلح أيضًا للتنفيذ مع مراهق. بخصوص محرك السيرفو MG996R، فهو متوفر بنسختين: إما 180° أو 360°. بماذا تنصح؟
    مع أطيب التحيات،
    Emmanuel

    رد
    • مرحبًا Emmanuel، شكرًا لك على كلماتك اللطيفة! أنصح باستخدام نسخة 180° من محرك السيرفو MG996R في هذا المشروع، لأن سيرفو 180° يتيح التحكم الدقيق في الزاوية، وهذا ضروري لتحديد المواضع والحركة في الأذرع الروبوتية والتطبيقات المشابهة. أما سيرفو 360° فمصمم للدوران المستمر، وهو أنسب لمهام مثل تحريك العجلات حيث لا حاجة إلى التحكم في الزاوية. مع أطيب التحيات، OmArTronics.

      رد
  3. سيدي، نفّذت التوصيلات نفسها لكنها لا تعمل، من فضلك أخبرني كم
    من التيار يجب أن أزوّد به لوحة قيادة السيرفو pca9685

    رد
    • تستهلك لوحة قيادة السيرفو PCA9685 نفسها تيارًا ضئيلًا جدًا، عادةً أقل من 10mA. لكن التيار الإجمالي المطلوب يعتمد على محركات السيرفو التي تستخدمها. فكل محرك سيرفو MG996R مثلًا قد يسحب ما يصل إلى 2A (وبحد أقصى 2,5 A) تحت الحمل. تأكد من أن مزود الطاقة لديك قادر على توفير تيار كافٍ لجميع محركات السيرفو الموصولة، مع مراعاة مجموع أقصى تيار تسحبه معًا.

      رد
  4. مرحبًا، أحاول تشغيله لكن يظهر لي الخطأ 507 باستمرار، ولا أستطيع توصيل التطبيق بالروبوت. كيف أجعله يعمل؟

    رد
  5. مرحبًا، كيف يمكنني العثور على هذه المسامير الملولبة والبراغي في مكان واحد؟ هل يوجد موقع تسوق على الإنترنت تتوفر فيه جميعها؟

    رد
  6. لتشغيل المحركات الـ 6، ما مقدار الطاقة اللازمة، أي الجهد والتيار بالأمبير، وما المحوّل الذي استخدمته لذلك

    رد
    • أستخدم ستة محركات سيرفو تتغذى عبر لوحة قيادة PCA9685 من مزود طاقة خارجي بجهد 6 V.
      يسحب كل محرك سيرفو عادةً من 300 إلى 600 mA حسب الحمل، لذا عليك أن تحسب لستة محركات سيرفو تيارًا إجماليًا يبلغ نحو 3 إلى 5 A.
      أستخدم مزود الطاقة القابل للضبط Hanmatek HM305P، لكن أي محوّل بجهد من 5 V إلى 6 V وبتيار مقنَّن لا يقل عن 5 A سيعمل جيدًا.
      أما لوحة Arduino نفسها فتتغذى بالطاقة بشكل منفصل عبر USB.

      رد
  7. مرحبًا، أتمنى أن تكون بخير. لديّ سؤال عن البراغي: ما نوع البراغي اللازمة لتجميع القطع؟ أعتقد أنني سأحصل معها على براغي محركات السيرفو، لذا هل يمكنك من فضلك أن تخبرني بالبراغي المطلوبة وكميتها لتجميع القطع.

    رد

أضف تعليق