ตอนที่ 22: การเชื่อมต่อเซนเซอร์ LiDAR เข้ากับ ROS (ดวงตาเลเซอร์ 2 มิติ)

1. 🎯 ตอนที่ 22: การเชื่อมต่อเซนเซอร์ LiDAR เข้ากับ ROS (ดวงตาเลเซอร์ 2 มิติ)
สวัสดีครับน้องๆ วิศวกรหุ่นยนต์ทุกคน! ในตอนที่แล้วเราได้เรียนรู้วิธีการควบคุมมอเตอร์ให้หุ่นยนต์วิ่งไปมาด้วย ros2_control กันไปแล้ว แต่ปัญหาคือ… หุ่นยนต์ของเราตอนนี้ “ตาบอด” ครับ! ถ้าเราสั่งให้มันเดินหน้า มันก็จะเดินไปชนกำแพงดังโครมแบบไม่รู้อีโหน่อีเหน่
เพื่อให้หุ่นยนต์รับรู้สภาพแวดล้อมรอบตัว เราต้องติด “ดวงตา” ให้กับมัน และอุปกรณ์ยอดฮิตที่เป็นพระเอกในวงการหุ่นยนต์เคลื่อนที่อัตโนมัติ (AMR) ก็คือ LiDAR (Light Detection and Ranging) นั่นเองครับ วันนี้พี่จะพาไปเจาะลึกว่าหุ่นยนต์รับรู้ข้อมูลเลเซอร์อย่างไร โครงสร้างแพ็กเกจข้อมูลหน้าตาเป็นแบบไหน และเราจะดึงข้อมูลนี้มาแสดงผลใน RViz ได้อย่างไร เตรียมตัวให้พร้อมครับ!
2. 📖 เปิดฉาก (The Hook)
ลองนึกภาพน้องๆ กำลังเดินหลับตาอยู่ในห้องมืดๆ สิครับ วิธีเดียวที่จะรู้ว่ามีกำแพงอยู่ตรงหน้าคือการยื่นมือคลำไปเรื่อยๆ ใช่ไหมครับ? หุ่นยนต์ก็เหมือนกัน!
LiDAR คืออุปกรณ์ที่ทำหน้าที่ยื่น “มือเลเซอร์” ออกไปคลำทางแทน หลักการของมันคือการยิงแสงเลเซอร์ออกไปกระทบวัตถุ แล้วจับเวลาที่แสงสะท้อนกลับมา (Time of Flight) เพื่อคำนวณระยะทาง ความเจ๋งคือมันมีกระจกหมุนอยู่ข้างในด้วยมอเตอร์ ทำให้มันสามารถกวาดเลเซอร์รอบตัวได้ถึง 360 องศาภายในเสี้ยววินาที!
แต่ข้อมูลที่ LiDAR ส่งมาให้ ROS ไม่ใช่ภาพสวยๆ นะครับ มันคือ “อาร์เรย์ของตัวเลข” จำนวนมหาศาลที่บอกระยะทางในแต่ละมุมองศา ถ้าเราไม่เข้าใจโครงสร้างข้อความนี้ เราก็จะไม่มีทางเขียนโค้ดให้หุ่นยนต์หลบหลีกสิ่งกีดขวางได้เลยครับ!
3. 🧠 แก่นวิชา (Core Concepts)
ในระบบ ROS ข้อมูลที่ส่งออกมาจาก LiDAR จะถูกบรรจุอยู่ในมาตรฐาน Message ที่ชื่อว่า sensor_msgs/LaserScan เสมอครับ (มักจะถูก Publish ออกมาที่ Topic ชื่อ /scan) โครงสร้างของกล่องพัสดุนี้ประกอบด้วยฟิลด์สำคัญๆ ดังนี้ครับ:
std_msgs/Header header: ส่วนหัวที่บอกstamp(เวลาที่สแกน) และframe_id(ชื่อแกนพิกัดที่เลเซอร์ติดอยู่ เช่นlaser_linkหรือlaser_frame)float32 angle_minและangle_max: มุมเริ่มต้นและมุมสิ้นสุดของการกวาดเลเซอร์ (หน่วยเป็นเรเดียน)float32 angle_increment: ความละเอียดของมุมระหว่างการยิงเลเซอร์แต่ละเส้น (เช่น เลเซอร์ยิงห่างกันทุกๆ 1 องศา)float32 range_minและrange_max: ระยะทางใกล้สุดและไกลสุดที่เซนเซอร์ตัวนี้วัดได้ (เช่น วัดได้ตั้งแต่ 0.1 เมตร ถึง 10.0 เมตร)float32[] ranges(พระเอกของเรา!): นี่คือ “อาร์เรย์ (Array)” ที่เก็บค่าระยะทาง (Distance) ที่วัดได้ในแต่ละมุมองศาเรียงต่อกันไปครับ!float32[] intensities: ค่าความเข้มของแสงสะท้อน (ใช้วิเคราะห์พื้นผิววัตถุได้ แต่บางเซนเซอร์ก็ไม่มีค่านี้มาให้)
Trick ทางวิศวกรรม: ถ้าหุ่นยนต์ติด LiDAR หันหน้าตรง การหาว่า “มีกำแพงอยู่ข้างหน้าหุ่นยนต์ไหม?” เรามักจะไปดึงค่าจาก ตำแหน่งตรงกลางของอาร์เรย์ ranges ครับ! (เช่น ถ้ามี 720 ค่า ค่าตรงกลางแถวๆ Index 360 คือด้านหน้าสุดของหุ่นยนต์)

4. 💻 ร่ายมนต์โค้ดและคำสั่ง (Show me the Code)
เรามาลองเขียน Node Python สั้นๆ เพื่อ Subscribe ดักฟังข้อมูล /scan แล้วปริ้นต์ระยะทางด้านหน้าสุดออกมาดูกันครับ:
ไฟล์โค้ด Python (lidar_obstacle_detector.py):
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
import numpy as np
class LidarProcessor(Node):
def __init__(self):
super().__init__('lidar_processor_node')
# 1. สร้าง Subscriber เพื่อดักฟัง Topic /scan ด้วย Message ชนิด LaserScan
self.subscription = self.create_subscription(
LaserScan,
'/scan',
self.scan_callback,
10
)
self.get_logger().info('Lidar Processor Node Started!')
# 2. ฟังก์ชัน Callback ที่จะทำงานทุกครั้งที่ได้รับข้อมูลเลเซอร์ 1 รอบ
def scan_callback(self, msg: LaserScan):
# 3. ดึงอาร์เรย์ระยะทางออกมา
ranges = msg.ranges
# 4. หากำแพงที่อยู่ตรงหน้าเป๊ะๆ (ตรงกลางของ Array)
front_index = len(ranges) // 2
front_distance = ranges[front_index]
# 5. หาวัตถุที่อยู่ใกล้หุ่นยนต์ที่สุดจากการสแกนรอบตัว
# (ข้อควรระวัง: ต้องกรองค่าที่วัดไม่ได้ หรือ inf ทิ้งไปก่อน)
valid_ranges = [r for r in ranges if not np.isinf(r) and not np.isnan(r)]
if valid_ranges:
min_distance = min(valid_ranges)
# แจ้งเตือนถ้าระยะใกล้กว่า 1 เมตร
if min_distance < 1.0:
self.get_logger().warn(f'⚠️ ระวัง! เจอสิ่งกีดขวางที่ระยะ {min_distance:.2f} เมตร!')
else:
self.get_logger().info(f'ทางสะดวก (ระยะหน้าสุด: {front_distance:.2f} m)')
def main(args=None):
rclpy.init(args=args)
node = LidarProcessor()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()การนำไปแสดงผลใน RViz (เพื่อให้เห็นเป็นภาพ!) การนั่งดูตัวเลขปริ้นต์รัวๆ คงไม่ใช่วิถีของวิศวกรครับ เราต้องเห็นภาพ!
- พิมพ์คำสั่ง
ros2 run rviz2 rviz2 - ที่พาเนลซ้ายมือ (Displays) ตรง Global Options -> Fixed Frame ให้เลือกชื่อเฟรมของ LiDAR (เช่น
laser,laser_linkหรือbase_link) - กดปุ่ม Add ด้านล่างซ้าย
- เลือกปลั๊กอิน LaserScan แล้วกด OK
- ขยายเมนู LaserScan ออกมา ตรงช่อง Topic ให้เลือก
/scan - (Optional) ปรับค่า
Size (m)ให้จุดใหญ่ขึ้น (เช่น 0.05) และปรับColor Transformerเป็นFlatColorหรือIntensity
ปิ๊ง! น้องๆ จะเห็นจุดสีแดงๆ ลอยขึ้นมาประกอบกันเป็นรูปร่างของห้องรอบตัวหุ่นยนต์แบบ Real-time เลยครับ!
5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
ในฐานะที่พี่เขียนโค้ดชนกำแพงมาแล้วนับไม่ถ้วน นี่คือสิ่งที่น้องๆ ต้องระวังครับ:
- กับดักค่า
inf(Infinity) และNaN: วิศวกรมือใหม่มักจะเอา Array ของrangesไปเข้าสมการบวกลบคูณหารตรงๆ แล้วโปรแกรมก็ Crash ครับ! ต้องระวังไว้ว่า ถ้าเลเซอร์ยิงไปเจอวัตถุที่ ใกล้เกินไป (ต่ำกว่าrange_min) หรือ ไกลเกินไป (เกินrange_max) เซนเซอร์จะพ่นค่าinf(อนันต์) หรือNaN(Not a Number) ออกมา เราต้องเขียนโค้ดกรองค่าพวกนี้ทิ้งก่อนเสมอ! - RViz มองไม่เห็นเลเซอร์ (TF Error):
ถ้าน้องเลือก Topic
/scanแล้ว แต่หน้าจอ RViz ยังมืดสนิทพร้อม Error สีแดง “No tf data…” แปลว่าระบบยังไม่รู้จักความสัมพันธ์ของพิกัดครับ (TF Tree ขาดหาย) น้องต้องแน่ใจว่าได้เปิดโหนดrobot_state_publisherที่ปล่อย URDF ซึ่งเชื่อมต่อbase_linkเข้ากับเฟรมของเลเซอร์ไว้เรียบร้อยแล้ว - LiDAR ยอดฮิตในวงการ ROS:
ถ้าน้องๆ อยากทำหุ่นยนต์จริง พี่ขอแนะนำ LiDAR รุ่นประหยัดที่เข้ากันได้ดีกับ ROS เช่น RPLIDAR (จากค่าย SLAMTEC), Hokuyo (เช่นรุ่น URG-04LX) หรือ YDLIDAR ครับ อุปกรณ์พวกนี้มี Package เสียบปุ๊บ พ่น Topic
/scanให้ใช้ได้ทันที ประหยัดเวลาไปได้เยอะมาก!
6. 🏁 บทสรุป (To be continued…)
การเชื่อมต่อเซนเซอร์ LiDAR เข้ากับ ROS ถือเป็นการเปิด “ดวงตา” ให้กับหุ่นยนต์อย่างเป็นทางการครับ ด้วยข้อความ sensor_msgs/LaserScan เราสามารถดึงตัวเลขนับร้อยค่ามาวิเคราะห์หาจุดที่ใกล้ที่สุด เพื่อสั่งให้หุ่นยนต์เบรกฉุกเฉิน หรือเดินหลบหลีกสิ่งกีดขวางได้
แต่แค่การหลบหลีกมันยังไม่พอหรอกครับ! การจะทำให้หุ่นยนต์เดินอัตโนมัติจากจุด A ไป B ได้ มันต้อง “จำ” ได้ด้วยว่าเคยเดินไปตรงไหนแล้วบ้าง ในตอนต่อไป พี่จะพาน้องๆ นำข้อมูลจาก LiDAR เหล่านี้ ไปประกอบกันเพื่อสร้าง “แผนที่ห้อง 2 มิติ (Mapping)” ด้วยอัลกอริทึม SLAM เตรียมตัวตื่นเต้นกันได้เลยครับ!
ต้องการที่ปรึกษาด้านการออกแบบสถาปัตยกรรมหุ่นยนต์ (Robotics) และระบบ Automation ให้กับองค์กรของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p