วางแผนเส้นทางและ waypoint
UAT 304 การวางแผนภารกิจและการบินอัตโนมัติของระบบอากาศยานไร้คนขับ
บทเรียน
เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ
- จัดลำดับจุดตรวจด้วยวิธีเพื่อนบ้านใกล้สุดและปรับปรุงด้วย 2-opt
- แบ่งเส้นทางเป็นหลายเที่ยวบินตามข้อจำกัดของแบตเตอรี่
- ตั้งค่า waypoint ความสูง และความเร็วให้ตรงกับงาน
- ตรวจแผนเส้นทางกับพื้นที่ห้ามบินและสิ่งกีดขวางก่อนอัปโหลด
ทำไมต้องรู้
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 ซึ่งอยู่ใกล้กัน แทนที่จะทิ้งไว้เป็นจุดสุดท้ายแล้วบินกลับไกล ระยะรวมลดลงเล็กน้อยในกรณีนี้ แต่เมื่อจุดมากขึ้นหรือกระจายกว่านี้ ส่วนต่างมักมากขึ้น ทั้งสองวิธีไม่รับประกันคำตอบดีที่สุด แต่เร็วพอสำหรับงานภาคสนาม
แบ่งเป็นหลายเที่ยวบิน
แบตเตอรี่หนึ่งก้อนบินได้จำกัด เมื่อเส้นทางยาวเกิน ต้องแบ่งเป็นหลายเที่ยว แต่ละเที่ยวเริ่มและจบที่จุดขึ้นบิน ระยะสูงสุดต่อเที่ยวต้องหักพลังงานสำรองสำหรับ 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) ซึ่งพิจารณาการแบ่งกับลำดับพร้อมกัน
ตั้งค่า waypoint
- ความสูง ต้องระบุว่าเทียบกับจุดขึ้นบิน ระดับทะเล หรือพื้นดินใต้โดรน (terrain following) ในพื้นที่ลาดชัน ความสูงเทียบจุดขึ้นบินอาจทำให้โดรนเข้าใกล้พื้นหรือสิ่งกีดขวางมากเกินไป
- ความเร็ว ใน ArduPilot Copter 4.6 ตั้งด้วย
WPNAV_SPEEDหน่วย cm/s แต่รุ่น 4.7 เปลี่ยนเป็นWP_SPDหน่วย m/s และเปลี่ยนระหว่างภารกิจได้ด้วยคำสั่ง DO_CHANGE_SPEED เลือกความเร็วตามงาน: ถ่ายภาพนิ่งที่จุดตรวจอาจหยุดลอยตัว ส่วนการบินระหว่างจุดใช้ความเร็วที่ประหยัดพลังงาน - การกระทำที่จุด เช่น หมุนกล้อง ถ่ายภาพ หรือหยุดรอ ต้องมีเวลาเผื่อในการคำนวณเวลาบิน
- ตรวจก่อนอัปโหลด ด้วยโปรแกรมตามที่เรียนใน UAT 301 โมดูล 3 ทั้งความสูง ขอบเขต และคำสั่งสุดท้าย
ปฏิบัติการประจำโมดูล
ปฏิบัติการ: วางเส้นทางตรวจจุดในวิทยาเขต
- เลือกจุดตรวจ 8–12 จุดในวิทยาเขต อ่านพิกัดจากแผนที่ แล้วแปลงเป็นเมตรจากจุดขึ้นบิน
- จัดลำดับด้วยตัวอย่างที่ 1 และเทียบกับลำดับที่ทีมเลือกเองด้วยสายตา
- แบ่งเที่ยวบินด้วยตัวอย่างที่ 2 ตามระยะที่โดรนฝึกบินได้จริงหลังหักพลังงานสำรอง
- วางภารกิจใน QGroundControl ตั้งความสูง ความเร็ว และการกระทำที่แต่ละจุด แล้วบันทึกไฟล์ .plan
- บินจำลองใน SITL เทียบเวลาและระยะจริงกับที่คำนวณ
ข้อผิดพลาดที่พบบ่อย
ระวัง
- เรียงจุดตามหมายเลข แทนที่จะจัดลำดับตามระยะ
- ไม่เผื่อพลังงานสำรอง เมื่อแบ่งเที่ยวบิน
- ใช้ความสูงเทียบจุดขึ้นบินในพื้นที่ลาดชัน
- ลืมเวลาหยุดถ่ายภาพ ที่แต่ละจุด
- เชื่อว่าคำตอบของฮิวริสติกดีที่สุดเสมอ
สรุป
- การบินผ่านทุกจุดด้วยระยะสั้นที่สุดคือปัญหาการเดินทางของพนักงานขาย ใช้เพื่อนบ้านใกล้สุดแล้วปรับด้วย 2-opt
- เส้นทางยาวแบ่งเป็นหลายเที่ยว แต่ละเที่ยวต้องอยู่ในระยะที่แบตเตอรี่รองรับหลังหักสำรอง
- ตั้งความสูง ความเร็ว และการกระทำที่ waypoint ให้ตรงกับงานและภูมิประเทศ
- ตรวจแผนด้วยโปรแกรมก่อนอัปโหลดทุกครั้ง
แบบฝึกตรวจความเข้าใจ
- จุด A (0,0) B (300,400) ระยะเท่าใด
- เส้นทาง H-A-B-H ยาว 2,000 m และ H-B-A-H ยาว 1,800 m ควรเลือกเส้นทางใด
- 2-opt ปรับเส้นทางอย่างไร
- ถ้าเส้นทางยาว 7,900 m และบินได้เที่ยวละ 3,500 m ต้องบินอย่างน้อยกี่เที่ยว (ไม่นับระยะกลับเพิ่ม)
- ทำไมความสูงเทียบจุดขึ้นบินจึงอันตรายในพื้นที่ลาดชัน
เฉลย
- m
- H-B-A-H เพราะสั้นกว่า
- กลับลำดับช่วงหนึ่งของเส้นทาง ถ้าสั้นลงก็เก็บไว้ ทำซ้ำจนไม่มีการกลับใดสั้นลง
- เที่ยว แต่ในทางปฏิบัติมักต้องมากกว่านี้เพราะต้องบินกลับจุดขึ้นบินทุกเที่ยว
- พื้นดินอาจสูงขึ้นระหว่างทาง โดรนที่รักษาความสูงเทียบจุดขึ้นบินจะเข้าใกล้พื้นหรือสิ่งกีดขวาง
สรุปสูตรสำคัญ
| ความยาวเส้นทาง | |
| เงื่อนไขแต่ละเที่ยวบิน |
แหล่งอ้างอิงหลัก
- Croes, G. A. (1958). A method for solving traveling-salesman problems. Operations Research, 6(6), 791–812. link
- QGroundControl. QGroundControl user guide. link
- QGroundControl Dev Team. Plan file format. QGroundControl developer guide. link
- ArduPilot Dev Team. Mission command list. ArduPilot Copter documentation. link
- ArduPilot Dev Team. Parameter list (Copter stable V4.6.3). ArduPilot Copter documentation. link
- ArduPilot Dev Team. Parameter list (Copter stable V4.7.1). ArduPilot Copter documentation. link
อ่านเพิ่มเติม
ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล
ในชั้นเรียน / ภาคสนาม
ปฏิบัติการในห้องแล็บหรือภาคสนามตามใบงาน พร้อม checklist ความปลอดภัย
หลักฐานการเรียนรู้: ใบงานที่ผ่านการตรวจและผล quiz