สวัสดีชาว Maker สายซิ่งทุกคนครับ! ในยุคที่เทรนด์รถยนต์ไร้คนขับ (Self-driving cars) กำลังมาแรง ระบบควบคุมและวิศวกรรมต่างๆ ถูกพัฒนาไปไกลมาก แต่รู้ไหมครับว่าพื้นฐานสำคัญอย่างหนึ่งของการนำทางรถยนต์ก็คือ "การตรวจจับเส้นเลนถนน (Road Lane Detection)" นั่นเอง
วันนี้เราจะพามาทำระบบตรวจจับเลนถนนแบบง่ายๆ และประมวลผลไวปรี๊ดด้วย Raspberry Pi 3 คู่กับ OpenCV (ไลบรารีประมวลผลภาพยอดฮิต) โดยโปรเจกต์นี้ตั้งใจหลีกเลี่ยงวิธี Linear regression เพื่อลดภาระการคำนวณ ทำให้เราได้เฟรมเรตสูงถึง 17 FPS เลยทีเดียว! เหมาะมากสำหรับสภาพแวดล้อมที่สัญญาณรบกวนต่ำ (Low noise environment) พร้อมแล้วมาลุยกันเลยครับ!
เตรียมอุปกรณ์ (Hardware Components)
ของที่ต้องใช้มีไม่เยอะครับ เน้นฮาร์ดแวร์พื้นฐานที่สาย DIY น่าจะมีติดบ้านกันอยู่แล้ว:
บอร์ดหลัก: Raspberry Pi 3 Model B
กล้อง: Raspberry Pi Camera Module
ไมโครคอนโทรลเลอร์ช่วยคุมพวงมาลัย: Arduino UNO (สำหรับควบคุม Servo)
มอเตอร์: Servos (Tower Pro MG996R) สำหรับกลไกเลี้ยวแบบ Ackermann steering mechanism
💡 Maker's Tip: การทำหุ่นยนต์รถขับเคลื่อนอัตโนมัติ นอกจากวงจรจะเป๊ะแล้ว "แชสซีรถและจุดยึดกล้อง" ก็สำคัญมากครับ แนะนำให้ใช้ เครื่องปริ้นท์ 3D ออกแบบโครงรถและ Mount ยึดกล้อง Pi Camera ให้ได้องศาที่พอดี หากเพื่อนๆ กำลังมองหา บอร์ด Raspberry Pi, Arduino UNO, มอเตอร์ Servo หรืออยากได้ เส้นพลาสติก 3D Print (Filament) คุณภาพสูงเพื่อไปปริ้นท์โครงรถสุดเท่ แวะมาเลือกช้อปของแท้พร้อมส่งได้ที่ Globalbyte เลยครับ! มีของแต่งโปรเจกต์เพียบ!
การตั้งค่าฮาร์ดแวร์และกล้อง (Camera Configuration)
เริ่มต้นจากการต่อสายแพของ Pi Camera เข้ากับพอร์ต CSI บนบอร์ด Raspberry Pi ให้เรียบร้อยครับ (หันแถบสีน้ำเงินหรือจุดคอนแทคให้ถูกฝั่ง)
การเชื่อมต่อสายกล้องเข้ากับพอร์ตบนบอร์ด Raspberry Pi
สำหรับการตั้งค่ากล้องบนระบบปฏิบัติการ (Enable Camera) สามารถทำตามคู่มือทางการของ Raspberry Pi ได้ที่ ลิงก์นี้เลยครับ
การติดตั้งซอฟต์แวร์ OpenCV (Software Setup)
เราต้องลงไลบรารี OpenCV สำหรับ Python ซึ่งขั้นตอนนี้จะใช้เวลา Compile นานพอสมควร (ประมาณ 2 ชั่วโมง) ดังนั้นเสียบสายชาร์จและตั้งจอทิ้งไว้ได้เลยครับ ให้เปิด Terminal แล้วรันคำสั่งพื้นฐาน (Generic stuff) เหล่านี้ก่อน:
จากนั้นให้เลือกรันคำสั่งติดตั้งตามเวอร์ชัน Python ที่คุณใช้งานครับ (เลือกอันใดอันหนึ่ง)
ทฤษฎีเบื้องหลัง: Hough Transform คืออะไร?
ระหว่างที่รอ Raspberry Pi รันคำสั่ง Make (ประมาณ 2 ชั่วโมง) เรามาทำความเข้าใจ Hough Transform กันก่อนครับ เทคนิคนี้คือหัวใจสำคัญที่อยู่เบื้องหลังอัลกอริทึมการตรวจจับเส้นเลนในโลกความจริงส่วนใหญ่เลยล่ะ ลองดูวิดีโออธิบายการทำงานจากคุณ Thales Sehn Körting ด้านล่างนี้ได้เลยครับ (สามารถอ่าน Documentation ของ opencv-python เพิ่มเติมได้ที่นี่ )
VIDEO
โค้ด Python สำหรับ Raspberry Pi (Lane Detection)
เมื่อลง OpenCV เสร็จแล้ว ให้รันโค้ด Python ด้านล่างนี้ครับ โค้ดนี้จะใช้ cv2.HoughLinesP เพื่อหาเส้นขอบถนน และคำนวณมุม (Theta) หากมุมเกินค่า Threshold (ค่าความคลาดเคลื่อน) ที่ตั้งไว้ ระบบจะสั่งงานผ่านขา GPIO ของ Pi เพื่อส่งสัญญาณให้ Arduino หักพวงมาลัยเลี้ยวซ้ายหรือขวาครับ
from picamera.array import PiRGBArray
import RPi.GPIO as GPIO
from picamera import PiCamera
import time
import cv2
import numpy as np
import math
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(8, GPIO.OUT)
theta=0
minLineLength = 5
maxLineGap = 10
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 30
rawCapture = PiRGBArray(camera, size=(640, 480))
time.sleep(0.1)
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
image = frame.array
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(blurred, 85, 85)
lines = cv2.HoughLinesP(edged,1,np.pi/180,10,minLineLength,maxLineGap)
if(lines !=None):
for x in range(0, len(lines)):
for x1,y1,x2,y2 in lines[x]:
cv2.line(image,(x1,y1),(x2,y2),(0,255,0),2)
theta=theta+math.atan2((y2-y1),(x2-x1))
#print(theta)
# GPIO pins were connected to arduino for servo steering control
threshold=6
if(theta>threshold):
GPIO.output(7,True)
GPIO.output(8,False)
print("left")
if(theta<-threshold):
GPIO.output(8,True)
GPIO.output(7,False)
print("right")
if(abs(theta)<threshold):
GPIO.output(8,False)
GPIO.output(7,False)
print("straight")
theta=0
cv2.imshow("Frame",image)
key = cv2.waitKey(1) & 0xFF
rawCapture.truncate(0)
if key == ord("q"):
break
คลิกดูโค้ด Python ฉบับเต็ม (View full Python code) ซ่อนโค้ด Python (View less)
ตัวอย่างผลลัพธ์การทำงาน (Sample Outputs)
มาดูภาพตัวอย่างการใช้ Hough Transform ตรวจจับขอบของเส้นเลน (สีเขียว) กันครับ!
คลิกเพื่อดูภาพตัวอย่างการตรวจจับเส้นเลน (View Output Images) ซ่อนภาพตัวอย่าง (Hide Images)
โค้ด Arduino สำหรับคุมพวงมาลัย (Servo Control)
ในฝั่งของมอเตอร์บังคับเลี้ยว เราจะต่อขา GPIO จาก Raspberry Pi เข้ากับบอร์ด Arduino Mega / UNO เพื่อทำหน้าที่อ่านสัญญาณ (HIGH/LOW) แล้วสั่งให้ Servo Motor หมุนทำมุมเลี้ยวซ้าย (118 องศา), ขวา (62 องศา) หรือตรง (90 องศา) ครับ
#include <Servo.h>
Servo myservo;
void setup() {
myservo.attach(10); // attach servo motor PWM (orange) wire to pin 10
pinMode(0, INPUT); // attach GPIO 7 & 8 pins from Pi to arduino pin 0 & 1
pinMode(1, INPUT);
}
void loop() {
if(digitalRead(0)==HIGH && digitalRead(1)==LOW)
{
myservo.write(118);
}
if(digitalRead(1)==HIGH && digitalRead(0)==LOW)
{
myservo.write(62);
}
if(digitalRead(1)==LOW && digitalRead(0)==LOW)
{
myservo.write(90);
}
}
นี่เป็นเพียงจุดเริ่มต้นของการทำรถยนต์อัตโนมัติเท่านั้น หากใครมีไอเดียเจ๋งๆ หรืออยากลองปรับปรุงโค้ดให้หลบหลีกสิ่งกีดขวางได้ด้วย ก็ลองนำไปต่อยอดกันดูนะครับ!
*คำเตือน: เนื้อหานี้เป็นการสรุปและเรียบเรียงแนวคิดจากโปรเจกต์ต้นฉบับภาษาอังกฤษ ข้อมูลการติดตั้งโปรแกรมและโค้ดที่แสดงในบทความอาจต้องมีการปรับแก้ให้ตรงกับเวอร์ชันของ OS และฮาร์ดแวร์ของผู้ใช้งาน ผู้สนใจควรศึกษารายละเอียดเชิงลึก ข้อจำกัดของระบบ และวิธีแก้ปัญหาเพิ่มเติมจาก
เว็บไซต์ต้นฉบับ ก่อนลงมือปฏิบัติ