รูปปกบทความ

1. 🎯 ตอนที่ 11: กระจายเสียงให้ก้องโลก! พื้นฐานการเขียน Publisher Node ด้วย Python

สวัสดีครับน้องๆ วิศวกรหุ่นยนต์ทุกคน! ผ่านมา 10 ตอนแล้ว ทฤษฎีเราแน่นปึ้ก วันนี้ถึงเวลาที่เราจะมา “ลงมือเขียนโค้ด” กันจริงๆ จังๆ สักทีครับ!

เวลาที่เราสร้างหุ่นยนต์ สมมติว่าน้องต่อเซ็นเซอร์วัดอุณหภูมิเสร็จแล้ว หุ่นยนต์อ่านค่าได้แล้ว… แต่ถ้ามันไม่ยอมส่งข้อมูลนี้ออกไปให้ระบบอื่นรู้ เซ็นเซอร์ตัวนั้นก็ไร้ค่าใช่ไหมครับ? วันนี้พี่จะพาน้องๆ มาสวมบทบาทเป็น “ดีเจสถานีวิทยุ” ด้วยการเขียนโค้ดสร้าง Publisher Node เพื่อกระจายเสียงส่งข้อมูลออกไปให้ทั่วทั้งระบบ ROS ด้วยภาษาโปรดของพวกเราอย่าง Python กันครับ!

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

สมัยก่อนตอนพี่หัดเขียน ROS 1 ใหม่ๆ พี่มักจะเขียนโค้ดแบบสคริปต์ยาวๆ รันจากบนลงล่างอยู่ใน while loop ยักษ์ๆ ซึ่งมันก็ทำงานได้นะ (ด้วยไลบรารี rospy) แต่พอโปรเจกต์หุ่นยนต์มันใหญ่ขึ้น โค้ดเริ่มพันกันยุ่งเหยิง จัดการยากมาก

พอเข้าสู่ยุคของ ROS 2 ผู้พัฒนาเขารู้จุดอ่อนข้อนี้ดีครับ เขาเลยปรับโครงสร้างการเขียนโค้ดฝั่ง Python ใหม่ทั้งหมดผ่านไลบรารีที่ชื่อว่า rclpy โดยบังคับให้เราเขียนแบบ “Object-Oriented Programming (OOP)” หรือการเขียนโปรแกรมเชิงวัตถุ ซึ่งมันทำให้โค้ดของเราสะอาด เป็นระเบียบ และนำไปใช้ซ้ำ (Reuse) ได้ง่ายขึ้นเป็นกอง! วันนี้เราจะมาเจาะลึกโครงสร้างโค้ดเหล่านี้กันแบบบรรทัดต่อบรรทัดเลยครับ

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

ก่อนจะไปดูโค้ด พี่ขอสรุปความแตกต่างระหว่างการเขียน Publisher ใน ROS 1 (rospy) และ ROS 2 (rclpy) ให้เห็นภาพชัดๆ ก่อนครับ:

  • ยุค ROS 1 (rospy): การเขียนโค้ดจะเป็นแบบสคริปต์ (Procedural) เราจะประกาศ rospy.init_node() ตั้งชื่อ Node จากนั้นสร้าง rospy.Publisher แล้วใช้คำสั่ง rate.sleep() ยัดไว้ในลูป while not rospy.is_shutdown(): เพื่อหน่วงเวลาการส่งข้อมูลให้ได้ความถี่ (Rate) ตามที่ต้องการ,.
  • ยุค ROS 2 (rclpy): การเขียนโค้ดจะเปลี่ยนมาใช้โครงสร้างแบบ คลาส (Class) โดยสืบทอดคุณสมบัติมาจากคลาส Node ของ ROS 2 สิ่งที่เปลี่ยนไปอย่างเห็นได้ชัดคือ เราจะไม่ใช้ while loop อีกต่อไป! แต่เราจะใช้กลไกของ Timer (ตัวจับเวลา) ร่วมกับ Callback Function แทน,. เมื่อถึงเวลาที่กำหนด Timer จะเรียกฟังก์ชันให้ทำงานอัตโนมัติ ทำให้ระบบไม่ต้องมานั่งรอ (Block) อยู่ในลูปครับ,.
รูปประกอบโครงสร้างโค้ด Publisher

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

เรามาดูหน้าตาของโค้ดกันครับ พี่จะเอาโค้ดของ ROS 2 (rclpy) มาชำแหละให้ดูทีละบรรทัด สไตล์วิศวกรคุยกัน!

ตัวอย่างโค้ด ROS 2 Publisher (ด้วย rclpy):

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

# 1. สร้างคลาสสืบทอดจาก Node ของ ROS 2
class MinimalPublisher(Node):
    def __init__(self):
        # 2. ตั้งชื่อสถานีวิทยุ (Node Name)
        super().__init__('minimal_publisher')
        
        # 3. ตั้งเสาส่งสัญญาณ (สร้าง Publisher) 
        # โครงสร้าง: create_publisher(ชนิดข้อมูล, 'ชื่อ Topic', Queue Size)
        self.publisher_ = self.create_publisher(String, 'topic', 10)
        
        # 4. ตั้งนาฬิกาปลุก (สร้าง Timer) ทำงานทุกๆ 0.5 วินาที
        timer_period = 0.5 
        self.timer = self.create_timer(timer_period, self.timer_callback)

    # 5. ฟังก์ชันที่จะถูกเรียกเมื่อนาฬิกาปลุกดัง (Callback)
    def timer_callback(self):
        msg = String() # สร้างกล่องพัสดุเปล่าๆ ชนิด String
        msg.data = 'Hello, ROS 2!' # เอาข้อความใส่ลงไปในกล่อง
        
        self.publisher_.publish(msg) # ส่งพัสดุออกอากาศ!
        self.get_logger().info('Publishing: "%s"' % msg.data) # ปริ้นต์ลงจอไว้ดูเล่น

# 6. ฟังก์ชันหลักสำหรับรันโปรแกรม
def main(args=None):
    rclpy.init(args=args) # สตาร์ทเครื่องยนต์ ROS 2
    
    minimal_publisher = MinimalPublisher() # สร้างอ็อบเจกต์จากคลาสที่เราเขียน
    
    rclpy.spin(minimal_publisher) # สั่งให้ Node ทำงานวนไปเรื่อยๆ (รอรับ Event)
    
    minimal_publisher.destroy_node() # เมื่อโดนสั่งปิด ให้ทำลาย Node ทิ้งซะ
    rclpy.shutdown() # ดับเครื่องยนต์ ROS 2

if __name__ == '__main__':
    main()

ชำแหละโค้ดสไตล์รุ่นพี่ติวน้อง:

  • บรรทัด super().__init__('minimal_publisher'): นี่คือการเรียกใช้งาน Constructor ของคลาสแม่ (Node) เพื่อบอก ROS 2 ว่า “เฮ้ย ฉันขอตั้งชื่อ Node นี้นะว่า minimal_publisher”,.
  • บรรทัด self.create_publisher(...): เป็นการเปิดช่องทางการสื่อสารครับ พารามิเตอร์ตัวแรกคือ String (บอกว่าจะคุยด้วยภาษาอะไร), ตัวที่สองคือ 'topic' (คลื่นความถี่ที่จะส่งไป), และตัวเลข 10 คือ Queue Size (ขนาดคิวรับฝากข้อความ),.
  • บรรทัด self.create_timer(...): แทนที่เราจะใช้ลูป while เราใช้นาฬิกาปลุกแทนครับ โดยมันจะไปเรียกฟังก์ชัน self.timer_callback ให้ทำงานทุกๆ 0.5 วินาที (หรือ 2 Hz).
  • บรรทัด rclpy.spin(...): คำสั่งนี้โคตรสำคัญ! ถ้าไม่มีบรรทัดนี้ โปรแกรมจะรันจบแล้วปิดตัวทันที การใช้ spin() คือการบอกให้ Node “ตื่นตัวอยู่เสมอ” เพื่อรอจังหวะที่ Timer ดัง หรือรอรับข้อความจากระบบนั่นเองครับ.

(เปรียบเทียบกับ ROS 1 rospy สั้นๆ: โค้ดจะหน้าตาประมาณ pub = rospy.Publisher('topic', String, queue_size=10) แล้วตามด้วยลูป while not rospy.is_shutdown(): pub.publish(msg); rate.sleep() ซึ่งเป็นแบบ Procedural ล้วนๆ ครับ,)

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

  • ความลับของเลข 10 (Queue Size): น้องๆ เห็นเลข 10 ตอนเราประกาศ create_publisher ไหมครับ? ค่านี้สำคัญมาก! มันคือบัฟเฟอร์ (Buffer) สำหรับกักเก็บข้อความ สมมติว่า Node เราผลิตข้อมูลเร็วมาก แต่ส่งออก Network ไม่ทัน (อาจจะเพราะ Wi-Fi หน่วง) ROS 2 จะเก็บข้อความไว้ในคิวนี้ 10 ข้อความล่าสุด ถ้าคิวเต็ม มันจะโยนข้อความที่เก่าที่สุดทิ้ง (Drop) เพื่อป้องกันไม่ให้ RAM คอมพิวเตอร์เต็มจนระบบพังครับ,. สำหรับข้อมูลเซ็นเซอร์ทั่วไป ค่า 10 ถือว่าเหมาะสมแล้ว
  • ลาก่อน while loop สุดบรรลัย: ใน ROS 1 การใช้ while not rospy.is_shutdown(): ทำให้ CPU Core หนึ่งต้องทำงานตลอดเวลา (บางทีรันจน CPU วิ่ง 100% ถ้าลืมใส่ sleep()). แต่โครงสร้าง OOP และ spin() ของ ROS 2 ช่วยให้ระบบจัดการ Thread และ Resource ได้ดีขึ้นมาก ฟังก์ชันจะถูกเรียกใช้เมื่อมี Event จริงๆ เท่านั้น ทำให้ประหยัดทรัพยากรคอมพิวเตอร์ไปได้เยอะเลยครับ!.

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

และนี่ก็คือโครงสร้างมาตรฐานของการเขียน Publisher Node ด้วย Python ใน ROS 2 ครับ! พอเราใช้โครงสร้างคลาส (OOP) น้องๆ จะเห็นเลยว่าเราสามารถจับตัวแปรต่างๆ ยัดไว้ใน self ทำให้โค้ดเป็นระเบียบ และสามารถขยายสเกลเพื่อเชื่อมต่อกับเซ็นเซอร์จริงๆ ได้อย่างง่ายดาย

ตอนนี้เรามี “สถานีวิทยุ” ที่คอยกระจายเสียงแล้ว แต่ถ้าไม่มีคนฟัง มันก็เหงาแย่เลยใช่ไหมครับ? ในตอนต่อไป พี่จะพาน้องๆ ไปเขียนโค้ดสร้าง Subscriber Node เพื่อคอยเงี่ยหูฟังข้อมูลที่เราเพิ่งจะส่งออกไปกัน เตรียมตัวให้พร้อม แล้วพบกันครับ!


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