black_grayscale_line_following.py
# هذا العمل مرخص بموجب ترخيص MIT.
# حقوق النشر (c) 2013-2023 OpenMV LLC. جميع الحقوق محفوظة.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# مثال تتبع الخط الأسود بالتدرج الرمادي
#
# يتطلب صنع روبوت متتبع للخط الكثير من الجهد. يوضح سكربت هذا المثال
# كيفية القيام بجزء الرؤية الحاسوبية من روبوت تتبع الخط. يمكنك
# استخدام مخرجات هذا السكربت لتشغيل روبوت ذي دفع تفاضلي من أجل
# تتبع خط. يقوم هذا السكربت فقط بتوليد قيمة انعطاف واحدة تخبر
# روبوتك بالتوجه يسارًا أو يمينًا.
#
# لكي يعمل هذا السكربت بشكل صحيح، يجب أن توجّه الكاميرا نحو خط بزاوية
# حوالي 45 درجة. يرجى التأكد من أن الخط فقط هو ضمن
# مجال رؤية الكاميرا.
import csi
import time
import math
# يتتبع خطًا أسود. استخدم [(128, 255)] لتتبع خط أبيض.
GRAYSCALE_THRESHOLD = [(0, 64)]
# كل منطقة اهتمام (roi) هي (x, y, w, h). ستحاول خوارزمية اكتشاف الخط إيجاد
# مركز ثقل أكبر كتلة في كل منطقة اهتمام. سيتم بعد ذلك
# أخذ متوسط موقع x لمراكز الثقل بأوزان مختلفة حيث يُخصَّص الوزن الأكبر
# لمنطقة الاهتمام القريبة من أسفل الصورة وأقل لمنطقة الاهتمام التالية وهكذا.
ROIS = [ # [منطقة اهتمام (ROI)، الوزن]
(0, 100, 160, 20, 0.7), # ستحتاج إلى ضبط الأوزان لتطبيقك
(0, 50, 160, 20, 0.3), # بناءً على كيفية إعداد روبوتك.
(0, 0, 160, 20, 0.1),
]
# حساب مقسوم الوزن (نحسب هذا حتى لا تضطر لجعل مجموع الأوزان يساوي 1).
weight_sum = 0
for r in ROIS:
weight_sum += r[4] # r[4] هو وزن منطقة الاهتمام (roi).
# إعداد الكاميرا...
csi0 = csi.CSI()
csi0.reset() # تهيئة مستشعر الكاميرا.
csi0.pixformat(csi.GRAYSCALE) # استخدام التدرج الرمادي.
csi0.framesize(csi.QQVGA) # استخدام QQVGA من أجل السرعة.
csi0.snapshot(time=2000) # السماح للإعدادات الجديدة بأن تصبح فعالة.
csi0.auto_gain(False) # يجب إيقافه من أجل تتبع الألوان
csi0.auto_whitebal(False) # يجب إيقافه من أجل تتبع الألوان
clock = time.clock() # تتبع معدل الإطارات (FPS).
while True:
clock.tick() # تتبع عدد الميلي ثانية المنقضية بين استدعاءات snapshot().
img = csi0.snapshot() # التقاط صورة وإرجاعها.
centroid_sum = 0
for r in ROIS:
blobs = img.find_blobs(
GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True
) # r[0:4] هي مجموعة منطقة الاهتمام (roi).
if blobs:
# إيجاد الكتلة ذات أكبر عدد من البكسلات.
largest_blob = max(blobs, key=lambda b: b.pixels)
# رسم مستطيل حول الكتلة.
img.draw_detection(largest_blob)
centroid_sum += largest_blob.cx * r[4] # r[4] هو وزن منطقة الاهتمام (roi).
center_pos = centroid_sum / weight_sum # تحديد مركز الخط.
# تحويل center_pos إلى زاوية انحراف. نستخدم عملية
# غير خطية بحيث تصبح الاستجابة أقوى كلما ابتعدنا عن الخط
# أكثر. من الجيد استخدام العمليات غير الخطية على مخرجات الخوارزميات
# مثل هذه لإحداث "مشغّل" (trigger) للاستجابة.
deflection_angle = 0
# الرقم 80 هو نصف دقة X، والرقم 60 هو نصف دقة Y. إن
# المعادلة أدناه تحسب فقط زاوية مثلث حيث يكون
# الضلع المقابل للمثلث هو انحراف موقع المركز
# عن المركز، والضلع المجاور هو نصف دقة Y. هذا يحدّ
# مخرج الزاوية إلى حوالي -45 إلى 45. (ليس تمامًا -45 و45).
deflection_angle = -math.atan((center_pos - 80) / 60)
# تحويل الزاوية من راديان إلى درجات.
deflection_angle = math.degrees(deflection_angle)
# الآن لديك زاوية تخبرك بمقدار انعطاف الروبوت والتي
# تدمج الجزء الأقرب من الخط إلى الروبوت وأجزاء
# الخط الأبعد عن الروبوت للحصول على تنبؤ أفضل.
print("Turn Angle: %f" % deflection_angle)
print(clock.fps()) # ملاحظة: تعمل كاميرا OpenMV الخاصة بك بحوالي نصف السرعة أثناء
# الاتصال بحاسوبك. يجب أن يزداد معدل الإطارات (FPS) بعد قطع الاتصال.