التحكم بالحاسوب بحركة اليد بدلًا من الفأرة باستخدام الاردوينو

مبتدئ

image_pdf

مقدمة

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

سوف تتمكن من برمجة الاردوينو مع حساس الموجات فوق الصوتية، بحيث يقوم بمهام كإيقاف الفيديو أو تقديم وترجيع الفيديو وكذلك مهام التحكم بالصوت.

arduino-python-gesture-control

المواد والأدوات

التحكم بالحاسوب بحركات اليد

اردوينو اونو

التحكم بالحاسوب بحركات اليد

1× سلك الاردوينو

التحكم بالحاسوب بحركات اليد

حزمة أسلاك توصيل (ذكر – أنثى)

التحكم بالحاسوب بحركات اليد

حساس المسافة (HC-SR04)

التحكم بالحاسوب بحركات اليد

1× شريط لاصق ذو وجهين

توصيل الدائرة

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

للمزيد حول حساس الموجات فوق الصوتية يمكنك الرجوع للدرس التالي حساب المسافة بإستخدام حساس الموجات فوق صوتية

arduino-python-gesture-control

تثبيت القطع على جهاز الحاسوب

قم بقص الشريط اللاصق لثلاث قطع صغيرة وثبتها على جهاز الحاسوب كما هو واضح بالصورة:

التحكم بالحاسوب بحركات اليد

ثبت الدائرة الكهربائية كما هو موضح:

التحكم بالحاسوب بحركات اليد

الكود البرمجي للتحقق من قراءة المدخلات

في البداية سنقوم برفع كود برمجي لمحاكاة مشروع التحكم بالحاسوب بحركات اليد بدلًا من الفأرة والتحقق من أن الحساس يعطي قراءات صحيحة، ويتم طباعة الأوامر على شاشة الاتصال التسلسلي

ارفع الكود التالي إلى لوحة الاردوينو عن طريق (IDE) وافتح شاشة الاتصال التسلسلي.

const int trigger1 = 2; //Trigger pin of 1st Sesnor
const int echo1 = 3; //Echo pin of 1st Sesnor
const int trigger2 = 4; //Trigger pin of 2nd Sesnor
const int echo2 = 5;//Echo pin of 2nd Sesnor long time_taken;
int dist,distL,distR; void setup() { Serial.begin(9600);
pinMode(trigger1, OUTPUT);  pinMode(echo1, INPUT); 
pinMode(trigger2, OUTPUT); 
pinMode(echo2, INPUT); 
} /*###Function to calculate distance###*/ void calculate_distance(int trigger, int echo) { digitalWrite(trigger, LOW); delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW); time_taken = pulseIn(echo, HIGH);
dist= time_taken*0.034/2;
if (dist>50)
dist = 50; } void loop() { //infinite loopy calculate_distance(trigger1,echo1); distL =dist; //get distance of left sensor
calculate_distance(trigger2,echo2);
distR =dist; //get distance of right sensor //Uncomment for debudding
/*Serial.print("L=");
Serial.println(distL); Serial.print("R="); Serial.println(distR);
*/ //Pause Modes -Hold
if ((distL >40 && distR>40) && (distL <50 && distR<50)) //Detect both hands
{Serial.println("Play/Pause"); delay (500);} calculate_distance(trigger1,echo1);
distL =dist;
calculate_distance(trigger2,echo2);
distR =dist; if ((distL >40 && distL<50) && (distR ==50)) //Detect Left Hand {Serial.println("Rewind"); delay (500);} if ((distR >40 && distR<50) && (distL ==50)) //Detect Right Hand {Serial.println("Forward"); delay (500);} //Control Modes
//Lock Left - Control Mode if (distL>=13 && distL<=17) {
  delay(100); //Hand Hold Time   calculate_distance(trigger1,echo1);
distL =dist;   if (distL>=13 && distL<=17) {     Serial.println("Left Locked");     while(distL<=40)     {
      calculate_distance(trigger1,echo1);
      distL =dist;
      if (distL<10) //Hand pushed in        {Serial.println ("Vup"); delay (300);}       if (distL>20) //Hand pulled out
      {Serial.println ("Vdown"); delay (300);} }
} } //Lock Right - Control Mode if (distR>=13 && distR<=17) {   delay(100); //Hand Hold Time   calculate_distance(trigger2,echo2);   distR =dist;
  if (distR>=13 && distR<=17)
{     Serial.println("Right Locked");
  while(distR<=40)
{       calculate_distance(trigger2,echo2);       distR =dist;       if (distR<10) //Right hand pushed in       {Serial.println ("Rewind"); delay (300);}       if (distR>20) //Right hand pulled out
      {Serial.println ("Forward"); delay (300);} }
}
} delay(200); }

شرح الكود البرمجي

عرفنا  المتغيرات اللازمة التي  يستخدمها كلا حساسي الموجات فوق الصوتية.

المخرج للحساس الأول (trigger1) والمدخل للحساس الأول (echo1).

المخرج للحساس الثاني (trigger2) والمدخل للحساس الثاني (echo2).

const int trigger1 = 2; //Trigger pin of 1st Sesnor
const int echo1 = 3; //Echo pin of 1st Sesnor
const int trigger2 = 4; //Trigger pin of 2nd Sesnor
const int echo2 = 5;//Echo pin of 2nd Sesnor long time_taken;
int dist,distL,distR; void setup() { Serial.begin(9600); 
pinMode(trigger1, OUTPUT);  pinMode(echo1, INPUT); 
pinMode(trigger2, OUTPUT); 
pinMode(echo2, INPUT); 
}.

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

/*###Function to calculate distance###*/
void calculate_distance(int trigger, int echo)
{
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
digitalWrite(trigger, LOW); time_taken = pulseIn(echo, HIGH);
dist= time_taken*0.034/2;
if (dist>50)
dist = 50; }

داخل دالة ()Loop، يتم التحقق من قيمة المسافة وعلى أساسها يتم الاختيار من بين الاجراءات.

نستخدم المتغير distL ويشير إلى مقدار المسافة بين حساس الموجات الصوتية و اليد الموجود باليسار

نستخدم المتغير distR ويشير إلى مقدار المسافة بين حساس الموجات الصوتية و اليد الموجود باليمين

calculate_distance(trigger1,echo1);
distL =dist; //get distance of left sensor

calculate_distance(trigger2,echo2);
distR =dist; //get distance of right sensor

بناء على المسافة (عند وضع كلتا اليدين على الحساسين في نفس الوقت وكانت المسافة أكبر من 40 وأصغر من 50) سيتوقف الفيديو وعند الرغبة بتشغيل الفيديو مرة أخرى يمكنك إرجاع كلتا يديك لكلا الحساسين.

if ((distL >40 && distR>40) && (distL <50 && distR<50)) //Detect both hands
{Serial.println("Play/Pause"); delay (500);}

بناء على المسافة (المسافة بين الحساس الأيسر واليد اليسرى أكبر من 40 وأقل من 50 والمسافة بين الحساس الأيمن واليد اليمنى تساوي 50)  سيتم ترجيع الفيديو للخلف.

بناء على المسافة (المسافة بين الحساس الأيمن واليد اليمنى أكبر من 40 وأقل من 50 والمسافة بين الحساس الأيسر واليد اليسرى تساوي 50)  سيتم تقديم الفيديو للامام.

if ((distL >40 && distL<50) && (distR ==50)) //Detect Left Hand
{Serial.println("Rewind"); delay (500);}

if ((distR >40 && distR<50) && (distL ==50)) //Detect Right Hand
{Serial.println("Forward"); delay (500);}

إذا كانت المسافة (المسافة بين الحساس الأيسر ويدك اليسرى أقل من 10) سيزيد حجم الصوت.

إذا كانت المسافة (المسافة بين الحساس الأيسر ويدك اليسرى أكبر من 20)  سينقص حجم الصوت.

//Lock Left - Control Mode
if (distL>=13 && distL<=17)
{
  delay(100); //Hand Hold Time
  calculate_distance(trigger1,echo1);
  distL =dist;
  if (distL>=13 && distL<=17)
  {
    Serial.println("Left Locked");
    while(distL<=40)
    {
      calculate_distance(trigger1,echo1);
      distL =dist;
      if (distL<10) //Hand pushed in 
      {Serial.println ("Vup"); delay (300);}
      if (distL>20) //Hand pulled out
      {Serial.println ("Vdown"); delay (300);}
    }
  }
}

إذا كانت المسافة (المسافة بين الحساس الأيمن ويدك اليمنى أقل من 10) سيتم ترجيع الفيديو للخلف.

إذا كانت المسافة (المسافة بين الحساس الأيمن ويدك اليمنى أكبر من 20)  سيتم تقديم الفيديو للأمام.

//Lock Right - Control Mode
if (distR>=13 && distR<=17)
{
  delay(100); //Hand Hold Time
  calculate_distance(trigger2,echo2);
 distR =dist;
if (distR>=13 && distR<=17)
{
Serial.println("Right Locked");
    while(distR<=40)
{
calculate_distance(trigger2,echo2);
 distR =dist;
 if (distR<10) //Right hand pushed in
 {Serial.println ("Rewind"); delay (300);}
 if (distR>20) //Right hand pulled out
 {Serial.println ("Forward"); delay (300);}
 }
}
}
delay(200);
}

تنصيب (Python IDLE) و (Pyserial)

1- تنصيب (Python IDLE)

تثبيت البايثون على نظام ويندوز سوا كان نظام تشغيل 32 بت أو 64 بت هو نفسه.

 انقر على الرابط التالي Python 3.9.2 وثبت البرنامج على جهاز الحاسوب.

حمّل نسخة 32 بت دائمًا مهما كان نظام التشغيل.

التحكم بالحاسوب

افتح ملف exe الذي تم تنزيله واتبع التعليمات لا تقم بتغيير المسار الذي يتم فيه تثبيت Python.

سيكون المسار C:\Program Files (x86)\Python39-32 بشكل افتراضي اتركه كما هو عليه.

التحكم بالحاسوب بحركات اليد

2- ضبط إعدادات لوحة الأوامر

بعد تنصيب البايثون على  جهازك، علينا اجراء التعديلات ليتم السماح بتنفيذ أوامره في شاشة الأوامر Command Prompt.

علينا اضافة مترجم اوامر البايثون إلى امتدادات الأوامر – PATH environment variable.
عليك الذهاب للوحة التحكم بويندوز واتباع المسار التالي:
Control Panel\System and Security\System
اختر من القائمة Advanced system setting:

التحكم بالحاسوب بحركات اليد

انقر على Environment variable:

التحكم بالحاسوب بحركات اليد

انقر على Path من قائمة System Variables.

arduino-python-gesture-control

انقر على New وأضف المسار التالي (أو المسار الذي قمت بتحميل البرنامج عليه):
C:\Program Files (x86)\Python39-32

 انقر على New مرة أخرى وضع مسار مجلد Scripts:

C:\Program Files (x86)\Python39-32\Scripts

التحكم بالحاسوب

بعد اتمامك للخطوات سيكتمل تنصيب البرنامج، يمكنك التحقق من وجوده وذلك بالبحث عنه مع قائمة البرامج Python IDLE.

3- تنصيب (Pyserial)

بعد ذلك علينا تنصيب Pyserial انقر على الرابط التالي وحمله على حاسوبك Pyserial 3.5 

التحكم بالحاسوب عن طريق التلويح

بعد تحميله فك الضغط عنه وانسخ المسار الذي يتواجد فيه ملف Pyserial.

انقر بالسهم اليمين على Command Prompt واختر من القائمة Run as administrator.

arduino-python-gesture-control

اكتب الأمر التالي وضع المسار الذي قمت بتحميل Pyserial فيه:

cd (Pyserial المسار لبرنامج)

حمل setup.py.

python setup.py install
4- تنصيب مكتبة (Pyautogui)

تركيب وحدة Pyautogui للويندوز:

تأكد من أن جهاز الحاسوب متصل بالإنترنت واتبع الخطوات أدناه:

الخطوة 1: افتح صفحة الأوامر بويندوز Windows prompt وقم بتغيير المسار إلى المجلد الذي قمت بتثبيت به البايثون.

cd C:\Program Files (x86)\Python39-32

الخطوة 2: داخل مسار بايثون، سنقوم بترقية Pip وهي أداة في البايثون تساعدنا على تثبيت وحدات البايثون بسهولة استخدم الأمر التالي لترقيتها.

pip install –-upgrade pip

 الخطوة 3: ثبت وحدة Pyautogui.

pip install pyautogui

  الكود البرمجي (بايثون)

افتح برنامج IDLE (Python 3.9 32-bit) من قائمة File اختر New File والصق الكود البرمجي التالي.

التحكم بالحاسوب بحركات اليد

ارفع الكود البرمجي للوحة الاردوينو من قائمة Run انقر على Run module.

import serial #Serial imported for Serial communication
import time #Required to use delay functions
import pyautogui
ArduinoSerial = serial.Serial('com18',9600) #Create Serial port object called arduinoSerialData
time.sleep(2) #wait for 2 seconds for the communication to get established
while 1:
    incoming = str (ArduinoSerial.readline()) #read the serial data and print it as line
    print (incoming)
    if 'Play/Pause' in incoming:
        pyautogui.typewrite(['space'], 0.2)
    if 'Rewind' in incoming:
        pyautogui.hotkey('ctrl', 'left')  
    if 'Forward' in incoming:
        pyautogui.hotkey('ctrl', 'right') 
    if 'Vup' in incoming:         pyautogui.hotkey('ctrl', 'down')     if 'Vdown' in incoming:       pyautogui.hotkey('ctrl', 'up')
  incoming = "";

شرح الكود البرمجي

افتح صفحة جديدة في IDLE Python وقم باستدعاء المكتبات المطلوبة pyautogui, serial python و time.

import serial #Serial imported for Serial communication
import time #Required to use delay functions
import pyautogui

حدد المنفذ COM المستخدم في الاتصال مع الاردوينو.
(هذا سطر قابل للتغيير بناء على نوع المنفذ الذي ستستخدمه في المشروع يمكنك تعيينه عن طريق برنامج اردوينو IDE من قائمة Port).

ArduinoSerial = serial.Serial('com18',9600) #Create Serial port object called arduinoSerialData 
time.sleep(2) #wait for 2 seconds for the communication to get established

 في هذا السطر تتم قراءة المسافة بين اليدين والحساس من المنفذ التسلسلي.

وعلى أساس تلك المسافة يتم تنفيذ الاجراءات وربطها مع اختصارات لوحة المفاتيح.

الاختصارات المستخدمة في هذا الدرس من مشغل VLC:

Space :ايقاف/تشغيل الملف

 Ctrl +  السهم يمين أو يسار: التقديم أو الترجيع دقيقة

Ctrl + السهم للأعلى والأسفل: رفع وخفض مستوي الصوت

while 1:
    incoming = str (ArduinoSerial.readline()) #read the serial data and print it as line
    print incoming
    
    if 'Play/Pause' in incoming:
        pyautogui.typewrite(['space'], 0.2)

    if 'Rewind' in incoming:
        pyautogui.hotkey('ctrl', 'left')  

    if 'Forward' in incoming:
        pyautogui.hotkey('ctrl', 'right') 

    if 'Vup' in incoming:
        pyautogui.hotkey('ctrl', 'down')
        
    if 'Vdown' in incoming:
        pyautogui.hotkey('ctrl', 'up')

ستلاحظ كقدرتك على التحكم بالحاسوب بحركات اليد بدلًا من الفأرة باستخدام الاردوينو يمكنك اختبار صحة الخطوات والاجراءات من خلال الصفحة المنبثقة بعد النقر على Run modul ستظهر  صفحة IDLE Shell.

التحكم بالحاسوب بحركات اليد

لا تنسى إيقاف مصدر الطاقة بعد الانتهاء من استخدام النظام.

 

X
Product added to the cart