بناء روبوت تتبع الخط باستخدام مستشعر الألوان TCS34725 RGB

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

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

ملخص سريع

يستخدم روبوت تتبع الخط هذا لوحة Arduino Uno ومستشعر الألوان TCS34725 RGB ودرع المحركات Arduino Motor Shield Rev3. في كل مرة يبدأ فيها التشغيل، يقيس الروبوت بنفسه الشريط الأبيض والسطح الداكن. بعد ذلك يوجّهه متحكم PID على طول حافة الشريط، ويصحّح التوجيه بقدرٍ يتناسب مع مدى ابتعاد المستشعر عن الحافة. يتضمن المقال مخطط التوصيل وكود Arduino الكامل وخطوات ضبط PID.

يعتمد هذا المشروع على روبوت تتبع الخط KY-033. كان روبوتي KY-033 يتبع الخط، لكنه لم يسر بسلاسة قط، وظل يتأرجح من جانب إلى آخر طوال الوقت. يستبدل هذا الإصدار مستشعرات الأشعة تحت الحمراء KY-033 بمستشعر TCS34725 واحد، ويستبدل التوجيه بأسلوب التشغيل والإيقاف (on/off) بمتحكم PID. يتبع الروبوت الجديد الخط بسلاسة أكبر، حتى في المنعطفات الأضيق.

كيف يعمل الروبوت

تقرأ لوحة Arduino Uno المستشعر، وتُجري حساب PID، وترسل أمر سرعة إلى كل محرك. أما درع المحركات Arduino Motor Shield Rev3، وهو لوحة توسعة تُركَّب فوق لوحة Uno، فيقود محركَي التيار المستمر (DC) الاثنين. يُثبَّت مستشعر TCS34725 على الجانب السفلي من الهيكل ويتجه نحو المسار. يقيس المستشعر الضوء في أربع قنوات (الأحمر والأخضر والأزرق وClear، أي القناة غير المرشَّحة). لا يستخدم برنامج Arduino (Sketch) إلا قناة Clear، وهي قيمة سطوع تميّز الشريط الأبيض عن السطح الداكن. يعمل الروبوت بحلقة تحكم مغلقة: تذهب قراءة المستشعر إلى متحكم PID، فيضبط المتحكم سرعات المحركات، ثم يغيّر الموضع الجديد للروبوت القراءة التالية.

المكونات المطلوبة (قائمة المواد)

إذا كنت قد بنيت روبوت KY-033 من قبل، فيمكنك إعادة استخدام الهيكل والفواصل المطبوعة والمحركات والعجلات ولوحة Arduino ودرع المحركات. ركّبتُ مستشعر TCS34725 على الروبوت نفسه، لذا فإن الوحدة هي القطعة الجديدة الوحيدة.

المكوّنالكميةمطلوب / اختياريملاحظات
الهيكل1مطلوبمطبوع بطابعة ثلاثية الأبعاد (الخطوة 1) من جزأين، لوح القاعدة والغطاء؛ من بلاستيك PLA أو ABS
فاصل المستشعر1 لكل ثقب تثبيتمطلوبمطبوع بطابعة ثلاثية الأبعاد (الخطوة 1)، بعرض 7 mm وارتفاع 13.5 mm
فاصل Arduino4مطلوبمطبوع بطابعة ثلاثية الأبعاد (الخطوة 1)، بارتفاع 14 mm، فاصل واحد لكل ثقب تثبيت في لوحة Uno
محرك تيار مستمر بعلبة تروس2مطلوبمحركات TT صفراء بعلبة تروس، وهي النوع الشائع منخفض التكلفة للروبوتات الصغيرة
العجلات2مطلوبيجب أن تناسب أعمدة محركات TT
عجلة حرة الدوران (Caster)1مطلوبعجلة كروية حرة أو عجلة دوّارة في المقدمة
Arduino Uno1مطلوبتشغّل برنامج Arduino (Sketch)
Arduino Motor Shield Rev31مطلوبيُركَّب فوق لوحة Uno ويقود المحركين كليهما
مستشعر الألوان TCS34725 RGB1مطلوبيقرأ سطوع المسار أسفل الروبوت
أسلاك التوصيل (Jumper)عدةمطلوبذكر-أنثى وذكر-ذكر
براغي M3 وحشوات ملولبةحسب الحاجةمطلوبلتثبيت المحركات والفواصل على الهيكل. الحشوات الملولبة جُلَب معدنية ذات سنّ داخلي تستقر في الثقوب المطبوعة.
البطارية1مطلوببطارية LiPo (ليثيوم بوليمر) بجهد 7.4 V من خليتين (2S)؛ تغذّي المحركات ولوحة Arduino عبر الدرع
مفتاح الطاقة1اختيارييطفئ الروبوت بين الاختبارات

الخطوة 1: تصميم الروبوت في Autodesk Inventor

صمّمتُ القطع في برنامج التصميم ثلاثي الأبعاد (3D) Autodesk Inventor: الهيكل (لوح قاعدة وغطاء)، وفواصل المستشعر، وفواصل Arduino. يحمل الهيكل المحركات والمستشعر ولوحة Arduino مع درعها والبطارية. يبلغ عرض كل فاصل من فواصل المستشعر 7 mm وارتفاعه 13.5 mm. تثبّت فواصل المستشعر المستشعرَ في الجهة الأمامية السفلية على ارتفاع من 10 إلى 15 mm فوق الأرض؛ وتفترض خطوات المعايرة واستكشاف الأخطاء وإصلاحها هذا الارتفاع. أما فواصل Arduino الأربعة فارتفاعها 14 mm، وهي تحمل لوحة Uno.

الخطوة 2: طباعة المكونات بطابعة ثلاثية الأبعاد

طبعتُ القطع على طابعة Creality Ender 3. تصلح أي طابعة FDM (النمذجة بالترسيب المنصهر)؛ فهي تبني القطع طبقةً فوق طبقة من خيط بلاستيكي مصهور. بعد الطباعة، أزل الدعامات، وصنفر الحواف الخشنة، وتأكد من أن ثقوب البراغي والفتحات مناسبة قبل التجميع.

الخطوة 3: تجميع الروبوت

3D rendering of the robot: blue body with an orange top and bottom, the power switch and the OmArTronics lettering on top, two wheels with orange rims.

تركيب المحركات والعجلات

  1. ثبّت محركَي التيار المستمر على الهيكل باستخدام براغي M3 والحشوات الملولبة، بحيث تتجه أعمدة المحركات إلى الخارج. سخّنتُ الحشوات مسبقًا وضغطتها داخل الثقوب المطبوعة.
  2. اضغط العجلات على أعمدة المحركات، وتأكد من أن كلتيهما تدوران بحرية دون ملامسة الهيكل.
  3. ركّب العجلة الحرة في المقدمة. مع عجلتَي القيادة، يرتكز الروبوت على ثلاث نقاط.

تركيب الإلكترونيات

  1. ثبّت فواصل Arduino الأربعة على الهيكل، وركّب لوحة Arduino Uno عليها.
  2. ركّب درع المحركات Arduino Motor Shield Rev3 فوق لوحة Uno، وتأكد من أن جميع أطراف التوصيل (الأطراف الموجودة أسفل الدرع) تتطابق مع مقابس لوحة Uno.
  3. ركّب وحدة TCS34725 على فواصل المستشعر في الجهة الأمامية السفلية من الهيكل، بحيث يتجه المستشعر نحو المسار.
  4. ثبّت البطارية على الهيكل؛ استخدمتُ أربطة الكابلات. لا توصّلها إلا بعد اكتمال التوصيلات في الخطوة 4. ثبّت جميع القطع جيدًا حتى لا يرتخي أي شيء أثناء سير الروبوت.

الخطوة 4: توصيل المكونات

يتصل المستشعر عبر I2C، وهو ناقل بسلكين: يحمل SDA البيانات، ويحمل SCL إشارة الساعة. تعمل المحركات عبر درع المحركات (Motor Shield). يعرض مخطط التوصيل الدائرة كاملة مع بطارية 9 V؛ أما روبوتي فيعمل بدلًا منها ببطارية LiPo بجهد 7.4 V.

Wiring diagram: Motor Shield Rev3 on the Arduino Uno, two DC motors on the motor terminals, a 9 V battery and a power switch on the power input, and the TCS34725 sensor on 5 V, GND, A4 and A5.

توصيلات المحركات

توصَّل محركات التيار المستمر بأطراف المحركات في الدرع. يحدد الدرع اتجاه كل محرك عبر طرف اتجاه، وسرعته عبر طرف PWM (تعديل عرض النبضة) . يشغّل PWM الطرف ويطفئه بسرعة كبيرة؛ ونسبة زمن التشغيل هي التي تحدد السرعة.

المحركطرف التوصيل على الدرعطرف الاتجاهطرف PWM (السرعة)
المحرك الأيسر (Motor A)المحرك Aالطرف الرقمي 12 (DIR_A)الطرف الرقمي 3 (PWM_A)
المحرك الأيمن (Motor B)المحرك Bالطرف الرقمي 13 (DIR_B)الطرف الرقمي 11 (PWM_B)

توصيلات المستشعر (I2C)

طرف TCS34725طرف Arduinoملاحظات
VIN5 Vتغذية المستشعر بالطاقة
GNDGNDأرضي مشترك
SDAA4 (SDA)خط بيانات I2C
SCLA5 (SCL)خط ساعة I2C

توصيلات الطاقة

المكوّنالتوصيلملاحظات
البطارية (LiPo بجهد 7.4 V)مدخل الطاقة الخارجية لدرع المحركات (Motor Shield)تغذّي المحركين كليهما ولوحة Arduino عبر الدرع
مفتاح الطاقة (اختياري)على التوالي مع السلك الموجب للبطاريةيطفئ الروبوت دون فصل البطارية

الخطوة 5: فهم تحكم PID في هذا الروبوت

PID اختصار لـ Proportional-Integral-Derivative (تناسبي-تكاملي-تفاضلي). كان روبوت KY-033 يُبقي الشريط بين مستشعرَيه الاثنين. واستخدم تحكمًا من نوع bang-bang (إما السير إلى الأمام مباشرة أو انعطاف ثابت يكاد يكون في المكان نفسه، ولا شيء بينهما)، لذلك كان يتعرّج على طول الخط. أما هذا الروبوت فيستخدم قيمة قناة Clear، ويوجّه نفسه بقدرٍ يتناسب مع المسافة بين القراءة والعتبة (middleValue).

PID control loop of the robot: setpoint (middleValue), error, PID correction, motors, and the sensor reading fed back.

ماذا يعني الخطأ ونقطة الضبط والتصحيح في هذا الروبوت

  • نقطة الضبط: القيمة المستهدفة للمتحكم. وهي هنا middleValue، أي متوسط قراءتَي المعايرة، وهي تمثل الحد الفاصل بين الشريط الأبيض والسطح الداكن.
  • متغير العملية: القيمة المقيسة، وهي هنا القراءة الحالية لقناة Clear c.
  • الخطأ: middleValue - c. فوق السطح الداكن تكون قيمة c منخفضة ويكون الخطأ موجبًا: أي أن المستشعر انحرف يسارًا عن الشريط. وفوق الشريط الأبيض تكون قيمة c مرتفعة ويكون الخطأ سالبًا. يعيد التصحيح توجيه الروبوت نحو الحد الفاصل، فيتبع الحافة اليسرى للشريط.
  • التصحيح: خرج متحكم PID. يُضاف إلى سرعة المحرك الأيسر ويُطرح من سرعة المحرك الأيمن. هذا هو التوجيه التفاضلي (Differential steering): ينعطف الروبوت لأن إحدى العجلتين تدور أسرع من الأخرى.

مكونات PID الثلاثة

التناسبي (P): يستجيب للخطأ الحالي. يضرب هذا الحد الخطأ الحالي في معامل الكسب Kp. إذا انحرف المستشعر عن حافة الشريط، يُنتج الحد P تصحيحًا يتناسب مع المسافة. وقيمة Kp الأكبر تُسرّع الاستجابة، لكنها تسبب تجاوز الهدف (Overshoot) والتذبذب إذا كانت مرتفعة جدًا. المعادلة: P = Kp * error.

التكاملي (I): يجمع الخطأ عبر الزمن. يجمع هذا الحد خطأ كل دورة ويضرب المجموع في Ki. يزيل التكامل الانحراف الثابت، الناتج مثلًا عن محرك أبطأ من الآخر أو عن مسار غير متماثل. يحصر الكود هذا المجموع ضمن ±4 حتى لا يكبر إلى حدٍّ يجعله يواصل التوجيه بعد زوال الخطأ (تشبّع التكامل، Integral windup). المعادلة: I = Ki * sumError.

التفاضلي (D): يستجيب لسرعة تغيّر الخطأ. يضرب هذا الحد تغيّر الخطأ منذ الدورة السابقة في Kd. وهو يُخمد الحركة: إذا تأرجح الروبوت نحو الشريط بسرعة، يقلل الحد D التصحيح ويحدّ من التجاوز. توضح الخطوة 8 متى ترفع قيمة Kd. المعادلة: D = Kd * (error - previousError).

معادلة PID المجمّعة

يجمع برنامج Arduino الحدود الثلاثة: correction = Kp * error + Ki * sumError + Kd * (error - previousError). ثم يغيّر التصحيح سرعات المحركات: speedLeft = baseSpeed + correction و speedRight = baseSpeed - correction.

عندما يكون الخطأ صفرًا (أي أن المستشعر يقع تمامًا على العتبة)، يدور المحركان كلاهما بسرعة baseSpeed ويسير الروبوت في خط مستقيم. وعندما يكون الخطأ موجبًا أو سالبًا، يدور أحد المحركين أسرع والآخر أبطأ، فيعود الروبوت نحو حافة الشريط.

مع قراءاتي من الخطوة 7 (نحو 2 فوق السطح الداكن و8 فوق الشريط الأبيض)، تبلغ قيمة middleValue 5، ويتراوح الخطأ من -3 إلى +3. عندئذٍ يصل الحد P إلى Kp × 3 = 24 × 3 = 72. ويبقى الحد I ضمن ±4 (Ki = 1.0 مضروبًا في الحد sumError)، ويبقى الحد D ضمن ±6. يتولى الحد P معظم التوجيه.

الخطوة 6: برمجة الروبوت (كود Arduino)

ارفع برنامج Arduino أدناه إلى لوحة Uno باستخدام Arduino IDE، وهو برنامج البرمجة الخاص بـ Arduino. قبل الرفع، ثبّت مكتبة Adafruit TCS34725 (كود جاهز يتواصل مع المستشعر): افتح مدير المكتبات (Library Manager) في Arduino IDE وابحث عن “Adafruit TCS34725”. الكود نفسه موجود في مستودع GitHub.

برنامج Arduino الكامل (Sketch)

/**
 * Author: Omar Draidrya
 * Date: 2024/12/06
 * Line-Following Robot with TCS34725.
 */
#include <Wire.h>
#include <Adafruit_TCS34725.h>
// Initialize TCS34725 sensor
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_2_4MS, TCS34725_GAIN_4X);
// Motor control pins
#define DIR_A 12
#define DIR_B 13
#define PWM_A 3
#define PWM_B 11
// PID parameters
float Kp = 24.0;  // Proportional gain
float Ki = 1.0;   // Integral gain
float Kd = 1.0;   // Derivative gain
int baseSpeed = 60;  // Base speed
// Middle value for black/white
int middleValue = 3; // Adjusted based on measured values
// Global variables for PID
float error = 0, previousError = 0, sumError = 0;
void setup() {
  Serial.begin(9600);
  // Initialize TCS34725 sensor
  if (!tcs.begin()) {
    Serial.println("Error: TCS34725 not detected. Check wiring!");
    while (1);
  }
  Serial.println("TCS34725 sensor detected!");
  // Configure motor control pins
  pinMode(DIR_A, OUTPUT);
  pinMode(DIR_B, OUTPUT);
  pinMode(PWM_A, OUTPUT);
  pinMode(PWM_B, OUTPUT);
  // Perform sensor calibration
  calibrateSensor();
}
void loop() {
  uint16_t r, g, b, c;
  tcs.getRawData(&r, &g, &b, &c);
  // Calculate error
  error = middleValue - (float)c ;
  // PID calculation
  sumError += error;
  sumError = constrain(sumError, -4, 4); // Limit integral component
  if (abs(error) < 2.0) {
    sumError = 0; // Reset for small errors
  }
  float differential = error - previousError;
  float correction = Kp * error + Ki * sumError + Kd * differential;
  previousError = error;
  // Adjust motor speeds
  int speedLeft = baseSpeed + (int)correction;
  int speedRight = baseSpeed - (int)correction;
  speedLeft = constrain(speedLeft, 20, 255);
  speedRight = constrain(speedRight, 20, 255);
  controlMotors(speedLeft, speedRight);
}
void calibrateSensor() {
  uint16_t r, g, b, c;
  // Measure black value
  Serial.println("Calibrating: Measuring black value...");
  controlMotors(-85, 85); // Slightly turn left
  delay(350);
   // Stop motors after calibration
  controlMotors(0, 0);
  delay(50);
  tcs.getRawData(&r, &g, &b, &c);
  int blackValue = c;
  Serial.print("Black Value: ");
  Serial.println(blackValue);
  // Measure white value
  Serial.println("Calibrating: Measuring white value...");
  controlMotors(85, -85); // Slightly turn right
  delay(500);
    // Stop motors after calibration
  controlMotors(0, 0);
  delay(50);
  tcs.getRawData(&r, &g, &b, &c);
  int whiteValue = c;
  Serial.print("White Value: ");
  Serial.println(whiteValue);
  // Calculate middle value
  middleValue = (blackValue + whiteValue) / 2;
  Serial.print("Middle Value: ");
  Serial.println(middleValue);
  // Stop motors after calibration
  controlMotors(0, 0);
}
void controlMotors(int speedLeft, int speedRight) {
  if (speedLeft >= 0) {
    digitalWrite(DIR_A, HIGH);
  } else {
    digitalWrite(DIR_A, LOW);
    speedLeft = abs(speedLeft);
  }
  if (speedRight >= 0) {
    digitalWrite(DIR_B, HIGH);
  } else {
    digitalWrite(DIR_B, LOW);
    speedRight = abs(speedRight);
  }
  analogWrite(PWM_A, speedLeft);
  analogWrite(PWM_B, speedRight);
}

تهيئة المستشعر

Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_2_4MS, TCS34725_GAIN_4X);

زمن التكامل (Integration time) هو المدة التي يجمع فيها المستشعر الضوء لقراءة واحدة. عند 2.4 ms يقدّم المستشعر قيمة جديدة كل بضعة أجزاء من الألف من الثانية، فيستجيب الروبوت بسرعة للخط. ويضخّم الكسب 4× الإشارة دون أن يدفع المستشعر إلى قيمته القصوى (التشبّع) فوق الشريط الأبيض. إذا كانت قراءاتك منخفضة جدًا أو مرتفعة جدًا، فجرّب إعداد كسب آخر (1× أو 4× أو 16× أو 60×).

تعريفات أطراف المحركات

#define DIR_A 12
#define DIR_B 13
#define PWM_A 3
#define PWM_B 11

تتوافق هذه الأطراف مع درع المحركات Arduino Motor Shield Rev3. DIR_A و DIR_B يحددان اتجاه كل محرك (HIGH للأمام، وLOW للخلف). PWM_A و PWM_B يحددان السرعة، من 0 (متوقف) إلى 255 (السرعة القصوى). يغيّر تصحيح PID قيمتَي PWM هاتين كلًّا على حدة، وبذلك يوجّه الروبوت.

إجراء المعايرة

void calibrateSensor() {
  // Measures the light intensity for black and white areas.
  // Calculates the middle value (threshold) as the average of the two.
}

calibrateSensor() تعمل مرة واحدة عند بدء التشغيل. فهي تقيس السطح الداكن والشريط الأبيض، وتضبط قيمة middleValue على متوسط القراءتين. تشرح الخطوة 7 وضعية البدء وكل خطوة من خطوات المعايرة.

الحلقة الرئيسية وحساب الخطأ

void loop() {
  uint16_t r, g, b, c;
  tcs.getRawData(&r, &g, &b, &c);
  // Reads the light intensity from the sensor.
  // Calculates error and adjusts motor speeds using PID control.
}

تقرأ كل دورة القنوات الأربع جميعها، لكنها لا تستخدم إلا قيمة Clear c. والخطأ هو middleValue - c؛ وتشرح الخطوة 5 إشارته. ويدخل هذا الخطأ بإشارته في حساب PID.

حساب تصحيح PID

float correction = Kp * error + Ki * sumError + Kd * differential;

هذا السطر هو جوهر المتحكم، فهو يجمع الحدود الثلاثة في قيمة تصحيح واحدة. يحتفظ المتغير differential بتغيّر الخطأ منذ الدورة السابقة (error - previousError). sumError يُحصر ضمن ±4 (الخطوة 5)، ويُعاد ضبطه إلى الصفر عندما يقع الخطأ بين -2.0 و+2.0، حتى لا يتراكم أي تصحيح بينما الروبوت على حافة الشريط أصلًا.

تحديد السرعة

بعد التصحيح، تُحصر سرعتا المحركين كلتاهما في المجال من 20 إلى 255 باستخدام constrain(). تحت 20 قد لا تدور المحركات إطلاقًا بسبب الاحتكاك. أما 255 فهي القيمة القصوى لـ PWM.

دالة التحكم في المحركات

void controlMotors(int speedLeft, int speedRight) {
  // Adjusts motor direction and speed based on the calculated correction.
}

controlMotors() تستقبل سرعة ذات إشارة لكل محرك. القيم الموجبة تحرّك الروبوت إلى الأمام، والقيم السالبة تحرّكه إلى الخلف، وهذا ما تستخدمه دورانات المعايرة. تضبط الدالة طرف الاتجاه (HIGH أو LOW)، وتكتب القيمة المطلقة للسرعة على طرف PWM. وتتولى الدالة نفسها القيادة والتوجيه ودوران المعايرة.

الخطوة 7: المعايرة على المسار

تتغير قراءات المستشعر المطلقة مع الإضاءة وارتفاع المستشعر ولون السطح ومادة الشريط. لذلك، وبدلًا من عتبة ثابتة، يقيس الروبوت المسار الفعلي في كل مرة يبدأ فيها، ويحسب العتبة منه. القيمة الابتدائية middleValue = 3 في برنامج Arduino ليست سوى قيمة مؤقتة. calibrateSensor() تضع مكانها المتوسط المقيس. عندما اختبرتُ المستشعر وحده أول مرة، كانت قراءة قناة Clear نحو 2 فوق السطح الداكن ونحو 8 فوق الشريط الأبيض. وعندئذٍ تكون العتبة (2 + 8) / 2 = 5. ويُبقي زمن التكامل القصير البالغ 2.4 ms القراءات منخفضة إلى هذا الحد.

وضعية البدء

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

ما يفعله إجراء المعايرة

أسماء المتغيرات مأخوذة من برنامج Arduino: blackValue هو قراءة السطح الداكن، whiteValue هو قراءة الشريط الأبيض.

  • قِس السطح الداكن (blackValue): يستدير الروبوت يسارًا لمدة 350 ms، ثم يتوقف ويخزّن قراءة قناة Clear.
  • قِس الشريط الأبيض (whiteValue): يستدير الروبوت يمينًا لمدة 500 ms، وهي مدة أطول قليلًا كي يعبر المستشعر إلى الشريط، ثم يتوقف ويخزّن القراءة.
  • احسب العتبة: middleValue = (blackValue + whiteValue) / 2.
  • اطبع القيم الثلاث جميعها على الشاشة التسلسلية (Serial Monitor)، وهي نافذة Arduino IDE التي تعرض النص الذي ترسله اللوحة عبر USB.

إذا أعطت المعايرة قيمًا غير جيدة

  • قيم متقاربة: لا يستطيع المستشعر تمييز الشريط عن السطح. افحص ارتفاع المستشعر (من 10 إلى 15 mm)، وتحقق من تباين المسار، وقارن القيم الثلاث المطبوعة.
  • قيم معكوسة (blackValue أعلى من whiteValue): بدأ الروبوت من الوضعية الخاطئة، أو أن أزمنة الدوران تحتاج إلى تعديل.
  • القيمتان كلتاهما صفر: افحص توصيلات I2C (SDA إلى A4، وSCL إلى A5) ورسالة اكتشاف المستشعر عند بدء التشغيل.

الخطوة 8: الاختبار والضبط

Program flow of the sketch (calibration, then reading the sensor, calculating the error and PID control in a loop) and the control loop with middleValue 5, sensor reading 2 and error 3.

إعداد مسار الاختبار

  • استخدم شريطًا لاصقًا أبيض بعرض 50 mm على سطح داكن غير لامع. يضيء مصباح LED الأبيض الموجود على الوحدة المسارَ أسفل المستشعر. اتركه مضاءً: يبقى طرف LED غير موصول، كما في مخطط التوصيل.
  • ابدأ بمسار بيضاوي أو منعطفات واسعة. تجنّب المنعطفات الحادة بزاوية 90 درجة إلى أن يُضبط PID.
  • حافظ على إضاءة متساوية للمسار، فالظلال والأضواء الكاشفة الساطعة تغيّر القراءات.

ضبط معاملات PID

يستخدم برنامج Arduino القيم Kp = 24.0, Ki = 1.0, Kd = 1.0 و baseSpeed = 60. ظللتُ أغيّر معاملات الكسب على مسار الاختبار حتى تبع الروبوت الحافة، وهذه هي القيم التي انتهيت إليها. قد تحتاج محركاتك وبطاريتك ومسارك إلى قيم مختلفة.

  • ابدأ بالمعامل Kp فقط. مجموعة Ki = 0 و Kd = 0. ارفع قيمة Kp تدريجيًا بدءًا من قيمة منخفضة مثل 5 حتى يتبع الروبوت الخط. إذا تجاوز الهدف وتذبذب، فاخفض قيمة Kp قليلًا.
  • أضف Ki بحذر. إذا ظل الروبوت ينجرف إلى أحد الجانبين أو فاتته المنعطفات الواسعة، فارفع قيمة Ki بخطوات صغيرة، مثل 0.5. والإفراط في Ki يسبب تذبذبًا بطيئًا وعدم استقرار.
  • أضف Kd عند الحاجة فقط. إذا ظل الروبوت يتذبذب بعد ضبط Kp، فإن قيمة صغيرة من Kd، مثلًا من 0.5 إلى 2.0، تُخمد هذا التذبذب. أما القيمة المرتفعة جدًا من Kd فتجعل الروبوت بطيء الاستجابة أو مرتعشًا.
  • أبقِ قيمة baseSpeed بين 40 و60 خلال الاختبارات الأولى (يستخدم برنامج Arduino القيمة 60). تمنح السرعة المنخفضة متحكم PID وقتًا أطول للاستجابة. ارفعها تدريجيًا بعد أن يتبع الروبوت الخط بصورة موثوقة.

افتح الشاشة التسلسلية (Serial Monitor) على 9600 baud، وهو معدل البيانات الذي يضبطه Serial.begin(9600) في setup(). بعد المعايرة، يطبع برنامج Arduino قيمة الأسود وقيمة الأبيض والقيمة الوسطى. ولمراقبة الخطأ أثناء الضبط، أضف Serial.println(error); في نهاية loop(). يُبطئ الخرج الإضافي الحلقة، لذا احذف هذا السطر بعد ضبط معاملات الكسب.

استكشاف المشكلات الشائعة وإصلاحها

المشكلةالسبب المحتملالحل
لا يتبع الروبوت الخط إطلاقًالم يُكتشف المستشعر، أو التوصيلات خاطئة، أو فشلت المعايرةافحص توصيلات I2C (SDA إلى A4، وSCL إلى A5). افتح الشاشة التسلسلية (Serial Monitor) وتحقق من رسالة اكتشاف المستشعر وقيم المعايرة الثلاث. أعد وضع الروبوت في مكانه ثم أعد التشغيل.
يتذبذب الروبوت بشدة حول الخطKp مرتفع جدًا أو Kd منخفض جدًااخفض Kp بنسبة من 20 إلى 30 %. أضف قيمة صغيرة من Kd (من 0.5 إلى 2.0) لإخماد التذبذب.
يستجيب الروبوت ببطء شديد وتفوته المنعطفاتKp منخفض جدًا أو baseSpeed مرتفع جدًاارفع Kp تدريجيًا. اخفض baseSpeed لمنح المتحكم وقتًا أطول.
قراءات المستشعر غير مستقرة أو مشوَّشةالمستشعر بعيد جدًا عن السطح، أو الضوء المحيط، أو توصيلات مرتخيةاخفض المستشعر إلى ارتفاع من 10 إلى 15 mm فوق المسار. احجب الأضواء العلوية عن المستشعر. افحص جميع توصيلات الأسلاك.
يُجري الروبوت المعايرة بشكل غير صحيحوضعية بدء خاطئة أو تباين منخفضضع الروبوت عند الحافة اليسرى للشريط الأبيض على السطح الداكن. تحقق من التباين: شريط أبيض غير لامع على سطح داكن غير لامع.

مشكلات المحركات والطاقة والمسار

المشكلةالسبب المحتملالحل
المحركات ضعيفة أو لا تتحركبطارية ضعيفة، أو قيمة PWM منخفضة جدًا، أو أسلاك المحرك مبدّلةاشحن البطارية أو استبدلها. تحقق من أن السرعة الدنيا البالغة 20 تكفي لتحريك محركاتك. بدّل سلكَي المحرك إذا كان الاتجاه خاطئًا.
يدور أحد المحركين أسرع من الآخرفروق بين المحركات أو مشكلة في التوصيلاتأمر طبيعي في محركات TT منخفضة التكلفة. يعوّض الحد P الفروق الصغيرة. ولا يضيف الحد I هنا أكثر من ±4 (الخطوة 5)، لذا إذا ظل الروبوت ينجرف إلى أحد الجانبين، فارفع قيمة Ki بخطوات صغيرة.
يتحرك الروبوت إلى الأمام والخلف بدلًا من الدوران في مكانه أثناء المعايرة، أو يدور في دوائر أثناء تتبع الخطأحد المحركين موصول بالعكسبدّل سلكَي المحرك الذي يدور في الاتجاه الخاطئ.
تباين الخط غير كافٍالشريط مشابه جدًا للسطح، أو أن السطح لامع ويعكس الضوءاستخدم شريطًا أبيض غير لامع على سطح داكن غير لامع. تجنّب الأرضيات اللامعة والأشرطة المعدنية.
يتغير السلوك مع نفاد شحن البطاريةينخفض جهد البطارية تحت حمل المحركاتاستخدم بطارية LiPo بجهد 7.4 V مشحونة بالكامل. تفقد بطارية 9 V من نوع PP3 (النوع المستطيل الصغير) جهدها بسرعة تحت حمل المحركات. فكّر في إضافة مراقب لجهد البطارية.

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

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

نعم، مع بعض القيود. يناسب درع المحركات Motor Shield Rev3 لوحة Arduino Mega أيضًا، لكن أطراف I2C في لوحة Mega تقع على 20 (SDA) و21 (SCL)، لذا وصّل المستشعر بها بدلًا من A4/A5. أما لوحة Nano فلا تقبل الدرع، وستحتاج إلى وحدة قيادة محركات منفصلة توصّلها يدويًا.

هل يمكنني استخدام عدة مستشعرات TCS34725 في هذا الروبوت؟

لمستشعر TCS34725 عنوان I2C ثابت (الرقم الذي تستخدمه لوحة Arduino لاختيار جهاز على الناقل)، لذلك لا يمكن لمستشعرين أن يتشاركا الناقل مباشرة. ستحتاج إلى مُضاعِف I2C (Multiplexer) مثل TCA9548A، وهو يبدّل بين عدة أجهزة لها العنوان نفسه. ويكفي مستشعر واحد للمسارات الموصوفة هنا.

هل يمكنني تعديل هذا المشروع لتتبع خط ملوّن بدلًا من شريط أبيض على سطح داكن؟

نعم. يُرجع المستشعر قيم الأحمر والأخضر والأزرق وClear، لذا يمكنك استخدام قناة لونية بدلًا من قناة Clear. لتتبع خط أحمر، قارن القناة الحمراء بالقناتين الخضراء والزرقاء. ويتطلب ذلك تعديلات على حساب الخطأ.

الموارد والتنزيلات

  • مستودع GitHub: كود Arduino الكامل على GitHub.
  • ملفات STL: الهيكل والفواصل في متجر OmArTronics.
  • مكتبة Adafruit TCS34725: في Arduino IDE: مدير المكتبات (Library Manager)، ثم ابحث عن “Adafruit TCS34725”.

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

الخطوات التالية

من هنا يمكنك رفع قيمة baseSpeed، أو تصميم مسار بمنعطفات أضيق، أو تتبع خط ملوّن باستخدام قنوات RGB، أو إضافة مزيد من المستشعرات عبر مُضاعِف I2C. يُبقي برنامج Arduino سرعة كلتا العجلتين عند 20 أو أكثر: فعند أكبر خطأ وهو +3، يمنح الحد P وحده العجلة الداخلية 60 – 72 = -12، ثم constrain() ترفعها إلى 20. لذلك لا يدور الروبوت في مكانه أبدًا. وللمنعطفات الحادة بزاوية 90 درجة، اضبط الحد الأدنى في constrain() على قيمة أقل من الصفر حتى تتمكن العجلة الداخلية من الدوران إلى الخلف.

رأي واحد حول “Building a Line Following Robot with TCS34725 RGB Sensor”

أضف تعليق