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 ปัดเศษให้เป็นจำนวนเต็ม
2. ตัวอย่างคำนวณ: pArduino->move_left_cm(100) ส่งอะไร รอกี่ ms
ทำตามทีละขั้น ใช้ดูได้กับทุกคำสั่ง move_*_cm
-
เปิดโค้ดของคำสั่งนั้น ใน
protocol.cppvoid 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); } -
หา direction บรรทัดแรกเขียน
set_direction(3, ...)จึงเป็น dir 3 (1 = หน้า, 2 = หลัง, 3 = ซ้าย, 4 = ขวา) -
หา speed ใน
protocol.hppประกาศmove_left_cm(uint16_t distance_cm, uint8_t speed = 2)ถ้าเราไม่ใส่ speed ค่าตั้งต้นคือ 2 -
หาตัวคูณ ฟังก์ชันใช้
MS_PER_CM_LEFTเปิดconfig.hppได้ 15.65 (ms ต่อ 1 ซม.) -
คูณ 100 ซม. × 15.65 = 1565 ms (
ms_roundปัดเป็นจำนวนเต็ม ตรงนี้พอดีเลยไม่มีเศษ) -
ดูว่าทิ้งท้ายด้วยอะไร
poshold(speed)คือset_direction(7, 2)สั่งหยุดลอยนิ่ง (dir 7)
สรุปว่าบรรทัดเดียวนี้ทำ 3 อย่างตามลำดับ
| ลำดับ | สิ่งที่เกิด | ค่า |
|---|---|---|
| 1 | ส่ง set_direction | dir 3, speed 2 |
| 2 | delay | 100 × 15.65 = 1565 ms |
| 3 | ส่ง poshold (เบรก) | set_direction(7, 2) |
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
ลองเปลี่ยนเป็นคำสั่งอื่นดู ตอบได้ด้วยวิธีเดียวกัน
| คำสั่ง | dir | speed | ตัวคูณ | เวลารอ |
|---|---|---|---|---|
move_forward_cm(250) | 1 | 2 | 15.46 | 3865 ms |
move_backward_cm(100) | 2 | 2 | 15.16 | 1516 ms |
move_left_cm(100) | 3 | 2 | 15.65 | 1565 ms |
move_right_cm(200) | 4 | 2 | 15.65 | 3130 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 ms | 152 ms | 157 ms | 119 ms |
| 50 ซม. | 773 ms | 758 ms | 783 ms | 595 ms |
| 100 ซม. | 1546 ms | 1516 ms | 1565 ms | 1189 ms |
| 250 ซม. | 3865 ms | 3790 ms | 3913 ms | 2973 ms |
| 300 ซม. | 4638 ms | 4548 ms | 4695 ms | 3567 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. วัดเองทีละขั้น
ใช้โค้ดสั้นนี้ใน 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 ÷ ระยะที่วัดได้ (ซม.)ตัวอย่างบันทึกผล (ตัวเลขสมมติ เพื่อแสดงวิธีคิด ไม่ใช่ผลวัดจริง)
| รอบ | เวลาที่สั่ง | ระยะที่วัดได้ |
|---|---|---|
| 1 | 3000 ms | 190 ซม. |
| 2 | 3000 ms | 195 ซม. |
| 3 | 3000 ms | 192 ซม. |
| 4 | 3000 ms | 188 ซม. |
| 5 | 3000 ms | 193 ซม. |
| เฉลี่ย | 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.*
ลองทำ
- คำนวณเวลาของ
drone.ml(255)ด้วยมือ (ตอบ: 255 × 15.65 = 3991 ms) - วัดค่า ms/cm ทิศหน้าของโดรนตัวคุณเอง 5 รอบ ลงตารางแล้วเทียบกับ 15.46
- ลองวัดอีกครั้งหลังบินไป 5 รอบ ค่าเปลี่ยนไหม (แบตลด)
พังตรงไหนบ่อย
- ใช้ค่าจากคู่มือโดยไม่วัด ได้ระยะเพี้ยนทั้งภารกิจ
- วัดตอนแบตเต็ม แต่แข่งตอนแบตเหลือครึ่ง ระยะสั้นลง วัดและแข่งที่ระดับแบตใกล้กัน
- วัดแค่รอบเดียว รอบเดียวพลาดได้ ใช้ค่าเฉลี่ย 5 รอบ
- วัดจากจุดที่โดรนเริ่มหยุด ไม่ใช่จุดที่หยุดสนิท ต้องรอจนนิ่ง
- ใช้ค่าซ้าย-ขวาของหน้ากับหลัง ทิศต่างกันค่าต่างกัน