1. ปล่อยสัมภาระด้วยเซอร์โว
เซอร์โว 2 ตัวคุมประตูบอล 4 ช่อง อ่านค่า pulse 1900 / 1000 / 2550 / 490 จากโค้ดของชมรม
ภารกิจทิ้งสัมภาระต้องปล่อยลูกบอลลงแท่นให้ตรง ชุดปล่อยของชมรมใช้ เซอร์โว 2 ตัว แต่มี ประตู 4 ช่อง เพราะเซอร์โวหนึ่งตัวดันประตูได้สองบาน โดยดันไปคนละทิศ
คิดเหมือนประตูบานเลื่อนสองบานที่ผูกกับก้านเดียวกัน ดันก้านไปซ้ายบานหนึ่งเปิด ดันไปขวาอีกบานเปิด ตรงกลางคือปิดทั้งคู่
1. เซอร์โวฟังอะไร
เซอร์โวไม่รู้จักคำว่า "องศา" มันรู้จักแค่ ความกว้างของพัลส์ สายสัญญาณถูกยกเป็น HIGH ทุก 20 มิลลิวินาที ยาวกี่ไมโครวินาที เซอร์โวก็หมุนไปตำแหน่งนั้น
โค้ดเต็มของการส่งพัลส์อยู่ใน Servo.ino ฟังก์ชันเดียว
void release_servo_angle(uint8_t port_pin, int pulseWidth) {
uint32_t t = micros();
while (micros() - t < 1500000) {
digitalWrite(port_pin, HIGH);
delayMicroseconds(pulseWidth);
digitalWrite(port_pin, LOW);
delayMicroseconds(20000 - pulseWidth);
}
}อ่านทีละบรรทัด
- วนซ้ำ 1.5 วินาที (1,500,000 µs) ให้เซอร์โวมีเวลาไปถึงตำแหน่ง
- ยกขา HIGH ค้างเท่า
pulseWidthแล้วกด LOW ที่เหลือของเฟรม 20,000 µs - ฟังก์ชันนี้ บล็อกโปรแกรม ตลอด 1.5 วินาที ระหว่างนั้น Arduino ทำอย่างอื่นไม่ได้
ถ้าสั่งสองตัวพร้อมกัน ใช้ release_dual_servo_angle(pin1, pulse1, pin2, pulse2) ฟังก์ชันนี้ยก HIGH พร้อมกัน ตัวที่พัลส์สั้นกว่าลง LOW ก่อน แล้วรอส่วนต่าง จากนั้นปิดทั้งคู่
2. ใช้พอร์ตไหน
protocol.hpp กำหนดขาของแต่ละพอร์ต ชุดปล่อยบอลใน Drone_Mission.ino ใช้สองพอร์ต
| พอร์ต | ช่องที่คุม | ค่าคงที่ |
|---|---|---|
PORT3 | ช่อง 1 และ 2 | BALL_SERVO_12_PIN |
PORT6 | ช่อง 3 และ 4 | BALL_SERVO_34_PIN |
3. ค่า pulse ในโค้ดมีสองชุด
ในโฟลเดอร์ drone_sanam5 มีค่า pulse ปรากฏสองชุด ที่ไม่เหมือนกัน ดูทั้งสองชุดให้ชัดก่อนแก้อะไร
Servo.ino · README.ino · Test_ball.ino | Drone_Mission.ino (ที่ภารกิจใช้) | |
|---|---|---|
| ปิด | 1900 | 1200 (BALL_12_CLOSE_US, BALL_34_CLOSE_US) |
| ช่อง 1 | 1000 | 450 |
| ช่อง 2 | 2550 | 2000 |
| ช่อง 3 | 1000 (PORT6) | 1900 |
| ช่อง 4 | 2550 (PORT6) | 500 |
| เปิดทั้งหมด | 490 (drop_payload_all4) หรือ 2550 | 2550 (PORT3) และ 2600 (PORT6) |
เลข 1900 จึงมีความหมายไม่เหมือนกัน ในชุดแรกคือ "ปิด" ในชุดหลังคือ "เปิดช่อง 3" ชุดแรกเขียนไว้ให้ทดสอบทีละพอร์ต ส่วนชุดหลังคือชุดที่ setupDroneMissionMode() ใช้ตอนเริ่มต้น (มันเรียก close_all_ball_gate() ซึ่งใช้ 1200)
อย่าผสมสองชุด
ถ้าเรียก release_servo_angle(PORT3, 1900) ในโค้ดภารกิจ ประตูจะไม่ปิดเหมือนที่ README บอก เพราะตำแหน่งปิดของชุดภารกิจคือ 1200 ดูว่าไฟล์ไหนเป็นต้นทางของค่านั้นก่อนคัดลอก
4. ขั้นตอนปล่อยจริง (ดูภาพก่อน แล้วอ่านโค้ดตามลำดับ)
drone.sh(HEIGHT_DROP);ลูกศรแดง = ทิศหัวโดรน · เส้นฟ้า = เส้นทาง · ภาพช่วยเข้าใจ ไม่ใช่สเกลจริง
1ตั้งความสูง 45 ซม.
โดรนปรับแรงยกให้ลอยที่ความสูง 45 ซม. จากพื้น ถ้าอยู่ต่ำกว่าจะขึ้น ถ้าสูงกว่าจะลง
เวลาจริงบนโดรนประมาณ 0.40 วินาที (ในภาพเร่งให้ดูง่าย)
ภารกิจไม่ได้เรียก release_servo_angle ตรงๆ แต่ห่อเป็นชื่อที่อ่านง่ายใน Drone_Mission.ino
void open_pair_ch1_ch4() {
drone.servoReleaseDual(
BALL_SERVO_12_PIN, BALL_CH1_OPEN_US,
BALL_SERVO_34_PIN, BALL_CH4_OPEN_US);
}
void mission_drop_ch1_ch4() {
open_pair_ch1_ch4();
delay(MISSION_DROP_WAIT_MS); // 300 ms
close_all_ball_gate();
delay(MISSION_CLOSE_WAIT_MS); // 100 ms
}ปล่อยเป็นคู่ ช่อง 1 กับ 4 หรือ ช่อง 2 กับ 3 ตัวแปร payload_round10 ในโค้ดอธิบายไว้ว่า 0 = ปล่อยช่อง 1&4 และ 1 = ปล่อยช่อง 2&3 ซึ่งตรงกับตัวจำลองบนเว็บนี้ที่ตั้งแท่นฝั่งซ้ายเป็นประตู 1&4 และฝั่งขวาเป็น 2&3
ลองนับเวลาหนึ่งครั้งที่ปล่อย เพราะฟังก์ชัน servo บล็อก 1.5 วินาทีต่อครั้ง
เปิดคู่ 1.5 วินาที
รอ 0.3 วินาที (MISSION_DROP_WAIT_MS)
ปิดทุกช่อง 1.5 วินาที
รอ 0.1 วินาที (MISSION_CLOSE_WAIT_MS)
รวม ≈ 3.4 วินาที ต่อการปล่อยหนึ่งครั้งสี่แท่นก็ราว 13.6 วินาที ตัวเลขนี้คำนวณจากค่าในโค้ด ไม่ได้จับเวลาจริง ต้องเผื่อไว้ในงบ 150 วินาที
5. ฟังก์ชันปล่อยตามรอบใน Servo.ino
Servo.ino มีชุดฟังก์ชันที่เลือกการปล่อยตามหมายเลขรอบ (round) เพื่อไม่ต้องเขียนเลขซ้ำ
| ฟังก์ชัน | รอบ 0 | รอบ 1 | รอบ 2 | รอบ 3 |
|---|---|---|---|---|
drop_payload_by_round05 | PORT3 → 1000 | PORT6 → 1000 | PORT3 → 2550 | PORT6 → 2550 |
drop_payload_by_round10 | คู่ PORT3 1000 · PORT6 1000 | คู่ 2550 | คู่ 1000 | คู่ 2550 |
drop_payload_by_round_all | คู่ 1000 | คู่ 2550 | ไม่มี | ไม่มี |
และ drop_payload_all4() เปิดสุดที่ 490 รอ 300 ms แล้วกลับมาที่ 1900
void drop_payload_all4() {
release_dual_servo_angle(PORT6, 490, PORT3, 490);
delay(300);
release_dual_servo_angle(PORT6, 1900, PORT3, 1900);
}ถ้าเขียนด้วย DroneEasy เรียกผ่านชื่อสั้น ๆ ได้เลย เช่น drone.dropPayloadRound05(0) หรือ drone.servoReleaseDual(PORT3, 1000, PORT6, 1000)
ลองทำ
- เปิด
Test_ball.inoอ่านลำดับในtest_release_the_ball()ทีละบรรทัด เดาก่อนว่าประตูไหนจะขยับ แล้วค่อยรันกับชุดบนโต๊ะ (ถอดใบพัดก่อนเสมอ) - ลองเลื่อนค่าเปิดช่อง 1 (450) ขึ้นทีละ 25 แล้วดูว่าประตูเปิดกว้างขึ้นหรือแคบลง จดค่าที่บอลหลุดครบพอดี
- คำนวณเวลาปล่อยทั้ง 4 แท่นของท่า T เมื่อใช้
mission_drop_ch1_ch4สองครั้งและmission_drop_ch2_ch3สองครั้ง ว่าเหลือเวลาบินกี่วินาทีจาก 150 - ดูโดรนปล่อยบอลในตัวจำลอง
พังตรงไหนบ่อย
- ประตูไม่ปิดสนิท บอลหลุดระหว่างบิน ปรับค่าปิด (1200 ในชุดภารกิจ) ทีละ 25–50 ตามที่
README.inoแนะนำ - เซอร์โวสั่นแล้วร้อน ค่า pulse ต่ำหรือสูงเกินช่วงที่กลไกไปถึงได้ เซอร์โวดันชนขอบ คอมเมนต์ในโค้ดเขียนไว้ว่าค่าต่ำไปทำให้เซอร์โวดันสุดแล้วสั่น
- ใช้ค่าผิดชุด คัดลอก 1900 จาก README ไปใช้ในโค้ดภารกิจ แล้วประตูช่อง 3 เปิดเอง
- ลืม
pinModeถ้าขาไม่ได้เป็น OUTPUT เซอร์โวนิ่งsetupDroneMissionMode()ตั้งPORT3กับPORT6ไว้แล้ว อย่าลบ - นับเวลาไม่ครบ ฟังก์ชัน servo บล็อกทีละ 1.5 วินาที หลายครั้งรวมกันกินงบเวลาจากที่คิดไว้
- เปิดคู่ผิดคู่ ปล่อยช่อง 1&4 ที่แท่นซ้ายแล้วค่อยปล่อย 2&3 ที่แท่นขวา ถ้าสลับ บอลจะลงผิดแท่น
อ่านต่อที่ การจูนเซอร์โวด้วยองศา เพื่อเลิกจำเลข µs ด้วยมือ