โมดูล 3/5 · สัปดาห์ 7–9 · 27 ชม.

ROS 2

UAT 308 ระบบอัตโนมัติและหุ่นยนต์

เวลาเรียนประมาณ 90 นาทีร่าง รอตรวจปรับปรุงล่าสุด 28 กันยายน 2569

บทเรียน

เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ

  1. อธิบาย node, topic, service และ action ของ ROS 2 และบทบาทของ DDS
  2. เลือกนโยบาย QoS ด้าน history, depth และ reliability ให้เหมาะกับข้อมูลแต่ละชนิด
  3. วิเคราะห์เวลาหน่วงและการทิ้งข้อความเมื่อผู้รับประมวลผลช้ากว่าผู้ส่ง
  4. จับคู่ข้อความจากเซนเซอร์หลายตัวตามเวลาด้วยค่า slop ที่เหมาะสม

ความรู้พื้นฐานที่ควรมี: UAT 308 โมดูล 1–2 · UAT 314 โมดูล 5 (ROS 2 และการเชื่อมต่อ flight controller)

ทำไมต้องรู้

UAT 314 แนะนำแนวคิดของ ROS 2 และการเชื่อมกับ flight controller ผ่าน uXRCE-DDS และ MAVROS หน่วยความรู้เรื่อง ROS 2 และการเชื่อมต่อกับ flight stack ของคลังความรู้โดรนอธิบาย node topic service action และการจำลอง ส่วนหน่วยความรู้เรื่องจาก Embedded System สู่ AI Robot อธิบายการต่อกล้องและ sensor fusion บนฮาร์ดแวร์ Edge AI Macenski และคณะ (2022) สรุปว่า ROS 2 สร้างบน DDS เพื่อให้ตั้งคุณภาพการสื่อสาร (QoS) ได้ตามงาน ปัญหาที่พบบ่อยที่สุดในห้องปฏิบัติการไม่ใช่การเขียน node แต่คือ ข้อมูลมาช้า มาไม่ครบ หรือมาไม่ตรงเวลากัน โมดูลนี้จึงเน้นการตั้ง QoS และการจับคู่ข้อมูลตามเวลา

องค์ประกอบของ ROS 2

node คือโปรแกรมหนึ่งหน่วย topic ส่งข้อมูลต่อเนื่องแบบผู้ส่งหลายรายถึงผู้รับหลายราย เช่นภาพกล้องและค่า LiDAR service เป็นการถามตอบครั้งเดียว เช่นขอเปิดไฟส่องสว่าง action ใช้กับงานที่ใช้เวลานานและต้องรายงานความคืบหน้าหรือยกเลิกได้ เช่นสั่งรถวิ่งไปยังแถวแผงที่ 12 ใต้ ROS 2 คือ DDS ซึ่งค้นหากันเองในเครือข่ายโดยไม่ต้องมีตัวกลาง

นโยบาย QoS

เอกสาร ROS 2 อธิบายนโยบายหลักดังนี้ history แบบ keep last เก็บเฉพาะ N ตัวอย่างล่าสุดตาม depth ส่วน keep all เก็บทั้งหมดเท่าที่ทรัพยากรของมิดเดิลแวร์รองรับ reliability แบบ best effort พยายามส่งแต่อาจหายเมื่อเครือข่ายไม่ดี แบบ reliable รับประกันการส่งโดยอาจส่งซ้ำหลายครั้ง โปรไฟล์ค่าเริ่มต้นใช้ reliable, keep last, depth 10 ส่วนโปรไฟล์สำหรับข้อมูลเซนเซอร์ใช้ best effort, keep last, depth 5 เพราะสำหรับภาพกล้อง ข้อมูลล่าสุดสำคัญกว่าการได้ข้อมูลเก่าครบทุกภาพ ผู้ส่งกับผู้รับต้องตั้ง QoS ที่เข้ากันได้ มิฉะนั้นจะไม่เชื่อมต่อกัน

ตัวอย่างที่ 1 กล้อง 30 Hz กับตัวตรวจจุดร้อนที่ใช้เวลา 50 ms

กล้องความร้อนส่งภาพ 30 Hz เป็นเวลา 3 s ตัวตรวจจุดร้อนประมวลผลภาพละ 50 ms (ทำได้ 20 ภาพต่อวินาที) เปรียบเทียบ keep last depth 1 กับ depth 10 (แบบจำลองคิวอย่างง่าย ไม่รวมเวลาส่งผ่านเครือข่าย)

from collections import deque

PUB_HZ = 30          # กล้องส่งภาพ 30 Hz
PROC = 0.050         # ผู้รับใช้เวลาประมวลผลภาพละ 50 ms
DURATION = 3.0

def run(depth):
    pubs = [k / PUB_HZ for k in range(int(DURATION * PUB_HZ))]
    q = deque()
    dropped, done, lat = 0, 0, []
    t_free = 0.0
    i = 0
    while i < len(pubs) or q:
        t_next = pubs[i] if i < len(pubs) else float("inf")
        if q and t_free <= t_next:
            stamp = q.popleft()
            start = max(t_free, stamp)
            lat.append(start + PROC - stamp)
            t_free = start + PROC
            done += 1
        else:
            if len(q) == depth:
                q.popleft()          # KEEP_LAST ทิ้งข้อความเก่าที่สุด
                dropped += 1
            q.append(t_next)
            i += 1
    lat.sort()
    return done, dropped, sum(lat) / len(lat), lat[len(lat) // 2]

for depth in [1, 10]:
    done, dropped, avg, med = run(depth)
    print(f"depth={depth:>2}  processed {done}  dropped {dropped}  "
          f"mean latency {avg*1000:.0f} ms  median {med*1000:.0f} ms")
depth= 1  processed 61  dropped 29  mean latency 66 ms  median 67 ms
depth=10  processed 70  dropped 20  mean latency 334 ms  median 367 ms

ผู้รับช้ากว่าผู้ส่งจึงต้องทิ้งภาพบางส่วนไม่ว่าจะตั้ง depth เท่าใด ความต่างคือ depth 10 ทำให้ภาพที่ถูกประมวลผลเป็นภาพเก่า ต้องรอในคิวราว s บวกเวลาประมวลผล เวลาหน่วงจึงเกือบ 0.4 s ส่วน depth 1 ได้ภาพล่าสุดเสมอ เวลาหน่วงราว 67 ms ถ้ารถวิ่ง 1 m/s ความต่างนี้เท่ากับตำแหน่งจุดร้อนคลาดราว 30 cm สำหรับงานควบคุมและตรวจจับแบบเวลาจริง คิวสั้นเหมาะกว่า ส่วนข้อมูลที่ต้องครบทุกชิ้น เช่นบันทึกเหตุการณ์ ควรใช้ reliable และคิวยาว

กราฟเวลาหน่วงเทียบกับเวลา 0 ถึง 3 วินาที เส้นสีเขียว depth 1 อยู่ราว 50 ถึง 80 มิลลิวินาทีตลอด เส้นสีชมพู depth 10 ไต่ขึ้นเป็นเส้นตรงจนราว 370 มิลลิวินาทีแล้วคงที่ และเพิ่มขึ้นอีกช่วงท้ายเมื่อคิวระบายภาพที่ค้าง
ภาพที่ 1 เวลาหน่วงของภาพเมื่อผู้รับช้ากว่าผู้ส่ง

จับคู่ข้อมูลจากหลายเซนเซอร์ตามเวลา

การหลอมรวมกล้องกับ LiDAR ต้องใช้ข้อความที่วัดในเวลาใกล้กัน แพ็กเกจ message_filters ของ ROS มี ApproximateTimeSynchronizer ซึ่งรับพารามิเตอร์ slop เป็นวินาทีที่กำหนดว่าข้อความต่างเวลากันได้มากเท่าใดจึงจับคู่กันได้ ตัวอย่างต่อไปใช้วิธีอย่างง่ายคือหาภาพที่เวลาใกล้ที่สุดของแต่ละรอบ LiDAR ซึ่งง่ายกว่าอัลกอริทึมจริงของแพ็กเกจ แต่แสดงผลของ slop ได้ชัด

ตัวอย่างที่ 2 กล้อง 15 Hz กับ LiDAR 10 Hz

กล้องส่ง 15 Hz มีความแปรปรวนของเวลาเล็กน้อย LiDAR ส่ง 10 Hz เริ่มช้ากว่า 7 ms เป็นเวลา 2 s (ข้อมูลจำลอง)

import numpy as np

rng = np.random.default_rng(3)
cam = np.arange(0, 2.0, 1/15) + rng.normal(0, 0.004, 30)    # กล้อง 15 Hz
lidar = np.arange(0.007, 2.0, 1/10)                          # LiDAR 10 Hz

def pair(slop):
    pairs = []
    for t in lidar:
        j = np.argmin(np.abs(cam - t))
        if abs(cam[j] - t) <= slop:
            pairs.append((t, cam[j]))
    return pairs

for slop in [0.005, 0.020, 0.040]:
    p = pair(slop)
    gaps = [abs(a - b) * 1000 for a, b in p]
    print(f"slop {slop*1000:>2.0f} ms  paired {len(p)}/{len(lidar)}  "
          f"largest gap {max(gaps):.1f} ms")
slop  5 ms  paired 3/20  largest gap 3.2 ms
slop 20 ms  paired 10/20  largest gap 15.1 ms
slop 40 ms  paired 20/20  largest gap 34.1 ms

เพราะอัตรา 15 กับ 10 Hz ไม่ลงตัวกัน ครึ่งหนึ่งของรอบ LiDAR จึงมีภาพห่างเกิน 20 ms slop เล็กได้คู่ที่ตรงเวลาแต่น้อย slop ใหญ่ได้ครบแต่บางคู่ห่างกันถึง 34 ms ถ้ารถหมุนตัว 30 องศาต่อวินาที ความต่าง 34 ms เท่ากับทิศคลาดราว 1 องศา ทางแก้ที่ดีกว่าการขยาย slop คือทริกเกอร์เซนเซอร์ให้วัดพร้อมกัน หรือเลือกอัตราที่ลงตัวกัน

เส้นเวลา 0 ถึง 1 วินาทีสองแถว แถวบนคือจังหวะภาพกล้องสีฟ้า 15 ครั้ง แถวล่างคือจังหวะ LiDAR สีทอง 10 ครั้ง เส้นสีเขียวโยงคู่ที่ห่างไม่เกิน 20 มิลลิวินาทีห้าคู่ และจุดสีชมพูใต้รอบ LiDAR อีกห้ารอบที่ไม่มีคู่
ภาพที่ 2 จับคู่ข้อความกล้องกับ LiDAR ตามเวลา

ปฏิบัติการประจำโมดูล

ปฏิบัติการ: ตั้ง QoS และวัดเวลาหน่วงจริง

  1. เขียน node ส่งภาพจากกล้องฝึกที่ 30 Hz และ node รับที่หน่วงเวลา 50 ms ต่อภาพ ใส่เวลาประทับทุกข้อความ
  2. วัดจำนวนภาพที่ประมวลผลและเวลาหน่วงเมื่อ depth เป็น 1, 5 และ 10 เทียบกับตัวอย่างที่ 1
  3. ลองตั้ง reliability ของผู้ส่งกับผู้รับไม่เข้ากัน สังเกตผล แล้วใช้ ros2 topic info --verbose ตรวจ QoS
  4. บันทึก bag ของกล้องกับ LiDAR แล้วจับคู่ด้วย ApproximateTimeSynchronizer ที่ slop ต่างกัน นับจำนวนคู่
  5. สรุปตาราง QoS ที่เลือกสำหรับทุก topic ของรถ UGV พร้อมเหตุผล

ข้อผิดพลาดที่พบบ่อย

ระวัง

  • ใช้ reliable และคิวยาวกับภาพกล้อง จนภาพที่ประมวลผลเป็นภาพเก่า
  • ตั้ง QoS ผู้ส่งกับผู้รับไม่เข้ากัน แล้วคิดว่าโค้ดเสีย
  • ใช้เวลาที่รับข้อความแทนเวลาที่วัด ในการจับคู่
  • ขยาย slop จนจับคู่ข้อมูลที่ต่างเวลามาก
  • ไม่วัดเวลาหน่วงจริง ของทั้งสายตั้งแต่เซนเซอร์ถึงผลลัพธ์

สรุป

  • ROS 2 สร้างบน DDS มี topic, service และ action สำหรับงานต่างชนิด
  • QoS กำหนด history, depth และ reliability ให้เหมาะกับข้อมูลแต่ละแบบ
  • ผู้รับที่ช้ากว่าผู้ส่งต้องทิ้งข้อมูล คิวยาวทำให้เวลาหน่วงเพิ่ม
  • การจับคู่ตามเวลาต้องเลือก slop อย่างระวัง และดีที่สุดคือให้เซนเซอร์วัดพร้อมกัน

แบบฝึกตรวจความเข้าใจ

  1. งานใดควรใช้ action แทน service
  2. keep last depth 5 หมายความว่าอะไร
  3. ผู้ส่ง 30 Hz และคิว depth 10 เต็ม ภาพเก่าสุดในคิวรอมานานประมาณเท่าใด
  4. ทำไมโปรไฟล์ข้อมูลเซนเซอร์จึงใช้ best effort
  5. ถ้ารถหมุน 30 องศาต่อวินาที และคู่ข้อมูลต่างเวลากัน 20 ms ทิศคลาดเท่าใด
เฉลย
  1. งานที่ใช้เวลานานและต้องรายงานความคืบหน้าหรือยกเลิกได้ เช่นสั่งรถวิ่งไปยังตำแหน่ง
  2. เก็บเฉพาะ 5 ข้อความล่าสุด ข้อความเก่ากว่าถูกทิ้ง
  3. ประมาณ s
  4. ข้อมูลล่าสุดสำคัญกว่าการได้ข้อมูลเก่าครบ และการส่งซ้ำทำให้ช้า

สรุปสูตรสำคัญ

อายุของข้อความเก่าสุดในคิวเต็ม
เงื่อนไขจับคู่ตามเวลา

แหล่งอ้างอิงหลัก

  1. Open Robotics. ROS 2 documentation. link
  2. Macenski, S., Foote, T., Gerkey, B., Lalancette, C., & Woodall, W. (2022). Robot Operating System 2: Design, architecture, and uses in the wild. Science Robotics, 7(66), eabm6074. link
  3. Open Robotics. Quality of Service settings. ROS 2 documentation (Jazzy). link
  4. Open Robotics. Approximate synchronizer (Python). message_filters documentation (ROS 2 Jazzy). link

อ่านเพิ่มเติม

ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล

ในชั้นเรียน / ภาคสนาม

ปฏิบัติการในห้องแล็บหรือภาคสนามตามใบงาน พร้อม checklist ความปลอดภัย

หลักฐานการเรียนรู้: ใบงานที่ผ่านการตรวจและผล quiz

แบบทดสอบประจำโมดูล

แบบทดสอบนี้ใช้ตรวจความเข้าใจ (formative) ไม่ใช่การสอบเก็บคะแนน

โดเมนความรู้: ระบบอัตโนมัติ หุ่นยนต์ และฝูงโดรน · การเขียนโปรแกรมและเทคโนโลยีดิจิทัล · เซนเซอร์และระบบสมองกลฝังตัว · ปัญญาประดิษฐ์และคอมพิวเตอร์วิทัศน์