รถหุ่นยนต์หลบสิ่งกีดขวาง

สิ่งหนึ่งที่่ค้างคาใจมาตั้งแต่เด็กคืองานอดิเรกด้านอิเล็กทรอนิกส์ ด้วยความที่เราเรียนจบมาทางนี้ ซึ่งที่ผ่านมาเราก็เคยเล่นๆ เลิกๆ เป็นพักๆ ปัญหาส่วนใหญ่ที่พบคือ พอเราต่อวงจรในแบบที่อยากได้เสร็จแล้ว เราก็จะไม่รู้ว่าจะต่อยอดมันได้ยังไง มันเหมือนเป็นของเล่นที่เล่นแล้วก็หยุดอยู่แค่นั้น หนนี้ก็เป็นอีกครั้งหนึ่งที่เรากลับมาหามันใหม่ ในยุคสมัยที่เปลี่ยนไป คือเข้าสู่โลกของ Robotics และ AI และรวมไปถึง IoT ก็ไม่รู้เหมือนกันว่าจะเล่นๆ เลิกๆ อีกเป็นรอบที่ล้านรึเปล่า เหอๆ

ก่อนหน้านี้ผมเลยเล่น Raspberry Pi อยู่ แต่ส่วนที่ไม่ค่อยชอบเกี่ยวกับมันคือ มันเป็นคอมพิวเตอร์ดีๆ นี่เอง มีระบบปฏิบัติการ ทำให้เวลาปิดเครื่องจะต้องส่งคำสั่งปิด ไม่เหมือนเครื่องใช้ไฟฟ้าที่สามารถเปิดปิดได้ทันที ทำให้มันไม่สะดวก และโดยเฉพาะอย่างยิ่ง เวลาไฟดับ ไฟตก ซึ่งบ้านเราไฟก็ไม่ได้นิ่งตลอดเวลาขนาดนั้น ถ้าเรามี Pi ไว้ทำงานอะไรสักอย่างเปิดทิ้งไว้ตลอดเวลา ก็จะต้องมี UPS ให้มันด้วย ไม่งั้นไม่รอดแน่ๆ ไฟตกทีเดียวไปหมด ทำให้รอบนี้ผมหันมาสนใจ Arduino และผองเพื่อนมากกว่า

โปรเจ็ค Arduino แรกที่อยากทำก็คือรถหุ่นยนต์นี่แหละ ตอนแรกนึกถึงรถที่บังคับไปมาได้ แต่ไปๆ มาๆ อยากให้มันมีความ autonomous สักนิด เหมาะกับยุคสมัย ก็เลยอยากได้รถที่วิ่งแล้วหลบสิ่งกีดขวางไปมาได้เองดีกว่า แม้จะยังไม่ใช่ machine learning อย่างแท้จริง เป็นแค่ logic ง่อยๆ ธรรมดา ก็ถือเป็นจุดเริ่มต้นที่ดี

Arduino Uno R3

ผมเลือกใช้ Arduino Uno R3 เป็นสมองของรถ ไม่ใช่อะไร มันเป็นรุ่นมาตรฐาน ในการขับเคลื่อน จำเป็นต้องมีสิ่งที่เรียกว่า L298N Motor Driver เพื่อให้มีกำลังไฟมาพอที่จะขับมอเตอร์ล้อได้ด้วย และมี ultrasonic sensor ที่ช่วย Detect สิ่งกีดขวางตรงหน้า เพื่อที่จะได้หลบได้ ในส่วนของล้อก็เลือกแบบง่ายที่สุดคือแค่ 2 ล้อ และเป็นล้อที่เลี้ยวง่ายๆ ด้วยการให้ล้อหนึ่งหมุนทวนเข็ม อีกล้อหมุนตามเข็ม ไม่ต้องมีพวงมาลัย หรือเพลาที่เอียงได้ให้ยุ่งยากอะไร โดยมอเตอร์เหลืองที่ใช้สามารถขับได้ด้วยไฟตรงตั้งแต่ 3-12V เลย และส่วนสุดท้ายที่เพิ่มเติมขึ้นมาคือ Sensor Shield ที่ไม่ได้มีประโยชน์อะไรแค่ทำให้ Arduino สามารถเชื่อมต่อกับอุปกรณ์ต่อพ่วงได้เยอะขึ้น เพราะมีพอร์ตมากขึ้น แค่นั้นเอง

DC Motor และล้อ
Sensor Shield V5

อุปกรณ์ที่ใช้

สิ่งที่ต้องเรียนรู้เพิ่มเติมในโลกของ Arduino คือ การเขียนโปรแกรมให้มันผ่าน Arduino IDE ซึ่งเป็นซอฟต์แวร์ สำหรับเขียนคำสั่งง่ายๆ คอมไพล์ แล้วอัพโหลดเข้าไปในตัว Arduino ผ่านสาย USB ทักษะอีกอย่างหนึ่งที่ต้องมีเวลาเล่น Arduino คือ การบัดกรี เพื่อเชื่อมต่อสายไฟต่างๆ เข้าด้วยกันแบบถาวร ซึ่งเลี่ยงไม่ได้ เพราะไม่ใช่ทุกส่วนจะต่อเข้าหากันผ่านสายจัมเปอร์ได้หมด บางส่วนก็ยังจำเป็นต้องบัดกรีอยู่ เช่น ส่วนที่ต่อกับกะบะถ่านไฟฉาย หรือมอเตอร์ และสวิตซ์ปิดเปิดเป็นต้น ดังนั้นควรมีอุปกรณ์บัดกรีไว้ประจำตัว และระมัดระวังเรื่องการสูดดมควัน ควรทำงานในที่มีอากาศถ่ายเทเสมอ และมีพัดลมช่วยเป่าควันที่เกิดขึ้นออกไปในทางที่ห่างตัวเรา รวมทั้งต้องมีคีมปลอกสายไฟ เพื่อให้ทำงานได้สะดวกและดูเรียบร้อยขึ้นด้วย

L298N

L298N Motor Driver

สำหรับตัวขับมอเตอร์ตัวนี้ สามารถขับมอเตอร์ให้เคลื่อนไหวได้ต่างกันสองตัว (Out 1,Out 2) โดยใช้ไฟจากแหล่งจ่ายได้ Vcc  และยังจ่ายไฟออกไปเลี้ยง Arduino ได้ด้วยทางพอร์ต 5V ทำให้ไม่ต้องมีแหล่งจ่ายไฟหลายแหล่ง (ต้องใส่ Jumper 5VEN ไว้เมื่อต้องการให้พอร์ต 5V กลายเป็นแหล่งจ่ายไฟออก) ส่วนการบังคับล้อก็ทำผ่านพอร์ตสัญญาณ (IN 1,2,3,4, ENA, ENB) ซึ่งสามารถปรับได้ทั้งทิศทางและความเร็วรอบ  รายละเอียดของการใช้งานสามารถดูได้จาก ที่นี่

Ultrasonic Sensor 

หลักการของ sensor ตัวนี้คือมันจะส่งคลื่นอินฟาเรดออกไปให้สะท้อนกลับมา แล้วคำนวณหาว่ามีสิ่งกีดขวางอยู่ข้างหน้าหรือไม่ โดยวัดเวลาที่ใช้ในการสะท้อนกลับ ซึ่งเสียงมีความเร็ว 340 เมตรต่อวินาที เดินทางไปกลับ เท่ากับว่า ถ้าใช้เวลาเดินทาง T วินาที ก็เท่ากับมีสิ่งกีดขวางอยู่ข้างหน้าห่างออกไป (34x T)/2  เป็นต้น

ภาพวงจรเชื่อมต่อ

ตรรกของโปรแกรมก็ง่ายๆ หุ่นยนต์จะวิ่งไปข้างหน้าเสมอ แต่เมื่อไรก็ตามที่จับสิ่งกีดขวางตรงหน้าที่ห่างออกไปไม่เกิน 15 ซม.ได้ จะทำการถอยหลัง 15 ซม. แล้วหมุนตัวโดยสุ่มทิศทาง แล้วค่อยวิ่งไปข้างหน้าเหมือนเดิม ถ้าหากเจอสิ่งกีดขวางอีกก็ทำแบบเดิมอีก ไปเรื่อยๆ แค่นั้นเลย

ตัวอย่าง code ที่ใช้

// Motor A connections
int enA = 9;
int in1 = 8;
int in2 = 7;
// Motor B connections
int enB = 3;
int in3 = 5;
int in4 = 4;

int trigPin = 11; // TRIG pin
int echoPin = 10; // ECHO pin

float duration_us, distance_cm;

void setup() {
// Set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);

// Turn off motors – Initial state
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);

Serial.begin (9600);

// configure the trigger pin to output mode
pinMode(trigPin, OUTPUT);
// configure the echo pin to input mode
pinMode(echoPin, INPUT);

}

void loop() {

if (isClear()) {

// Set Speed
analogWrite(enA, 128);
analogWrite(enB, 128);

// Turn on motor A & B
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);

} else {

changeDirection();

}
delay(500);

}

// This function lets you control spinning direction of motors
void changeDirection() {

digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
delay(1000);

digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
delay(1500);

}

bool isClear() {
// generate 10-microsecond pulse to TRIG pin
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// measure duration of pulse from ECHO pin
duration_us = pulseIn(echoPin, HIGH);

// calculate the distance
distance_cm = 0.017 * duration_us;

if (distance_cm<15) {
return false; }
else {
return true;
}

}

 

Leave a Reply

Your email address will not be published. Required fields are marked *