كيف صنعت سيارة تحكم عن بعد (الجزء 2)

الأربعاء, ديسمبر 13, 2017


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

بناء السيارة

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


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

عملت على صنع لوحة بلاستيكية لأثبت عليها القطع الإلكترونية، أردوينو و L298N Driver، هنا سنحتاج أنابيب PVC، قد يبدو الأمر غريبا، أنا نفسي لم اصدق ان الامر سينجح في أول مرة.

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

باستعمال المنشار قطعت جزء من الأنبوب بطول 15cm ثم قطعته من المنتصف، قمت بعدها بتسخينه على النار حتى يصبح لينا و يمكنني تسويته، بعد التسخين بشكل جيد، وضعته على سطح مكتبي، و استعملت لوحا خشبيا حتى أضغط عليه و أسويه، في النهاية حصلت على لوح بلاستيكي صلب، لونه قبيح، لكن العمل عليه سهل.

لم يكن تقطيعه سهلا، استعملت cutter و مسطرة معدنية، سبب لي هذا الكثير من الآلام في يدي و الكثير من الجروح، هذا ماذا يحدث عندما لا تتوفر على الادوات المناسبة للعمل، قمت باستعمال مثقابي لوضع ثقوب لنثبت بها القطع الإلكترونية.

لتثبيت القطع الإلكترونية استعملت بعض البراغي التي احتفظ بها من الخردة التي أجمعها، السيارة نفسها كان بها عدد كبير من البراغي استعملتها لتثبيت القطع الإلكترونية


لتغذية أردوينو و دارة قيادة المحرك L298N Driver استعملت بطارتين 18650 مركبتين على التوالي، كل بطارية توفر جهد 3.7 فولت ، و معا يوفران جهد 7.4 فولت، و حتى الآن هذا كافي لتغذية السيارة و السير بسرعة متوسطة، لاحقا سأحتاج إضافة بطارية أخرى حتى اوفر التغذية اللازمة لقطع إلكترونية أخرى و لتشغيل المحرك بسرعة أكبر.

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

اضطررت أن اصنع حامل البطاريات بنفسي من أنابيب PVC، و قمت بتركيبه أسفل السيارة مكان البطاريات القديمة.


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

دارة الشحن بها منفذ Micro USB و USB، أي يمكن شحنها عن طريق اي شاحن بمنفذ MicroUsb

 

و لتشغيل السيارة و إطفائها أضفت قاطع تيار، حصلت عليه من السيارة نفسها، و قمت بنفس الوقت بتمرير الاسلاك الكهربائية من 
البطاريات اسفل السيارة إلى أعلى السيارة لتجهيزها لربطها مع القطع الإلكترونية.


السيارة ما زالت تحتاج لمحرك أمامي للتحكم في دوران العجلات الأمامية، اخترت استعمال محرك Servo، هذا النوع من المحركات التحكم به سهل، و يمكنه الدوران بزاوية محددة، و حسب بحثي كل سيارات التحكم عن بعد Rc car تستعمل هذا النوع من المحركات للتحكم بالعجلات الأمامية.

في هاته اللحظة التي اكتب فيها هذا الموضوع المحرك الذي استعملته تعطل، و انكسرت التروس 'Gears' البلاستيكية داخله، بسبب كثرة اصطدام العجلات الامامية للسيارة مما يسبب ضغط على المحرك، لحل هذا المشكل اشتريت الان محرك سيرفو اخر لكن بتروس 'Gears' من المعدن، و أفكر في طريقة لحماية العجلات الامامية من الاصطدامات.

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




و الآن حان وقت توصيل كل شيء مع بعض، استعملت أسلاك توصيل اغلبها من نوع Female to Female،الاسلاك المبعثرة في كل مكان مزعجة، أنا من الأشخاص الذي لا يهتمون إن كانت حياتهم مبعثرة، لكن عندما يتعلق الامر بالاسلاك يجب أن تكون مرتبة.

لهذا التوفر على اسلاك من انواع مختلفة مهم، و إلا ينتهي بك الامر مع فوضى من الاسلاك في كل مكان، و تصبح ارهابيا مشتبها به.

الصورة الآتية توضح كيفية توصيل جميع القطع الإلكترونية في السيارة.




جهاز التحكم 

بنيت جهاز التحكم فقط على لوحة التجارب، فقط كمرحلة أولى حتى استقر على نموذج، ثم أنتقل إلى تلحيم 'Solder' جميع القطع معا، حتى أحصل على جهاز تحكم صغير الحجم و مريح في التحكم.


ثبتت لوحة التجارب و أردوينو على لوح بلاستيكي من أنابيب PVC، و قمت بتوصيل جميع القطع الإلكترونية معا على لوحة التجارب باستعمال اسلاك التوصيل.

اخترت أن أسير مع نفس توزيع الأزرار في جهاز تحكم PS، زر Analog على اليسار للتحكم في السرعة للأمام و اليسار، و الأزرار الأربعة على اليمين للتحكم في الإتجاه أو التقدم للأمام أو الرجوع للوراء.

البرمجة 

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

جهاز التحكم يعمل كالآتي، Analog Joystick تتحكم فقط في التقدم للأمام و الرجوع للوراء، بينما الأزرار على اليمين تتحكم في تقدم السيارة إلى الأمام، الرجوع للوراء، الدوران يمينا و الدوران يسارا.

- نبرمج  جهاز التحكم عند الضغط على زر التقدم للأمام (أو تحريك Joystick للأمام)، إرسال أمر 'a' للسيارة، ما دمت أضغط على الزر يستمر جهاز التحكم بإرسال الأمر 'a' للسيارة.
- نبرمج السيارة عند استقبال الأمر 'a' لشتغيل المحرك الخلفي للتقدم للأمام، و عندما تتوقف عن استقبال أي أمر،تقوم بتوقيف المحركات.

إرسال الأوامر يكون ببساطة عن طريق Serial Communication بين وحدة الإرسال HC-12 و أردوينو.
و إستقبالها في السيارة يكون بنفس الطريقة عن Serial Communication.
كود برنامج جهاز التحكم
#define x A0
#define y A1

#define FORWARD 15
#define BACKWARD 16
#define RIGHT 19
#define LEFT 2 



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(x, INPUT);
  pinMode(y, INPUT);
  
}

void loop() {
  
  int vx = analogRead(x);

  if(vx < 100 || digitalRead(FORWARD) == HIGH) sendCmd('a');
  else if (vx > 900 || digitalRead(BACKWARD)) sendCmd('b');
  
  if (digitalRead(RIGHT) == HIGH) sendCmd('c');
  else if (digitalRead(LEFT) == HIGH) sendCmd('d');
}


void sendCmd(char x){
  Serial.write(x);
  delayMicroseconds(50);
}
كود برنامج السيارة

#include <Servo.h>

#define RIGHT 120
#define LEFT 60
#define FORWARD 2
#define BACKWARD 3

unsigned long pre;
Servo Servo1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Servo1.attach(4);

  pinMode(FORWARD, OUTPUT);
  pinMode(BACKWARD, OUTPUT);
  for(int i=0; i<8; i++){
    digitalWrite(i, LOW);
  }
}

void loop() {
  if(Serial.available() > 0){
    pre = millis();
    char x = Serial.read();
    switch(x){     
      case 'a':
        forward();
      break;

      case 'b':
        backward();
      break;
      
      case 'c':
        left();
      break;

      case 'd':
        right();
      break;
    }

  } else {
    if(millis() - pre > 100){
      stopAll();
      stright();
    }
  }
}



void forward(){
    digitalWrite(FORWARD, HIGH);
    digitalWrite(BACKWARD, LOW);
}

void backward(){
  digitalWrite(FORWARD, LOW);
  digitalWrite(BACKWARD, HIGH);
}

void stopAll(){
  digitalWrite(FORWARD, LOW);
  digitalWrite(BACKWARD, LOW);
}


void right(){
  Servo1.write(RIGHT);
}


void left(){
  Servo1.write(LEFT);
}

void stright(){
  Servo1.write(85);
}

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

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

لماذا لا أقوم ببساطة بإرسال أمر واحد فقط عند الضغط على الزر، طالما أنا ضاغط على الزر فلا حاجة لإرسال نفس الأمر أكثر من مرة، و لا أرسل أمرا جديدا إلى عندما اتوقف عن الضغط عن الزر.

هنا سنحتاج إلى التحقق متى تغير الأمر نقوم بإرساله، و متى كان الأمر الذي سنقوم بإرساله هو نفس الأمر السابق فلا حاجة لإرساله.

و سيصبح الأمر كالتالي عند الضغط على الزر، فهنا سنرسل الأمر 'a'، طالما ما زلنا نضغط على الزر لا نرسل شيئا، لكن فقط عندما نتوقف عن الضغط عن الزر عنا نرسل أمر جديدا هو 'c' أمر التوقف.

يصبح الكود كالتالي:
كود جهاز التحكم

#define x A0
#define y A1

#define FORWARD 15
#define BACKWARD 16
#define RIGHT 19
#define LEFT 2 

char state1 = 0;
char oldState1 = state1;

char state2 = 0;
char oldState2 = state2;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(x, INPUT);
  pinMode(y, INPUT);
  pinMode(FORWARD, INPUT);
  pinMode(BACKWARD, INPUT);
  pinMode(RIGHT, INPUT);
  pinMode(LEFT, INPUT);
  for(int i=0;i<8;i++) digitalWrite(i, HIGH);
}

void loop() {
  
  // put your main code here, to run repeatedly:
  int vx = analogRead(x);
  if(vx > 900 || digitalRead(FORWARD) == HIGH) state1 = 'b';
  else if(vx < 100 || digitalRead(BACKWARD) == HIGH) state1 = 'a';
  else state1 = 'c';

  if(state1 != oldState1){
    oldState1 = state1;
    sendCmd(state1);
  }

  if(digitalRead(RIGHT)) state2 = 'e';
  else if(digitalRead(LEFT)) state2 = 'd';
  else state2 = 'f';

  if(state2 != oldState2){
    oldState2 = state2;
    sendCmd(state2);
  }
 }

void sendCmd(char x){
  Serial.println(x);
  delayMicroseconds(2000);
}
كود برنامج السيارة

#include <Servo.h>

#define RIGHT 120
#define LEFT 60
#define FORWARD 2
#define BACKWARD 3

char cmd;

Servo Servo1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Servo1.attach(4);

  pinMode(FORWARD, OUTPUT);
  pinMode(BACKWARD, OUTPUT);
  for(int i=0; i<8; i++){
    digitalWrite(i, LOW);
  }
  stright();
}

void loop() {
  if(Serial.available() == 1){
    cmd = Serial.read();
    //Serial.write(cmd);
  }
  switch(cmd){     
      case 'a':
        forward();
      break;

      case 'b':
        backward();
      break;
      
      case 'c':
        stopAll();
      break;

      case 'd':
        right();
      break;

      case 'e':
        left();
      break;

      case 'f':
        stright();
      break;
    }
}



void forward(){
    digitalWrite(FORWARD, HIGH);
    digitalWrite(BACKWARD, LOW);
}

void backward(){
  digitalWrite(FORWARD, LOW);
  digitalWrite(BACKWARD, HIGH);
}

void stopAll(){
  digitalWrite(FORWARD, LOW);
  digitalWrite(BACKWARD, LOW);
}


void right(){
  Servo1.write(RIGHT);
}


void left(){
  Servo1.write(LEFT);
}

void stright(){
  Servo1.write(100);
}

النهاية

و أخيرا بعد سنتين من المحاولة نجحت، سنتين بين أول محاولة فاشلة و أول محاولة فاشلة، بالرغم أنه مشروع بسيط، و كلف الكثير من المال و الجهد، لكنه كان ممتعا، الغاية من صنع الاشياء لم تكن اليوم الاشياء نفسها، بل الغاية كانت دوما هي متعة أن تصنع شيئا.

حسنا هذه ليست النهاية المشروع بدأ لتوه، تحديثات أخرى كبيرة قادمة في هذا المشروع، أخطط لتحويلها لسيارة ذاتية القيادة، يب SELF DRIVING CAR.
أحب أن أسمع أراء من هم أكثر خبرة مني إن كانت لديك أي فكرة، أو تريد المشاركة معي في بناء المشروع أهلا بك على Github، لا زلت جديدا هناك، لست جيدا للغاية في تلك الاشياء، لذا سأكون شاكرا لأي مساعدة.

مقالات مشابهة

0 comments