ชมรมโดรน

3. โหมดฝูงบินและ CRC-16

เฟรมที่ขึ้นต้นด้วย 0xFA รหัสคำสั่งฝูง และการอ่านข้อมูลสถานะของโดรนแต่ละลำ จากบันทึกโปรโตคอล RCSA

บินโดรนลำเดียว ถ้าข้อความเพี้ยนไปหนึ่งไบต์ โดรนก็แค่ทำผิดหนึ่งครั้ง แต่ถ้าสั่งโดรน 20 ลำพร้อมกันแล้วข้อมูลเพี้ยน ทุกลำอาจทำผิดพร้อมกัน โหมดฝูงบินจึงเพิ่ม CRC-16 ท้ายเฟรมไว้ตรวจว่าข้อความมาครบ

เหมือนใบเสร็จที่มีเลขตรวจสอบท้ายใบ ผู้รับคำนวณเลขนั้นจากเนื้อความใหม่ ถ้าไม่ตรงกัน ก็รู้ทันทีว่าใบเสร็จผิด

หน้านี้อิงบันทึกเท่านั้น

โฟลเดอร์โค้ดของชมรม (drone_sanam5) ไม่มีโค้ดโหมดฝูงบิน ข้อมูลทั้งหมดมาจาก RCSA_PROTOCOL_FULL_NOTES.md ที่สกัดจากแอป RCSA 1.0.0 บันทึกไม่ได้ระบุรูปแบบพหุนามของ CRC จึงไม่เขียนสูตรให้ ข้อมูลระดับบิตของฝั่ง Flight Controller ก็ไม่มี

เฟรม

เฟรมของโหมดฝูงบินเริ่มด้วยไบต์ 0xFA ตามด้วยข้อมูล และจบด้วย CRC-16 สองไบต์ ต่ำก่อนสูง0xFAหัวเฟรมdata[ … ]ID คำสั่ง + พารามิเตอร์CRC loไบต์ต่ำCRC hiไบต์สูงCRC-16 คำนวณจากส่วนนี้ (ตามบันทึกโปรโตคอล)ตัวอย่างรหัสคำสั่งฝูง: takeOff = 0x01 · autoLand = 0x02 · moveXY = 0x03จาก RCSA_PROTOCOL_FULL_NOTES.md ส่วน 4–5
เฟรมฝูงบิน ขึ้นต้น 0xFA ตามด้วยข้อมูล และจบด้วย CRC-16 สองไบต์ ไบต์ต่ำก่อน

ตามบันทึก ฟังก์ชันส่งทั่วไปทำงานดังนี้

ส่ง = 0xFA + data[] + CRC16(data)

CRC16 เป็นแบบอิงตาราง (table-based) คืนค่า [crc_low, crc_high]
  • ใช้ได้ทั้งช่องทาง TCP และ UDP
  • ฝั่งรับ (ข้อมูลสถานะจากโดรน) ก็ขึ้นต้น 0xFA แล้วตามด้วยไบต์ความยาว ไบต์ชนิดข้อมูล payload และ CRC 2 ไบต์
  • รองรับโดรนสูงสุด 20 ลำ

รูปร่างของเฟรม

  1. FAหัว
  2. dataคำสั่ง+พารามิเตอร์
  3. loCRC ต่ำ
  4. hiCRC สูง

รหัสคำสั่งของโหมดฝูง

บันทึกแบ่งเป็นสองชุดตาราง ชุดแรกคือรหัสที่แอปส่งไปที่รีโมท (ชั้น 1 ในบท คำสั่งเดินทางยังไง) ชุดที่สองคือรหัสภายใน "ภารกิจ" ของโดรนแต่ละลำ

คำสั่งฝูง (ชุดรีโมท)

รหัสชื่อ
100 (0x64)formation_flightNum
101 (0x65)formation_calibration
102 (0x66)formation_takeOff
103 (0x67)formation_autoland
104 (0x68)formation_move
105 (0x69)formation_setZ
150 (0x96)formation_sendMission
151 (0x97)formation_start
152 (0x98)formation_stop
153 (0x99)formation_moveXYZ
162 (0xA2)formation_clear
255 (0xFF)all_autoLand

ยังมีอีกหลายตัว (วงกลม สามเหลี่ยม สี่เหลี่ยม ไฟ RGB) ดูตารางเต็มในบันทึก

คำสั่งในภารกิจของแต่ละลำ

รหัสชื่อรหัสชื่อ
0calibrate8flip
1takeOff9jump
2autoLand10moveXYZ
3moveXY11atti
4speed12circle
5moveZ13circleAlt
6yaw50RGB
7local36051int

รหัส takeOff = 1 ในตารางนี้ ไม่ใช่ takeOff = 16 ของรีโมท และไม่ใช่ F_ARM = 1 ในแพ็กเก็ต I2C ทั้งสามเป็นตารางคนละชุด

ข้อมูลสถานะที่โดรนส่งกลับ

สำหรับข้อมูลชนิดหนึ่ง (บันทึกระบุ u=1, f=8) payload ถอดรหัสได้ดังนี้

payload สถานะของโดรน 1 ลำ

  1. X[0–1] int16
  2. Y[2–3] int16
  3. Z[4–5] int16
  4. V[6] แบต ×0.1
  5. R[7] กำลังรัน
  6. CS[8–9] checksum ภารกิจ
  7. ID[12–15] รหัสลำ
  8. T[16–19] เวลา uint32

ไบต์ [10]–[11] ไม่ได้ระบุไว้ในบันทึก และตำแหน่ง X Y ถูกแปลงเป็นช่องตาราง (grid/code index) ด้วยเซลล์ละ 40 หน่วย

นอกจากนี้บันทึกยังพบสตรีมเซนเซอร์แยกต่างหากที่ขึ้นต้น 0xFA เช่นกัน ถอดรหัสได้ความสูง ความดัน อุณหภูมิ ความเร่ง ไจโร มุม roll/pitch/yaw ระยะจากเรนจ์ไฟน์เดอร์ ความเร็ว แรงดันแบต และข้อมูลกล้อง (รายชื่อฟิลด์เท่านั้น ไม่มีตำแหน่งไบต์)

แนวคิดที่เอาไปใช้เองได้

แม้ชมรมไม่ได้ใช้โหมดฝูง แนวคิด "หัวเฟรม + ความยาว + ข้อมูล + CRC" ใช้ได้กับทุกการสื่อสาร เช่นส่งข้อมูลจาก Arduino ไปคอมพิวเตอร์เพื่อบันทึกการบิน แต่ต้องเลือกสูตร CRC เอง และตกลงกับฝั่งรับให้ตรงกัน อย่าเดาว่า CRC-16 ของ RCSA คือสูตรไหน

ลองทำ

  1. เขียนเฟรมสมมติ FA 01 02 lo hi แล้วอธิบายว่าส่วนไหนคือหัว ข้อมูล และ CRC (ไม่ต้องคำนวณ CRC)
  2. จากตาราง payload คำนวณว่าโดรนที่ส่งไบต์ [6] = 0x4A มีแรงดันแบตเท่าไร (74 × 0.1 = 7.4)
  3. ตอบ: ทำไมต้องระบุจำนวนโดรนสูงสุด 20 ลำในตัวรับ (คำใบ้: ขนาดบัฟเฟอร์ที่ต้องเตรียม)

พังตรงไหนบ่อย

  • เดาสูตร CRC CRC-16 มีหลายแบบ ค่าเริ่มต้น ทิศบิต และพหุนามต่างกันให้ผลต่างกัน บันทึกไม่ระบุ ต้องสกัดจากแอปหรือถามผู้ผลิต
  • สลับลำดับไบต์ CRC บันทึกบอกคืน [crc_low, crc_high] ต่ำก่อน
  • ใช้รหัสข้ามตาราง รหัสในภารกิจกับรหัสรีโมทคนละตาราง
  • คิดว่าอ่าน payload ทุกไบต์ได้ บางตำแหน่ง (เช่น [10]–[11]) ยังไม่ทราบความหมาย
  • ลืมว่าไม่มีโค้ดฝูงในโฟลเดอร์ชมรม ถ้าจะใช้ ต้องเขียนใหม่ทั้งหมดและทดสอบกับโดรนจริง

On this page