Introduction
พอได้ยินคำว่า "เลนฟอลโลว์วิ่ง" ฉันก็นึกถึงระบบช่วยเหลืออัตโนมัติในรถยนต์ที่คอยให้รถอยู่ในเลนตลอดเวลา แต่การจะสร้างระบบแบบนี้ขึ้นมาเนี่ย มันต้องใช้อะไรบ้างวะ? เพื่อให้เข้าใจความซับซ้อนของอัลกอริทึมเลนฟอลโลว์วิ่ง ฉันเลยตัดสินใจสร้างระบบนี้ขึ้นมาเองสำหรับรถโรเวอร์ใน Arduino Engineering Kit
ฉันได้เรียนรู้ว่า การจะสร้างอัลกอริทึมเลนฟอลโลว์วิ่งให้เวิร์ค ต้องมีสามส่วนหลัก: อัลกอริทึมตรวจจับเลน, ตรรกะการตามเลน, และอัลกอริทึมควบคุมเพื่อให้โรเวอร์ทำตามตรรกะนั้น ฉันเลยจับสองส่วนแรกมัดรวมกันเป็น อัลกอริทึมวิทัศน์ (vision) แล้วฝังลงไปในบอร์ด Raspberry Pi 3 (Pi) ส่วนบอร์ด Arduino MKR1000 นั้นเป็นที่รัน อัลกอริทึมควบคุม (controls) ซึ่งจะรับคำสั่งจาก Pi ผ่าน Wi-Fi ในโปรเจคนี้ เราจะโฟกัสที่เฟสวิทัศน์เป็นหลัก

สำหรับใครที่ยังไม่รู้จัก Arduino Engineering Kit ชุดนี้มันมาพร้อมกับฮาร์ดแวร์และซอฟต์แวร์ทั้งหมดที่ต้องใช้เพื่อสร้างและโปรแกรมโปรเจคภาคปฏิบัติสามอย่าง ซึ่งจะสอนคุณเกี่ยวกับแนวคิดพื้นฐานทางวิศวกรรมไปด้วยในตัว
ก่อนจะลงลึกถึงรายละเอียดของโรเวอร์ตามเลน นี่คือตัวอย่างการทำงานของมัน วิดีโอยังให้ภาพรวมของอัลกอริทึมวิทัศน์อีกด้วย
Physical setup
ภาพต่อไปนี้ (Fig 3) แสดงการตั้งค่าโรเวอร์ ถึงแม้ในภาพจะเห็น Pi อยู่บนตัวโรเวอร์ แต่ในการใช้งานจริง Pi ถูกวางไว้บนพื้นข้างปลั๊กไฟ เพราะแบตเตอรี่ของโรเวอร์จ่ายไฟให้ทั้ง Pi และตัวโรเวอร์พร้อมกันไม่ไหว

เพื่อที่จะดีพลอยอัลกอริทึมวิทัศน์ลง Pi ได้ เลนที่ใช้ต้องเรียบง่าย ฉันเลยเลือกใช้เลนสีขาวบนพื้นหลังสีเข้ม (เหมือนในภาพหน้าปก) เพื่อให้อัลกอริทึมตรวจจับเลนทำงานได้ง่ายและเร็ว
Software used
MATLAB, Simulink,Stateflow,Computer Vision Toolbox,Simulink Support Package for Arduino Hardware,Simulink Support Package for Raspberry Pi
เหตุผลใหญ่ที่ใช้ Simulink ก็เพราะมันช่วยลดความยุ่งยากในเรื่อง การสื่อสารระหว่าง Arduino กับ Raspberry Pi ซึ่งเป็นสิ่งสำคัญมากสำหรับโปรเจคนี้ การส่งข้อมูลระหว่างอุปกรณ์สองตัวที่เชื่อม Wi-Fi ได้มักจะวุ่นวายเพราะต้องกังวลเรื่องประเภทข้อมูล ขนาดข้อมูล และอัตราการสุ่มตัวอย่าง แต่ด้วย Simulink คุณแค่ ใช้บล็อกจาก Simulink Support Package เพื่อส่งและรับข้อมูล แล้วตั้งค่า IP Address ของแต่ละอุปกรณ์ให้ถูกต้องก็พอ
อีกข้อดีของการใช้ Simulink คือมันช่วยให้คุณโปรแกรมบอร์ดฮาร์ดแวร์ต่าง ๆ ได้โดยไม่ต้องมานั่งเขียนโค้ดเอง แค่คลิกปุ่มเดียว คุณก็สามารถสร้างโค้ด C/C++ เพื่อดีพลอยโมเดล Simulink ลงบนฮาร์ดแวร์ฝังตัวได้เลย

Vision algorithm
อัลกอริทึม Vision ตัวนี้มันจับทั้งตรวจจับเลนและตามเลนไปด้วยเลยนะน้อง ภาพรวมการทำงานมันเป็นแบบนี้:
1. ตรวจจับเลน (Lane detection):
a. รับและประมวลผลภาพเพื่อดึงขอบของเลนออกมา
b. จากตำแหน่งและความชันของเลนที่เจอ คำนวณหาจุดศูนย์กลางเลน
2. ตรรกะการตามเลน (Lane following logic):
a. เลี้ยวเพื่อให้ตรงกับจุดศูนย์กลางเลน แล้วขับไปข้างหน้าเล็กน้อย
Lane Detection

ในโมเดล Simulink นะ บล็อก Edge Detection นี่ตรงกับขั้นตอน 1a เลย ส่วน บล็อก Calculate Lane Center ก็ตรงกับขั้นตอน 1b

ข้างในระบบย่อย Edge Detection แสดงใน Fig 6 นี้แหละ ตรงนี้เราจะดึงขอบเขตเลนออกมาจากภาพอินพุตโดยใช้การกำหนดเกณฑ์สี (color thresholding) และบล็อกตรวจจับขอบ (edge detection) ที่มีมาให้ในตัว ทำให้เราไม่ต้องมานั่งเขียนโค้ดอัลกอริทึมซับซ้อนเองให้ปวดหัว สิ่งที่เราต้องทำก็แค่ปรับค่าเกณฑ์สีในโมเดล แล้วเลือกอัลกอริทึมตรวจจับขอบที่ให้ผลลัพธ์ดีที่สุด ตัวนี้แหละที่ช่วยให้เราปรับพารามิเตอร์บางตัวได้ในขณะที่อัลกอริทึมกำลังรันอยู่บนฮาร์ดแวร์ แล้วเห็นผลการเปลี่ยนแปลงทันทีเลย

บล็อก SDL Video Display ของ Simulink ช่วยให้เรามองเห็นผลลัพธ์ของอัลกอริทึม หรือสิ่งที่โรเวอร์เห็นได้ (Fig 7) งานนี้จัดไปวัยรุ่น!
ส่วนบล็อก Calculate Lane Center นี่เป็น MATLAB Function block ซึ่งทำให้เรารันฟังก์ชัน MATLAB บนฮาร์ดแวร์ผ่าน Simulink ได้โดยตรง ฟังก์ชันนี้ทำงานหลักๆ 3 อย่าง:
1) เลือกส่วนของภาพ (slice) จากภาพที่ตรวจจับขอบแล้วมา โดยเลือกส่วนที่อยู่ใกล้ๆ ด้านล่างเพื่อให้เห็นแค่เลนเดียว
2) หาความชันของขอบที่เจอ ถ้าค่ามันเป็นบวก โรเวอร์ก็รู้ว่านั่นคือขอบซ้าย และต้องแก้ไขโดยการเลี้ยวขวา ในทางกลับกัน ถ้าค่ามันเป็นลบ โรเวอร์ก็ต้องเลี้ยวซ้าย
3) หาจุดศูนย์กลางของภาพ (เครื่องหมายบวกสีแดงใน Fig8) และจุดศูนย์กลางของเลน (ระยะครึ่งทางระหว่างเลนที่ตรวจจับได้กับอีกฝั่งของภาพ; เครื่องหมายบวกสีเขียวใน Fig8) ระยะห่างระหว่างสองจุดนี้คือขนาดของการเลี้ยวที่โรเวอร์ต้องการ

Integrated Computer Vision Navigation
ยานยนต์หุ่นยนต์ขั้นสูงตัวนี้ใช้สถาปัตยกรรมการประมวลผลแบบผสมผสานเพื่อให้สามารถตามเลนได้อย่างอัตโนมัติในความเร็วสูง สู้งานนะน้อง!
- MATLAB Image Processing Hub: Raspberry Pi ทำหน้าที่จับภาพวิดีโอสดและส่งเฟรมไปยังพีซีที่รัน MATLAB สคริปต์ MATLAB จะใช้ "Hough Transform" ในการระบุเส้นเลนและคำนวณมุมเลี้ยวที่ต้องการ
- Real-Time Kinematic Serial Bridge: MATLAB จะส่งค่ามุมเลี้ยวและความเร็วที่คำนวณได้ไปยัง Arduino ผ่านการสื่อสารแบบอนุกรมความเร็วสูง Arduino จะทำหน้าที่เป็นตัวควบคุมมอเตอร์ระดับล่าง คอยจัดการสัญญาณ PWM ให้กับล้อ ห้ามช็อตนะตัวนี้!
Performance
- Closed-Loop Speed Maintenance: Arduino จะคอยเฝ้าดูตัวเข้ารหัสแสง (optical encoders) บนล้อแบบละเอียดยิบ เพื่อให้มั่นใจว่ารถโรเวอร์ของเราจะรักษาความเร็วเป้าหมายไว้ได้ แม้จะกำลังเลี้ยวหรือปีนเนินอยู่ก็ตาม งานนี้ต้องแม่น!
Logic การตามเลน
เราใช้ Stateflow มาจัดการให้รถโรเวอร์ของเราทำงานเป็น 3 สถานะ (state) คือ start, drive และ turn ไอ้เจ้า Stateflow นี่แหละที่โคตรมีประโยชน์สำหรับโปรเจคแบบนี้ เวลาที่เราอยากให้มันทำอะไรตามเหตุการณ์ (event) ที่เกิดขึ้น
เราอยากให้รถเริ่มขยับก็ต่อเมื่อมั่นใจแล้วว่าการเชื่อมต่อระหว่าง Pi กับ Arduino นั้นพร้อมแล้ว (นี่แหละ event ตัวแรก) ซึ่งสถานะนี้เราเรียกว่า Start ใน Fig 9 ด้านล่างนี้ ในทำนองเดียวกัน เราก็อยากให้รถออกจากสถานะ Turn ไปสู่สถานะ Drive ได้ ก็ต่อเมื่อมันหันหัวไปในทิศทางที่ต้องการแล้วเท่านั้น (นี่ก็เป็นอีก event นึง)

Start: ในสถานะนี้ เราจะเรียกใช้ฟังก์ชัน receivedHandshake เพื่อให้แน่ใจว่าการเชื่อมต่อระหว่าง Arduino กับ Pi นั้นเกิดขึ้นจริงก่อนที่จะปล่อยให้รถขับอัตโนมัติ และเพื่อความชัวร์ เรายังเพิ่มดีเลย์ 3 วินาทีก่อนให้รถขยับ เพื่อลดปัญหาที่อาจเกิดจากความล่าช้า (latency) อีกด้วย ห้ามใจร้อน!
Turn: สถานะ Turn จะเรียกฟังก์ชัน turnToLaneCenter ซึ่งใช้ algorithm การตรวจจับเลนที่เราเห็นกันไปแล้วในหัวข้อก่อนหน้า จากนั้นก็จะส่งคำสั่งไปให้ Arduino ผ่าน Wi-Fi เพื่อให้รถหันไปในทิศทางและมุมที่ต้องการ รถจะหยุดหันเมื่อตัวแปร headingReached กลายเป็น 1 (จริง) นี่แหละคือเงื่อนไขการออกจากสถานะ (exit condition) พอออกมาแล้วรถก็จะเข้าสู่สถานะ Drive ทันที
Drive: ในสถานะนี้จะเรียกฟังก์ชัน sendDistance ซึ่งจะขอให้ Arduino ขับรถโรเวอร์ไปข้างหน้า 5 นิ้ว ไม่ต้องกังวลเรื่องความแม่นยำเป๊ะๆ หรอก เพราะเดี๋ยวมันก็จะวนกลับมาที่สถานะ Turn อยู่ดี เงื่อนไขการออกจากสถานะที่นี่คือเวลา 5 วินาที เพราะนั่นคือเวลาที่รถเราใช้ในการเคลื่อนที่ 5 นิ้วในบางช่วงของเลนนั่นเอง
สรุปปิดงาน
จากการผสมผสาน algorithm เหล่านี้ที่รันอยู่บน Raspberry Pi เข้ากับ logic การควบคุมแบบง่ายๆ บน Arduino เราก็สามารถออกแบบ "โรเวอร์" อัตโนมัติตัวจริงที่วิ่งไปมาในเลนได้สำเร็จ เราได้เห็นกันแล้วว่า Simulink ช่วยเราได้ยังไงบ้าง:
1) ปรับแต่งพารามิเตอร์การแบ่งสี (color thresholding) สำหรับ algorithm ตรวจจับเลน
2) ดูภาพที่หุ่นยนต์เห็นผ่าน Wi-Fi แบบเรียลไทม์ และใช้ข้อมูลนั้นมาปรับปรุงทั้ง algorithm การตรวจจับขอบ (edge detection) และ logic การตามเลน
3) โปรแกรม Raspberry Pi และ Arduino โดยที่ไม่ต้องมานั่งเขียนโค้ด C/C++ ด้วยมือเองให้เมื่อย
พี่แนะนำให้ลอง implement algorithm บนฮาร์ดแวร์ที่หาได้ไม่ยากแบบนี้เป็นก้าวแรก ในการก้าวเข้าสู่โลกของ embedded hardware อย่างแท้จริง ใครมีไอเดียเจ๋งๆ อยากให้ลองปรับปรุงรถโรเวอร์คันนี้ยังไงบ้าง ก็คอมเมนต์มาแชร์กันได้เลยนะน้อง ถ้าสนใจจะทำโปรเจคแบบนี้บ้าง ลองมาคุยกันได้