ชมรมโดรน

5. ระยะกับเวลา และการวัดค่า ms/cm

โดรนกะระยะจากเวลา ค่า MS_PER_CM ใน config.hpp มาจากไหน และวิธีวัดเองทีละขั้น

โดรนของชมรมไม่มีสายวัดระยะแนวราบ มันแค่ "เหยียบคันเร่งทิศนี้ ความเร็วนี้ นานเท่านี้" แล้วหวังว่าจะไปถึงที่หมาย เหมือนขับรถด้วยนาฬิกา: ถ้ารู้ว่าความเร็วคงที่ 60 กม./ชม. ขับ 30 นาทีก็ได้ 30 กม. คำสั่ง fw(250) ใช้หลักเดียวกัน

1. สูตร

// protocol.cpp
set_direction(1, speed);
delay(ms_round(distance_cm * MS_PER_CM_FWD));
poshold(speed);

เวลา (ms) = ระยะ (ซม.) × MS_PER_CM ของทิศนั้น ค่า MS_PER_CM คือ "บินหนึ่งเซนติเมตรใช้กี่มิลลิวินาที" ms_round ปัดเศษให้เป็นจำนวนเต็ม

ระยะทางกับเวลา delayยิ่งไกลยิ่งต้องรอนาน เส้นตรง ความชันคือ ms ต่อ cm0100200300012345ระยะ (ซม.)เวลา (วินาที)ปกติ 15.2–15.7เร็ว 11.89250 ซม. → 3865 ms
เส้นตรงจากจุดศูนย์: ยิ่งไกลยิ่งต้อง delay นาน ความชันคือค่า ms/cm แถบฟ้าคือช่วงของทิศปกติ 15.16–15.65 เส้นแดงคือแบบเร็ว 11.89

2. ตัวอย่างคำนวณ: pArduino->move_left_cm(100) ส่งอะไร รอกี่ ms

ทำตามทีละขั้น ใช้ดูได้กับทุกคำสั่ง move_*_cm

  1. เปิดโค้ดของคำสั่งนั้น ใน protocol.cpp

    void Arduino::move_left_cm(uint16_t distance_cm, uint8_t speed) {
      set_direction(3, speed);                              // 3 = left
      delay(ms_round(distance_cm * MS_PER_CM_LEFT));
      poshold(speed);
    }
  2. หา direction บรรทัดแรกเขียน set_direction(3, ...) จึงเป็น dir 3 (1 = หน้า, 2 = หลัง, 3 = ซ้าย, 4 = ขวา)

  3. หา speed ใน protocol.hpp ประกาศ move_left_cm(uint16_t distance_cm, uint8_t speed = 2) ถ้าเราไม่ใส่ speed ค่าตั้งต้นคือ 2

  4. หาตัวคูณ ฟังก์ชันใช้ MS_PER_CM_LEFT เปิด config.hpp ได้ 15.65 (ms ต่อ 1 ซม.)

  5. คูณ 100 ซม. × 15.65 = 1565 ms (ms_round ปัดเป็นจำนวนเต็ม ตรงนี้พอดีเลยไม่มีเศษ)

  6. ดูว่าทิ้งท้ายด้วยอะไร poshold(speed) คือ set_direction(7, 2) สั่งหยุดลอยนิ่ง (dir 7)

สรุปว่าบรรทัดเดียวนี้ทำ 3 อย่างตามลำดับ

ลำดับสิ่งที่เกิดค่า
1ส่ง set_directiondir 3, speed 2
2delay100 × 15.65 = 1565 ms
3ส่ง poshold (เบรก)set_direction(7, 2)
กำลังโหลดโดรน 3 มิติ…
pArduino->move_left_cm(100);

ลูกศรแดง = ทิศหัวโดรน · เส้นฟ้า = เส้นทาง · ภาพช่วยเข้าใจ ไม่ใช่สเกลจริง

เลื่อนไปทางซ้าย 100 ซม.

โดรนเอียงตัวเล็กน้อยแล้วเลื่อนไปทางซ้าย 100 ซม. โค้ดรอ 100 × 15.65 = 1565 ms จากนั้นสั่งเบรกให้ลอยนิ่ง

เวลาจริงบนโดรนประมาณ 1.96 วินาที (ในภาพเร่งให้ดูง่าย)

ข้อสังเกต: move_left_cm เองไม่รอหลังเบรก ถ้าใช้ drone.ml(100) จะมี settle(400) ต่อท้าย เวลารวมจึงเป็น 1565 + 400 = 1965 ms

ลองเปลี่ยนเป็นคำสั่งอื่นดู ตอบได้ด้วยวิธีเดียวกัน

คำสั่งdirspeedตัวคูณเวลารอ
move_forward_cm(250)1215.463865 ms
move_backward_cm(100)2215.161516 ms
move_left_cm(100)3215.651565 ms
move_right_cm(200)4215.653130 ms

3. หาตัวคูณเอง: ทำไมต้องหาและคิดยังไง

ตัวคูณคือ "เวลาที่ใช้ต่อ 1 ซม." ผู้ผลิตไม่ให้ค่านี้ ต้องวัดเอง หลักคิดมีข้อเดียว

ตัวคูณ = เวลาที่โดรนบิน ÷ ระยะที่มันไปได้จริง

วิธี A: วัดตรงๆ (ละเอียดที่สุด อยู่ในหัวข้อ 6 ด้านล่าง) สั่งบินด้วยเวลาคงที่ เช่น 3000 ms แล้ววัดว่าไปกี่ ซม.

วิธี B: แก้ค่าเดิมให้ตรง ถ้ามีค่าอยู่แล้ว แค่ปรับ ลองสั่ง move_left_cm(100) ด้วยตัวคูณเดิม แล้ววัดระยะที่ไปจริง

ตัวคูณใหม่ = ตัวคูณเดิม × ระยะที่สั่ง ÷ ระยะที่ไปได้จริง

ตัวอย่าง (ตัวเลขสมมติ เพื่อแสดงวิธีคิด)

  • สั่ง 100 ซม. ด้วยตัวคูณ 15.65 โดรนรอ 1565 ms
  • วัดได้จริงแค่ 92 ซม. แปลว่าโดรนช้ากว่าที่คิด (บินนาน 1565 ms ได้แค่ 92 ซม.)
  • ตัวคูณจริง = 1565 ÷ 92 = 17.01 ms/ซม.
  • ตัวคูณใหม่ = 15.65 × 100 ÷ 92 = 17.01 สองสูตรได้ค่าเดียวกัน
  • ใช้แล้วสั่ง 100 ซม. จะรอ 100 × 17.01 = 1701 ms ซึ่งนานขึ้นพอดีกับที่โดรนต้องใช้

ถ้าวัดได้ มากกว่า ที่สั่ง (เช่น 108 ซม.) ตัวคูณใหม่จะลดลง = 15.65 × 100 ÷ 108 ≈ 14.49

เคล็ดลับให้ค่าแม่นขึ้น

  • สั่งระยะไกลหน่อย (200–300 ซม.) การวัดคลาด 2 ซม. จะกระทบน้อยกว่าสั่ง 50 ซม.
  • ทำ 5 รอบแล้วเฉลี่ย
  • วัดในทิศทางเดียวกันกับที่จะใช้ หน้า หลัง ซ้าย ขวา ค่าไม่เท่ากัน
  • วัดที่แบตเตอรี่ระดับเดียวกับตอนแข่ง

4. ค่าใน config.hpp

// config.hpp
// constexpr float MS_PER_CM_FWD       = 16.39f;   // ค่าเก่า ถูกคอมเมนต์ไว้
constexpr float MS_PER_CM_FWD       = 15.46f;
constexpr float MS_PER_CM_BACK      = 15.16f;
constexpr float MS_PER_CM_LEFT      = 15.65f;
constexpr float MS_PER_CM_RIGHT     = 15.65f;

constexpr float MS_PER_CM_FWD_FAST  = 11.89f;
constexpr float MS_PER_CM_BACK_FAST = 11.89f;
constexpr float MS_PER_CM_LEFT_FAST = 11.89f;
constexpr float MS_PER_CM_RIGHT_FAST= 11.89f;
ระยะหน้า (15.46)หลัง (15.16)ซ้าย/ขวา (15.65)หน้าเร็ว (11.89)
10 ซม.155 ms152 ms157 ms119 ms
50 ซม.773 ms758 ms783 ms595 ms
100 ซม.1546 ms1516 ms1565 ms1189 ms
250 ซม.3865 ms3790 ms3913 ms2973 ms
300 ซม.4638 ms4548 ms4695 ms3567 ms

ความเร็วเฉลี่ยของ fw ประมาณ 100 ÷ 15.46 × 10 ≈ 65 ซม./วินาที ส่วนแบบเร็วประมาณ 84 ซม./วินาที ลองกรอกตัวเลขเอง:

delay ≈ 3865 ms ≈ 3.87 วินาที · ความเร็วเฉลี่ย ≈ 65 ซม./วินาที

คู่มือกับโค้ดไม่ตรงกัน ให้ยึดโค้ด และวัดเอง

คู่มือ PDF/HTML ของชมรมเขียน MS_PER_CM_FWD และ MS_PER_CM_BACK เป็น 16.39 แต่ config.hpp ตอนนี้เป็น 15.46 และ 15.16 (บรรทัด 16.39 ถูกคอมเมนต์ทิ้งไว้) หน้านี้ใช้ค่าตามโค้ด ตัวเลขทุกตัวเป็นค่าของโดรน แบต และพื้นสนามวันที่วัด ต้องวัดซ้ำกับโดรนที่จะใช้จริงทุกครั้งที่เปลี่ยนโดรน เปลี่ยนใบพัด หรือแบตเริ่มอ่อน

5. ทำไมต้องวัดซ้ำ

  • แบตเตอรี่: แรงดันลด แรงใบพัดลด ที่ speed เดิมโดรนช้าลง ระยะเท่าเดิมใช้เวลาเพิ่ม
  • น้ำหนัก: ติดชุดลูกบอลหรือชุดยิง โดรนหนักขึ้น เอียงตัวช้าลง
  • ลมและพื้น: Optical Flow มองพื้นเพื่อกันไหล พื้นเรียบสีเดียวทำให้คลาดเคลื่อน
  • speed ที่ใช้: ค่า MS_PER_CM_* วัดที่ speed 2 (กลุ่มปกติ) และ 3 (กลุ่ม fast) เปลี่ยน speed แล้วค่าไม่ตรง

6. วัดเองทีละขั้น

ขั้นตอนวัด ms ต่อ cm1ติดเทปที่พื้น ทำเส้นเริ่มและวัดระยะไว้2สั่งไปหน้า delay(3000) แล้ว poshold รอให้นิ่ง3วัดระยะที่โดรนหยุดจริง (ซม.)4ms/cm = 3000 ÷ ระยะ ทำ 5 รอบ แล้วเฉลี่ย5ใส่ค่าใน config.hpp แล้วลอง fw(100) เทียบ
ห้าขั้นตอนวัดค่า ms/cm ทำแล้วจดตารางเหมือนทดลองวิทยาศาสตร์

ใช้โค้ดสั้นนี้ใน handler ของปุ่มที่ว่าง (ตัวอย่างเขียนขึ้นใหม่ ไม่ได้อยู่ในไฟล์ของชมรม)

void TestMsPerCm() {
  drone.calibration();
  delay(3000);
  drone.takeOff();
  delay(4000);
  drone.sh(HEIGHT_TAKEOFF);

  pArduino->set_direction(1, 2);   // เริ่มบินหน้า speed 2
  delay(3000);                     // บินด้วยเวลาคงที่ 3000 ms
  pArduino->poshold(2);            // เบรก
  delay(1500);                     // รอให้นิ่งก่อนวัด
  drone.autoLand();
}

หลังโดรนลงจอด วัดว่ามันออกจากเส้นเริ่มไปกี่เซนติเมตร (วัดที่ตำแหน่งหยุดจริง ซึ่งรวมระยะเบรกไว้แล้ว เหมือนที่ fw ทำ) แล้วคำนวณ

ms/cm = 3000 ÷ ระยะที่วัดได้ (ซม.)

ตัวอย่างบันทึกผล (ตัวเลขสมมติ เพื่อแสดงวิธีคิด ไม่ใช่ผลวัดจริง)

รอบเวลาที่สั่งระยะที่วัดได้
13000 ms190 ซม.
23000 ms195 ซม.
33000 ms192 ซม.
43000 ms188 ซม.
53000 ms193 ซม.
เฉลี่ย191.6 ซม.

ms/cm = 3000 ÷ 191.6 ≈ 15.66 แล้วนำไปแทนใน config.hpp

constexpr float MS_PER_CM_FWD       = 15.66f;

ทำซ้ำทุกทิศ (หลัง ซ้าย ขวา) และทุกกลุ่ม (ปกติ, fast) แล้วทดสอบด้วย drone.fw(100) เทียบเทปวัด ถ้าคลาดเกิน 5 ซม. ทำขั้น 2–5 ใหม่

ถ้าอยากลองค่าโดยไม่แก้ config.hpp ใช้ drone.moveTimeDir(1, 100, 15.66f) แทน ดู drone.*

ลองทำ

  1. คำนวณเวลาของ drone.ml(255) ด้วยมือ (ตอบ: 255 × 15.65 = 3991 ms)
  2. วัดค่า ms/cm ทิศหน้าของโดรนตัวคุณเอง 5 รอบ ลงตารางแล้วเทียบกับ 15.46
  3. ลองวัดอีกครั้งหลังบินไป 5 รอบ ค่าเปลี่ยนไหม (แบตลด)

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

  • ใช้ค่าจากคู่มือโดยไม่วัด ได้ระยะเพี้ยนทั้งภารกิจ
  • วัดตอนแบตเต็ม แต่แข่งตอนแบตเหลือครึ่ง ระยะสั้นลง วัดและแข่งที่ระดับแบตใกล้กัน
  • วัดแค่รอบเดียว รอบเดียวพลาดได้ ใช้ค่าเฉลี่ย 5 รอบ
  • วัดจากจุดที่โดรนเริ่มหยุด ไม่ใช่จุดที่หยุดสนิท ต้องรอจนนิ่ง
  • ใช้ค่าซ้าย-ขวาของหน้ากับหลัง ทิศต่างกันค่าต่างกัน

On this page