رادار Arduino باستخدام مستشعر الموجات فوق الصوتية HC-SR04 ومحرك سيرفو: دليل كامل لبنائه بنفسك

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

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

📋 ملخص سريع

يتحول مستشعر الموجات فوق الصوتية HC-SR04 المثبّت على محرك سيرفو SG90 إلى رادار بسيط. يمسح السيرفو المجال من 15 إلى 165 درجة، وعند كل درجة يقيس Arduino Uno المسافة ويرسل الزاوية والمسافة إلى حاسوبك عبر الاتصال التسلسلي (وصلة البيانات عبر كابل USB). ويرسم برنامج Processing اختياري القراءات على هيئة شاشة رادار. أما Processing فهو برنامج مجاني لرسم الرسوميات، وكلمة Sketch هي اسم البرنامج في كل من Processing وArduino IDE (البرنامج الذي تكتب فيه كود Arduino وترفعه إلى اللوحة). ويمكن إضافة صفارة (Buzzer) لتعمل إنذارًا اختياريًا للمسافة.

كيف يعمل الرادار

يتكون الرادار من ثلاثة أجزاء أساسية (السيرفو، ومستشعر الموجات فوق الصوتية، وArduino Uno) وإضافتين اختياريتين (شاشة الرادار في Processing، والصفارة).

‏ محرك سيرفو SG90 يدير مستشعر HC-SR04 ذهابًا وإيابًا. وإذا لم تكن قد تعاملت مع محركات السيرفو من قبل، فإن دليل التحكم بمحرك السيرفو مع Arduino الذي أعددته يشرح التوصيلات وطريقة التحكم.

عند كل درجة، يُطلق مستشعر الموجات فوق الصوتية HC-SR04 نبضة صوتية ويستمع إلى صداها ليحدد المسافة إلى أقرب جسم. ولإلقاء نظرة أقرب على المستشعر، راجع ما كتبته في شرح مستشعر المسافة بالموجات فوق الصوتية مع Arduino.

‏ Arduino Uno يحدد للسيرفو الاتجاه الذي يشير إليه، ويشغّل المستشعر، ويحسب المسافة، ثم يرسل الزاوية والمسافة عبر الاتصال التسلسلي إلى حاسوبك. وإذا كنت جديدًا على برمجة Arduino، فإن دليل أساسيات برمجة Arduino الذي أعددته يشرح setup() وloop() والمتغيرات والشاشة التسلسلية Serial Monitor (النافذة في Arduino IDE التي تعرض النص الذي ترسله اللوحة).

‏ برنامج Processing على الحاسوب يستطيع رسم البيانات على هيئة شاشة رادار. وهو اختياري: فالشاشة التسلسلية تعرض القراءات نفسها على هيئة نص. أما صفارة بيزو (صفارة صغيرة يهتز قرصها الخزفي لإصدار الصوت) فيمكنها أن تُطلق تنبيهًا عندما يقترب جسم إلى مسافة محددة.

مبدأ الاستشعار بالموجات فوق الصوتية

يُطلق مستشعر الموجات فوق الصوتية نبضة صوتية عالية التردد تبلغ 40 kHz (أعلى بكثير من مدى السمع البشري)، ثم يستمع إلى الصدى المرتد من الأجسام القريبة. ويدلّك الزمن بين النبضة والصدى على بُعد الجسم. وتستخدم الخفافيش المبدأ نفسه للتنقل في الظلام. ويسمي المهندسون ذلك طريقة زمن الطيران (Time-of-Flight).

Time-of-flight diagram: the transmitter sends a sound pulse, an obstacle reflects it, the receiver picks up the echo, and the distance is d = c × Δt / 2

كيف تعمل دورة القياس في HC-SR04

يحتوي HC-SR04 في واجهته على محوّلَين أسطوانيين (Transducers)، والمحوّل يحوّل الإشارة الكهربائية إلى صوت، أو الصوت إلى إشارة كهربائية. أحدهما هو المرسِل، الذي يرسل النبضة، والآخر هو المستقبِل، الذي يلتقط الصدى. وتمر دورة القياس الواحدة بأربع مراحل.

الإرسال: يضبط Arduino الطرف TRIG على HIGH (5 V) لمدة 10 ميكروثوانٍ. واستجابةً لذلك، يُطلق HC-SR04 دفعة من ثماني موجات صوتية بتردد 40 kHz تنتشر إلى الخارج على شكل مخروط عرضه نحو 15 درجة.

الانعكاس: عندما تصطدم الموجة الصوتية بجسم ما، ترتد عائدةً نحو المستشعر.

الاستقبال: يلتقط محوّل الاستقبال الصدى العائد، ويُبقي HC-SR04 طرفه ECHO على HIGH مدةً تساوي زمن رحلة الموجة الصوتية ذهابًا وإيابًا.

حساب المسافة: يقرأ Arduino مدة نبضة الطرف ECHO باستخدام pulseIn() ويطبّق المعادلة المسافة = (الزمن × سرعة الصوت) / 2. ينتقل الصوت بسرعة 0.034 cm تقريبًا في الميكروثانية (340 m/s). وتقسم على 2 لأن الصوت يذهب إلى الجسم ثم يعود، فيقطع المسافة مرتين. وفي الكود: distance = duration * 0.034 / 2. ويستخدم درسي عن مستشعر المسافة بالموجات فوق الصوتية مع Arduino القيمة الأدق 0.0343 cm في الميكروثانية (343 m/s عند 20 °C). والفرق أقل من 1 %، أي نحو 2 mm عند مسافة 25 cm.

لماذا يُنتج السيرفو مسحًا راداريًا

يقيس مستشعر الموجات فوق الصوتية الثابت المسافة في اتجاه واحد فقط. أما إذا ثُبّت على سيرفو يتحرك ذهابًا وإيابًا، فإنه يعطي قراءة للمسافة عند كل زاوية. ويقرن Arduino كل قياس بزاوية السيرفو ويرسلهما معًا عبر الاتصال التسلسلي. وعند رسم أزواج الزاوية والمسافة هذه معًا، تحصل على منظر علوي على طريقة الرادار لكل ما يوجد أمام المستشعر.

3D render of the radar: the HC-SR04 in the printed sensor bracket on the SG90 servo, which sits in the printed servo base on a wooden base plate

المكونات وقائمة المواد

المكوّنالغرضمطلوب؟ملاحظات
Arduino Unoلوحة المتحكم الدقيق الرئيسيةنعمتصلح أي لوحة متوافقة مع Uno
مستشعر الموجات فوق الصوتية HC-SR04يقيس المسافة بنبضات فوق صوتيةنعمالمدى من 2 cm إلى 400 cm (حسب ورقة البيانات)؛ وتقل موثوقية القراءات بعد 200 إلى 300 cm
محرك سيرفو SG90يحرّك المستشعر ماسحًا قوسًا قدره 150 درجةنعمسيرفو صغير قياسي (Micro Servo)
لوحة التجارب (Breadboard)لوحة تجارب بدون لحام (Breadboard)نعمبنصف الحجم أو بالحجم الكامل
أسلاك توصيل Jumper (ذكر-ذكر وذكر-أنثى)توصيل جميع المكوناتنعم10 أسلاك على الأقل
كابل USB (من Type A إلى B)يرفع الكود إلى اللوحة وينقل البيانات التسلسليةنعمكابل USB قياسي للوحة Arduino
صفارة بيزو (Piezo)تنبيه مسموع للأجسام القريبةاختيارييُنصح بصفارة سلبية (Passive)، مثل الوحدة KY-006 الظاهرة في مخطط التوصيل (فهي تُصدر النغمة ذات التردد 2000 Hz المحددة في الكود؛ أما الصفارة النشطة فلها نغمة ثابتة خاصة بها)
طابعة ثلاثية الأبعاد وخيط طباعة (PLA أو ABS، وهما نوعان شائعان من البلاستيك المستخدم في الطباعة ثلاثية الأبعاد)حوامل مخصصة للمستشعر والسيرفواختيارييفي الشريط اللاصق أو الغراء الساخن بالغرض أيضًا
حاسوب مثبّت عليه Arduino IDEكتابة كود Arduino ورفعه إلى اللوحةنعمتنزيل Arduino IDE
حاسوب مثبّت عليه Processingشاشة الرادار على الحاسوباختياريتنزيل مجاني من processing.org

تصميم حوامل مخصصة وطباعتها بطابعة ثلاثية الأبعاد (اختياري)

يُبقي حامل المستشعر المطبوع مستشعر HC-SR04 أكثر استقامةً وثباتًا مما يفعله الشريط اللاصق، ويبدو المشروع أكثر ترتيبًا. وإذا لم تكن لديك طابعة ثلاثية الأبعاد، فاستخدم الشريط اللاصق أو الغراء الساخن أو الأربطة البلاستيكية لتثبيت المستشعر على ذراع السيرفو (Horn، أي الذراع البلاستيكي المركّب على عمود السيرفو). صممتُ ثلاث قطع مطبوعة: حامل المستشعر، وقاعدة السيرفو، ولوحة قاعدة مسطحة بأبعاد 70 × 70 mm. وفي الفيديو ثبّتُّ قاعدة السيرفو على لوح خشبي وثقبتُ اللوح بنفسي. ويصلح أي برنامج CAD (برامج التصميم بمساعدة الحاسوب مثل Fusion 360 أو Tinkercad) لتصميم نسختك الخاصة.

حامل المستشعر: صمّمه بحيث يثبّت HC-SR04 بإحكام. واترك الواجهة الأمامية مفتوحة كي لا يعترض شيء مسار الصوت لأيٍّ من المحوّلين. ويحتاج الجزء الخلفي إلى شق أو ثقب برغي لتثبيته على ذراع السيرفو.

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

تجد ملفات STL (صيغة الملفات القياسية للطباعة ثلاثية الأبعاد) الخاصة بحامل المستشعر وقاعدة السيرفو ولوحة القاعدة في متجر OmArTronics.

3D render of the printed sensor bracket holding the HC-SR04
3D render of the SG90 servo in the printed servo base, screwed to a wooden base plate

تجميع المكونات المادية

الخطوة 1: ثبّت المستشعر. ثبّت HC-SR04 في حامل المستشعر المطبوع، أو ألصقه بالشريط اللاصق على ذراع السيرفو. وتأكد من أن لا شيء يغطي أيًّا من المحوّلين.

الخطوة 2: ثبّت السيرفو. ضع السيرفو في قاعدة السيرفو المطبوعة. وإذا لم تكن لديك قاعدة مطبوعة، فثبّت جسم السيرفو على الطاولة بمعجون لاصق أو بشريط لاصق مزدوج الوجه.

الخطوة 3: اربط المستشعر بالسيرفو. اربط حامل المستشعر بذراع السيرفو بالبرغي الصغير المرفق مع السيرفو، أو استخدم تصميم تعشيق Snap-fit (قطع تنطبق معًا بنقرة دون براغٍ). وتأكد من أن المستشعر يدور بسلاسة عندما يتحرك السيرفو.

الخطوة 4: نفّذ التوصيلات. اتبع الجداول في القسم التالي، ووصّل كل شيء بلوحة Arduino عبر لوحة التجارب (Breadboard) باستخدام أسلاك التوصيل (Jumper).

مخطط التوصيل وتوصيلات الأطراف

وصّل المكونات الأساسية وفق الجدول الأول؛ وللصفارة جدولها الخاص أدناه. في الجداول، VCC هو مدخل الطاقة للقطعة، وGND هو الأرضي (0 V).

توصيلات الرادار الأساسية

المكوّنطرف المكوّنطرف Arduinoملاحظات
سيرفو SG90الإشارة (برتقالي/أصفر)الطرف 8إشارة التحكم (يمكن لمكتبة Servo، وهي كود جاهز للتحكم في السيرفو يأتي مع Arduino IDE، أن تشغّل السيرفو من أي طرف رقمي)
سيرفو SG90VCC (أحمر)5 Vتغذية السيرفو
سيرفو SG90GND (بني/أسود)GNDأرضي مشترك
HC-SR04VCC5 Vتغذية المستشعر
HC-SR04GNDGNDأرضي مشترك
HC-SR04TRIGالطرف 9خرج نبضة القدح (Trigger)
HC-SR04ECHOالطرف 10دخل نبضة الصدى

ملاحظة: يسحب SG90 نحو 100 mA عندما يتحرك بحرية، وما يصل إلى نحو 650 mA عند التوقف القسري (Stall، أي عندما يُعاق ولا يستطيع الدوران). ويوفّر منفذ USB تيارًا قدره 500 mA. وهنا لا يدير السيرفو سوى حامل المستشعر، لذا يمكن تشغيله من الطرف 5 V في Arduino لاختبار على الطاولة. أما في قفل الباب بكلمة مرور باستخدام Arduino الذي بنيته، فيدفع السيرفو مزلاجًا قد يعيق حركته، ولذلك أخصص له هناك دائمًا مصدر تغذية مستقلًا. وإذا أُعيد تشغيل Arduino أثناء حركة السيرفو، فغذِّ السيرفو من مزود طاقة خارجي بجهد 5 V وتيار 1 A أو أكثر، ووصّل GND الخاص بهذا المزود بطرف GND في Arduino.

توصيلات الصفارة الاختيارية

المكوّنطرف المكوّنطرف Arduinoملاحظات
صفارة بيزو (Piezo)الموجب (+)، أو S في وحدة KY-006الطرف 12سلك الإشارة لإخراج النغمة
صفارة بيزو (Piezo)السالب (−)GNDأرضي مشترك

مهم: يجب أن تتصل جميع توصيلات GND (السيرفو، والمستشعر، والصفارة) بطرف GND نفسه في Arduino. فمسارات الأرضي المنفصلة تسبب قراءات مضطربة للمستشعر وارتعاشًا في السيرفو (Jitter، أي اهتزازات صغيرة غير منضبطة). واستخدم خطوط التغذية في لوحة التجارب (الشريطان الطويلان + و− على حافة لوحة التجارب) لتوزيع 5 V وGND.

Breadboard wiring diagram: HC-SR04 with TRIG on pin 9 and ECHO on pin 10, SG90 signal on pin 8, a 9 V battery on VIN, and a red note on the servo's red wire: 5 V, not 9 V
The same wiring diagram with a KY-006 buzzer module on pin 12 and red notes: servo red wire on 5 V, not 9 V, and the buzzer's middle pin not needed

تصحّح الملاحظات الحمراء كلا المخططين: فالسلك الأحمر للسيرفو مكانه 5 V، وليس بطارية 9 V. إذ إن SG90 مصمم للعمل بجهد من 4.8 إلى 6 V، وجهد 9 V يسبب له سخونة زائدة ويتلفه. أما بطارية 9 V نفسها فتبقى موصولة بـVIN، وهو مدخل Arduino للتغذية الخارجية ويقبل من 7 إلى 12 V. وتشير الملاحظة الثانية إلى الطرف الأوسط في KY-006: لا تحتاج الوحدة إلا إلى S و−، لذا اترك الطرف الأوسط دون توصيل.

كود رادار Arduino: البرنامج الأساسي

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

/**
 * Arduino Ultrasonic Radar — Core Sketch
 * Author: Omar Draidrya
 * Date: 2024/05/09
 * This code controls a servo motor and measures distance
 * using an HC-SR04 ultrasonic sensor.
 */

#include <Servo.h>

Servo myServo;

const int trigPin = 9;
const int echoPin = 10;

long duration;
int distance;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Serial.begin(9600);
  myServo.attach(8);
}

void loop() {
  // Forward sweep: 15 to 165 degrees
  for (int i = 15; i <= 165; i++) {
    myServo.write(i);
    delay(30);
    distance = calculateDistance();
    Serial.print(i);
    Serial.print(",");
    Serial.print(distance);
    Serial.print(".");
  }
  // Return sweep: 165 back to 15 degrees
  for (int i = 165; i > 15; i--) {
    myServo.write(i);
    delay(30);
    distance = calculateDistance();
    Serial.print(i);
    Serial.print(",");
    Serial.print(distance);
    Serial.print(".");
  }
}

int calculateDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  return distance;
}

كيف يعمل الكود

منطق مسح السيرفو: تتولى حلقتا for عملية المسح (وحلقة for تكرر كتلة من الكود عددًا محددًا من المرات). تنتقل الأولى من 15 إلى 165 درجة، وتعود الثانية من 165 إلى 15. واخترنا المدى من 15 إلى 165 بدلًا من 0 إلى 180 لأن كثيرًا من محركات السيرفو الرخيصة لا تبلغ المدى الكامل من 0 إلى 180 درجة، فتطنّ أو ترتعش عند نهايات حركتها الميكانيكية. ويمنح التأخير البالغ 30 ms بين كل درجة وأخرى السيرفو وقتًا ليستقر قبل القياس التالي.

قياس المسافة باستخدام pulseIn(): تُشغّل الدالة calculateDistance() المستشعر وتستدعي pulseIn(echoPin, HIGH). وتنتظر هذه الدالة (ولا يفعل البرنامج شيئًا آخر في أثناء ذلك) حتى يصبح الطرف ECHO على HIGH، ثم تعيد المدة التي بقي فيها على HIGH بالميكروثانية، وهي زمن رحلة الصوت ذهابًا وإيابًا. وتُحوَّل هذه المدة إلى سنتيمترات بالمعادلة المذكورة في دورة القياس أعلاه.

الخرج التسلسلي والاختبار

صيغة الخرج التسلسلي: تُرسَل كل قراءة بالصيغة angle,distance. على سبيل المثال، 90,25. تعني أن المستشعر عند 90 درجة ويرى جسمًا على بُعد 25 cm. والنقطة هي الفاصل (المحرف الذي يحدد أين تنتهي قراءة وتبدأ التالية). وإضافة وحدات مثل “cm” أو استخدام فاصل مختلف يُفسد التحليل في Processing، لذا غيّر خرج Arduino ومحلّل Processing (الكود الذي يقسم النص إلى زاوية ومسافة) معًا.

الاختبار بالشاشة التسلسلية (Serial Monitor): قبل إعداد Processing، ارفع البرنامج إلى اللوحة وافتح الشاشة التسلسلية Serial Monitor (Tools > Serial Monitor) بسرعة 9600 baud. والـbaud هو سرعة النقل: يضبطها Serial.begin(9600) في البرنامج، ويجب أن تستخدم الشاشة التسلسلية القيمة نفسها. ينبغي أن ترى تدفقًا متواصلًا من أزواج الزاوية والمسافة مثل 15,40.16,38.17,35. تتوالى على الشاشة. وإذا لم ترَ سوى أصفار أو أرقام كبيرة جدًا، فافحص التوصيلات وراجع قسم استكشاف الأخطاء وإصلاحها أدناه.

ترقية اختيارية: إضافة صفارة للتنبيه من العوائق

بعد أن يعمل الرادار الأساسي، يمكنك إضافة صفارة بيزو تُصدر صوتًا عندما يقترب جسم أكثر من اللازم، مثل مستشعر ركن السيارة ولكن على مكتبك.

/**
 * Arduino Ultrasonic Radar — Buzzer Upgrade
 * Author: Omar Draidrya
 * Date: 2024/05/09
 * Adds a buzzer alert when an obstacle is within threshold distance.
 */

#include <Servo.h>

Servo myServo;

const int trigPin = 9;
const int echoPin = 10;
const int buzzerPin = 12;
const int alertThreshold = 10; // cm — change this value to adjust sensitivity

long duration;
int distance;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(9600);
  myServo.attach(8);
}

void loop() {
  for (int i = 15; i <= 165; i++) {
    myServo.write(i);
    delay(30);
    distance = calculateDistance();
    Serial.print(i);
    Serial.print(",");
    Serial.print(distance);
    Serial.print(".");

    if (distance <= alertThreshold) {
      tone(buzzerPin, 2000);
    } else {
      noTone(buzzerPin);
    }
  }
  for (int i = 165; i > 15; i--) {
    myServo.write(i);
    delay(30);
    distance = calculateDistance();
    Serial.print(i);
    Serial.print(",");
    Serial.print(distance);
    Serial.print(".");

    if (distance <= alertThreshold) {
      tone(buzzerPin, 2000);
    } else {
      noTone(buzzerPin);
    }
  }
}

int calculateDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  return distance;
}

كيف تعمل الصفارة: بعد كل قياس للمسافة، يتحقق الكود مما إذا كانت القراءة مساوية لـalertThreshold أو أقل منها (10 cm افتراضيًا). فإن كانت كذلك، يشغّل tone(buzzerPin, 2000) الصفارة بتردد 2000 Hz؛ وإلا يوقفها noTone(). غيّر قيمة alertThreshold إلى المسافة التي تريدها: 20 cm لتنبيه مبكر، أو 5 cm إذا أردت أن تنطلق الصفارة مع الأجسام القريبة جدًا فقط. وفي الفيديو استخدمتُ القيمة الافتراضية 10 cm.

ترقية اختيارية: عرض الرادار في الزمن الحقيقي باستخدام Processing

يقرأ برنامج Processing أدناه البيانات التسلسلية القادمة من Arduino ويرسم شاشة الرادار في الزمن الحقيقي.

ماذا يفعل برنامج Processing

يفتح كود Processing الاتصال التسلسلي مع Arduino بسرعة 9600 baud، ويجمع المحارف الواردة حتى يصل إلى فاصل النقطة (bufferUntil(‘.’)). ثم يقسم كل قراءة عند الفاصلة إلى زاوية ومسافة ويرسم النتيجة. تظهر كل قراءة على هيئة خط داخل حلقات قوسية تحدد نطاقات المسافة. يشير اللون الأزرق إلى المساحة الخالية حتى الجسم المكتشف، ويشير البرتقالي إلى المنطقة الممتدة من الجسم حتى الحلقة الخارجية. وإذا لم يوجد جسم ضمن maxDistance، يبقى الخط كله أزرق. ويعرض نص فوق الشاشة الزاوية الحالية والمسافة المقيسة.

Processing radar screen at 41 degrees and 22 cm, with blue lines for free space and orange lines behind a detected object

كيفية إعداد Processing

الخطوة 1: نزّل Processing وثبّته من processing.org.

الخطوة 2: أغلق الشاشة التسلسلية Serial Monitor في Arduino IDE إن كانت مفتوحة. فلا يمكن إلا لبرنامج واحد استخدام المنفذ التسلسلي في الوقت نفسه.

الخطوة 3: انسخ كود Processing أدناه إلى برنامج (Sketch) جديد وشغّله. أبعاد النافذة 1920 × 1080 بكسل. وعلى شاشة أصغر، خفّض size() وradarRadius معًا، مثل size(1280, 720) وradarRadius = 500. أما السطر float x = distance * 20; في drawDetection() فيحوّل السنتيمترات إلى بكسلات بمعامل القياس 20 (800 px / 40 cm). وبعد تغيير radarRadius أو maxDistance، اكتب float x = distance * radarRadius / maxDistance; بدلًا من ذلك.

الخطوة 4: إذا ظهرت شاشة الرادار دون خط مسح، فغيّر فهرس المنفذ التسلسلي. ففي السطر String portName = Serial.list()[0];، غيّر [0] إلى [1] أو [2]، بحسب المنفذ الذي تستخدمه لوحة Arduino لديك (مثل COM3 على Windows أو /dev/ttyUSB0 على Linux). واطبع Serial.list() في نافذة الإخراج (Console) في Processing لترى جميع المنافذ المتاحة.

كود الرادار في Processing

/**
 * Arduino Radar — Processing Visualization
 * Date: 2024/05/09
 * Reads serial data from Arduino and draws a radar display.
 */

import processing.serial.*;

Serial communicationPort;
String serialData = "";
float scanAngle = 0;
float scanDistance = 0;
int radarRadius = 800;
int maxDistance = 40; // cm

void setup() {
  size(1920, 1080);
  smooth();
  String portName = Serial.list()[0]; // Adjust index if needed
  communicationPort = new Serial(this, portName, 9600);
  communicationPort.bufferUntil('.');
  background(0);
}

void draw() {
  drawRadarBackground();
  if (serialData.length() > 0) {
    parseSerialData();
    drawDetection();
  }
  displayInfo(scanDistance, scanAngle);
}

void drawRadarBackground() {
  pushMatrix();
  translate(width / 2, height - 200);
  noFill();
  stroke(80);
  strokeWeight(1);
  for (int i = 0; i < 5; i++) {
    float r = radarRadius * (i + 1) / 5.0;
    arc(0, 0, r * 2, r * 2, PI, TWO_PI);
  }
  for (int i = 0; i < 180; i += 10) {
    float x = radarRadius * cos(radians(i));
    float y = radarRadius * sin(radians(i));
    line(0, 0, x, -y);
    if (i % 30 == 0) {
      fill(255);
      textSize(16);
      text(i + "°", x + 5, -y + 5);
    }
  }
  popMatrix();
}

void parseSerialData() {
  String[] tokens = serialData.split(",");
  if (tokens.length >= 2) {
    scanAngle = float(tokens[0]);
    scanDistance = float(tokens[1]);
  }
}

void drawDetection() {
  float angle = radians(scanAngle);
  float distance = scanDistance;
  float x = distance * 20;
  float fullX = radarRadius * cos(angle);
  float fullY = radarRadius * sin(angle);

  pushMatrix();
  translate(width / 2, height - 200);
  strokeWeight(4);
  noStroke();
  fill(0, 20);
  rect(-radarRadius, -radarRadius, radarRadius * 2, radarRadius);

  if (distance > 0 && distance <= maxDistance) {
    stroke(0, 0, 255);
    line(0, 0, x * cos(angle), -x * sin(angle));
    stroke(255, 165, 0);
    line(x * cos(angle), -x * sin(angle), fullX, -fullY);
  } else {
    stroke(0, 0, 255);
    line(0, 0, fullX, -fullY);
  }
  popMatrix();
  serialData = "";
}

void displayInfo(float distance, float angle) {
  fill(0);
  noStroke();
  rect(10, 10, 260, 80);
  fill(255);
  textSize(20);
  text("Angle: " + nf(angle, 1, 2) + "°", 30, 30);
  text("Distance: " + nf(distance, 1, 2) + " cm", 30, 60);
}

void serialEvent(Serial p) {
  serialData = p.readStringUntil('.');
  serialData = serialData.substring(0, serialData.length() - 1);
}

المعايرة والدقة والقيود

محاذاة السيرفو: لا تكون معظم محركات السيرفو المخصصة للهواة معايَرة بدقة تامة عند شرائها، لذا قد لا تشير الزاوية 90 إلى الأمام مباشرةً في السيرفو لديك. وإذا بدت شاشة الرادار مُدارة أو منزاحة، فاضبط وضع حامل المستشعر على ذراع السيرفو أو أضف إزاحة في الكود: عرّف const int angleOffset = 5; واكتب myServo.write(i + angleOffset);. استخدم قيمة سالبة للتصحيح في الاتجاه المعاكس، واستمر في طباعة i كي تظل شاشة الرادار تعرض من 15 إلى 165 درجة.

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

الأسطح العاكسة واللينة: تُنتج الأسطح الصلبة المستوية، مثل الجدران والصناديق، أصداءً قوية. أما الأقمشة اللينة والأسطح المائلة والأجسام الرفيعة مثل أرجل الكراسي، فتميل إلى امتصاص النبضة أو حرفها عن مسارها. وعندها لا يصل أي صدى إلى المستقبِل، فتسقط القراءة ولا يظهر الجسم على شاشة الرادار.

المدى والضوضاء وسرعة المسح

المدى الأقصى العملي: تذكر ورقة بيانات HC-SR04 مدى 400 cm، لكن موثوقية القراءات تقل بعد 200 إلى 300 cm لأن الأصداء تضعف. ويستخدم برنامج Processing افتراضيًا maxDistance = 40 cm، وهي قيمة تناسب العروض على الطاولة. ولعرض مدى أوسع، ارفع maxDistance وحدّث معامل القياس كما هو موضح في الخطوة 3 من الإعداد. وإذا رفعت maxDistance وحدها، فستُرسم الأجسام الأبعد من 40 cm خارج الحلقة الخارجية.

قراءات مشوشة أو متقلبة: القفزات العرضية في القراءات أمر طبيعي. وهي تنتج عن أصداء ترتد عن عدة أسطح قبل عودتها (الانعكاسات متعددة المسارات)، وعن الضوضاء الكهربائية، وعن أصداء متأخرة من النبضة السابقة. والحل البسيط هو مرشّح الوسيط (Median Filter): خذ ثلاث قراءات عند كل زاوية واستخدم القيمة الوسطى، فتُهمل أي قفزة منفردة. أما البرامج في هذا المقال فترسل كل قراءة خام دون أي ترشيح.

سرعة المسح مقابل معدل التحديث: يعني التأخير البالغ 30 ms لكل درجة أن المسح الأمامي الكامل يستغرق 4.5 ثانية على الأقل (151 خطوة، خطوة لكل درجة، مدة كل منها 30 ms). ويضيف كل قياس بضعة أجزاء من الألف من الثانية، وأكثر من ذلك حين لا يعود أي صدى. فإذا قصّرت التأخير صار المسح أسرع، لكن السيرفو يحظى بوقت أقل ليستقر وتزداد القراءات تشويشًا. وإذا زدته استقرت القياسات، لكن عرض الرادار يتجدد بوتيرة أبطأ.

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

إذا لم يعمل شيء كما ينبغي، فراجع قائمة الفحص هذه بندًا بندًا قبل استبدال أي قطعة.

السيرفو لا يتحرك: تأكد من أن سلك الإشارة موصول بالطرف 8، ومن أن VCC وGND موصولان بالطرفين 5 V وGND في Arduino. وجرّب المثال Sweep من مكتبة Servo في Arduino لتعرف هل المشكلة في السيرفو نفسه أم في كود الرادار.

يقرأ HC-SR04 دائمًا 0 أو نحو 650 cm: القيمة 0 تعني أن الطرف ECHO لم يصبح HIGH مطلقًا، وهذا يشير إلى مشكلة في التوصيلات أو التغذية. أما نحو 650 cm فتعني أنه لم يعد أي صدى: إذ تُبقي معظم الوحدات ECHO عندئذٍ على HIGH لنحو 38 ms. تحقق من أن TRIG موصول بالطرف 9 وECHO بالطرف 10، ومن أن المستشعر يعمل على 5 V لا على 3.3 V. وتأكد من أن حامل المستشعر لا يحجب المحوّلين. ثم وجّه المستشعر نحو جدار مستوٍ على بُعد نحو 20 cm وراقب الشاشة التسلسلية.

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

الصفارة تعمل دائمًا أو لا تنطلق أبدًا: تأكد من أن الصفارة موصولة بالطرف 12، ومن أن alertThreshold في الكود يحمل القيمة التي تريدها. وإذا كان المستشعر يقرأ مسافات خاطئة (انظر أعلاه)، فسيختل منطق الصفارة أيضًا. لذا أصلح المستشعر أولًا.

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

تعذّر اتصال Processing أو ظهور شاشة فارغة: أغلق الشاشة التسلسلية في Arduino وتحقق من فهرس المنفذ (الخطوتان 2 و4 من الإعداد).

عدم تطابق صيغة البيانات التسلسلية: إذا غيّرت أسطر Serial.print() في برنامج Arduino (مثلًا بإضافة وحدات أو استخدام فاصل مختلف)، فغيّر المحلّل في برنامج Processing بالطريقة نفسها.

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

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

هل يمكنني استخدام مستشعر موجات فوق صوتية آخر بدلًا من HC-SR04؟

نعم. فـHC-SR04 هو الخيار الأكثر شيوعًا لأنه رخيص ومتوفر على نطاق واسع. وتعمل أيضًا مستشعرات مثل US-015 أو JSN-SR04T إذا كانت تستخدم واجهة TRIG/ECHO نفسها. أما إذا كان البديل يستخدم بروتوكولًا مختلفًا (مثل I2C أو UART، اللذين يرسلان المسافة على هيئة بيانات رقمية بدلًا من طول نبضة)، فستحتاج إلى تعديل كود Arduino.

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

نعم. يعمل الكود دون تعديل على Arduino Nano وMega، لأنهما تستخدمان منطق 5 V نفسه الذي تستخدمه Uno (أي إن إشارة HIGH تساوي 5 V). تأكد من أن أرقام الأطراف تطابق توصيلاتك، ومن أن اللوحة توفر 5 V للمستشعر والسيرفو.

مصادر ذات صلة

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

‏ سيارة روبوتية تتفادى العوائق يضع مستشعر HC-SR04 والسيرفو نفسيهما على منصة متحركة تشق طريقها بنفسها.

أضف تعليق