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

วางแผนเส้นทางและ waypoint

UAT 304 การวางแผนภารกิจและการบินอัตโนมัติของระบบอากาศยานไร้คนขับ

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

บทเรียน

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

  1. จัดลำดับจุดตรวจด้วยวิธีเพื่อนบ้านใกล้สุดและปรับปรุงด้วย 2-opt
  2. แบ่งเส้นทางเป็นหลายเที่ยวบินตามข้อจำกัดของแบตเตอรี่
  3. ตั้งค่า waypoint ความสูง และความเร็วให้ตรงกับงาน
  4. ตรวจแผนเส้นทางกับพื้นที่ห้ามบินและสิ่งกีดขวางก่อนอัปโหลด

ความรู้พื้นฐานที่ควรมี: UAT 304 โมดูล 1–2 · UAT 312 โมดูล 1 (การวางแผนภารกิจ)

ทำไมต้องรู้

UAT 312 สอนวางแนวบินสำรวจแบบกลับไปกลับมาสำหรับทำแผนที่แล้ว งานอีกประเภทหนึ่งที่พบบ่อยคือ ตรวจเป็นจุด เช่น ตรวจเสาไฟ ถังเก็บน้ำ หรือจุดเสี่ยงน้ำท่วมหลายจุดในพื้นที่ ลำดับที่บินไปแต่ละจุดกำหนดระยะทางรวม เวลา และจำนวนเที่ยวบิน หน่วยความรู้เรื่องวางแผนบินเก็บภาพสำรวจของคลังความรู้โดรนเชื่อม GSD การซ้อนภาพ แนวบิน และภูมิประเทศเข้าด้วยกัน ส่วนหน่วยความรู้เรื่อง QGroundControl สาธิตการวาง waypoint และส่งออกภารกิจ กรณีของวิชานี้คือ ศูนย์ปฏิบัติการของเทศบาลแห่งหนึ่ง ที่ใช้โดรนหลายใบพัดตรวจพื้นที่ ตัวเลขเป็นข้อมูลสมมติ

ลำดับจุดตรวจ

ปัญหา “บินผ่านทุกจุดแล้วกลับบ้านด้วยระยะสั้นที่สุด” คือ ปัญหาการเดินทางของพนักงานขาย (traveling salesman problem) ซึ่งหาคำตอบดีที่สุดได้ยากเมื่อจุดมาก ในทางปฏิบัติใช้วิธีฮิวริสติก: เพื่อนบ้านใกล้สุด เลือกจุดที่ใกล้ที่สุดจากจุดปัจจุบันไปเรื่อย ๆ ได้คำตอบเร็วแต่มักมีเส้นตัดกัน ส่วน 2-opt (Croes, 1958) ลองกลับลำดับช่วงหนึ่งของเส้นทาง ถ้าสั้นลงก็เก็บไว้ ทำซ้ำจนไม่มีการกลับลำดับใดสั้นลง

ตัวอย่างที่ 1 จัดลำดับ 10 จุดตรวจ

พิกัดเป็นเมตรตะวันออกและเหนือจากจุดขึ้นบิน H

import math

pts = {"H": (0, 0), "P1": (420, 150), "P2": (900, -200), "P3": (1300, 400), "P4": (700, 800),
       "P5": (250, 1100), "P6": (-300, 900), "P7": (-600, 300), "P8": (-400, -500),
       "P9": (300, -700), "P10": (1100, -900)}

def dist(a, b):
    return math.dist(pts[a], pts[b])

def length(route):
    return sum(dist(route[i], route[i + 1]) for i in range(len(route) - 1))

left, route = [k for k in pts if k != "H"], ["H"]
while left:                                    # เพื่อนบ้านใกล้สุด
    nxt = min(left, key=lambda k: dist(route[-1], k))
    route.append(nxt)
    left.remove(nxt)
route.append("H")
print(f"nearest neighbour: {length(route):.0f} m  {'-'.join(route)}")

improved = True
while improved:                                # 2-opt
    improved = False
    for i in range(1, len(route) - 2):
        for j in range(i + 1, len(route) - 1):
            cand = route[:i] + route[i:j + 1][::-1] + route[j + 1:]
            if length(cand) < length(route) - 1e-9:
                route, improved = cand, True
print(f"after 2-opt:       {length(route):.0f} m  {'-'.join(route)}")
nearest neighbour: 8078 m  H-P1-P2-P3-P4-P5-P6-P7-P8-P9-P10-H
after 2-opt:       7916 m  H-P1-P2-P10-P3-P4-P5-P6-P7-P8-P9-H

2-opt ย้าย P10 ไปบินต่อจาก P2 ซึ่งอยู่ใกล้กัน แทนที่จะทิ้งไว้เป็นจุดสุดท้ายแล้วบินกลับไกล ระยะรวมลดลงเล็กน้อยในกรณีนี้ แต่เมื่อจุดมากขึ้นหรือกระจายกว่านี้ ส่วนต่างมักมากขึ้น ทั้งสองวิธีไม่รับประกันคำตอบดีที่สุด แต่เร็วพอสำหรับงานภาคสนาม

แผนที่จุดตรวจ 10 จุดรอบจุดขึ้นบิน H เส้นประสีเทาคือเส้นทางแบบเพื่อนบ้านใกล้สุดที่จบด้วยการบินกลับจาก P10 เส้นทึบสีฟ้าคือเส้นทางหลัง 2-opt ที่บิน P2 ไป P10 แล้วไป P3
ภาพที่ 1 เส้นทางแบบเพื่อนบ้านใกล้สุดและหลังปรับด้วย 2-opt

แบ่งเป็นหลายเที่ยวบิน

แบตเตอรี่หนึ่งก้อนบินได้จำกัด เมื่อเส้นทางยาวเกิน ต้องแบ่งเป็นหลายเที่ยว แต่ละเที่ยวเริ่มและจบที่จุดขึ้นบิน ระยะสูงสุดต่อเที่ยวต้องหักพลังงานสำรองสำหรับ RTL และลมแล้วตามที่เรียนใน UAT 312

ตัวอย่างที่ 2 แบ่งเส้นทางตามระยะต่อเที่ยว

โดรนบินได้ไม่เกิน 3,500 m ต่อเที่ยวหลังหักพลังงานสำรอง ใช้ลำดับจากตัวอย่างที่ 1 แล้วเติมจุดตามลำดับจนกว่าจะเกิน

import math

pts = {"H": (0, 0), "P1": (420, 150), "P2": (900, -200), "P3": (1300, 400), "P4": (700, 800),
       "P5": (250, 1100), "P6": (-300, 900), "P7": (-600, 300), "P8": (-400, -500),
       "P9": (300, -700), "P10": (1100, -900)}
order = ["P1", "P2", "P10", "P3", "P4", "P5", "P6", "P7", "P8", "P9"]   # จากตัวอย่างที่ 1
L_MAX = 3500                                   # m ต่อเที่ยว

def length(route):
    return sum(math.dist(pts[route[i]], pts[route[i + 1]]) for i in range(len(route) - 1))

sorties, cur = [], ["H"]
for p in order:
    if length(cur + [p, "H"]) <= L_MAX:
        cur.append(p)
    else:
        sorties.append(cur + ["H"])
        cur = ["H", p]
sorties.append(cur + ["H"])
for k, s in enumerate(sorties, 1):
    print(f"sortie {k}: {'-'.join(s):<20} {length(s):5.0f} m")
print(f"{len(sorties)} sorties, total {sum(length(s) for s in sorties):.0f} m")
sortie 1: H-P1-P2-P10-H         3189 m
sortie 2: H-P3-P4-H             3144 m
sortie 3: H-P5-P6-P7-H          3055 m
sortie 4: H-P8-P9-H             2130 m
4 sorties, total 11518 m

การแบ่งทำให้ระยะรวมเพิ่มขึ้น เพราะต้องบินกลับจุดขึ้นบินหลายครั้ง วิธีแบ่งตามลำดับแบบนี้ง่ายแต่ไม่ดีที่สุด ถ้าต้องการลดจำนวนเที่ยวหรือระยะรวมจริงจัง ต้องใช้วิธีจัดเส้นทางยานพาหนะ (vehicle routing) ซึ่งพิจารณาการแบ่งกับลำดับพร้อมกัน

แผนที่เดียวกันแบ่งเป็นสี่เที่ยวบินสี่สี เที่ยวที่ 1 H P1 P2 P10 เที่ยวที่ 2 H P3 P4 เที่ยวที่ 3 H P5 P6 P7 และเที่ยวที่ 4 H P8 P9 ทุกเที่ยวเริ่มและจบที่ H
ภาพที่ 2 เส้นทางที่แบ่งเป็นสี่เที่ยวบิน

ตั้งค่า waypoint

  • ความสูง ต้องระบุว่าเทียบกับจุดขึ้นบิน ระดับทะเล หรือพื้นดินใต้โดรน (terrain following) ในพื้นที่ลาดชัน ความสูงเทียบจุดขึ้นบินอาจทำให้โดรนเข้าใกล้พื้นหรือสิ่งกีดขวางมากเกินไป
  • ความเร็ว ใน ArduPilot Copter 4.6 ตั้งด้วย WPNAV_SPEED หน่วย cm/s แต่รุ่น 4.7 เปลี่ยนเป็น WP_SPD หน่วย m/s และเปลี่ยนระหว่างภารกิจได้ด้วยคำสั่ง DO_CHANGE_SPEED เลือกความเร็วตามงาน: ถ่ายภาพนิ่งที่จุดตรวจอาจหยุดลอยตัว ส่วนการบินระหว่างจุดใช้ความเร็วที่ประหยัดพลังงาน
  • การกระทำที่จุด เช่น หมุนกล้อง ถ่ายภาพ หรือหยุดรอ ต้องมีเวลาเผื่อในการคำนวณเวลาบิน
  • ตรวจก่อนอัปโหลด ด้วยโปรแกรมตามที่เรียนใน UAT 301 โมดูล 3 ทั้งความสูง ขอบเขต และคำสั่งสุดท้าย

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

ปฏิบัติการ: วางเส้นทางตรวจจุดในวิทยาเขต

  1. เลือกจุดตรวจ 8–12 จุดในวิทยาเขต อ่านพิกัดจากแผนที่ แล้วแปลงเป็นเมตรจากจุดขึ้นบิน
  2. จัดลำดับด้วยตัวอย่างที่ 1 และเทียบกับลำดับที่ทีมเลือกเองด้วยสายตา
  3. แบ่งเที่ยวบินด้วยตัวอย่างที่ 2 ตามระยะที่โดรนฝึกบินได้จริงหลังหักพลังงานสำรอง
  4. วางภารกิจใน QGroundControl ตั้งความสูง ความเร็ว และการกระทำที่แต่ละจุด แล้วบันทึกไฟล์ .plan
  5. บินจำลองใน SITL เทียบเวลาและระยะจริงกับที่คำนวณ

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

ระวัง

  • เรียงจุดตามหมายเลข แทนที่จะจัดลำดับตามระยะ
  • ไม่เผื่อพลังงานสำรอง เมื่อแบ่งเที่ยวบิน
  • ใช้ความสูงเทียบจุดขึ้นบินในพื้นที่ลาดชัน
  • ลืมเวลาหยุดถ่ายภาพ ที่แต่ละจุด
  • เชื่อว่าคำตอบของฮิวริสติกดีที่สุดเสมอ

สรุป

  • การบินผ่านทุกจุดด้วยระยะสั้นที่สุดคือปัญหาการเดินทางของพนักงานขาย ใช้เพื่อนบ้านใกล้สุดแล้วปรับด้วย 2-opt
  • เส้นทางยาวแบ่งเป็นหลายเที่ยว แต่ละเที่ยวต้องอยู่ในระยะที่แบตเตอรี่รองรับหลังหักสำรอง
  • ตั้งความสูง ความเร็ว และการกระทำที่ waypoint ให้ตรงกับงานและภูมิประเทศ
  • ตรวจแผนด้วยโปรแกรมก่อนอัปโหลดทุกครั้ง

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

  1. จุด A (0,0) B (300,400) ระยะเท่าใด
  2. เส้นทาง H-A-B-H ยาว 2,000 m และ H-B-A-H ยาว 1,800 m ควรเลือกเส้นทางใด
  3. 2-opt ปรับเส้นทางอย่างไร
  4. ถ้าเส้นทางยาว 7,900 m และบินได้เที่ยวละ 3,500 m ต้องบินอย่างน้อยกี่เที่ยว (ไม่นับระยะกลับเพิ่ม)
  5. ทำไมความสูงเทียบจุดขึ้นบินจึงอันตรายในพื้นที่ลาดชัน
เฉลย
  1. m
  2. H-B-A-H เพราะสั้นกว่า
  3. กลับลำดับช่วงหนึ่งของเส้นทาง ถ้าสั้นลงก็เก็บไว้ ทำซ้ำจนไม่มีการกลับใดสั้นลง
  4. เที่ยว แต่ในทางปฏิบัติมักต้องมากกว่านี้เพราะต้องบินกลับจุดขึ้นบินทุกเที่ยว
  5. พื้นดินอาจสูงขึ้นระหว่างทาง โดรนที่รักษาความสูงเทียบจุดขึ้นบินจะเข้าใกล้พื้นหรือสิ่งกีดขวาง

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

ความยาวเส้นทาง
เงื่อนไขแต่ละเที่ยวบิน

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

  1. Croes, G. A. (1958). A method for solving traveling-salesman problems. Operations Research, 6(6), 791–812. link
  2. QGroundControl. QGroundControl user guide. link
  3. QGroundControl Dev Team. Plan file format. QGroundControl developer guide. link
  4. ArduPilot Dev Team. Mission command list. ArduPilot Copter documentation. link
  5. ArduPilot Dev Team. Parameter list (Copter stable V4.6.3). ArduPilot Copter documentation. link
  6. ArduPilot Dev Team. Parameter list (Copter stable V4.7.1). ArduPilot Copter documentation. link

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

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

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

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

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

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

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

โดเมนความรู้: การสำรวจ ทำแผนที่ และภูมิสารสนเทศ · การวางแผนภารกิจ การบิน และการจำลอง