บูรณาการระบบอัตโนมัติ
UAT 322 ปฏิบัติการปัญญาประดิษฐ์และการประกอบรวมระบบอากาศยานไร้คนขับอัตโนมัติ
บทเรียน
เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ
- อธิบายการแบ่งหน้าที่ระหว่างคอมพิวเตอร์บนลำกับตัวควบคุมการบิน และช่องทางเชื่อมต่อ uXRCE-DDS และ MAVLink
- แปลงพิกัดและมุมหันระหว่างระบบ ENU ของ ROS กับ NED ของ PX4 ได้ถูกต้อง
- อธิบายเงื่อนไขของโหมด Offboard และ Guided และจำลองการเฝ้าระวังเมื่อคำสั่งขาดหาย
- ประมาณงบเวลาหน่วงของเส้นทางตั้งแต่รับภาพจนถึงคำสั่งถึงตัวควบคุมการบิน
ทำไมต้องรู้
ตัวควบคุมการบินเก่งเรื่องรักษาท่าทางและตำแหน่งหลายร้อยครั้งต่อวินาที แต่ไม่มีกำลังพอจะรันโมเดล AI หรือสร้างแผนที่ งานเหล่านั้นจึงย้ายไปอยู่บน คอมพิวเตอร์บนลำ (companion computer) เช่น บอร์ด Jetson หรือ Raspberry Pi ที่คุยกับตัวควบคุมการบินตลอดเวลา เหมือนนักบินผู้ช่วยที่บอกทิศทางให้นักบินหลักซึ่งยังถือคันบังคับอยู่ ถ้าสองฝั่งเข้าใจทิศทางไม่ตรงกัน หรือผู้ช่วยเงียบไปกลางอากาศ ผลอาจร้ายแรง โมดูลนี้ฝึกเชื่อมทั้งสองฝั่งให้ถูกและปลอดภัย
ทั้งวิชาใช้กรณีสมมติเดียว: โดรนสำรวจอัตโนมัติที่มีคอมพิวเตอร์บนลำ ตรวจจับสิ่งกีดขวางด้วยกล้องและตัววัดระยะ และทดสอบจาก SITL ไปจนถึงภาคสนาม โค้ด Python ของทุกโมดูลดาวน์โหลดได้ที่ /downloads/uat-322/
แบ่งหน้าที่ให้ชัด
- ตัวควบคุมการบิน ประมาณสถานะด้วย EKF ควบคุมตำแหน่งและท่าทาง และ ถือสิทธิ์ failsafe ไว้เสมอ ไม่ว่าคอมพิวเตอร์บนลำจะสั่งอะไร
- คอมพิวเตอร์บนลำ รับรู้สิ่งแวดล้อม วางแผนเส้นทาง และส่ง setpoint (ตำแหน่ง ความเร็ว หรือมุมหันที่ต้องการ) ให้ตัวควบคุมการบิน
- สถานีภาคพื้น ใช้ตั้งค่า เฝ้าดู และสั่งยกเลิกภารกิจ
ช่องทางเชื่อมต่อมีสองแบบหลัก
| ช่องทาง | ใช้กับ | ลักษณะ |
|---|---|---|
| uXRCE-DDS | PX4 ตั้งแต่รุ่น v1.14 กับ ROS 2 | หัวข้อ uORB ของ PX4 ปรากฏเป็นหัวข้อ ROS 2 โดยตรง ต้องใช้ข้อความ px4_msgs ที่ตรงรุ่น ใน SITL รันตัวกลางด้วย MicroXRCEAgent udp4 -p 8888 |
| MAVLink | ทั้ง PX4 และ ArduPilot | ส่งข้อความเช่น SET_POSITION_TARGET_LOCAL_NED ผ่านไลบรารีอย่าง MAVSDK หรือ MAVROS |
ArduPilot ก็มีอินเทอร์เฟซ ROS 2 ในตัว (AP_DDS) เช่นกัน เอกสาร PX4 แนะนำ ROS 2 Jazzy บน Ubuntu 24.04 ส่วนไลบรารี MAVSDK สำหรับ Python ต้องระวังว่าแพ็กเกจ mavsdk รุ่น 4 เป็น API ใหม่ที่ต่างจากตัวอย่างรุ่นเก่า ตัวอย่างเดิมที่ใช้ mavsdk_server ย้ายไปเป็นแพ็กเกจ mavsdk-grpc จึงต้องตรึงรุ่นให้ตรงกับเอกสารที่อ่าน
ทิศทางต้องตรงกัน
ROS ใช้ ENU (x ไปตะวันออก y ไปเหนือ z ขึ้น) ตามมาตรฐาน REP 103 แต่ PX4 ใช้ NED (x ไปเหนือ y ไปตะวันออก z ลง) ถ้าส่งตำแหน่งจาก ROS ไป PX4 โดยไม่แปลง คำสั่ง “ขึ้นไป 3 เมตร” จะกลายเป็น “ลงไป 3 เมตร”
ตัวอย่างที่ 1 แปลงเป้าหมายจาก ENU เป็น NED
import math
def enu_to_ned(east, north, up):
return north, east, -up
def yaw_enu_to_ned(yaw_enu):
yaw = math.pi / 2 - yaw_enu
return math.atan2(math.sin(yaw), math.cos(yaw)) # จัดให้อยู่ในช่วง −π ถึง π
print("target NED:", enu_to_ned(10.0, 5.0, 3.0))
for deg in (0, 90, 180):
print(f"yaw ENU {deg:>3}° -> NED {math.degrees(yaw_enu_to_ned(math.radians(deg))):6.1f}°")
target NED: (5.0, 10.0, -3.0)
yaw ENU 0° -> NED 90.0°
yaw ENU 90° -> NED 0.0°
yaw ENU 180° -> NED -90.0°
เป้าหมายที่อยู่ทางตะวันออก 10 m เหนือ 5 m และสูง 3 m กลายเป็น (เหนือ 5, ตะวันออก 10, ลง −3) ใน NED ส่วนมุมหัน ENU วัดจากทิศตะวันออกทวนเข็มนาฬิกา แต่ NED วัดจากทิศเหนือตามเข็มนาฬิกา การหันไปทางตะวันออกจึงเป็น 0° ใน ENU แต่เป็น 90° ใน NED ถ้าใช้ไลบรารีแปลงอยู่แล้ว เช่น ข้อความ ROS 2 ของ PX4 ต้องอ่านเอกสารว่าแปลงให้แล้วหรือยัง เพื่อไม่แปลงซ้ำสองครั้ง
เมื่อคอมพิวเตอร์บนลำเงียบ
ในโหมด Offboard ของ PX4 คอมพิวเตอร์บนลำต้องส่งสัญญาณยืนยันว่ายังทำงานอยู่ต่อเนื่องอย่างน้อย 2 Hz และต้องเริ่มส่ง setpoint ก่อน สลับเข้าโหมด ถ้าสัญญาณขาดนานกว่าพารามิเตอร์ COM_OF_LOSS_T (ค่าเริ่มต้น 1.0 วินาที) PX4 จะออกจาก Offboard ไปทำตามที่ตั้งใน COM_OBL_RC_ACT (ค่าเริ่มต้นคือโหมด Position) ส่วน ArduPilot ในโหมด Guided แนะนำให้ส่งคำสั่งความเร็วซ้ำทุกวินาที และโดรนจะหยุดถ้าไม่ได้รับคำสั่งนาน 3 วินาที
ตัวอย่างที่ 2 จำลองการเฝ้าระวังคำสั่ง Offboard
คอมพิวเตอร์บนลำส่ง setpoint ที่ 10 Hz ตั้งแต่ 0 ถึง 3.0 วินาที แล้วค้างไปจนถึง 4.5 วินาที ตัวเฝ้าระวังตรวจทุก 0.05 วินาที
stamps = [round(0.1 * k, 1) for k in range(31)] + [round(4.5 + 0.1 * k, 1) for k in range(11)]
LOSS_T = 1.0 # s เท่ากับค่าเริ่มต้นของ COM_OF_LOSS_T
print("setpoints in the first second:", sum(s < 1.0 for s in stamps))
last, failsafe, i, t = None, None, 0, 0.0
while t <= 5.5:
while i < len(stamps) and stamps[i] <= t + 1e-9:
last = stamps[i]
i += 1
if last is not None and failsafe is None and t - last > LOSS_T:
failsafe = t
t = round(t + 0.05, 2)
print(f"failsafe at {failsafe} s (stream stopped after 3.0 s)")
setpoints in the first second: 10
failsafe at 4.05 s (stream stopped after 3.0 s)
ในวินาทีแรกมี setpoint 10 ครั้ง สูงกว่าขั้นต่ำ 2 Hz มาก เมื่อสัญญาณหยุดที่ 3.0 วินาที ระบบรู้ตัวที่ 4.05 วินาที ช่วงนั้นโดรนยังบินตาม setpoint สุดท้ายไปอีกกว่า 1 วินาที จึงต้องทดสอบใน SITL ว่าโดรนทำอะไรเมื่อคอมพิวเตอร์บนลำค้าง ก่อนขึ้นบินจริง
งบเวลาหน่วง
ทุกขั้นในเส้นทางตั้งแต่กล้องจนถึงตัวควบคุมการบินใช้เวลา ผลรวมคือ เวลาหน่วง (latency) ระหว่างนั้นโดรนยังเคลื่อนที่ต่อ
stages = {"camera frame": 33, "detector": 45, "planner": 12, "DDS link": 4, "FC control": 3} # ms
total = sum(stages.values())
speed = 5.0 # m/s
print(f"total latency {total} ms; at {speed} m/s the drone moves {speed * total / 1000:.2f} m before reacting")
total latency 97 ms; at 5.0 m/s the drone moves 0.48 m before reacting
ตัวเลขแต่ละขั้นเป็นค่าสมมติ ต้องวัดจริงบนฮาร์ดแวร์ของตนเอง (จะทำในโมดูล 4) งบเวลานี้บอกว่าต้องเผื่อระยะปลอดภัยเท่าใด และบอกว่าควรลดเวลาที่ขั้นไหนก่อน ในตัวอย่างนี้ตัวตรวจจับใช้เวลามากที่สุด
ปฏิบัติการประจำโมดูล
ปฏิบัติการ: เชื่อมคอมพิวเตอร์บนลำกับ PX4 SITL
- ติดตั้ง PX4 SITL กับ Gazebo และ ROS 2 ตามรุ่นที่เอกสาร PX4 ระบุ บันทึกรุ่นทุกตัวที่ใช้
- รัน
MicroXRCEAgent udp4 -p 8888แล้วตรวจว่าเห็นหัวข้อของ PX4 ใน ROS 2 เช่น ตำแหน่งและสถานะของลำ - เขียนโหนดที่ส่ง setpoint ต่อเนื่องก่อนสลับเข้าโหมด Offboard แล้วสั่งให้ขึ้นไปลอยตัวที่เป้าหมายใน ENU ที่แปลงเป็น NED ด้วยโค้ดตัวอย่างที่ 1
- หยุดโหนดกลางคัน วัดเวลาที่ PX4 ออกจาก Offboard จาก log แล้วเทียบกับ
COM_OF_LOSS_T - วัดเวลาหน่วงจริงของเส้นทางคำสั่งด้วย timestamp ทั้งสองฝั่ง และบันทึกผลลงสมุดปฏิบัติการ
ข้อผิดพลาดที่พบบ่อย
ระวัง
- ส่งพิกัด ENU ให้ PX4 โดยไม่แปลง หรือแปลงซ้ำสองครั้ง
- สลับเข้า Offboard ก่อนเริ่มส่ง setpoint จึงเข้าโหมดไม่ได้หรือออกทันที
- ให้คอมพิวเตอร์บนลำคุม failsafe แทนตัวควบคุมการบิน
- ใช้ตัวอย่างโค้ดต่างรุ่นกับไลบรารีที่ติดตั้ง เช่น MAVSDK รุ่น 4 กับตัวอย่างรุ่น gRPC
- ไม่ได้วัดเวลาหน่วงจริง แล้วใช้ค่าจากเอกสารผู้ผลิต
สรุป
- ตัวควบคุมการบินรักษาเสถียรภาพและถือสิทธิ์ failsafe ส่วนคอมพิวเตอร์บนลำรับรู้ วางแผน และส่ง setpoint
- PX4 เชื่อม ROS 2 ผ่าน uXRCE-DDS และทั้ง PX4 กับ ArduPilot รองรับ MAVLink
- ROS ใช้ ENU แต่ PX4 ใช้ NED ต้องแปลงทั้งตำแหน่งและมุมหัน
- Offboard ต้องได้สัญญาณอย่างน้อย 2 Hz และจะออกจากโหมดเมื่อขาดนานกว่า
COM_OF_LOSS_T - งบเวลาหน่วงบอกระยะที่โดรนเคลื่อนไปก่อนตอบสนอง
แบบฝึกตรวจความเข้าใจ
- จุด ENU (east 4, north −2, up 6) เป็นพิกัด NED อะไร
- มุมหัน ENU 45° เป็นมุมหัน NED เท่าใด
- โหมด Offboard ของ PX4 ต้องการ setpoint อย่างน้อยกี่ Hz
- เวลาหน่วงรวม 120 ms ที่ความเร็ว 6 m/s โดรนเคลื่อนไปกี่เมตรก่อนตอบสนอง
- ทำไม failsafe จึงควรอยู่ที่ตัวควบคุมการบิน ไม่ใช่คอมพิวเตอร์บนลำ
เฉลย
- (north −2, east 4, down −6) หรือ
- อย่างน้อย 2 Hz และต้องเริ่มส่งก่อนเข้าโหมด
- m
- คอมพิวเตอร์บนลำอาจค้างหรือผิดพลาดได้ ตัวควบคุมการบินจึงต้องตัดสินใจเองเมื่อคำสั่งขาดหรือผิดปกติ
สรุปสูตรสำคัญ
| แปลง ENU เป็น NED | |
| แปลงมุมหัน | |
| ระยะที่เคลื่อนไประหว่างเวลาหน่วง |
แหล่งอ้างอิงหลัก
- PX4 Autopilot. uXRCE-DDS (PX4-ROS 2/DDS bridge). PX4 user guide (main). link
- PX4 Autopilot. ROS 2 user guide (uXRCE-DDS bridge and frame conventions). PX4 user guide (main). link
- PX4 Autopilot. Offboard mode (multicopter). PX4 user guide (main). link
- ArduPilot Dev Team. Copter commands in Guided mode. ArduPilot developer documentation. link
- ArduPilot Dev Team. ROS 2 interfaces (AP_DDS). ArduPilot developer documentation. link
- MAVLink Development Team. MAVSDK guide. link
- Foote, T., & Purvis, M. (2010). REP 103: Standard units of measure and coordinate conventions. ROS Enhancement Proposals. link
อ่านเพิ่มเติม
ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล
สถาปัตยกรรม PX4 และ ArduPilot
ROS 2 และการเชื่อมต่อกับ flight stack
เนื้อหาเจาะลึก: จาก Embedded System สู่ AI Robot และ ROS
อ่าน MAVLink telemetry จาก SITL
ในชั้นเรียน / ภาคสนาม
ปฏิบัติการเข้มข้นในแล็บและภาคสนาม บันทึกผลลงสมุดปฏิบัติการ
หลักฐานการเรียนรู้: สมุดปฏิบัติการที่อาจารย์ลงนาม