รูปปกบทความ

1. 🎯 ตอนที่ 4: Topics และ Messages การสื่อสารแบบไร้รอยต่อของหุ่นยนต์

สวัสดีครับน้องๆ ว่าที่วิศวกรหุ่นยนต์ทุกคน! ในตอนที่แล้วเราได้เห็นภาพรวมสถาปัตยกรรมของ ROS 2 กันไปแล้ว ว่ามันคือการแบ่งโปรแกรมก้อนใหญ่ๆ ให้กลายเป็นมดงานตัวเล็กๆ ที่เรียกว่า Node คำถามสำคัญที่ตามมาคือ… แล้วมดงานเหล่านี้มันส่งข้อมูลคุยกันได้อย่างไร?

วันนี้พี่จะพาไปเจาะลึกหัวใจสำคัญของการสื่อสารใน ROS 2 นั่นคือกลไก Publish / Subscribe ผ่านช่องทางที่เรียกว่า Topics และใช้ภาษากลางที่เรียกว่า Messages เตรียมตัวให้พร้อมครับ เพราะนี่คือพื้นฐานที่น้องๆ จะต้องใช้ในการเขียนโค้ดคุมหุ่นยนต์ไปตลอดชีวิต!

2. 📖 เปิดฉาก (The Hook)

ลองจินตนาการดูว่า น้องกำลังสร้างหุ่นยนต์เคลื่อนที่อัตโนมัติ หุ่นยนต์ตัวนี้มี “กล้อง” เป็นดวงตา และมี “สมองกล (Processor)” คอยประมวลผลเพื่อหลบหลีกสิ่งกีดขวาง ถ้าน้องใช้การเขียนโปรแกรมแบบเก่า สมองกลจะต้องไปสั่งกล้องว่า “เฮ้ย! ถ่ายรูปมาเดี๋ยวนี้ แล้วส่งมาให้ฉันวิเคราะห์” แล้วสมองกลก็ต้องนั่งรอ (Block) จนกว่ากล้องจะส่งรูปมาให้เสร็จ ถึงจะหันไปสั่งมอเตอร์ล้อให้หมุนได้… แบบนี้กว่าหุ่นยนต์จะขยับ คงเดินชนกำแพงไปแล้วใช่ไหมครับ?

ในโลกของ ROS 2 เราจะไม่ทำแบบนั้นครับ! เราจะให้กล้องทำงานของมันไป ถ่ายรูปเสร็จก็แค่ตะโกนประกาศออกไปเรื่อยๆ ส่วนสมองกลก็คอยเงี่ยหูฟังอย่างเดียว กลไกแบบนี้ช่วยให้ระบบทำงานขนานกันไปได้อย่างลื่นไหล ไม่ต้องมีใครมารอใคร นี่แหละครับคือพลังของระบบ Publish/Subscribe!

3. 🧠 แก่นวิชา (Core Concepts)

การสื่อสารแบบนี้ใน ROS 2 เปรียบเสมือนสถานีวิทยุกระจายเสียงครับ โดยมีองค์ประกอบหลักๆ 4 ส่วนดังนี้:

  • Publisher (ผู้ประกาศ): คือ Node ที่ทำหน้าที่ส่งข้อมูลออกไป เช่น Node ของกล้องทำหน้าที่ส่งภาพที่ถ่ายได้ออกไปเรื่อยๆ โดยที่มันไม่สนใจเลยว่าจะมีใครรอรับภาพของมันอยู่หรือไม่ (Anonymous)
  • Subscriber (ผู้ฟัง): คือ Node ที่คอยรับข้อมูล เช่น Node สมองกลประมวลผลภาพ (Computer Vision) ที่คอยเงี่ยหูฟังข้อมูลภาพ เมื่อมีภาพใหม่เข้ามา มันก็จะเรียกใช้ฟังก์ชัน Callback เพื่อนำภาพนั้นไปประมวลผลทันที
  • Topic (คลื่นสถานีวิทยุ): คือ “ช่องทาง” หรือชื่อของท่อส่งข้อมูลที่ Publisher และ Subscriber ใช้เพื่อมาเจอกัน เช่น กล้องอาจจะส่งข้อมูลไปที่คลื่นชื่อ /camera/image_raw สมองกลที่อยากได้ภาพก็ต้องจูนคลื่นมาที่ /camera/image_raw ให้ตรงกัน โดย Topic หนึ่งๆ สามารถมี Publisher และ Subscriber กี่ตัวมารุมส่งและรับข้อมูลก็ได้ (Many-to-Many)
  • Message (รูปแบบข้อมูล): คล้ายกับ “ภาษา” ที่ใช้คุยกันใน Topic นั้นๆ การที่ Node สองตัวจะคุยกันรู้เรื่อง ต้องใช้ Message Type เดียวกันเป๊ะๆ ตัว Message จะเป็นโครงสร้างข้อมูล (Data Structure) ที่กำหนดชนิดตัวแปรไว้ชัดเจน เช่น int32, float32, string หรือแม้แต่อาร์เรย์ (Array) โดยจะถูกนิยามไว้ในไฟล์นามสกุล .msg
รูปประกอบ Publish-Subscribe Model

4. 💻 ร่ายมนต์โค้ดและคำสั่ง (Show me the Code)

เรามาดูการใช้เครื่องมือผ่าน Terminal ของ ROS 2 กันก่อนครับ คำสั่งพวกนี้คือเครื่องมือหากินของวิศวกรเลยนะ:

# ขอดูหน่อยว่าตอนนี้ในหุ่นยนต์ มี "คลื่นสถานี (Topic)" อะไรกำลังออกอากาศอยู่บ้าง?
ros2 topic list  #

# แอบฟังข้อมูลที่กำลังวิ่งอยู่ใน Topic /counter แบบ Real-time
ros2 topic echo /counter  #

# ขอดูข้อมูลประจำตัวของ Topic /counter (เช่น ใครเป็นคน Publish, ใครเป็นคน Subscribe)
ros2 topic info /counter  #

# ขอดูโครงสร้าง "ภาษา (Message Interface)" ที่ Topic นี้ใช้คุยกันหน่อย
ros2 interface show std_msgs/msg/Int32  #

ทีนี้ลองมาดูตัวอย่างการร่ายมนต์โค้ด Python เบื้องต้นกันครับ พี่จะยกตัวอย่างการสร้าง Publisher และ Subscriber แบบง่ายๆ:

ฝั่ง Publisher (ส่งข้อมูล):

import rclpy
from rclpy.node import Node
from std_msgs.msg import String # นำเข้า Message ชนิด String (ข้อความ)

class SimplePublisher(Node):
    def __init__(self):
        super().__init__('talker_node')
        # สร้าง Publisher ประกาศบนคลื่นชื่อ 'chatter' ด้วยภาษาแบบ String
        # ตัวเลข 10 คือ Queue Size (ขนาดคิวรับฝากข้อความ)
        self.publisher_ = self.create_publisher(String, 'chatter', 10)
        
        # ตั้ง Timer ให้เรียกฟังก์ชัน timer_callback ทุกๆ 1 วินาที
        self.timer = self.create_timer(1.0, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = "Hello, ROS 2!" # ยัดข้อความใส่ฟิลด์ data
        self.publisher_.publish(msg) # สั่งส่งข้อความออกอากาศ!
        self.get_logger().info(f'กำลังส่ง: "{msg.data}"') # ปริ้นต์ลงจอไว้ดูเล่น

ฝั่ง Subscriber (รับข้อมูล):

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class SimpleSubscriber(Node):
    def __init__(self):
        super().__init__('listener_node')
        # สร้าง Subscriber จูนคลื่นไปที่ 'chatter' ด้วยภาษา String
        # และผูกกับ Callback Function ชื่อ listener_callback
        self.subscription = self.create_subscription(
            String,
            'chatter',
            self.listener_callback,
            10) 

    def listener_callback(self, msg):
        # เมื่อมีข้อความวิ่งเข้ามาที่ Topic นี้ ฟังก์ชันนี้จะถูกเรียกอัตโนมัติ (Event-Driven)
        self.get_logger().info(f'ได้รับข้อความแล้ว: "{msg.data}"')

5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)

  • เรื่องของ Queue Size สำคัญมาก: สังเกตตัวเลข 10 ในโค้ดตอนสร้าง Publisher/Subscriber ไหมครับ? มันคือการกำหนดบัฟเฟอร์ (Buffer) สำรองข้อความ สมมติว่ากล้องส่งภาพเร็วมาก (Publisher ส่งไว) แต่สมองกลประมวลผลไม่ทัน (Subscriber ทำงานช้า) ภาพที่ล้นเข้ามาจะถูกเก็บไว้ในคิวนี้ ถ้าคิวเต็ม (เกิน 10) ภาพเก่าที่สุดจะถูกโยนทิ้งไป (Drop) เพื่อป้องกันไม่ให้เมมโมรี่คอมพิวเตอร์เต็มจนระบบแครชนั่นเองครับ
  • การแยกส่วนการทำงาน (Decoupling): ข้อดีของการสื่อสารแบบนี้คือ ต่อให้ Node สมองกลเกิดพังและดับไป Node กล้องก็ยังคงทำหน้าที่ส่งภาพไปที่ Topic ได้อย่างปกติไม่เกิด Error ค้าง ความยืดหยุ่นนี้ทำให้เราสามารถเขียนโค้ดชิ้นใหม่มาเสียบแทนชิ้นเก่าได้เลยโดยไม่ต้องแก้โค้ดที่ระบบอื่นเลยครับ
  • ประสิทธิภาพผ่าน DDS: ใน ROS 2 ระบบเบื้องหลังของ Topic จะถูกขับเคลื่อนด้วย Middleware มาตรฐานอุตสาหกรรมที่เรียกว่า DDS (Data Distribution Service) ทำให้สามารถปรับแต่ง QoS (Quality of Service) ได้ว่าจะเน้น “ส่งข้อมูลให้เร็วที่สุด (Best Effort)” เหมาะกับข้อมูลเซ็นเซอร์ หรือ “ส่งให้ชัวร์ที่สุดห้ามตกหล่น (Reliable)” เหมาะกับข้อมูลสถานะหุ่นยนต์ครับ

6. 🏁 บทสรุป (To be continued…)

เห็นไหมครับว่าระบบ Topics และ Messages ของ ROS 2 นั้นถูกออกแบบมาให้จัดการข้อมูลแบบสตรีมมิ่ง (Streaming Data) เช่น ข้อมูลเซ็นเซอร์ หรือคำสั่งความเร็วมอเตอร์ ได้อย่างทรงพลังและเป็นอิสระต่อกัน

แต่ระบบ Topic เป็นเหมือนการ “กระจายเสียง” ฝ่ายเดียวครับ มันมีจุดอ่อนคือ เราจะไม่รู้เลยว่าผู้ฟังทำคำสั่งเราสำเร็จไหม? ถ้าเราต้องการส่งคำสั่งเช่น “ช่วยประมวลผลหน้าคนให้หน่อย แล้วส่งชื่อกลับมา” การใช้ Topic จะไม่ตอบโจทย์ ในตอนต่อไป พี่จะพาไปรู้จักกับระบบการสื่อสารแบบถาม-ตอบ (Request-Response) ที่เรียกว่า Services กันครับ รอติดตามได้เลย!


ต้องการที่ปรึกษาด้านการออกแบบสถาปัตยกรรมหุ่นยนต์ (Robotics) และระบบ Automation ให้กับองค์กรของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและพัฒนาซอฟต์แวร์แบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p