يحتوي هذا المقال على روابط تسويق بالعمولة مُعلَّمة بعلامة *. بصفتي شريكًا في برنامج Amazon Associates، أربح من عمليات الشراء المؤهلة، دون أي تكلفة إضافية عليك. يساعد ذلك على إبقاء الشروحات مجانية.
تسير هذه السيارة الروبوتية بمفردها وتلتف حول العوائق. وهي تعتمد على أربعة دروس سابقة: أساسيات برمجة Arduino, التحكم في محرك السيرفو, قياس المسافة بالموجات فوق الصوتية و التحكم في محركات التيار المستمر باستخدام وحدات قيادة المحركات.
📋 ملخص سريع
يقيس مستشعر الموجات فوق الصوتية HC-SR04 المثبَّت على محرك سيرفو SG90 المسافةَ أمام الروبوت وعلى جانبيه. وتقرر لوحة Arduino Uno المزوَّدة بدرع المحركات Arduino Motor Shield Rev3 الاتجاهَ الذي يسلكه الروبوت، وتقود محركَي التيار المستمر. يتناول هذا المقال قائمة القطع، والتجميع، والتوصيلات، والبرنامج الكامل (Sketch، أي برنامج Arduino) مع شرح له، وقيم الضبط، واستكشاف الأخطاء وإصلاحها.
كيف يعمل الروبوت
يكرر الروبوت حلقة «استشعر-فكّر-نفّذ» (sense-think-act): يقيس المسافة (الاستشعار)، ثم يقارنها بعتبات ثابتة (التفكير)، ثم يقود المحركات وفقًا لذلك (التنفيذ). العتبة (Threshold) قيمة مسافة ثابتة في الكود يتغير عندها سلوك الروبوت. ويستخدم الروبوت عتبتين: عندما تقل المسافة عن العتبة البعيدة يُبطئ، وعندما تقل عن العتبة القريبة يتوقف.
مستشعر الموجات فوق الصوتية HC-SR04 (قياس المسافة)
مستشعر الموجات فوق الصوتية HC-SR04 يُرسل نبضة فوق صوتية قصيرة ويستمع إلى الصدى المرتد من أقرب جسم. وله طرفا إشارة: يستقبل الطرف Trig نبضة البدء من Arduino، ويُعيد الطرف Echo نبضةً تدوم بقدر الزمن الذي استغرقه الصوت في الذهاب والعودة. تقيس لوحة Arduino هذا الزمن وتحوّله إلى مسافة. ويتكرر هذا القياس مرات عديدة في الثانية أثناء سير الروبوت.
محرك السيرفو SG90 (المسح بالمستشعر)
يُثبَّت المستشعر على محرك سيرفو SG90، وهو سيرفو صغير من فئة الوزن 9 g. أثناء تقدم الروبوت إلى الأمام، يحرّك السيرفو المستشعرَ يسارًا ويمينًا، فيرى الروبوت المسار أمامه وعلى جانبيه. وعندما يقترب عائق لمسافة أقل من العتبة القريبة، يدير السيرفو المستشعرَ إلى أقصى اليسار ثم إلى أقصى اليمين، ويقيس الروبوت الجهة التي فيها مساحة أكبر.
Arduino Motor Shield Rev3 (وحدة قيادة المحركات)
Arduino Motor Shield Rev3 هو لوحة إضافية (درع، Shield) تُركَّب فوق أطراف التوصيل في لوحة Uno (صفّا المقابس الممتدان على حافتيها). وهو يقود محركَي التيار المستمر. تحتوي شريحة القيادة فيه، وهي L298P، على جسرَي H (H-bridge). جسر H دائرة من أربعة مفاتيح تُمرّر التيار عبر المحرك في أيٍّ من الاتجاهين، وبهذه الطريقة يحدد الدرع اتجاه كل محرك (للأمام أو للخلف) على حدة. ويحدد الدرع أيضًا سرعة كل محرك. تُضبط السرعة بتقنية PWM (تعديل عرض النبضة): تشغّل لوحة Arduino المحرك وتطفئه نحو 490 مرة في الثانية، وتحدد نسبةُ زمن التشغيل (دورة التشغيل، Duty Cycle) السرعةَ. والدالة analogWrite() في Arduino هي التي تُخرج إشارة PWM هذه. وإذا شغّلت المحركين الأيسر والأيمن في اتجاهين متعاكسين، يدور الروبوت في مكانه.

تتصل المحركات بأطراف تثبيت لولبية (يُثبَّت السلك فيها ببرغي صغير). لكل محرك على لوحة Arduino طرف خاص للاتجاه، وآخر للسرعة، وثالث للفرملة؛ ويوقف طرف الفرملة المحرك بسرعة.
| الوظيفة | المحرك A (الأيسر) | المحرك B (الأيمن) |
|---|---|---|
| الاتجاه | 12 | 13 |
| السرعة (PWM) | 3 | 11 |
| الفرملة | 9 | 8 |
يقود الدرع محركَي تيار مستمر أو محركًا خطويًا واحدًا (محرك يتحرك بخطوات زاوية ثابتة)، ويتحمل تيارًا متواصلًا يصل إلى 2 A لكل قناة. لمزيد من المعلومات حول جسور H ووحدات قيادة المحركات، راجع شرحي عن جسر H المزدوج L298N ودرع المحركات Arduino Motor Shield.

منطق اتخاذ القرار
تقارن لوحة Arduino كل قراءة للمسافة بعتبتين. فعندما يكون الروبوت بعيدًا عن أي عائق، يسير بسرعة التجوال ويحرّك المستشعر للمسح. وعندما تقل المسافة عن العتبة البعيدة يُبطئ. وعندما تقل عن العتبة القريبة يتوقف، ويقيس المسافة إلى اليسار وإلى اليمين، ثم ينعطف نحو الجهة التي فيها مساحة أكبر. وإذا كانت الجهتان مسدودتين (طريق مسدود)، يرجع إلى الخلف أولًا ثم يعيد المسح.
المكونات (قائمة المواد)
| المكوّن | الكمية | مطلوب / اختياري | الغرض | ملاحظات |
|---|---|---|---|---|
| Arduino Uno | 1 | مطلوب | المتحكم الدقيق الرئيسي: يشغّل الكود | تصلح أي لوحة متوافقة مع Uno |
| Arduino Motor Shield Rev3 | 1 | مطلوب | يقود محركَي التيار المستمر ويتحكم فيهما | يُركَّب مباشرة فوق لوحة Arduino Uno |
| محركات تيار مستمر (من 3 إلى 6 V) | 2 | مطلوب | عجلتا الدفع اليسرى واليمنى | محركات تيار مستمر قياسية بعلبة تروس من فئة الهواة (علبة التروس المركبة على المحرك تخفض السرعة وترفع عزم الدوران، أي قوة الدوران) |
| محرك السيرفو (SG90) | 1 | مطلوب | يحرّك مستشعر الموجات فوق الصوتية يسارًا ويمينًا | يصلح أي سيرفو صغير من فئة الوزن 9 g |
| مستشعر الموجات فوق الصوتية (HC-SR04) | 1 | مطلوب | يقيس المسافة إلى العوائق | وحدة بـ 4 أطراف: VCC (تغذية 5 V)، وTrig، وEcho، وGND (الأرضي، 0 V) |
| أسلاك التوصيل (Jumper) | عدة | مطلوب | جميع التوصيلات الكهربائية بين المكونات | ذكر-ذكر وذكر-أنثى (الذكر = طرف بدبوس، الأنثى = طرف بمقبس) |
| خلايا AA قابلة لإعادة الشحن (NiMH، 1.2 V) | 8 | مطلوب | مزود الطاقة للمحركات وللوحة Arduino | NiMH اختصار لـ nickel-metal hydride (هيدريد النيكل المعدني). الجهد الاسمي: 8 × 1.2 V = 9.6 V. يقبل الدرع جهدًا من 5 إلى 12 V ويمرّره إلى لوحة Uno. |
| حاملات البطاريات (4 × AA) | 2 | مطلوب | تحمل الخلايا وتوصلها على التوالي | موصولة على التوالي للحصول على 9.6 V |
| مفتاح ذو ذراع (Toggle Switch) | 1 | مطلوب | مفتاح الطاقة الرئيسي | مفتاح بذراع يبقى في وضع التشغيل أو الإيقاف. يُركَّب في مسار السلك الموجب للبطارية. |
| هيكل الروبوت | 1 | مطلوب | إطار يحمل جميع المكونات | لوح أكريليك أو لوح مطبوع بطابعة ثلاثية الأبعاد |
| العجلات | 2 | مطلوب | تُركَّب على أعمدة محركات التيار المستمر | اختر ما يناسب مقاس عمود المحرك لديك |
| عجلة كروية (عجلة مساندة) | 1 | مطلوب | نقطة التلامس الثالثة مع الأرض | تصلح أيضًا عجلة دوّارة |
| البراغي والصواميل وفواصل التباعد | متنوعة | مطلوب | التجميع الميكانيكي | المقاس M3 (سن متري بقطر 3 mm) هو المقاس الشائع لتثبيت لوحات Arduino والهياكل |
| حوامل مطبوعة بطابعة ثلاثية الأبعاد | مجموعة | اختياري | حوامل للسيرفو ومستشعر الموجات فوق الصوتية ولوحة Arduino | يمكن استخدام الغراء الحراري أو الأربطة البلاستيكية أو الزوايا المعدنية بدلًا منها |
التجميع خطوة بخطوة
صمّمتُ الحوامل الثلاثة للوحة Arduino والسيرفو ومستشعر الموجات فوق الصوتية في Autodesk Inventor (برنامج تصميم 3D CAD)، ثم طبعتها على طابعة ثلاثية الأبعاد الخاصة بي.
الخطوة 1: ثبّت حاملات البطاريات
ثبّت حاملَي البطاريات (4 × AA) بالبراغي على الجهة السفلية أو الخلفية للهيكل. الحم الحاملين على التوالي (الطرف الموجب لأحدهما بالطرف السالب للآخر)، فتصبح الخلايا الـ 8 جميعها موصولة على التوالي بجهد اسمي 9.6 V. ويشكّل الحاملان مع خلاياهما حزمة البطاريات.
الخطوة 2: ركّب مفتاح التشغيل
الحم المفتاح ذا الذراع في السلك الموجب لحزمة البطاريات. وثبّته على الهيكل في مكان تصل إليه بسهولة لتطفئ الروبوت بسرعة.
الخطوة 3: ثبّت محركَي التيار المستمر
الحم سلكًا بكل طرف من طرفَي كل محرك. ثبّت محركًا على الجانب الأيسر للهيكل وآخر على الجانب الأيمن باستخدام البراغي والصواميل أو حوامل المحركات.
الخطوة 4: جهّز حامل Arduino
إذا كنت تستخدم حامل Arduino المطبوع بطابعة ثلاثية الأبعاد، فإنه يحتاج إلى حشوات نحاسية ملولبة (جُلَب نحاسية ذات سن داخلي). سخّن كل حشوة بكاوية اللحام واضغطها في ثقب التثبيت الخاص بها. وبذلك تحصل على أسنان لولبية متينة لتثبيت Arduino.
الخطوة 5: ثبّت لوحة Arduino والدرع
ثبّت الحامل المطبوع بطابعة ثلاثية الأبعاد (أو فواصل التباعد من قائمة القطع) على الهيكل بالبراغي، ثم ثبّت لوحة Arduino Uno على الحامل أو الفواصل. ركّب الدرع فوق لوحة Arduino، وتأكد من أن كل طرف من أطراف التوصيل يستقر في مقبسه قبل أن تضغطه إلى الأسفل.
الخطوة 6: ركّب محرك السيرفو
ثبّت حامل السيرفو المطبوع بطابعة ثلاثية الأبعاد في مقدمة الهيكل بشريط لاصق مزدوج الوجه أو بالبراغي، ثم ركّب السيرفو SG90 فيه. قبل تركيب ذراع السيرفو (Horn، وهو الذراع البلاستيكي على عمود السيرفو)، اضبط السيرفو على 90°. ارفع برنامجًا قصيرًا يحتوي على myservo.write(90)، أو أدِر العمود يدويًا إلى منتصف مداه. ركّب الذراع بحيث يتجه المستشعر إلى الأمام مباشرة. ويجب أن يدور الذراع بحرية من اليسار إلى اليمين.
الخطوة 7: ثبّت مستشعر الموجات فوق الصوتية
أدخِل المستشعر HC-SR04 في حامله المطبوع بطابعة ثلاثية الأبعاد (أو ثبّته بالغراء الحراري). ثبّت الحامل على ذراع السيرفو ببرغي صغير، حتى يدور المستشعر مع السيرفو.
الخطوة 8: ثبّت العجلة الكروية
ثبّت العجلة الكروية في مقدمة الهيكل أو مؤخرته، في الجهة المقابلة لمحركَي التيار المستمر. تمنح عجلتا الدفع والعجلة الكروية الروبوتَ تلامسًا ثابتًا مع الأرض في ثلاث نقاط.
الخطوة 9: ركّب عجلتَي الدفع
اضغط العجلتين على عمودَي المحركين في الجانبين. يجب أن تكونا مثبتتين بإحكام وأن تدورا دون أن تحتكا بالهيكل.
توصيلات السيارة الروبوتية

توصيلات محركات التيار المستمر
| المحرك | طرف التوصيل على الدرع |
|---|---|
| المحرك A (الأيسر)، السلك 1 | A− |
| المحرك A (الأيسر)، السلك 2 | A+ |
| المحرك B (الأيمن)، السلك 1 | B− |
| المحرك B (الأيمن)، السلك 2 | B+ |
توصيلات محرك السيرفو
| سلك السيرفو | يتصل بـ |
|---|---|
| الإشارة (برتقالي أو أصفر) | الطرف الرقمي 5 في Arduino (على أطراف توصيل الدرع) |
| VCC (أحمر) | الطرف 5 V على الدرع |
| GND (بني أو أسود) | الطرف GND على الدرع |
مهم: وصّل سلك الطاقة الخاص بالسيرفو بالطرف 5 V على الدرع، لا بالطرف 3.3 V. يحتاج السيرفو SG90 إلى 5 V؛ أما على 3.3 V فإنه يرتجف ويتحرك بضعف.
توصيلات مستشعر الموجات فوق الصوتية (HC-SR04)
| طرف HC-SR04 | يتصل بـ |
|---|---|
| VCC | 5 V على الدرع |
| Trig | الطرف الرقمي 7 في Arduino |
| Echo | الطرف الرقمي 6 في Arduino |
| GND | GND على الدرع |
توصيلات مزود الطاقة
| سلك البطارية أو المفتاح | يتصل بـ |
|---|---|
| الموجب (من مخرج المفتاح) | طرف الطاقة Vin على الدرع (+) |
| السالب (أرضي البطارية) | طرف الطاقة GND على الدرع (−) |
يمرّر الدرع جهد البطارية عبر وصلة Vin Connect (وصلة Jumper صغيرة على ظهر الدرع) إلى الطرف VIN في لوحة Uno. ويحوّله منظم الجهد الموجود على لوحة Uno إلى 5 V، فلا حاجة إلى كابل USB ما دامت حزمة البطاريات موصولة. وفي النسخة التي بنيتُها تبقى هذه الوصلة موصولة، فتتشارك لوحة Uno والمحركات حزمة البطاريات نفسها.
افحص جميع التوصيلات قبل تركيب الخلايا: عكس القطبية قد يتلف الدرع ولوحة Arduino. لا تضع الخلايا الـ 8 في الحاملات إلا بعد هذا الفحص، واترك المفتاح في وضع الإيقاف حتى يتم رفع البرنامج.
كود Arduino
يستخدم البرنامج مكتبة Servo (كود جاهز للتحكم في محركات السيرفو)، وهي مضمّنة مع Arduino IDE (البرنامج الذي تكتب فيه برامج Arduino وترفعها إلى اللوحة).
الإعداد وتعريف الأطراف
تعمل الدالة setup() مرة واحدة بعد تشغيل الطاقة: فهي تربط السيرفو بطرفه، وتضبط أوضاع الأطراف، وتفعّل الفرامل، وتعيد السيرفو إلى المنتصف.
/**
* Author: Omar Draidrya
* Date: 2024-06-09
* This code controls a robot with ultrasonic sensors and servo motors to avoid obstacles.
*/
#include <Servo.h>
// Create a Servo object to control the servo motor
Servo myservo;
int pos = 0; // Variable to store the servo position
// Define motor pins
int directionA = 12; // Pin for direction of Motor A
int speedA = 3; // Pin for speed of Motor A
int brakeA = 9; // Pin for brake of Motor A
int directionB = 13; // Pin for direction of Motor B
int speedB = 11; // Pin for speed of Motor B
int brakeB = 8; // Pin for brake of Motor B
// Define ultrasonic sensor pins
int trigger = 7; // Trigger pin
int echo = 6; // Echo pin
long duration = 0; // Variable to store the duration of the echo
long distance = 0; // Variable to store the distance from the obstacle
int currentAngle = 90; // Start with the sensor facing forward
int scanDirection = 1; // 1 for left, -1 for right
void setup() {
// Attach the servo on pin 5 to the servo object
myservo.attach(5);
// Set the trigger pin as OUTPUT and the echo pin as INPUT
pinMode(trigger, OUTPUT);
pinMode(echo, INPUT);
// Initialize Motor A pins
pinMode(directionA, OUTPUT);
pinMode(directionB, OUTPUT);
pinMode(brakeA, OUTPUT);
pinMode(brakeB, OUTPUT);
// Apply brakes (stop the motors)
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
// Set the servo to the center position initially
myservo.write(90);
delay(500);
}
الحلقة الرئيسية والدوال المساعدة
تعمل الدالة loop() مرارًا وتكرارًا بعد انتهاء setup().
void loop() {
// Measure the distance to the nearest obstacle
distance = measureDistance();
if (distance < 40) {
// Gradually reduce speed as the obstacle approaches
int speed = map(distance, 20, 40, 75, 128);
motorTurn(directionA, speedA, HIGH, speed);
motorTurn(directionB, speedB, HIGH, speed);
if (distance < 15) {
// Stop the motors
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
delay(500);
// Check surroundings
int leftDistance = checkDirection(175);
int rightDistance = checkDirection(5);
// Determine if the robot is in a dead end
if (leftDistance < 15 && rightDistance < 15) {
// Move backward
motorTurn(directionA, speedA, LOW, 128);
motorTurn(directionB, speedB, LOW, 128);
delay(500);
// Apply brakes
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
delay(500);
// Scan again after moving back
leftDistance = checkDirection(150);
rightDistance = checkDirection(30);
}
// Determine the best direction to turn
if (leftDistance > rightDistance) {
// Turn left
motorTurn(directionA, speedA, LOW, 128);
motorTurn(directionB, speedB, HIGH, 128);
} else {
// Turn right
motorTurn(directionA, speedA, HIGH, 128);
motorTurn(directionB, speedB, LOW, 128);
}
delay(500);
// Apply brakes
digitalWrite(brakeA, HIGH);
digitalWrite(brakeB, HIGH);
delay(500);
// Set the servo back to the center position
myservo.write(90);
delay(500);
}
} else {
// Move forward at a reduced speed
motorTurn(directionA, speedA, HIGH, 100);
motorTurn(directionB, speedB, HIGH, 100);
// Continuously scan left and right
currentAngle += scanDirection * 10;
if (currentAngle >= 150 || currentAngle <= 30) {
scanDirection = -scanDirection;
}
myservo.write(currentAngle);
delay(40); // Adjusted delay for more realistic servo movement
}
}
الدوال motorTurn() وmeasureDistance() وcheckDirection() هي الدوال المساعدة الثلاث التي تستدعيها loop().
// Function to set the direction and speed of motors
void motorTurn(int directionPin, int speedPin, int direction, int speed) {
digitalWrite(directionPin, direction);
analogWrite(speedPin, speed);
if (directionPin == directionA) {
digitalWrite(brakeA, LOW);
} else {
digitalWrite(brakeB, LOW);
}
}
// Function to measure the distance using the ultrasonic sensor
int measureDistance() {
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW);
duration = pulseIn(echo, HIGH);
distance = (duration / 2) / 29.1;
return distance;
}
// Function to check the distance in a specific direction
int checkDirection(int angle) {
myservo.write(angle);
delay(500); // Give the servo time to move
int measuredDistance = measureDistance();
return measuredDistance;
}
وظيفة كل جزء من البرنامج
تخصيص الأطراف
أطراف المحركات (12 و3 و9 للمحرك A، و13 و11 و8 للمحرك B) يحددها الدرع ولا يمكن تغييرها. أما الأطراف 7 (Trig) و6 (Echo) و5 (إشارة السيرفو) فهي أطراف حرة لا يستخدمها الدرع؛ ويمكنك نقلها إلى أطراف حرة أخرى إذا غيّرت أرقامها في الكود.
قياس المسافة
ترسل الدالة measureDistance() نبضة مدتها 10 µs على الطرف Trig (المتغير trigger في الكود) وتنتظر الصدى. ثم تحسب المسافة بالسنتيمتر وفق المعادلة distance = (duration / 2) / 29.1. والقسمة على 2 سببها أن الموجة الصوتية تقطع المسافة ذهابًا وإيابًا، أما 29.1 فهو العدد التقريبي من الميكروثواني الذي يحتاجه الصوت لقطع سنتيمتر واحد في الهواء.
التحكم في المحركات
تضبط الدالة motorTurn() اتجاه محرك واحد وسرعته. وHIGH وLOW هما مستويا الإشارة في الطرف الرقمي: HIGH يعني 5 V، وLOW يعني 0 V. تكتب motorTurn() القيمة HIGH (للأمام) أو LOW (للخلف) على طرف الاتجاه، وتضبط السرعة باستخدام analogWrite() (من 0 إلى 255)، ثم تحرر الفرامل. وكتابة HIGH على طرف الفرملة توقف ذلك المحرك بسرعة.
كيف يُبطئ الروبوت
تقيس loop() المسافة أمام الروبوت في كل دورة، وتستجيب على مراحل:
- أكثر من 40 cm (العتبة البعيدة): يسير الروبوت إلى الأمام بقيمة PWM 100 ويحرّك المستشعر للمسح.
- من 40 cm إلى 20 cm: يُبطئ الروبوت بما يتناسب مع المسافة. تحوّل الدالة map() رقمًا من نطاق إلى نطاق آخر؛ وهنا تحوّل map(distance, 20, 40, 75, 128) المسافة إلى قيمة PWM تساوي 128 عند 40 cm و75 عند 20 cm. ولأن 128 أعلى من سرعة التجوال البالغة 100، يتسارع الروبوت لفترة قصيرة عندما يعبر حد 40 cm. وللحصول على تباطؤ منتظم، غيّر 128 في map() إلى 100.
- من 20 cm إلى 15 cm: لا تقيّد map() ناتجها ضمن النطاق، لذلك تستمر السرعة في الانخفاض إلى ما دون 75 وتصل إلى نحو 62 عند 15 cm.
- أقل من 15 cm (العتبة القريبة): يتوقف الروبوت ويمسح محيطه.
منطق المسح
عندما تنخفض المسافة إلى أقل من 15 cm، يفرمل الروبوت المحركين وينتظر 500 ms. ثم يستدعي checkDirection(175) للنظر إلى اليسار وcheckDirection(5) للنظر إلى اليمين. تدير الدالة checkDirection() السيرفو إلى الزاوية المحددة، وتنتظر 500 ms حتى يصل إليها، ثم تأخذ قراءة واحدة للمسافة وتعيدها. ينعطف الروبوت نحو الجهة ذات المسافة الأكبر: محرك إلى الأمام والآخر إلى الخلف، بقيمة PWM 128 لمدة 500 ms. وبعد الانعطاف يفرمل، وينتظر 500 ms، ويعيد السيرفو إلى المنتصف عند 90°.
سلوك الرجوع للخلف عند الطريق المسدود
إذا كانت المسافتان اليسرى واليمنى كلتاهما أقل من 15 cm، فالروبوت في طريق مسدود. فيرجع إلى الخلف لمدة 500 ms بقيمة PWM 128، ثم يفرمل لمدة 500 ms، ويعيد المسح عند 150° (يسارًا) و30° (يمينًا). ثم يقارن القراءتين الجديدتين وينعطف نحو الجهة التي فيها مساحة أكبر، كما يفعل بعد المسح الأول.
مسح السيرفو أثناء السير
عندما تتوفر مساحة خالية تزيد على 40 cm، يسير الروبوت بقيمة PWM 100. ويحرّك السيرفو المستشعر بين 30° و150° بخطوات مقدارها 10°، مع توقف مدته 40 ms عند كل خطوة. وبهذا المسح يكتشف الروبوت أيضًا العوائق الموجودة على يسار المسار ويمينه. وينعكس اتجاه المسح في كل مرة يصل فيها السيرفو إلى 30° أو 150°.
الرفع والاختبار والمراقبة
- وصّل لوحة Arduino بحاسوبك بكابل USB وافتح Arduino IDE.
- اختر Tools > Board > Arduino Uno، ثم اختر منفذ لوحتك من Tools > Port.
- ارفع البرنامج (Sketch) إلى اللوحة.
- افصل كابل USB، وضع الروبوت على الأرض بحيث تكون أمامه مساحة خالية، ثم شغّل الطاقة. يبدأ الروبوت بالسير بعد نحو نصف ثانية من التشغيل.
يجب أن يسير الروبوت إلى الأمام، ويُبطئ عند اقترابه من عائق، ثم يتوقف، ويمسح يسارًا ويمينًا، وينعطف نحو الجهة الأكثر خلوًّا. وإذا دارت إحدى العجلات إلى الخلف أو انعطف الروبوت إلى الجهة الخاطئة، فستجد الحل في جدول استكشاف الأخطاء وإصلاحها.
كيفية ضبط الروبوت
عدّل هذه القيم في الكود لتناسب محركاتك ونوع الأرضية. القيم مكتوبة داخل loop() كأرقام صريحة. ابحث في البرنامج عن 40 و20 و15 و100 و128 و500 لتغييرها. تظهر العتبة البعيدة 40 مرتين: في if (distance < 40) وفي map().
| المعامل | القيمة الافتراضية | ما تتحكم فيه | نصيحة للضبط |
|---|---|---|---|
| العتبة البعيدة | 40 cm | المسافة التي يبدأ الروبوت دونها بالإبطاء | زِدها إذا فرمل الروبوت متأخرًا جدًا؛ وقلّلها إذا أبطأ مبكرًا جدًا |
| نهاية الإبطاء | 20 cm | المسافة التي تبلغ عندها map() سرعتها الدنيا 75 (PWM) | تظهر فقط في map(distance, 20, 40, 75, 128) |
| العتبة القريبة | 15 cm | المسافة التي يتوقف عندها الروبوت ويمسح محيطه | زِدها إذا اصطدم الروبوت قبل أن يتوقف؛ وقلّلها لتنقّل أدق في المساحات الضيقة |
| سرعة التقدم للأمام | 100 (PWM) | سرعة التجوال عندما يكون المسار خاليًا | النطاق من 0 إلى 255. القيمة الأعلى أسرع لكن يصعب معها التوقف في الوقت المناسب |
| سرعة الانعطاف | 128 (PWM) | السرعة أثناء الانعطاف يسارًا ويمينًا وأثناء الرجوع للخلف | زِدها إذا لم يُكمل الروبوت الانعطاف؛ وقلّلها على الأرضيات الزلقة |
| مدة الانعطاف | 500 ms | المدة التي ينعطف فيها الروبوت قبل أن يتوقف | زِدها للحصول على انعطافات أوسع؛ وقلّلها للتصحيحات الصغيرة |
| مدة الرجوع للخلف | 500 ms | المدة التي يرجع فيها الروبوت للخلف في الطريق المسدود | زِدها إذا لم يرجع الروبوت إلى الخلف مسافة كافية |
| نطاق مسح السيرفو | من 30° إلى 150° | نطاق المسح أثناء التقدم للأمام | نطاق أوسع: كشف أفضل للجانبين لكن المسح يصبح أبطأ |
| خطوة مسح السيرفو | 10° | مقدار تغيّر الزاوية في كل دورة من الحلقة | قيمة أصغر: مسح أكثر سلاسة لكن تغطية أبطأ |
| زمن التأخير في مسح السيرفو | 40 ms | التوقف بين خطوات السيرفو، وبالتالي بين قراءتين للمسافة | القيم الأقل تجعل المسح أسرع لكنها تترك وقتًا أقل بين القراءات. زِدها إذا كان السيرفو يرتجف؛ واستخدم 60 ms إذا كانت القراءات متذبذبة (راجع قسم استكشاف الأخطاء وإصلاحها) |
استكشاف الأخطاء وإصلاحها
| المشكلة | السبب المحتمل | الحل |
|---|---|---|
| الروبوت لا يتحرك إطلاقًا | انعدام التغذية بالطاقة، أو توصيلات مرتخية، أو عدم تحرير الفرامل | تحقق من مفتاح التشغيل ومن جهد البطارية (9.6 V اسميًا، ونحو 10.5 إلى 11 V مع خلايا مشحونة حديثًا). تحقق من توصيلات أطراف المحركات ومن أن برنامج Arduino (Sketch) يُرفع إلى اللوحة دون أخطاء. |
| يعمل محرك واحد فقط | أحد المحركين غير موصول، أو يوجد سلك مقطوع | وصّل المحرك السليم بأطراف المحرك الآخر لاختبار تلك القناة. افحص نقاط اللحام على المحرك. |
| إحدى العجلتين تدور إلى الخلف (يدور الروبوت حول نفسه أو ينحرف بدلًا من السير في خط مستقيم) | أسلاك المحرك معكوسة | بدّل بين سلكي ذلك المحرك (A+ وA−، أو B+ وB−). |
| ينعطف الروبوت يمينًا بينما يجب أن ينعطف يسارًا | المحرك A والمحرك B مُبدَّلان | بدّل بين توصيلات المحرك A والمحرك B على الدرع. |
| مستشعر الموجات فوق الصوتية يعطي قراءات غير مستقرة أو صفرية | توصيلات مرتخية، أو أطراف خاطئة، أو جسم قريب جدًا أو بعيد جدًا | تحقق من Trig (الطرف 7) وEcho (الطرف 6). يتراوح مدى HC-SR04 بين نحو 2 cm و400 cm. انتظر 60 ms على الأقل بين قياسين متتاليين حتى يتلاشى الصدى السابق. لا يتوقف المسح سوى 40 ms في كل خطوة، لذا زِد قيمة delay(40) في loop() إلى 60. لرؤية القراءات، أضف Serial.begin(9600); إلى setup() وSerial.println(distance); إلى loop()، ثم افتح الشاشة التسلسلية Serial Monitor (النافذة في Arduino IDE التي تعرض النص الذي ترسله اللوحة عبر USB). |
| السيرفو يهتز أو يرتعش | السيرفو موصول بـ 3.3 V، أو مزود طاقة ضعيف، أو مزود 5 V غير مستقر | وصّل VCC الخاص بالسيرفو بـ 5 V، وليس بـ 3.3 V. أضف مكثفًا كهروليتيًا سعته 100 µF (مكثف له ساق موجبة وساق سالبة، ويخفف الانخفاضات القصيرة في الجهد) بين خطي تغذية السيرفو، على أن تكون الساق المخططة (السالبة) على GND. |
| يستجيب الروبوت متأخرًا ويصطدم بالعوائق | قيم العتبة منخفضة جدًا، أو فترات التأخير في الحلقة طويلة جدًا | ارفع عتبة المسافة القريبة (مثلًا من 15 cm إلى 20 cm) حتى يتوقف الروبوت في وقت أبكر، أو عتبة المسافة البعيدة (مثلًا من 40 cm إلى 50 cm) حتى يخفض سرعته في وقت أبكر. قصّر فترات التأخير في الحلقة. |
| حزمة البطاريات تفرغ بسرعة | المحركات تسحب تيارًا عاليًا، أو الخلايا غير مشحونة بالكامل | استخدم خلايا NiMH مشحونة حديثًا. خفّض سرعة المحركات. تحقق من أن العجلات تدور دون احتكاك. |
| يُعاد تشغيل Arduino عند بدء دوران المحركات | انخفاض الجهد بسبب تيار المحركات | أضف مكثفًا كهروليتيًا سعته من 470 إلى 1000 µF (بجهد مقنن 16 V أو أكثر) بين طرفي التغذية في الدرع، على أن تكون الساق المخططة (السالبة) على GND. إذا استمرت إعادة التشغيل، فاقطع وصلة Vin Connect على ظهر الدرع، ليحصل الدرع ولوحة Uno على مصدري تغذية منفصلين. غذِّ لوحة Uno من بطارية خاصة بها عبر مقبس DC (مقبس الطاقة الدائري في Uno). |
الأسئلة الشائعة
يُركَّب Arduino Motor Shield Rev3 على أطراف التوصيل في Arduino Uno، ويناسب أيضًا Arduino Mega، لكنه لا يناسب Nano. مع Nano، استخدم وحدة L298N بدلًا منه؛ راجع ما كتبته في شرح وحدة قيادة المحركات L298N.
نعم. تستخدم وحدة L298N عائلة شرائح القيادة نفسها التي يستخدمها الدرع (نحو 2 A لكل قناة)، لكنها لوحة منفصلة. توصلها بأسلاك التوصيل (Jumper) وتغيّر أرقام الأطراف في الكود. يشرح درسي عن وحدة قيادة المحركات L298N الخيارين كليهما.
يستخدم هذا المشروع 8 خلايا NiMH بحجم AA موصولة على التوالي: 8 × 1.2 V = 9.6 V اسميًا. يقبل الدرع من 5 إلى 12 V على طرفي التغذية، وينقل هذا الجهد إلى الطرف VIN في Uno. تعمل أيضًا بطارية LiPo من نوع 2S (خليتان من الليثيوم بوليمر على التوالي، 7.4 V اسميًا و8.4 V عند الشحن الكامل). أما بطارية LiPo من نوع 3S فتصل إلى 12.6 V عند امتلائها، وهذا أعلى من الحد الأقصى للدرع البالغ 12 V.
توسعات ممكنة
- أضف التحكم عبر بلوتوث أو واي فاي (Wi-Fi): اجمع بين تجنب العوائق والتحكم عن بُعد عبر وحدة بلوتوث HC-05 أو وحدة واي فاي ESP8266. يوضح مشروعي سيارة روبوتية يُتحكَّم بها عبر البلوتوث كيفية توصيل وحدة HC-05 وبرمجتها. تُدار محركات تلك السيارة بواسطة Adafruit Motor Shield V1.2؛ وتتصل وحدة HC-05 فيها بالطرفين 0 و1، وهما طرفان يتركهما Arduino Motor Shield Rev3 حرّين.
- أضف وضع تتبع الخط: تكتشف مستشعرات الأشعة تحت الحمراء (IR) خطًا أسود على الأرض، وينتقل الروبوت بين تتبع الخط وتجنب العوائق.
- انتقل إلى هيكل 4WD (أربع عجلات دافعة): لا يحتوي الدرع إلا على قناتين، لذا وصّل محركي كل جانب على التوازي بقناة واحدة. أبقِ التيار في كل قناة دون 2 A.
في سيارة روبوتية لاحقة، استبدلت المستشعر الوحيد المركّب على السيرفو بأربعة مستشعرات HC-SR04 ثابتة، واحد على كل جانب، وبلوحة Arduino Mega. وهذا المشروع هو سيارتي الروبوتية المتقدمة ذاتية القيادة والمتحكم بها عبر بلوتوث.

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